From c04e7c31afb363fceb0a21aa2b0f6a5c1682785c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 6 May 2026 08:13:27 +0000 Subject: [PATCH] refactor: move llmExtract, extractMeta, buildDescriptor, types to workflow-util-role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../__tests__/committer.test.ts | 4 +-- packages/workflow-role-committer/package.json | 1 - .../workflow-role-committer/src/committer.ts | 10 ++++--- .../workflow-role-committer/tsconfig.json | 6 +---- .../__tests__/create-role.test.ts | 2 +- .../src/create-llm-adapter.ts | 2 +- packages/workflow-role-llm/src/create-role.ts | 3 +-- packages/workflow-role-llm/src/index.ts | 26 +++++++++---------- packages/workflow-role-reviewer/package.json | 1 + .../workflow-role-reviewer/src/reviewer.ts | 3 ++- packages/workflow-role-reviewer/tsconfig.json | 6 ++++- .../package.json | 1 + .../src/descriptor.ts | 2 +- .../src/roles.ts | 3 ++- .../tsconfig.json | 6 ++++- .../__tests__/build-descriptor.test.ts | 0 .../__tests__/extract-meta.test.ts | 0 .../__tests__/llm-extract.test.ts | 0 .../src/build-descriptor.ts | 0 .../src/extract-meta.ts | 0 packages/workflow-util-role/src/index.ts | 10 +++++++ .../src/llm-extract.ts | 2 -- .../src/types.ts | 0 23 files changed, 53 insertions(+), 35 deletions(-) rename packages/{workflow-role-llm => workflow-util-role}/__tests__/build-descriptor.test.ts (100%) rename packages/{workflow-role-llm => workflow-util-role}/__tests__/extract-meta.test.ts (100%) rename packages/{workflow-role-llm => workflow-util-role}/__tests__/llm-extract.test.ts (100%) rename packages/{workflow-role-llm => workflow-util-role}/src/build-descriptor.ts (100%) rename packages/{workflow-role-llm => workflow-util-role}/src/extract-meta.ts (100%) rename packages/{workflow-role-llm => workflow-util-role}/src/llm-extract.ts (99%) rename packages/{workflow-role-llm => workflow-util-role}/src/types.ts (100%) diff --git a/packages/workflow-role-committer/__tests__/committer.test.ts b/packages/workflow-role-committer/__tests__/committer.test.ts index 2f10788..45e2dd2 100644 --- a/packages/workflow-role-committer/__tests__/committer.test.ts +++ b/packages/workflow-role-committer/__tests__/committer.test.ts @@ -7,7 +7,7 @@ import { promisify } from "node:util"; import type { AgentFn, ThreadContext } 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 { gitExec } from "../src/git-exec.js"; @@ -83,7 +83,7 @@ describe("createCommitterRole", () => { const { repo } = await setupRepoWithRemote(); 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", message: "feat: add more", }); diff --git a/packages/workflow-role-committer/package.json b/packages/workflow-role-committer/package.json index 2096c42..7ee3649 100644 --- a/packages/workflow-role-committer/package.json +++ b/packages/workflow-role-committer/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@uncaged/workflow": "workspace:*", - "@uncaged/workflow-role-llm": "workspace:*", "@uncaged/workflow-util-role": "workspace:*", "zod": "^4.0.0" } diff --git a/packages/workflow-role-committer/src/committer.ts b/packages/workflow-role-committer/src/committer.ts index 05a9f93..e2fb3fe 100644 --- a/packages/workflow-role-committer/src/committer.ts +++ b/packages/workflow-role-committer/src/committer.ts @@ -1,7 +1,11 @@ import type { AgentFn, Role, RoleResult, ThreadContext } from "@uncaged/workflow"; -import type { LlmProvider } from "@uncaged/workflow-role-llm"; -import { extractMetaOrThrow } from "@uncaged/workflow-role-llm"; -import { decorateRole, onFail, withDryRun } from "@uncaged/workflow-util-role"; +import { + decorateRole, + extractMetaOrThrow, + type LlmProvider, + onFail, + withDryRun, +} from "@uncaged/workflow-util-role"; import * as z from "zod/v4"; import { gitExec } from "./git-exec.js"; diff --git a/packages/workflow-role-committer/tsconfig.json b/packages/workflow-role-committer/tsconfig.json index 0241dfc..9227ea6 100644 --- a/packages/workflow-role-committer/tsconfig.json +++ b/packages/workflow-role-committer/tsconfig.json @@ -6,9 +6,5 @@ "composite": true }, "include": ["src/**/*.ts"], - "references": [ - { "path": "../workflow" }, - { "path": "../workflow-role-llm" }, - { "path": "../workflow-util-role" } - ] + "references": [{ "path": "../workflow" }, { "path": "../workflow-util-role" }] } diff --git a/packages/workflow-role-llm/__tests__/create-role.test.ts b/packages/workflow-role-llm/__tests__/create-role.test.ts index a462537..299059a 100644 --- a/packages/workflow-role-llm/__tests__/create-role.test.ts +++ b/packages/workflow-role-llm/__tests__/create-role.test.ts @@ -1,7 +1,7 @@ import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"; import type { AgentFn, ThreadContext } 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 { createRole } from "../src/create-role.js"; diff --git a/packages/workflow-role-llm/src/create-llm-adapter.ts b/packages/workflow-role-llm/src/create-llm-adapter.ts index 9178bff..ba18233 100644 --- a/packages/workflow-role-llm/src/create-llm-adapter.ts +++ b/packages/workflow-role-llm/src/create-llm-adapter.ts @@ -1,6 +1,6 @@ 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 = | { kind: "http_error"; status: number; body: string } diff --git a/packages/workflow-role-llm/src/create-role.ts b/packages/workflow-role-llm/src/create-role.ts index 3ec9fc1..ccf64e5 100644 --- a/packages/workflow-role-llm/src/create-role.ts +++ b/packages/workflow-role-llm/src/create-role.ts @@ -1,7 +1,6 @@ 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 { extractMetaOrThrow } from "./extract-meta.js"; -import type { LlmProvider } from "./types.js"; export type CreateRoleArgs> = { name: string; diff --git a/packages/workflow-role-llm/src/index.ts b/packages/workflow-role-llm/src/index.ts index a8b66ba..402e9ab 100644 --- a/packages/workflow-role-llm/src/index.ts +++ b/packages/workflow-role-llm/src/index.ts @@ -1,21 +1,21 @@ export { + buildDescriptorFromRoles, decorateRole, - type OnFailOptions, - 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 { + extractMetaOrThrow, type LlmError, type LlmExtractArgs, + type LlmMessage, type LlmProvider, llmErrorToCause, llmExtract, llmExtractWithRetry, -} from "./llm-extract.js"; -export type { LlmMessage, MetaExtractConfig } from "./types.js"; + type MetaExtractConfig, + 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"; diff --git a/packages/workflow-role-reviewer/package.json b/packages/workflow-role-reviewer/package.json index 340c430..cf63a7c 100644 --- a/packages/workflow-role-reviewer/package.json +++ b/packages/workflow-role-reviewer/package.json @@ -11,6 +11,7 @@ "dependencies": { "@uncaged/workflow": "workspace:*", "@uncaged/workflow-role-llm": "workspace:*", + "@uncaged/workflow-util-role": "workspace:*", "zod": "^4.0.0" } } diff --git a/packages/workflow-role-reviewer/src/reviewer.ts b/packages/workflow-role-reviewer/src/reviewer.ts index 7e13576..5d6603d 100644 --- a/packages/workflow-role-reviewer/src/reviewer.ts +++ b/packages/workflow-role-reviewer/src/reviewer.ts @@ -1,5 +1,6 @@ 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"; export const reviewerMetaSchema = z.object({ diff --git a/packages/workflow-role-reviewer/tsconfig.json b/packages/workflow-role-reviewer/tsconfig.json index b270640..0241dfc 100644 --- a/packages/workflow-role-reviewer/tsconfig.json +++ b/packages/workflow-role-reviewer/tsconfig.json @@ -6,5 +6,9 @@ "composite": true }, "include": ["src/**/*.ts"], - "references": [{ "path": "../workflow" }, { "path": "../workflow-role-llm" }] + "references": [ + { "path": "../workflow" }, + { "path": "../workflow-role-llm" }, + { "path": "../workflow-util-role" } + ] } diff --git a/packages/workflow-template-solve-issue/package.json b/packages/workflow-template-solve-issue/package.json index 5c0815a..fa2e86d 100644 --- a/packages/workflow-template-solve-issue/package.json +++ b/packages/workflow-template-solve-issue/package.json @@ -14,6 +14,7 @@ "@uncaged/workflow-role-committer": "workspace:*", "@uncaged/workflow-role-llm": "workspace:*", "@uncaged/workflow-role-reviewer": "workspace:*", + "@uncaged/workflow-util-role": "workspace:*", "zod": "^4.0.0" } } diff --git a/packages/workflow-template-solve-issue/src/descriptor.ts b/packages/workflow-template-solve-issue/src/descriptor.ts index f15b659..ab6ffcc 100644 --- a/packages/workflow-template-solve-issue/src/descriptor.ts +++ b/packages/workflow-template-solve-issue/src/descriptor.ts @@ -1,6 +1,6 @@ import { committerMetaSchema } from "@uncaged/workflow-role-committer"; -import { buildDescriptorFromRoles } from "@uncaged/workflow-role-llm"; import { reviewerMetaSchema } from "@uncaged/workflow-role-reviewer"; +import { buildDescriptorFromRoles } from "@uncaged/workflow-util-role"; import { coderMetaSchema, plannerMetaSchema } from "./roles.js"; diff --git a/packages/workflow-template-solve-issue/src/roles.ts b/packages/workflow-template-solve-issue/src/roles.ts index 0795845..b255297 100644 --- a/packages/workflow-template-solve-issue/src/roles.ts +++ b/packages/workflow-template-solve-issue/src/roles.ts @@ -4,8 +4,9 @@ import { type CommitterPlanMeta, createCommitterRole, } 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 type { LlmProvider } from "@uncaged/workflow-util-role"; import * as z from "zod/v4"; const DRY_RUN_PROVIDER: LlmProvider = { diff --git a/packages/workflow-template-solve-issue/tsconfig.json b/packages/workflow-template-solve-issue/tsconfig.json index b270640..0241dfc 100644 --- a/packages/workflow-template-solve-issue/tsconfig.json +++ b/packages/workflow-template-solve-issue/tsconfig.json @@ -6,5 +6,9 @@ "composite": true }, "include": ["src/**/*.ts"], - "references": [{ "path": "../workflow" }, { "path": "../workflow-role-llm" }] + "references": [ + { "path": "../workflow" }, + { "path": "../workflow-role-llm" }, + { "path": "../workflow-util-role" } + ] } diff --git a/packages/workflow-role-llm/__tests__/build-descriptor.test.ts b/packages/workflow-util-role/__tests__/build-descriptor.test.ts similarity index 100% rename from packages/workflow-role-llm/__tests__/build-descriptor.test.ts rename to packages/workflow-util-role/__tests__/build-descriptor.test.ts diff --git a/packages/workflow-role-llm/__tests__/extract-meta.test.ts b/packages/workflow-util-role/__tests__/extract-meta.test.ts similarity index 100% rename from packages/workflow-role-llm/__tests__/extract-meta.test.ts rename to packages/workflow-util-role/__tests__/extract-meta.test.ts diff --git a/packages/workflow-role-llm/__tests__/llm-extract.test.ts b/packages/workflow-util-role/__tests__/llm-extract.test.ts similarity index 100% rename from packages/workflow-role-llm/__tests__/llm-extract.test.ts rename to packages/workflow-util-role/__tests__/llm-extract.test.ts diff --git a/packages/workflow-role-llm/src/build-descriptor.ts b/packages/workflow-util-role/src/build-descriptor.ts similarity index 100% rename from packages/workflow-role-llm/src/build-descriptor.ts rename to packages/workflow-util-role/src/build-descriptor.ts diff --git a/packages/workflow-role-llm/src/extract-meta.ts b/packages/workflow-util-role/src/extract-meta.ts similarity index 100% rename from packages/workflow-role-llm/src/extract-meta.ts rename to packages/workflow-util-role/src/extract-meta.ts diff --git a/packages/workflow-util-role/src/index.ts b/packages/workflow-util-role/src/index.ts index 973de1e..d3a6d45 100644 --- a/packages/workflow-util-role/src/index.ts +++ b/packages/workflow-util-role/src/index.ts @@ -1,3 +1,4 @@ +export { buildDescriptorFromRoles, type RoleDescriptorInput } from "./build-descriptor.js"; export { decorateRole, type OnFailOptions, @@ -6,3 +7,12 @@ export { type WithDryRunOptions, withDryRun, } 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"; diff --git a/packages/workflow-role-llm/src/llm-extract.ts b/packages/workflow-util-role/src/llm-extract.ts similarity index 99% rename from packages/workflow-role-llm/src/llm-extract.ts rename to packages/workflow-util-role/src/llm-extract.ts index adc7159..e405cd1 100644 --- a/packages/workflow-role-llm/src/llm-extract.ts +++ b/packages/workflow-util-role/src/llm-extract.ts @@ -2,8 +2,6 @@ import { err, ok, type Result } from "@uncaged/workflow"; import * as z from "zod/v4"; import type { LlmProvider } from "./types.js"; -export type { LlmProvider } from "./types.js"; - export type LlmExtractArgs = { text: string; schema: z.ZodType; diff --git a/packages/workflow-role-llm/src/types.ts b/packages/workflow-util-role/src/types.ts similarity index 100% rename from packages/workflow-role-llm/src/types.ts rename to packages/workflow-util-role/src/types.ts