import type { Schema, StartStep, WorkflowContext, WorkflowDefinition, WorkflowMessage, WorkflowSpec, } from "@uncaged/nerve-core"; import { END } from "@uncaged/nerve-core"; import { compileWorkflowSpec, type CompileWorkflowSpecDeps } from "@uncaged/nerve-daemon"; import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; import type { LlmProvider } from "@uncaged/nerve-workflow-utils"; import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; import { moderator } from "./moderator.js"; import type { WorkflowMeta } from "./moderator.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"; export type BuildSolveIssueDeps = { nerveRoot: string; provider: LlmProvider; }; type SolveHermesAgentMeta = Pick; function defaultAgentCreateContext( workdir: string, ): (start: StartStep, messages: WorkflowMessage[]) => WorkflowContext { return (start, messages) => ({ start, messages, workdir, signal: new AbortController().signal, }); } export function buildSolveIssue({ nerveRoot, provider }: BuildSolveIssueDeps): WorkflowDefinition { const compileDeps: CompileWorkflowSpecDeps = { extractFn: async (raw: string, schema: Schema, dryRun: boolean) => createLlmExtractFn({ provider, dryRun })(raw, schema), createContext: defaultAgentCreateContext(nerveRoot), }; const agentSpec: WorkflowSpec = { name: "solve-issue", roles: { "read-issue": { adapter: hermesAdapter, prompt: async (start: StartStep) => readIssuePrompt({ threadId: start.meta.threadId }), meta: zodMeta(readIssueMetaSchema), }, prepare: { adapter: hermesAdapter, prompt: async (start: StartStep) => preparePrompt({ threadId: start.meta.threadId }), meta: zodMeta(prepareMetaSchema), }, review: { adapter: hermesAdapter, prompt: async (start: StartStep) => reviewPrompt({ threadId: start.meta.threadId, nerveRoot }), meta: zodMeta(reviewMetaSchema), }, test: { adapter: hermesAdapter, prompt: async (start: StartStep) => testPrompt({ threadId: start.meta.threadId }), meta: zodMeta(testMetaSchema), }, }, moderator: () => END, }; const compiled = compileWorkflowSpec(agentSpec, compileDeps); return { name: "solve-issue", roles: { "read-issue": compiled.roles["read-issue"], prepare: compiled.roles.prepare, plan: buildPlanRole({ provider, nerveRoot }), implement: buildImplementRole({ provider, nerveRoot }), review: compiled.roles.review, test: compiled.roles.test, publish: buildPublishRole({ provider, nerveRoot }), }, moderator, }; }