refactor: move llmExtract, extractMeta, buildDescriptor, types to workflow-util-role

workflow-role-llm now only contains LLM-as-agent specifics:
  - createRole (wires agent + extract)
  - createLlmAdapter (OpenAI chat completions agent)

workflow-util-role now provides all role infrastructure:
  - decorators (decorateRole, withDryRun, onFail)
  - llmExtract / extractMetaOrThrow (structured extraction)
  - buildDescriptorFromRoles (zod → JSON Schema)
  - LlmProvider, LlmMessage types
This commit is contained in:
2026-05-06 08:13:27 +00:00
parent 6e62c7458d
commit c04e7c31af
23 changed files with 53 additions and 35 deletions
@@ -7,7 +7,7 @@ import { promisify } from "node:util";
import type { AgentFn, ThreadContext } from "@uncaged/workflow"; import type { AgentFn, ThreadContext } from "@uncaged/workflow";
import { START } from "@uncaged/workflow"; import { START } from "@uncaged/workflow";
import * as roleLlm from "@uncaged/workflow-role-llm"; import * as utilRole from "@uncaged/workflow-util-role";
import { createCommitterRole } from "../src/committer.js"; import { createCommitterRole } from "../src/committer.js";
import { gitExec } from "../src/git-exec.js"; import { gitExec } from "../src/git-exec.js";
@@ -83,7 +83,7 @@ describe("createCommitterRole", () => {
const { repo } = await setupRepoWithRemote(); const { repo } = await setupRepoWithRemote();
await appendFile(join(repo, "README.md"), "\nmore\n", "utf8"); await appendFile(join(repo, "README.md"), "\nmore\n", "utf8");
const spy = spyOn(roleLlm, "extractMetaOrThrow").mockResolvedValue({ const spy = spyOn(utilRole, "extractMetaOrThrow").mockResolvedValue({
branch: "feat/test-commit", branch: "feat/test-commit",
message: "feat: add more", message: "feat: add more",
}); });
@@ -10,7 +10,6 @@
}, },
"dependencies": { "dependencies": {
"@uncaged/workflow": "workspace:*", "@uncaged/workflow": "workspace:*",
"@uncaged/workflow-role-llm": "workspace:*",
"@uncaged/workflow-util-role": "workspace:*", "@uncaged/workflow-util-role": "workspace:*",
"zod": "^4.0.0" "zod": "^4.0.0"
} }
@@ -1,7 +1,11 @@
import type { AgentFn, Role, RoleResult, ThreadContext } from "@uncaged/workflow"; import type { AgentFn, Role, RoleResult, ThreadContext } from "@uncaged/workflow";
import type { LlmProvider } from "@uncaged/workflow-role-llm"; import {
import { extractMetaOrThrow } from "@uncaged/workflow-role-llm"; decorateRole,
import { decorateRole, onFail, withDryRun } from "@uncaged/workflow-util-role"; extractMetaOrThrow,
type LlmProvider,
onFail,
withDryRun,
} from "@uncaged/workflow-util-role";
import * as z from "zod/v4"; import * as z from "zod/v4";
import { gitExec } from "./git-exec.js"; import { gitExec } from "./git-exec.js";
@@ -6,9 +6,5 @@
"composite": true "composite": true
}, },
"include": ["src/**/*.ts"], "include": ["src/**/*.ts"],
"references": [ "references": [{ "path": "../workflow" }, { "path": "../workflow-util-role" }]
{ "path": "../workflow" },
{ "path": "../workflow-role-llm" },
{ "path": "../workflow-util-role" }
]
} }
@@ -1,7 +1,7 @@
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"; import { afterEach, describe, expect, mock, spyOn, test } from "bun:test";
import type { AgentFn, ThreadContext } from "@uncaged/workflow"; import type { AgentFn, ThreadContext } from "@uncaged/workflow";
import { START } from "@uncaged/workflow"; import { START } from "@uncaged/workflow";
import * as extractMetaModule from "@uncaged/workflow-role-llm"; import * as extractMetaModule from "@uncaged/workflow-util-role";
import * as z from "zod/v4"; import * as z from "zod/v4";
import { createRole } from "../src/create-role.js"; import { createRole } from "../src/create-role.js";
@@ -1,6 +1,6 @@
import { type AgentFn, err, ok, type Result, type ThreadContext } from "@uncaged/workflow"; import { type AgentFn, err, ok, type Result, type ThreadContext } from "@uncaged/workflow";
import type { LlmMessage, LlmProvider } from "./types.js"; import type { LlmMessage, LlmProvider } from "@uncaged/workflow-util-role";
export type LlmChatError = export type LlmChatError =
| { kind: "http_error"; status: number; body: string } | { kind: "http_error"; status: number; body: string }
@@ -1,7 +1,6 @@
import type { AgentFn, Role, ThreadContext } from "@uncaged/workflow"; import type { AgentFn, Role, ThreadContext } from "@uncaged/workflow";
import { extractMetaOrThrow, type LlmProvider } from "@uncaged/workflow-util-role";
import type * as z from "zod/v4"; import type * as z from "zod/v4";
import { extractMetaOrThrow } from "./extract-meta.js";
import type { LlmProvider } from "./types.js";
export type CreateRoleArgs<M extends Record<string, unknown>> = { export type CreateRoleArgs<M extends Record<string, unknown>> = {
name: string; name: string;
+13 -13
View File
@@ -1,21 +1,21 @@
export { export {
buildDescriptorFromRoles,
decorateRole, decorateRole,
type OnFailOptions, extractMetaOrThrow,
onFail,
type RoleDecorator,
type WithDryRunOptions,
withDryRun,
} from "@uncaged/workflow-util-role";
export { buildDescriptorFromRoles, type RoleDescriptorInput } from "./build-descriptor.js";
export { chatCompletionText, createLlmAdapter, type LlmChatError } from "./create-llm-adapter.js";
export { type CreateRoleArgs, createRole } from "./create-role.js";
export { extractMetaOrThrow } from "./extract-meta.js";
export {
type LlmError, type LlmError,
type LlmExtractArgs, type LlmExtractArgs,
type LlmMessage,
type LlmProvider, type LlmProvider,
llmErrorToCause, llmErrorToCause,
llmExtract, llmExtract,
llmExtractWithRetry, llmExtractWithRetry,
} from "./llm-extract.js"; type MetaExtractConfig,
export type { LlmMessage, MetaExtractConfig } from "./types.js"; type OnFailOptions,
onFail,
type RoleDecorator,
type RoleDescriptorInput,
type WithDryRunOptions,
withDryRun,
} from "@uncaged/workflow-util-role";
export { chatCompletionText, createLlmAdapter, type LlmChatError } from "./create-llm-adapter.js";
export { type CreateRoleArgs, createRole } from "./create-role.js";
@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@uncaged/workflow": "workspace:*", "@uncaged/workflow": "workspace:*",
"@uncaged/workflow-role-llm": "workspace:*", "@uncaged/workflow-role-llm": "workspace:*",
"@uncaged/workflow-util-role": "workspace:*",
"zod": "^4.0.0" "zod": "^4.0.0"
} }
} }
@@ -1,5 +1,6 @@
import type { AgentFn, Role, ThreadContext } from "@uncaged/workflow"; import type { AgentFn, Role, ThreadContext } from "@uncaged/workflow";
import { createRole, type LlmProvider } from "@uncaged/workflow-role-llm"; import { createRole } from "@uncaged/workflow-role-llm";
import type { LlmProvider } from "@uncaged/workflow-util-role";
import * as z from "zod/v4"; import * as z from "zod/v4";
export const reviewerMetaSchema = z.object({ export const reviewerMetaSchema = z.object({
@@ -6,5 +6,9 @@
"composite": true "composite": true
}, },
"include": ["src/**/*.ts"], "include": ["src/**/*.ts"],
"references": [{ "path": "../workflow" }, { "path": "../workflow-role-llm" }] "references": [
{ "path": "../workflow" },
{ "path": "../workflow-role-llm" },
{ "path": "../workflow-util-role" }
]
} }
@@ -14,6 +14,7 @@
"@uncaged/workflow-role-committer": "workspace:*", "@uncaged/workflow-role-committer": "workspace:*",
"@uncaged/workflow-role-llm": "workspace:*", "@uncaged/workflow-role-llm": "workspace:*",
"@uncaged/workflow-role-reviewer": "workspace:*", "@uncaged/workflow-role-reviewer": "workspace:*",
"@uncaged/workflow-util-role": "workspace:*",
"zod": "^4.0.0" "zod": "^4.0.0"
} }
} }
@@ -1,6 +1,6 @@
import { committerMetaSchema } from "@uncaged/workflow-role-committer"; import { committerMetaSchema } from "@uncaged/workflow-role-committer";
import { buildDescriptorFromRoles } from "@uncaged/workflow-role-llm";
import { reviewerMetaSchema } from "@uncaged/workflow-role-reviewer"; import { reviewerMetaSchema } from "@uncaged/workflow-role-reviewer";
import { buildDescriptorFromRoles } from "@uncaged/workflow-util-role";
import { coderMetaSchema, plannerMetaSchema } from "./roles.js"; import { coderMetaSchema, plannerMetaSchema } from "./roles.js";
@@ -4,8 +4,9 @@ import {
type CommitterPlanMeta, type CommitterPlanMeta,
createCommitterRole, createCommitterRole,
} from "@uncaged/workflow-role-committer"; } from "@uncaged/workflow-role-committer";
import { createRole, type LlmProvider } from "@uncaged/workflow-role-llm"; import { createRole } from "@uncaged/workflow-role-llm";
import { createReviewerRole, type ReviewerMeta } from "@uncaged/workflow-role-reviewer"; import { createReviewerRole, type ReviewerMeta } from "@uncaged/workflow-role-reviewer";
import type { LlmProvider } from "@uncaged/workflow-util-role";
import * as z from "zod/v4"; import * as z from "zod/v4";
const DRY_RUN_PROVIDER: LlmProvider = { const DRY_RUN_PROVIDER: LlmProvider = {
@@ -6,5 +6,9 @@
"composite": true "composite": true
}, },
"include": ["src/**/*.ts"], "include": ["src/**/*.ts"],
"references": [{ "path": "../workflow" }, { "path": "../workflow-role-llm" }] "references": [
{ "path": "../workflow" },
{ "path": "../workflow-role-llm" },
{ "path": "../workflow-util-role" }
]
} }
+10
View File
@@ -1,3 +1,4 @@
export { buildDescriptorFromRoles, type RoleDescriptorInput } from "./build-descriptor.js";
export { export {
decorateRole, decorateRole,
type OnFailOptions, type OnFailOptions,
@@ -6,3 +7,12 @@ export {
type WithDryRunOptions, type WithDryRunOptions,
withDryRun, withDryRun,
} from "./decorators.js"; } from "./decorators.js";
export { extractMetaOrThrow } from "./extract-meta.js";
export {
type LlmError,
type LlmExtractArgs,
llmErrorToCause,
llmExtract,
llmExtractWithRetry,
} from "./llm-extract.js";
export type { LlmMessage, LlmProvider, MetaExtractConfig } from "./types.js";
@@ -2,8 +2,6 @@ import { err, ok, type Result } from "@uncaged/workflow";
import * as z from "zod/v4"; import * as z from "zod/v4";
import type { LlmProvider } from "./types.js"; import type { LlmProvider } from "./types.js";
export type { LlmProvider } from "./types.js";
export type LlmExtractArgs<T> = { export type LlmExtractArgs<T> = {
text: string; text: string;
schema: z.ZodType<T>; schema: z.ZodType<T>;