refactor: add defaultAdapter + typed role union, adapters becomes Partial

- Each workflow factory takes defaultAdapter: AgentFn + adapters?: Partial<Record<RoleUnion, AgentFn>>
- index.ts only overrides roles that differ from default (planner/coder use cursor, rest fallback)
- Cleaner call sites, type-safe role names

Refs #15
This commit is contained in:
小橘 2026-04-29 12:38:21 +00:00
parent 1683e41b05
commit eaddd88109
6 changed files with 36 additions and 33 deletions

View File

@ -9,8 +9,11 @@ import { createPlannerRole } from "./roles/planner.js";
import { createReviewerRole } from "./roles/reviewer.js"; import { createReviewerRole } from "./roles/reviewer.js";
import { createTesterRole } from "./roles/tester.js"; import { createTesterRole } from "./roles/tester.js";
type DevelopSenseRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer';
export type CreateDevelopSenseDeps = { export type CreateDevelopSenseDeps = {
adapters: Record<string, AgentFn>; defaultAdapter: AgentFn;
adapters?: Partial<Record<DevelopSenseRole, AgentFn>>;
extract: LlmExtractorConfig; extract: LlmExtractorConfig;
cwd: string; cwd: string;
}; };
@ -20,12 +23,13 @@ export function createDevelopSenseWorkflow({
extract, extract,
cwd, cwd,
}: CreateDevelopSenseDeps): WorkflowDefinition<SenseMeta> { }: CreateDevelopSenseDeps): WorkflowDefinition<SenseMeta> {
const a = (role: DevelopSenseRole) => adapters?.[role] ?? defaultAdapter;
const roles = { const roles = {
planner: createPlannerRole(adapters.planner, extract), planner: createPlannerRole(a('planner'), extract),
coder: createCoderRole(adapters.coder, extract), coder: createCoderRole(a('coder'), extract),
reviewer: createReviewerRole(adapters.reviewer, extract, cwd), reviewer: createReviewerRole(a('reviewer'), extract, cwd),
tester: createTesterRole(adapters.tester, extract, cwd), tester: createTesterRole(a('tester'), extract, cwd),
committer: createWorkspaceCommitterRole(adapters.committer, { committer: createWorkspaceCommitterRole(a('committer'), {
extract, extract,
nerveRoot: cwd, nerveRoot: cwd,
workflowName: "develop-sense", workflowName: "develop-sense",

View File

@ -16,6 +16,7 @@ if (!apiKey || !baseUrl) {
const CURSOR_TIMEOUT_MS = 300_000; const CURSOR_TIMEOUT_MS = 300_000;
const workflow = createDevelopSenseWorkflow({ const workflow = createDevelopSenseWorkflow({
defaultAdapter: hermesAdapter,
adapters: { adapters: {
planner: createCursorAdapter({ planner: createCursorAdapter({
type: "cursor", type: "cursor",
@ -24,9 +25,6 @@ const workflow = createDevelopSenseWorkflow({
timeout: CURSOR_TIMEOUT_MS, timeout: CURSOR_TIMEOUT_MS,
}), }),
coder: cursorAdapter, coder: cursorAdapter,
reviewer: hermesAdapter,
tester: hermesAdapter,
committer: hermesAdapter,
}, },
extract: { provider: { apiKey, baseUrl, model } }, extract: { provider: { apiKey, baseUrl, model } },
cwd: NERVE_ROOT, cwd: NERVE_ROOT,

View File

@ -9,8 +9,11 @@ import { createPlannerRole } from "./roles/planner.js";
import { createReviewerRole } from "./roles/reviewer.js"; import { createReviewerRole } from "./roles/reviewer.js";
import { createTesterRole } from "./roles/tester.js"; import { createTesterRole } from "./roles/tester.js";
type DevelopWorkflowRole = 'planner' | 'coder' | 'reviewer' | 'tester' | 'committer';
export type CreateDevelopWorkflowDeps = { export type CreateDevelopWorkflowDeps = {
adapters: Record<string, AgentFn>; defaultAdapter: AgentFn;
adapters?: Partial<Record<DevelopWorkflowRole, AgentFn>>;
extract: LlmExtractorConfig; extract: LlmExtractorConfig;
nerveRoot: string; nerveRoot: string;
}; };
@ -20,12 +23,13 @@ export function createDevelopWorkflowWorkflow({
extract, extract,
nerveRoot, nerveRoot,
}: CreateDevelopWorkflowDeps): WorkflowDefinition<WorkflowMeta> { }: CreateDevelopWorkflowDeps): WorkflowDefinition<WorkflowMeta> {
const a = (role: DevelopWorkflowRole) => adapters?.[role] ?? defaultAdapter;
const roles = { const roles = {
planner: createPlannerRole(adapters.planner, extract), planner: createPlannerRole(a('planner'), extract),
coder: createCoderRole(adapters.coder, extract), coder: createCoderRole(a('coder'), extract),
reviewer: createReviewerRole(adapters.reviewer, extract, nerveRoot), reviewer: createReviewerRole(a('reviewer'), extract, nerveRoot),
tester: createTesterRole(adapters.tester, extract, nerveRoot), tester: createTesterRole(a('tester'), extract, nerveRoot),
committer: createWorkspaceCommitterRole(adapters.committer, { committer: createWorkspaceCommitterRole(a('committer'), {
extract, extract,
nerveRoot, nerveRoot,
workflowName: "develop-workflow", workflowName: "develop-workflow",

View File

@ -17,6 +17,7 @@ if (!apiKey || !baseUrl) {
const CURSOR_TIMEOUT_MS = 300_000; const CURSOR_TIMEOUT_MS = 300_000;
const workflow = createDevelopWorkflowWorkflow({ const workflow = createDevelopWorkflowWorkflow({
defaultAdapter: hermesAdapter,
adapters: { adapters: {
planner: createCursorAdapter({ planner: createCursorAdapter({
type: "cursor", type: "cursor",
@ -25,9 +26,6 @@ const workflow = createDevelopWorkflowWorkflow({
timeout: CURSOR_TIMEOUT_MS, timeout: CURSOR_TIMEOUT_MS,
}), }),
coder: cursorAdapter, coder: cursorAdapter,
reviewer: hermesAdapter,
tester: hermesAdapter,
committer: hermesAdapter,
}, },
extract: { provider: { apiKey, baseUrl, model } }, extract: { provider: { apiKey, baseUrl, model } },
nerveRoot: NERVE_ROOT, nerveRoot: NERVE_ROOT,

View File

@ -12,8 +12,11 @@ import { createReadIssueRole } from "./roles/read-issue/index.js";
import { createReviewRole } from "./roles/review/index.js"; import { createReviewRole } from "./roles/review/index.js";
import { createTestRole } from "./roles/test/index.js"; import { createTestRole } from "./roles/test/index.js";
type SolveIssueRole = 'read-issue' | 'prepare' | 'plan' | 'implement' | 'committer' | 'review' | 'test' | 'publish';
export type CreateSolveIssueDeps = { export type CreateSolveIssueDeps = {
adapters: Record<string, AgentFn>; defaultAdapter: AgentFn;
adapters?: Partial<Record<SolveIssueRole, AgentFn>>;
nerveRoot: string; nerveRoot: string;
extract: LlmExtractorConfig; extract: LlmExtractorConfig;
}; };
@ -23,17 +26,18 @@ export function createSolveIssueWorkflow({
nerveRoot, nerveRoot,
extract, extract,
}: CreateSolveIssueDeps): WorkflowDefinition<WorkflowMeta> { }: CreateSolveIssueDeps): WorkflowDefinition<WorkflowMeta> {
const a = (role: SolveIssueRole) => adapters?.[role] ?? defaultAdapter;
return { return {
name: "solve-issue", name: "solve-issue",
roles: { roles: {
"read-issue": createReadIssueRole(adapters["read-issue"], extract), "read-issue": createReadIssueRole(a("read-issue"), extract),
prepare: createPrepareRole(adapters.prepare, extract), prepare: createPrepareRole(a("prepare"), extract),
plan: createPlanRole(adapters.plan, { extract, nerveRoot }), plan: createPlanRole(a("plan"), { extract, nerveRoot }),
implement: createImplementRole(adapters.implement, { extract, nerveRoot }), implement: createImplementRole(a("implement"), { extract, nerveRoot }),
committer: createCommitterRole(adapters.committer, { extract, nerveRoot }), committer: createCommitterRole(a("committer"), { extract, nerveRoot }),
review: createReviewRole(adapters.review, extract, nerveRoot), review: createReviewRole(a("review"), extract, nerveRoot),
test: createTestRole(adapters.test, extract), test: createTestRole(a("test"), extract),
publish: createPublishRole(adapters.publish, { extract, nerveRoot }), publish: createPublishRole(a("publish"), { extract, nerveRoot }),
}, },
moderator, moderator,
}; };

View File

@ -16,9 +16,8 @@ if (provider === null) {
const CURSOR_TIMEOUT_MS = 300_000; const CURSOR_TIMEOUT_MS = 300_000;
const workflow = createSolveIssueWorkflow({ const workflow = createSolveIssueWorkflow({
defaultAdapter: hermesAdapter,
adapters: { adapters: {
"read-issue": hermesAdapter,
prepare: hermesAdapter,
plan: createCursorAdapter({ plan: createCursorAdapter({
type: "cursor", type: "cursor",
mode: "ask", mode: "ask",
@ -30,10 +29,6 @@ const workflow = createSolveIssueWorkflow({
model: "auto", model: "auto",
timeout: CURSOR_TIMEOUT_MS, timeout: CURSOR_TIMEOUT_MS,
}), }),
committer: hermesAdapter,
review: hermesAdapter,
test: hermesAdapter,
publish: hermesAdapter,
}, },
nerveRoot: NERVE_ROOT, nerveRoot: NERVE_ROOT,
extract: { provider }, extract: { provider },