From 1683e41b05e2d581babca56d74fc8786c36a73e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 29 Apr 2026 12:35:07 +0000 Subject: [PATCH 1/3] refactor: decouple adapters from workflow factories, roles export createXxxRole MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename build* → create* workflow factories - Workflow factories accept adapters: Record - Each role file exports createXxxRole(adapter, ...) factory - _shared/workspace-committer accepts adapter as first param - All adapter imports moved to index.ts (injection point) - solve-issue roles also updated Closes #15 --- workflows/_shared/workspace-committer.ts | 22 +++--- workflows/develop-sense/build.ts | 76 ++++--------------- workflows/develop-sense/index.ts | 20 ++++- workflows/develop-sense/roles/coder.ts | 12 +++ workflows/develop-sense/roles/committer.ts | 2 +- workflows/develop-sense/roles/planner.ts | 12 +++ workflows/develop-sense/roles/reviewer.ts | 17 +++++ workflows/develop-sense/roles/tester.ts | 17 +++++ workflows/develop-workflow/build.ts | 76 ++++--------------- workflows/develop-workflow/index.ts | 20 ++++- workflows/develop-workflow/roles/coder.ts | 12 +++ workflows/develop-workflow/roles/committer.ts | 2 +- workflows/develop-workflow/roles/planner.ts | 12 +++ workflows/develop-workflow/roles/reviewer.ts | 17 +++++ workflows/develop-workflow/roles/tester.ts | 17 +++++ workflows/solve-issue/build.ts | 69 ++++++----------- workflows/solve-issue/index.ts | 30 +++++++- .../solve-issue/roles/committer/index.ts | 12 +-- .../solve-issue/roles/implement/index.ts | 21 ++--- workflows/solve-issue/roles/plan/index.ts | 19 ++--- workflows/solve-issue/roles/prepare/index.ts | 14 ++++ workflows/solve-issue/roles/publish/index.ts | 12 +-- .../solve-issue/roles/read-issue/index.ts | 14 ++++ workflows/solve-issue/roles/review/index.ts | 19 +++++ workflows/solve-issue/roles/test/index.ts | 14 ++++ 25 files changed, 337 insertions(+), 221 deletions(-) diff --git a/workflows/_shared/workspace-committer.ts b/workflows/_shared/workspace-committer.ts index c429b35..938b4b3 100644 --- a/workflows/_shared/workspace-committer.ts +++ b/workflows/_shared/workspace-committer.ts @@ -1,5 +1,4 @@ -import type { Role, RoleResult, StartStep } from "@uncaged/nerve-core"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, Role, RoleResult, StartStep } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; @@ -62,15 +61,18 @@ or \`\`\``; } -export function buildWorkspaceCommitterRole({ - extract, - nerveRoot, - workflowName, - conventionalCommitScopeHint, - branchCheckoutExample, -}: BuildWorkspaceCommitterDeps): Role { +export function createWorkspaceCommitterRole( + adapter: AgentFn, + { + extract, + nerveRoot, + workflowName, + conventionalCommitScopeHint, + branchCheckoutExample, + }: BuildWorkspaceCommitterDeps, +): Role { const innerRole = createRole( - hermesAdapter, + adapter, async (start: StartStep) => workspaceCommitterPrompt({ threadId: start.meta.threadId, diff --git a/workflows/develop-sense/build.ts b/workflows/develop-sense/build.ts index 7b83a02..06b9bf8 100644 --- a/workflows/develop-sense/build.ts +++ b/workflows/develop-sense/build.ts @@ -1,75 +1,31 @@ -import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core"; -import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; -import { createRole } from "@uncaged/nerve-workflow-utils"; -import { - coderMetaSchema, - coderPrompt, -} from "./roles/coder.js"; -import { - buildWorkspaceCommitterRole, -} from "./roles/committer.js"; -import { - plannerMetaSchema, - plannerPrompt, -} from "./roles/planner.js"; -import { - reviewerMetaSchema, - reviewerPrompt, -} from "./roles/reviewer.js"; -import { - testerMetaSchema, - testerPrompt, -} from "./roles/tester.js"; import { moderator } from "./moderator.js"; import type { SenseMeta } from "./moderator.js"; +import { createCoderRole } from "./roles/coder.js"; +import { createWorkspaceCommitterRole } from "./roles/committer.js"; +import { createPlannerRole } from "./roles/planner.js"; +import { createReviewerRole } from "./roles/reviewer.js"; +import { createTesterRole } from "./roles/tester.js"; -export type BuildDevelopSenseDeps = { +export type CreateDevelopSenseDeps = { + adapters: Record; extract: LlmExtractorConfig; cwd: string; }; -const CURSOR_TIMEOUT_MS = 300_000; - -export function buildDevelopSenseWorkflow({ +export function createDevelopSenseWorkflow({ + adapters, extract, cwd, -}: BuildDevelopSenseDeps): WorkflowDefinition { +}: CreateDevelopSenseDeps): WorkflowDefinition { const roles = { - planner: createRole( - createCursorAdapter({ - type: "cursor", - mode: "ask", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - }), - async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), - plannerMetaSchema, - extract, - ), - coder: createRole( - cursorAdapter, - async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), - coderMetaSchema, - extract, - ), - reviewer: createRole( - hermesAdapter, - async (start: StartStep) => - reviewerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }), - reviewerMetaSchema, - extract, - ), - tester: createRole( - hermesAdapter, - async (start: StartStep) => - testerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }), - testerMetaSchema, - extract, - ), - committer: buildWorkspaceCommitterRole({ + planner: createPlannerRole(adapters.planner, extract), + coder: createCoderRole(adapters.coder, extract), + reviewer: createReviewerRole(adapters.reviewer, extract, cwd), + tester: createTesterRole(adapters.tester, extract, cwd), + committer: createWorkspaceCommitterRole(adapters.committer, { extract, nerveRoot: cwd, workflowName: "develop-sense", diff --git a/workflows/develop-sense/index.ts b/workflows/develop-sense/index.ts index ee9d343..1a021c6 100644 --- a/workflows/develop-sense/index.ts +++ b/workflows/develop-sense/index.ts @@ -1,5 +1,7 @@ import { join } from "node:path"; -import { buildDevelopSenseWorkflow } from "./build.js"; +import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor"; +import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import { createDevelopSenseWorkflow } from "./build.js"; const HOME = process.env.HOME ?? "/home/azureuser"; const NERVE_ROOT = join(HOME, ".uncaged-nerve"); @@ -11,7 +13,21 @@ if (!apiKey || !baseUrl) { throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL"); } -const workflow = buildDevelopSenseWorkflow({ +const CURSOR_TIMEOUT_MS = 300_000; + +const workflow = createDevelopSenseWorkflow({ + adapters: { + planner: createCursorAdapter({ + type: "cursor", + mode: "ask", + model: "auto", + timeout: CURSOR_TIMEOUT_MS, + }), + coder: cursorAdapter, + reviewer: hermesAdapter, + tester: hermesAdapter, + committer: hermesAdapter, + }, extract: { provider: { apiKey, baseUrl, model } }, cwd: NERVE_ROOT, }); diff --git a/workflows/develop-sense/roles/coder.ts b/workflows/develop-sense/roles/coder.ts index 5f3c0a3..4bee332 100644 --- a/workflows/develop-sense/roles/coder.ts +++ b/workflows/develop-sense/roles/coder.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const coderMetaSchema = z.object({ @@ -36,3 +39,12 @@ Return \`done: true\` ONLY when ALL of the following are true: Return \`done: false\` if you made progress but there is still work to do.`; } + +export function createCoderRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), + coderMetaSchema, + extract, + ); +} diff --git a/workflows/develop-sense/roles/committer.ts b/workflows/develop-sense/roles/committer.ts index 8c6f0ed..44ed5e8 100644 --- a/workflows/develop-sense/roles/committer.ts +++ b/workflows/develop-sense/roles/committer.ts @@ -1,5 +1,5 @@ export { - buildWorkspaceCommitterRole, + createWorkspaceCommitterRole, committerMetaSchema, type BuildWorkspaceCommitterDeps, type CommitterMeta, diff --git a/workflows/develop-sense/roles/planner.ts b/workflows/develop-sense/roles/planner.ts index c5fec19..3287047 100644 --- a/workflows/develop-sense/roles/planner.ts +++ b/workflows/develop-sense/roles/planner.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const plannerMetaSchema = z.object({ @@ -22,3 +25,12 @@ Pick a good kebab-case name for this sense. Produce a PLAN (not code) in markdow Output ONLY the plan. Be precise and implementation-ready.`; } + +export function createPlannerRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), + plannerMetaSchema, + extract, + ); +} diff --git a/workflows/develop-sense/roles/reviewer.ts b/workflows/develop-sense/roles/reviewer.ts index 9eb8414..1a04f12 100644 --- a/workflows/develop-sense/roles/reviewer.ts +++ b/workflows/develop-sense/roles/reviewer.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const reviewerMetaSchema = z.object({ @@ -43,3 +46,17 @@ or { "approved": false } \`\`\``; } + +export function createReviewerRole( + adapter: AgentFn, + extract: LlmExtractorConfig, + nerveRoot: string, +): Role { + return createRole( + adapter, + async (start: StartStep) => + reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }), + reviewerMetaSchema, + extract, + ); +} diff --git a/workflows/develop-sense/roles/tester.ts b/workflows/develop-sense/roles/tester.ts index 7c0571e..8ec7a43 100644 --- a/workflows/develop-sense/roles/tester.ts +++ b/workflows/develop-sense/roles/tester.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const testerMetaSchema = z.object({ @@ -39,3 +42,17 @@ If any step fails, include the relevant error output. Output a clear summary: what you checked, what passed, what failed, and why.`; } + +export function createTesterRole( + adapter: AgentFn, + extract: LlmExtractorConfig, + nerveRoot: string, +): Role { + return createRole( + adapter, + async (start: StartStep) => + testerPrompt({ threadId: start.meta.threadId, nerveRoot }), + testerMetaSchema, + extract, + ); +} diff --git a/workflows/develop-workflow/build.ts b/workflows/develop-workflow/build.ts index b0c2b16..c08e18a 100644 --- a/workflows/develop-workflow/build.ts +++ b/workflows/develop-workflow/build.ts @@ -1,75 +1,31 @@ -import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core"; -import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; -import { createRole } from "@uncaged/nerve-workflow-utils"; -import { - coderMetaSchema, - coderPrompt, -} from "./roles/coder.js"; -import { - buildWorkspaceCommitterRole, -} from "./roles/committer.js"; -import { - plannerMetaSchema, - plannerPrompt, -} from "./roles/planner.js"; -import { - reviewerMetaSchema, - reviewerPrompt, -} from "./roles/reviewer.js"; -import { - testerMetaSchema, - testerPrompt, -} from "./roles/tester.js"; import { moderator } from "./moderator.js"; import type { WorkflowMeta } from "./moderator.js"; +import { createCoderRole } from "./roles/coder.js"; +import { createWorkspaceCommitterRole } from "./roles/committer.js"; +import { createPlannerRole } from "./roles/planner.js"; +import { createReviewerRole } from "./roles/reviewer.js"; +import { createTesterRole } from "./roles/tester.js"; -export type BuildDevelopWorkflowDeps = { +export type CreateDevelopWorkflowDeps = { + adapters: Record; extract: LlmExtractorConfig; nerveRoot: string; }; -const CURSOR_TIMEOUT_MS = 300_000; - -export function buildDevelopWorkflow({ +export function createDevelopWorkflowWorkflow({ + adapters, extract, nerveRoot, -}: BuildDevelopWorkflowDeps): WorkflowDefinition { +}: CreateDevelopWorkflowDeps): WorkflowDefinition { const roles = { - planner: createRole( - createCursorAdapter({ - type: "cursor", - mode: "ask", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - }), - async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), - plannerMetaSchema, - extract, - ), - coder: createRole( - cursorAdapter, - async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), - coderMetaSchema, - extract, - ), - reviewer: createRole( - hermesAdapter, - async (start: StartStep) => - reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }), - reviewerMetaSchema, - extract, - ), - tester: createRole( - hermesAdapter, - async (start: StartStep) => - testerPrompt({ threadId: start.meta.threadId, nerveRoot }), - testerMetaSchema, - extract, - ), - committer: buildWorkspaceCommitterRole({ + planner: createPlannerRole(adapters.planner, extract), + coder: createCoderRole(adapters.coder, extract), + reviewer: createReviewerRole(adapters.reviewer, extract, nerveRoot), + tester: createTesterRole(adapters.tester, extract, nerveRoot), + committer: createWorkspaceCommitterRole(adapters.committer, { extract, nerveRoot, workflowName: "develop-workflow", diff --git a/workflows/develop-workflow/index.ts b/workflows/develop-workflow/index.ts index d9c2cc4..cbb9599 100644 --- a/workflows/develop-workflow/index.ts +++ b/workflows/develop-workflow/index.ts @@ -1,5 +1,7 @@ import { join } from "node:path"; -import { buildDevelopWorkflow } from "./build.js"; +import { createCursorAdapter, cursorAdapter } from "@uncaged/nerve-adapter-cursor"; +import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import { createDevelopWorkflowWorkflow } from "./build.js"; const HOME = process.env.HOME ?? "/home/azureuser"; const NERVE_ROOT = join(HOME, ".uncaged-nerve"); @@ -12,7 +14,21 @@ if (!apiKey || !baseUrl) { throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL"); } -const workflow = buildDevelopWorkflow({ +const CURSOR_TIMEOUT_MS = 300_000; + +const workflow = createDevelopWorkflowWorkflow({ + adapters: { + planner: createCursorAdapter({ + type: "cursor", + mode: "ask", + model: "auto", + timeout: CURSOR_TIMEOUT_MS, + }), + coder: cursorAdapter, + reviewer: hermesAdapter, + tester: hermesAdapter, + committer: hermesAdapter, + }, extract: { provider: { apiKey, baseUrl, model } }, nerveRoot: NERVE_ROOT, }); diff --git a/workflows/develop-workflow/roles/coder.ts b/workflows/develop-workflow/roles/coder.ts index 75f5d63..c09f562 100644 --- a/workflows/develop-workflow/roles/coder.ts +++ b/workflows/develop-workflow/roles/coder.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const coderMetaSchema = z.object({ @@ -55,3 +58,12 @@ Return \`done: true\` ONLY when ALL of the following are true: Return \`done: false\` if you made progress but there is still work to do, or if build/lint has errors you plan to fix in the next iteration.`; } + +export function createCoderRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), + coderMetaSchema, + extract, + ); +} diff --git a/workflows/develop-workflow/roles/committer.ts b/workflows/develop-workflow/roles/committer.ts index 8c6f0ed..44ed5e8 100644 --- a/workflows/develop-workflow/roles/committer.ts +++ b/workflows/develop-workflow/roles/committer.ts @@ -1,5 +1,5 @@ export { - buildWorkspaceCommitterRole, + createWorkspaceCommitterRole, committerMetaSchema, type BuildWorkspaceCommitterDeps, type CommitterMeta, diff --git a/workflows/develop-workflow/roles/planner.ts b/workflows/develop-workflow/roles/planner.ts index 6bc344c..ce2bdb0 100644 --- a/workflows/develop-workflow/roles/planner.ts +++ b/workflows/develop-workflow/roles/planner.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const plannerMetaSchema = z.object({ @@ -51,3 +54,12 @@ or { "ready": false } \`\`\``; } + +export function createPlannerRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), + plannerMetaSchema, + extract, + ); +} diff --git a/workflows/develop-workflow/roles/reviewer.ts b/workflows/develop-workflow/roles/reviewer.ts index 9eb8414..1a04f12 100644 --- a/workflows/develop-workflow/roles/reviewer.ts +++ b/workflows/develop-workflow/roles/reviewer.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const reviewerMetaSchema = z.object({ @@ -43,3 +46,17 @@ or { "approved": false } \`\`\``; } + +export function createReviewerRole( + adapter: AgentFn, + extract: LlmExtractorConfig, + nerveRoot: string, +): Role { + return createRole( + adapter, + async (start: StartStep) => + reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }), + reviewerMetaSchema, + extract, + ); +} diff --git a/workflows/develop-workflow/roles/tester.ts b/workflows/develop-workflow/roles/tester.ts index bc0d09a..f740e2a 100644 --- a/workflows/develop-workflow/roles/tester.ts +++ b/workflows/develop-workflow/roles/tester.ts @@ -1,3 +1,6 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; export const testerMetaSchema = z.object({ @@ -40,3 +43,17 @@ If any step fails, include the relevant error output. Output a clear summary: what you checked, what passed, what failed, and why.`; } + +export function createTesterRole( + adapter: AgentFn, + extract: LlmExtractorConfig, + nerveRoot: string, +): Role { + return createRole( + adapter, + async (start: StartStep) => + testerPrompt({ threadId: start.meta.threadId, nerveRoot }), + testerMetaSchema, + extract, + ); +} diff --git a/workflows/solve-issue/build.ts b/workflows/solve-issue/build.ts index 2fa7b04..8c958af 100644 --- a/workflows/solve-issue/build.ts +++ b/workflows/solve-issue/build.ts @@ -1,64 +1,39 @@ -import type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, WorkflowDefinition } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; -import { createRole } from "@uncaged/nerve-workflow-utils"; import { moderator } from "./moderator.js"; import type { WorkflowMeta } from "./moderator.js"; -import { buildCommitterRole } from "./roles/committer/index.js"; -import { buildImplementRole } from "./roles/implement/index.js"; -import { buildPlanRole } from "./roles/plan/index.js"; -import { prepareMetaSchema } from "./roles/prepare/index.js"; -import { preparePrompt } from "./roles/prepare/prompt.js"; -import { buildPublishRole } from "./roles/publish/index.js"; -import { readIssueMetaSchema } from "./roles/read-issue/index.js"; -import { readIssuePrompt } from "./roles/read-issue/prompt.js"; -import { reviewMetaSchema } from "./roles/review/index.js"; -import { reviewPrompt } from "./roles/review/prompt.js"; -import { testMetaSchema } from "./roles/test/index.js"; -import { testPrompt } from "./roles/test/prompt.js"; +import { createCommitterRole } from "./roles/committer/index.js"; +import { createImplementRole } from "./roles/implement/index.js"; +import { createPlanRole } from "./roles/plan/index.js"; +import { createPrepareRole } from "./roles/prepare/index.js"; +import { createPublishRole } from "./roles/publish/index.js"; +import { createReadIssueRole } from "./roles/read-issue/index.js"; +import { createReviewRole } from "./roles/review/index.js"; +import { createTestRole } from "./roles/test/index.js"; -export type BuildSolveIssueDeps = { +export type CreateSolveIssueDeps = { + adapters: Record; nerveRoot: string; extract: LlmExtractorConfig; }; -export function buildSolveIssue({ +export function createSolveIssueWorkflow({ + adapters, nerveRoot, extract, -}: BuildSolveIssueDeps): WorkflowDefinition { +}: CreateSolveIssueDeps): WorkflowDefinition { return { name: "solve-issue", roles: { - "read-issue": createRole( - hermesAdapter, - async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }), - readIssueMetaSchema, - extract, - ), - prepare: createRole( - hermesAdapter, - async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }), - prepareMetaSchema, - extract, - ), - plan: buildPlanRole({ extract, nerveRoot }), - implement: buildImplementRole({ extract, nerveRoot }), - committer: buildCommitterRole({ extract, nerveRoot }), - review: createRole( - hermesAdapter, - async (start: StartStep) => - reviewPrompt({ threadId: start.meta.threadId, nerveRoot }), - reviewMetaSchema, - extract, - ), - test: createRole( - hermesAdapter, - async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }), - testMetaSchema, - extract, - ), - publish: buildPublishRole({ extract, nerveRoot }), + "read-issue": createReadIssueRole(adapters["read-issue"], extract), + prepare: createPrepareRole(adapters.prepare, extract), + plan: createPlanRole(adapters.plan, { extract, nerveRoot }), + implement: createImplementRole(adapters.implement, { extract, nerveRoot }), + committer: createCommitterRole(adapters.committer, { extract, nerveRoot }), + review: createReviewRole(adapters.review, extract, nerveRoot), + test: createTestRole(adapters.test, extract), + publish: createPublishRole(adapters.publish, { extract, nerveRoot }), }, moderator, }; diff --git a/workflows/solve-issue/index.ts b/workflows/solve-issue/index.ts index 321aef6..5709a99 100644 --- a/workflows/solve-issue/index.ts +++ b/workflows/solve-issue/index.ts @@ -1,5 +1,7 @@ import { join } from "node:path"; -import { buildSolveIssue } from "./build.js"; +import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; +import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import { createSolveIssueWorkflow } from "./build.js"; import { resolveDashScopeProvider } from "./lib/provider.js"; const HOME = process.env.HOME ?? "/home/azureuser"; @@ -11,6 +13,30 @@ if (provider === null) { throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL (or cfg get equivalents)"); } -const workflow = buildSolveIssue({ nerveRoot: NERVE_ROOT, extract: { provider } }); +const CURSOR_TIMEOUT_MS = 300_000; + +const workflow = createSolveIssueWorkflow({ + adapters: { + "read-issue": hermesAdapter, + prepare: hermesAdapter, + plan: createCursorAdapter({ + type: "cursor", + mode: "ask", + model: "auto", + timeout: CURSOR_TIMEOUT_MS, + }), + implement: createCursorAdapter({ + type: "cursor", + model: "auto", + timeout: CURSOR_TIMEOUT_MS, + }), + committer: hermesAdapter, + review: hermesAdapter, + test: hermesAdapter, + publish: hermesAdapter, + }, + nerveRoot: NERVE_ROOT, + extract: { provider }, +}); export default workflow; diff --git a/workflows/solve-issue/roles/committer/index.ts b/workflows/solve-issue/roles/committer/index.ts index fcd95e3..2070cd2 100644 --- a/workflows/solve-issue/roles/committer/index.ts +++ b/workflows/solve-issue/roles/committer/index.ts @@ -1,5 +1,4 @@ -import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; @@ -14,14 +13,17 @@ export const committerMetaSchema = z.object({ }); export type CommitterMeta = z.infer; -export type BuildCommitterDeps = { +export type CreateCommitterRoleDeps = { extract: LlmExtractorConfig; nerveRoot: string; }; -export function buildCommitterRole({ extract, nerveRoot }: BuildCommitterDeps): Role { +export function createCommitterRole( + adapter: AgentFn, + { extract, nerveRoot }: CreateCommitterRoleDeps, +): Role { const innerRole = createRole( - hermesAdapter, + adapter, async (start: StartStep) => committerPrompt({ threadId: start.meta.threadId, diff --git a/workflows/solve-issue/roles/implement/index.ts b/workflows/solve-issue/roles/implement/index.ts index 0d0dba0..7b386d9 100644 --- a/workflows/solve-issue/roles/implement/index.ts +++ b/workflows/solve-issue/roles/implement/index.ts @@ -1,5 +1,4 @@ -import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; +import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; @@ -12,17 +11,15 @@ export const implementMetaSchema = z.object({ }); export type ImplementMeta = z.infer; -export type BuildImplementDeps = { +export type CreateImplementRoleDeps = { extract: LlmExtractorConfig; nerveRoot: string; }; -const CURSOR_TIMEOUT_MS = 300_000; - -export function buildImplementRole({ - extract, - nerveRoot, -}: BuildImplementDeps): Role { +export function createImplementRole( + adapter: AgentFn, + { extract, nerveRoot }: CreateImplementRoleDeps, +): Role { return async (start: StartStep, messages: WorkflowMessage[]): Promise> => { const cwd = resolveRepoCwd(messages); if (cwd === null) { @@ -33,11 +30,7 @@ export function buildImplementRole({ } const innerRole = createRole( - createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - }), + adapter, async (innerStart: StartStep) => buildImplementPrompt({ threadId: innerStart.meta.threadId, diff --git a/workflows/solve-issue/roles/plan/index.ts b/workflows/solve-issue/roles/plan/index.ts index c17a4db..3520760 100644 --- a/workflows/solve-issue/roles/plan/index.ts +++ b/workflows/solve-issue/roles/plan/index.ts @@ -1,5 +1,4 @@ -import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; +import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; @@ -12,14 +11,15 @@ export const planMetaSchema = z.object({ }); export type PlanMeta = z.infer; -export type BuildPlanDeps = { +export type CreatePlanRoleDeps = { extract: LlmExtractorConfig; nerveRoot: string; }; -const CURSOR_TIMEOUT_MS = 300_000; - -export function buildPlanRole({ extract, nerveRoot }: BuildPlanDeps): Role { +export function createPlanRole( + adapter: AgentFn, + { extract, nerveRoot }: CreatePlanRoleDeps, +): Role { return async (start: StartStep, messages: WorkflowMessage[]): Promise> => { const cwd = resolveRepoCwd(messages); if (cwd === null) { @@ -30,12 +30,7 @@ export function buildPlanRole({ extract, nerveRoot }: BuildPlanDeps): Role buildPlanPrompt({ threadId: innerStart.meta.threadId, diff --git a/workflows/solve-issue/roles/prepare/index.ts b/workflows/solve-issue/roles/prepare/index.ts index 5301e0b..97c8eca 100644 --- a/workflows/solve-issue/roles/prepare/index.ts +++ b/workflows/solve-issue/roles/prepare/index.ts @@ -1,6 +1,20 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; +import { preparePrompt } from "./prompt.js"; + export const prepareMetaSchema = z.object({ ready: z.boolean().describe("true if repo is ready and baseline build ok"), }); export type PrepareMeta = z.infer; + +export function createPrepareRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }), + prepareMetaSchema, + extract, + ); +} diff --git a/workflows/solve-issue/roles/publish/index.ts b/workflows/solve-issue/roles/publish/index.ts index a314638..ddaa10b 100644 --- a/workflows/solve-issue/roles/publish/index.ts +++ b/workflows/solve-issue/roles/publish/index.ts @@ -1,7 +1,6 @@ import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; -import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; +import type { AgentFn, Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; @@ -13,7 +12,7 @@ export const publishMetaSchema = z.object({ }); export type PublishMeta = z.infer; -export type BuildPublishDeps = { +export type CreatePublishRoleDeps = { extract: LlmExtractorConfig; nerveRoot: string; }; @@ -22,9 +21,12 @@ function logPath(nerveRoot: string): string { return join(nerveRoot, "logs", `solve-issue-publish-${Date.now()}.log`); } -export function buildPublishRole({ extract, nerveRoot }: BuildPublishDeps): Role { +export function createPublishRole( + adapter: AgentFn, + { extract, nerveRoot }: CreatePublishRoleDeps, +): Role { const innerRole = createRole( - hermesAdapter, + adapter, async (start: StartStep) => buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }), publishMetaSchema, diff --git a/workflows/solve-issue/roles/read-issue/index.ts b/workflows/solve-issue/roles/read-issue/index.ts index 0b029e7..fd58933 100644 --- a/workflows/solve-issue/roles/read-issue/index.ts +++ b/workflows/solve-issue/roles/read-issue/index.ts @@ -1,6 +1,20 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; +import { readIssuePrompt } from "./prompt.js"; + export const readIssueMetaSchema = z.object({ ready: z.boolean().describe("true if issue content was fetched and markers are present"), }); export type ReadIssueMeta = z.infer; + +export function createReadIssueRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }), + readIssueMetaSchema, + extract, + ); +} diff --git a/workflows/solve-issue/roles/review/index.ts b/workflows/solve-issue/roles/review/index.ts index c7112ba..7908463 100644 --- a/workflows/solve-issue/roles/review/index.ts +++ b/workflows/solve-issue/roles/review/index.ts @@ -1,6 +1,25 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; +import { reviewPrompt } from "./prompt.js"; + export const reviewMetaSchema = z.object({ approved: z.boolean().describe("true if diff is clean and ready for tests"), }); export type ReviewMeta = z.infer; + +export function createReviewRole( + adapter: AgentFn, + extract: LlmExtractorConfig, + nerveRoot: string, +): Role { + return createRole( + adapter, + async (start: StartStep) => + reviewPrompt({ threadId: start.meta.threadId, nerveRoot }), + reviewMetaSchema, + extract, + ); +} diff --git a/workflows/solve-issue/roles/test/index.ts b/workflows/solve-issue/roles/test/index.ts index ef0467c..0a2edab 100644 --- a/workflows/solve-issue/roles/test/index.ts +++ b/workflows/solve-issue/roles/test/index.ts @@ -1,6 +1,20 @@ +import type { AgentFn, Role, StartStep } from "@uncaged/nerve-core"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; +import { testPrompt } from "./prompt.js"; + export const testMetaSchema = z.object({ passed: z.boolean().describe("true if all test commands passed"), }); export type TestMeta = z.infer; + +export function createTestRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { + return createRole( + adapter, + async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }), + testMetaSchema, + extract, + ); +} From eaddd881094aa60da392d18a3189922f392a1746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 29 Apr 2026 12:38:21 +0000 Subject: [PATCH 2/3] refactor: add defaultAdapter + typed role union, adapters becomes Partial - Each workflow factory takes defaultAdapter: AgentFn + adapters?: Partial> - index.ts only overrides roles that differ from default (planner/coder use cursor, rest fallback) - Cleaner call sites, type-safe role names Refs #15 --- workflows/develop-sense/build.ts | 16 ++++++++++------ workflows/develop-sense/index.ts | 4 +--- workflows/develop-workflow/build.ts | 16 ++++++++++------ workflows/develop-workflow/index.ts | 4 +--- workflows/solve-issue/build.ts | 22 +++++++++++++--------- workflows/solve-issue/index.ts | 7 +------ 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/workflows/develop-sense/build.ts b/workflows/develop-sense/build.ts index 06b9bf8..3e8904d 100644 --- a/workflows/develop-sense/build.ts +++ b/workflows/develop-sense/build.ts @@ -9,8 +9,11 @@ import { createPlannerRole } from "./roles/planner.js"; import { createReviewerRole } from "./roles/reviewer.js"; import { createTesterRole } from "./roles/tester.js"; +type DevelopSenseRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer'; + export type CreateDevelopSenseDeps = { - adapters: Record; + defaultAdapter: AgentFn; + adapters?: Partial>; extract: LlmExtractorConfig; cwd: string; }; @@ -20,12 +23,13 @@ export function createDevelopSenseWorkflow({ extract, cwd, }: CreateDevelopSenseDeps): WorkflowDefinition { + const a = (role: DevelopSenseRole) => adapters?.[role] ?? defaultAdapter; const roles = { - planner: createPlannerRole(adapters.planner, extract), - coder: createCoderRole(adapters.coder, extract), - reviewer: createReviewerRole(adapters.reviewer, extract, cwd), - tester: createTesterRole(adapters.tester, extract, cwd), - committer: createWorkspaceCommitterRole(adapters.committer, { + planner: createPlannerRole(a('planner'), extract), + coder: createCoderRole(a('coder'), extract), + reviewer: createReviewerRole(a('reviewer'), extract, cwd), + tester: createTesterRole(a('tester'), extract, cwd), + committer: createWorkspaceCommitterRole(a('committer'), { extract, nerveRoot: cwd, workflowName: "develop-sense", diff --git a/workflows/develop-sense/index.ts b/workflows/develop-sense/index.ts index 1a021c6..1d6e6fb 100644 --- a/workflows/develop-sense/index.ts +++ b/workflows/develop-sense/index.ts @@ -16,6 +16,7 @@ if (!apiKey || !baseUrl) { const CURSOR_TIMEOUT_MS = 300_000; const workflow = createDevelopSenseWorkflow({ + defaultAdapter: hermesAdapter, adapters: { planner: createCursorAdapter({ type: "cursor", @@ -24,9 +25,6 @@ const workflow = createDevelopSenseWorkflow({ timeout: CURSOR_TIMEOUT_MS, }), coder: cursorAdapter, - reviewer: hermesAdapter, - tester: hermesAdapter, - committer: hermesAdapter, }, extract: { provider: { apiKey, baseUrl, model } }, cwd: NERVE_ROOT, diff --git a/workflows/develop-workflow/build.ts b/workflows/develop-workflow/build.ts index c08e18a..abcde86 100644 --- a/workflows/develop-workflow/build.ts +++ b/workflows/develop-workflow/build.ts @@ -9,8 +9,11 @@ import { createPlannerRole } from "./roles/planner.js"; import { createReviewerRole } from "./roles/reviewer.js"; import { createTesterRole } from "./roles/tester.js"; +type DevelopWorkflowRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer'; + export type CreateDevelopWorkflowDeps = { - adapters: Record; + defaultAdapter: AgentFn; + adapters?: Partial>; extract: LlmExtractorConfig; nerveRoot: string; }; @@ -20,12 +23,13 @@ export function createDevelopWorkflowWorkflow({ extract, nerveRoot, }: CreateDevelopWorkflowDeps): WorkflowDefinition { + const a = (role: DevelopWorkflowRole) => adapters?.[role] ?? defaultAdapter; const roles = { - planner: createPlannerRole(adapters.planner, extract), - coder: createCoderRole(adapters.coder, extract), - reviewer: createReviewerRole(adapters.reviewer, extract, nerveRoot), - tester: createTesterRole(adapters.tester, extract, nerveRoot), - committer: createWorkspaceCommitterRole(adapters.committer, { + planner: createPlannerRole(a('planner'), extract), + coder: createCoderRole(a('coder'), extract), + reviewer: createReviewerRole(a('reviewer'), extract, nerveRoot), + tester: createTesterRole(a('tester'), extract, nerveRoot), + committer: createWorkspaceCommitterRole(a('committer'), { extract, nerveRoot, workflowName: "develop-workflow", diff --git a/workflows/develop-workflow/index.ts b/workflows/develop-workflow/index.ts index cbb9599..dfad6a9 100644 --- a/workflows/develop-workflow/index.ts +++ b/workflows/develop-workflow/index.ts @@ -17,6 +17,7 @@ if (!apiKey || !baseUrl) { const CURSOR_TIMEOUT_MS = 300_000; const workflow = createDevelopWorkflowWorkflow({ + defaultAdapter: hermesAdapter, adapters: { planner: createCursorAdapter({ type: "cursor", @@ -25,9 +26,6 @@ const workflow = createDevelopWorkflowWorkflow({ timeout: CURSOR_TIMEOUT_MS, }), coder: cursorAdapter, - reviewer: hermesAdapter, - tester: hermesAdapter, - committer: hermesAdapter, }, extract: { provider: { apiKey, baseUrl, model } }, nerveRoot: NERVE_ROOT, diff --git a/workflows/solve-issue/build.ts b/workflows/solve-issue/build.ts index 8c958af..cf267a0 100644 --- a/workflows/solve-issue/build.ts +++ b/workflows/solve-issue/build.ts @@ -12,8 +12,11 @@ import { createReadIssueRole } from "./roles/read-issue/index.js"; import { createReviewRole } from "./roles/review/index.js"; import { createTestRole } from "./roles/test/index.js"; +type SolveIssueRole = 'read-issue' | 'prepare' | 'plan' | 'implement' | 'committer' | 'review' | 'test' | 'publish'; + export type CreateSolveIssueDeps = { - adapters: Record; + defaultAdapter: AgentFn; + adapters?: Partial>; nerveRoot: string; extract: LlmExtractorConfig; }; @@ -23,17 +26,18 @@ export function createSolveIssueWorkflow({ nerveRoot, extract, }: CreateSolveIssueDeps): WorkflowDefinition { + const a = (role: SolveIssueRole) => adapters?.[role] ?? defaultAdapter; return { name: "solve-issue", roles: { - "read-issue": createReadIssueRole(adapters["read-issue"], extract), - prepare: createPrepareRole(adapters.prepare, extract), - plan: createPlanRole(adapters.plan, { extract, nerveRoot }), - implement: createImplementRole(adapters.implement, { extract, nerveRoot }), - committer: createCommitterRole(adapters.committer, { extract, nerveRoot }), - review: createReviewRole(adapters.review, extract, nerveRoot), - test: createTestRole(adapters.test, extract), - publish: createPublishRole(adapters.publish, { extract, nerveRoot }), + "read-issue": createReadIssueRole(a("read-issue"), extract), + prepare: createPrepareRole(a("prepare"), extract), + plan: createPlanRole(a("plan"), { extract, nerveRoot }), + implement: createImplementRole(a("implement"), { extract, nerveRoot }), + committer: createCommitterRole(a("committer"), { extract, nerveRoot }), + review: createReviewRole(a("review"), extract, nerveRoot), + test: createTestRole(a("test"), extract), + publish: createPublishRole(a("publish"), { extract, nerveRoot }), }, moderator, }; diff --git a/workflows/solve-issue/index.ts b/workflows/solve-issue/index.ts index 5709a99..fed8314 100644 --- a/workflows/solve-issue/index.ts +++ b/workflows/solve-issue/index.ts @@ -16,9 +16,8 @@ if (provider === null) { const CURSOR_TIMEOUT_MS = 300_000; const workflow = createSolveIssueWorkflow({ + defaultAdapter: hermesAdapter, adapters: { - "read-issue": hermesAdapter, - prepare: hermesAdapter, plan: createCursorAdapter({ type: "cursor", mode: "ask", @@ -30,10 +29,6 @@ const workflow = createSolveIssueWorkflow({ model: "auto", timeout: CURSOR_TIMEOUT_MS, }), - committer: hermesAdapter, - review: hermesAdapter, - test: hermesAdapter, - publish: hermesAdapter, }, nerveRoot: NERVE_ROOT, extract: { provider }, From a609dc2486cfc9cefe0ff2a0d3d705879f23c94d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Wed, 29 Apr 2026 12:41:10 +0000 Subject: [PATCH 3/3] refactor: derive adapter keys from Meta type instead of manual union --- workflows/develop-sense/build.ts | 7 +++---- workflows/develop-workflow/build.ts | 7 +++---- workflows/solve-issue/build.ts | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/workflows/develop-sense/build.ts b/workflows/develop-sense/build.ts index 3e8904d..e49b0e1 100644 --- a/workflows/develop-sense/build.ts +++ b/workflows/develop-sense/build.ts @@ -9,21 +9,20 @@ import { createPlannerRole } from "./roles/planner.js"; import { createReviewerRole } from "./roles/reviewer.js"; import { createTesterRole } from "./roles/tester.js"; -type DevelopSenseRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer'; - export type CreateDevelopSenseDeps = { defaultAdapter: AgentFn; - adapters?: Partial>; + adapters?: Partial>; extract: LlmExtractorConfig; cwd: string; }; export function createDevelopSenseWorkflow({ + defaultAdapter, adapters, extract, cwd, }: CreateDevelopSenseDeps): WorkflowDefinition { - const a = (role: DevelopSenseRole) => adapters?.[role] ?? defaultAdapter; + const a = (role: keyof SenseMeta) => adapters?.[role] ?? defaultAdapter; const roles = { planner: createPlannerRole(a('planner'), extract), coder: createCoderRole(a('coder'), extract), diff --git a/workflows/develop-workflow/build.ts b/workflows/develop-workflow/build.ts index abcde86..c64c139 100644 --- a/workflows/develop-workflow/build.ts +++ b/workflows/develop-workflow/build.ts @@ -9,21 +9,20 @@ import { createPlannerRole } from "./roles/planner.js"; import { createReviewerRole } from "./roles/reviewer.js"; import { createTesterRole } from "./roles/tester.js"; -type DevelopWorkflowRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer'; - export type CreateDevelopWorkflowDeps = { defaultAdapter: AgentFn; - adapters?: Partial>; + adapters?: Partial>; extract: LlmExtractorConfig; nerveRoot: string; }; export function createDevelopWorkflowWorkflow({ + defaultAdapter, adapters, extract, nerveRoot, }: CreateDevelopWorkflowDeps): WorkflowDefinition { - const a = (role: DevelopWorkflowRole) => adapters?.[role] ?? defaultAdapter; + const a = (role: keyof WorkflowMeta) => adapters?.[role] ?? defaultAdapter; const roles = { planner: createPlannerRole(a('planner'), extract), coder: createCoderRole(a('coder'), extract), diff --git a/workflows/solve-issue/build.ts b/workflows/solve-issue/build.ts index cf267a0..d43499c 100644 --- a/workflows/solve-issue/build.ts +++ b/workflows/solve-issue/build.ts @@ -12,21 +12,20 @@ import { createReadIssueRole } from "./roles/read-issue/index.js"; import { createReviewRole } from "./roles/review/index.js"; import { createTestRole } from "./roles/test/index.js"; -type SolveIssueRole = 'read-issue' | 'prepare' | 'plan' | 'implement' | 'committer' | 'review' | 'test' | 'publish'; - export type CreateSolveIssueDeps = { defaultAdapter: AgentFn; - adapters?: Partial>; + adapters?: Partial>; nerveRoot: string; extract: LlmExtractorConfig; }; export function createSolveIssueWorkflow({ + defaultAdapter, adapters, nerveRoot, extract, }: CreateSolveIssueDeps): WorkflowDefinition { - const a = (role: SolveIssueRole) => adapters?.[role] ?? defaultAdapter; + const a = (role: keyof WorkflowMeta) => adapters?.[role] ?? defaultAdapter; return { name: "solve-issue", roles: {