diff --git a/package.json b/package.json index 44cb05f..da65fd4 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "@uncaged/nerve-adapter-cursor": "link:../repos/nerve/packages/adapter-cursor", "@uncaged/nerve-adapter-hermes": "link:../repos/nerve/packages/adapter-hermes", "@uncaged/nerve-core": "latest", - "@uncaged/nerve-daemon": "latest", "@uncaged/nerve-workflow-utils": "link:../repos/nerve/packages/workflow-utils", "drizzle-orm": "latest", "zod": "^4.3.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08cb6a2..bad942f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,9 +24,6 @@ importers: '@uncaged/nerve-core': specifier: link:../repos/nerve/packages/core version: link:../repos/nerve/packages/core - '@uncaged/nerve-daemon': - specifier: link:../repos/nerve/packages/daemon - version: link:../repos/nerve/packages/daemon '@uncaged/nerve-workflow-utils': specifier: link:../repos/nerve/packages/workflow-utils version: link:../repos/nerve/packages/workflow-utils @@ -112,9 +109,6 @@ importers: '@uncaged/nerve-core': specifier: link:../../../repos/nerve/packages/core version: link:../../../repos/nerve/packages/core - '@uncaged/nerve-daemon': - specifier: link:../../../repos/nerve/packages/daemon - version: link:../../../repos/nerve/packages/daemon '@uncaged/nerve-workflow-utils': specifier: link:../../../repos/nerve/packages/workflow-utils version: link:../../../repos/nerve/packages/workflow-utils @@ -143,9 +137,6 @@ importers: '@uncaged/nerve-core': specifier: link:../../../repos/nerve/packages/core version: link:../../../repos/nerve/packages/core - '@uncaged/nerve-daemon': - specifier: link:../../../repos/nerve/packages/daemon - version: link:../../../repos/nerve/packages/daemon '@uncaged/nerve-workflow-utils': specifier: link:../../../repos/nerve/packages/workflow-utils version: link:../../../repos/nerve/packages/workflow-utils @@ -174,9 +165,6 @@ importers: '@uncaged/nerve-core': specifier: link:../../../repos/nerve/packages/core version: link:../../../repos/nerve/packages/core - '@uncaged/nerve-daemon': - specifier: link:../../../repos/nerve/packages/daemon - version: link:../../../repos/nerve/packages/daemon '@uncaged/nerve-workflow-utils': specifier: link:../../../repos/nerve/packages/workflow-utils version: link:../../../repos/nerve/packages/workflow-utils diff --git a/workflows/develop-sense/build.ts b/workflows/develop-sense/build.ts index 5649151..174c58b 100644 --- a/workflows/develop-sense/build.ts +++ b/workflows/develop-sense/build.ts @@ -1,17 +1,8 @@ -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 { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; +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 { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { coderPrompt } from "./roles/coder/prompt.js"; import { coderMetaSchema } from "./roles/coder/index.js"; @@ -26,84 +17,54 @@ import { moderator } from "./moderator.js"; import type { SenseMeta } from "./moderator.js"; export type BuildSenseGeneratorDeps = { - provider: LlmProvider; + extract: LlmExtractorConfig; cwd: string; }; const CURSOR_TIMEOUT_MS = 300_000; -type SenseAgentMeta = Pick; - -function defaultAgentCreateContext( - workdir: string, -): (start: StartStep, messages: WorkflowMessage[]) => WorkflowContext { - return (start, messages) => ({ - start, - messages, - workdir, - signal: new AbortController().signal, - }); -} - export function buildSenseGenerator({ - provider, + extract, cwd, }: BuildSenseGeneratorDeps): WorkflowDefinition { - const compileDeps: CompileWorkflowSpecDeps = { - extractFn: async (raw: string, schema: Schema, dryRun: boolean) => - createLlmExtractFn({ provider, dryRun })(raw, schema), - createContext: defaultAgentCreateContext(cwd), + 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: buildCommitterRole({ nerveRoot: cwd }), }; - const agentSpec: WorkflowSpec = { - name: "develop-sense", - roles: { - planner: { - adapter: createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - mode: "ask", - }), - prompt: async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), - meta: zodMeta(plannerMetaSchema), - }, - coder: { - adapter: createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - }), - prompt: async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), - meta: zodMeta(coderMetaSchema), - }, - reviewer: { - adapter: hermesAdapter, - prompt: async (start: StartStep) => - reviewerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }), - meta: zodMeta(reviewerMetaSchema), - }, - tester: { - adapter: hermesAdapter, - prompt: async (start: StartStep) => - testerPrompt({ threadId: start.meta.threadId, nerveRoot: cwd }), - meta: zodMeta(testerMetaSchema), - }, - }, - moderator: () => END, - }; - - const compiled = compileWorkflowSpec(agentSpec, compileDeps); - return { name: "develop-sense", - roles: { - planner: compiled.roles.planner, - coder: compiled.roles.coder, - reviewer: compiled.roles.reviewer, - tester: compiled.roles.tester, - committer: buildCommitterRole({ nerveRoot: cwd }), - }, + roles, moderator, }; } diff --git a/workflows/develop-sense/index.ts b/workflows/develop-sense/index.ts index 39f93b1..47363b6 100644 --- a/workflows/develop-sense/index.ts +++ b/workflows/develop-sense/index.ts @@ -12,7 +12,7 @@ if (!apiKey || !baseUrl) { } const workflow = buildSenseGenerator({ - provider: { apiKey, baseUrl, model }, + extract: { provider: { apiKey, baseUrl, model } }, cwd: NERVE_ROOT, }); diff --git a/workflows/develop-sense/package.json b/workflows/develop-sense/package.json index 43e2f26..dff8549 100644 --- a/workflows/develop-sense/package.json +++ b/workflows/develop-sense/package.json @@ -10,7 +10,6 @@ "@uncaged/nerve-adapter-cursor": "latest", "@uncaged/nerve-adapter-hermes": "latest", "@uncaged/nerve-core": "latest", - "@uncaged/nerve-daemon": "latest", "@uncaged/nerve-workflow-utils": "latest", "zod": "^4.3.6" }, diff --git a/workflows/develop-workflow/build.ts b/workflows/develop-workflow/build.ts index bb31777..dbc5d6a 100644 --- a/workflows/develop-workflow/build.ts +++ b/workflows/develop-workflow/build.ts @@ -1,17 +1,8 @@ -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 { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; +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 { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { coderPrompt } from "./roles/coder/prompt.js"; import { coderMetaSchema } from "./roles/coder/index.js"; @@ -26,84 +17,54 @@ import { moderator } from "./moderator.js"; import type { WorkflowMeta } from "./moderator.js"; export type BuildWorkflowGeneratorDeps = { - provider: LlmProvider; + extract: LlmExtractorConfig; nerveRoot: string; }; const CURSOR_TIMEOUT_MS = 300_000; -type WorkflowAgentMeta = Pick; - -function defaultAgentCreateContext( - workdir: string, -): (start: StartStep, messages: WorkflowMessage[]) => WorkflowContext { - return (start, messages) => ({ - start, - messages, - workdir, - signal: new AbortController().signal, - }); -} - export function buildWorkflowGenerator({ - provider, + extract, nerveRoot, }: BuildWorkflowGeneratorDeps): WorkflowDefinition { - const compileDeps: CompileWorkflowSpecDeps = { - extractFn: async (raw: string, schema: Schema, dryRun: boolean) => - createLlmExtractFn({ provider, dryRun })(raw, schema), - createContext: defaultAgentCreateContext(nerveRoot), + 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: buildCommitterRole({ nerveRoot }), }; - const agentSpec: WorkflowSpec = { - name: "develop-workflow", - roles: { - planner: { - adapter: createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - mode: "ask", - }), - prompt: async (start: StartStep) => plannerPrompt({ threadId: start.meta.threadId }), - meta: zodMeta(plannerMetaSchema), - }, - coder: { - adapter: createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, - }), - prompt: async (start: StartStep) => coderPrompt({ threadId: start.meta.threadId }), - meta: zodMeta(coderMetaSchema), - }, - reviewer: { - adapter: hermesAdapter, - prompt: async (start: StartStep) => - reviewerPrompt({ threadId: start.meta.threadId, nerveRoot }), - meta: zodMeta(reviewerMetaSchema), - }, - tester: { - adapter: hermesAdapter, - prompt: async (start: StartStep) => - testerPrompt({ threadId: start.meta.threadId, nerveRoot }), - meta: zodMeta(testerMetaSchema), - }, - }, - moderator: () => END, - }; - - const compiled = compileWorkflowSpec(agentSpec, compileDeps); - return { name: "develop-workflow", - roles: { - planner: compiled.roles.planner, - coder: compiled.roles.coder, - reviewer: compiled.roles.reviewer, - tester: compiled.roles.tester, - committer: buildCommitterRole({ nerveRoot }), - }, + roles, moderator, }; } diff --git a/workflows/develop-workflow/index.ts b/workflows/develop-workflow/index.ts index 61afeb3..7e9c0de 100644 --- a/workflows/develop-workflow/index.ts +++ b/workflows/develop-workflow/index.ts @@ -13,7 +13,7 @@ if (!apiKey || !baseUrl) { } const workflow = buildWorkflowGenerator({ - provider: { apiKey, baseUrl, model }, + extract: { provider: { apiKey, baseUrl, model } }, nerveRoot: NERVE_ROOT, }); diff --git a/workflows/develop-workflow/package.json b/workflows/develop-workflow/package.json index 895d8fa..336bcf0 100644 --- a/workflows/develop-workflow/package.json +++ b/workflows/develop-workflow/package.json @@ -10,7 +10,6 @@ "@uncaged/nerve-adapter-cursor": "latest", "@uncaged/nerve-adapter-hermes": "latest", "@uncaged/nerve-core": "latest", - "@uncaged/nerve-daemon": "latest", "@uncaged/nerve-workflow-utils": "latest", "zod": "^4.3.6" }, diff --git a/workflows/solve-issue/build.ts b/workflows/solve-issue/build.ts index fdac54d..0c67ec3 100644 --- a/workflows/solve-issue/build.ts +++ b/workflows/solve-issue/build.ts @@ -1,16 +1,7 @@ -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 type { StartStep, WorkflowDefinition } from "@uncaged/nerve-core"; import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; -import type { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; +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"; @@ -28,69 +19,44 @@ import { testPrompt } from "./roles/test/prompt.js"; export type BuildSolveIssueDeps = { nerveRoot: string; - provider: LlmProvider; + extract: LlmExtractorConfig; }; -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); - +export function buildSolveIssue({ + nerveRoot, + extract, +}: BuildSolveIssueDeps): WorkflowDefinition { 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 }), + "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 }), + 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 }), }, moderator, }; diff --git a/workflows/solve-issue/index.ts b/workflows/solve-issue/index.ts index c31f7ed..321aef6 100644 --- a/workflows/solve-issue/index.ts +++ b/workflows/solve-issue/index.ts @@ -11,6 +11,6 @@ if (provider === null) { throw new Error("Set DASHSCOPE_API_KEY and DASHSCOPE_BASE_URL (or cfg get equivalents)"); } -const workflow = buildSolveIssue({ nerveRoot: NERVE_ROOT, provider }); +const workflow = buildSolveIssue({ nerveRoot: NERVE_ROOT, extract: { provider } }); export default workflow; diff --git a/workflows/solve-issue/package.json b/workflows/solve-issue/package.json index a05fb08..ce6e1eb 100644 --- a/workflows/solve-issue/package.json +++ b/workflows/solve-issue/package.json @@ -10,7 +10,6 @@ "@uncaged/nerve-adapter-cursor": "latest", "@uncaged/nerve-adapter-hermes": "latest", "@uncaged/nerve-core": "latest", - "@uncaged/nerve-daemon": "latest", "@uncaged/nerve-workflow-utils": "latest", "zod": "^4.3.6" }, diff --git a/workflows/solve-issue/roles/implement/index.ts b/workflows/solve-issue/roles/implement/index.ts index b739e42..0d0dba0 100644 --- a/workflows/solve-issue/roles/implement/index.ts +++ b/workflows/solve-issue/roles/implement/index.ts @@ -1,9 +1,7 @@ -import type { Role, RoleResult, Schema, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { END } from "@uncaged/nerve-core"; -import { compileWorkflowSpec } from "@uncaged/nerve-daemon"; +import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; -import type { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; import { resolveRepoCwd } from "../../lib/repo-context.js"; @@ -15,13 +13,16 @@ export const implementMetaSchema = z.object({ export type ImplementMeta = z.infer; export type BuildImplementDeps = { - provider: LlmProvider; + extract: LlmExtractorConfig; nerveRoot: string; }; const CURSOR_TIMEOUT_MS = 300_000; -export function buildImplementRole({ provider, nerveRoot }: BuildImplementDeps): Role { +export function buildImplementRole({ + extract, + nerveRoot, +}: BuildImplementDeps): Role { return async (start: StartStep, messages: WorkflowMessage[]): Promise> => { const cwd = resolveRepoCwd(messages); if (cwd === null) { @@ -31,42 +32,28 @@ export function buildImplementRole({ provider, nerveRoot }: BuildImplementDeps): }; } - const innerSpec = { - main: { - adapter: createCursorAdapter({ - type: "cursor", - model: "auto", - timeout: CURSOR_TIMEOUT_MS, + const innerRole = createRole( + createCursorAdapter({ + type: "cursor", + model: "auto", + timeout: CURSOR_TIMEOUT_MS, + }), + async (innerStart: StartStep) => + buildImplementPrompt({ + threadId: innerStart.meta.threadId, + nerveRoot, }), - prompt: async (start: StartStep) => - buildImplementPrompt({ - threadId: start.meta.threadId, - nerveRoot, - }), - meta: zodMeta(implementMetaSchema), - }, - }; - - const compiled = compileWorkflowSpec( - { - name: "_implement-inner", - roles: innerSpec, - moderator: () => END, - }, - { - extractFn: async (raw: string, schema: Schema, dryRun: boolean) => - createLlmExtractFn({ provider, dryRun })(raw, schema), - createContext: (s, m) => ({ - start: s, - messages: m, - workdir: cwd, - signal: new AbortController().signal, - }), - }, + implementMetaSchema, + extract, ); + const innerStart = { + ...start, + meta: { ...start.meta, workdir: cwd }, + } as StartStep; + try { - return await compiled.roles.main(start, messages); + return await innerRole(innerStart, messages); } catch (e) { const msg = e instanceof Error ? e.message : String(e); return { diff --git a/workflows/solve-issue/roles/plan/index.ts b/workflows/solve-issue/roles/plan/index.ts index 192ce88..c17a4db 100644 --- a/workflows/solve-issue/roles/plan/index.ts +++ b/workflows/solve-issue/roles/plan/index.ts @@ -1,9 +1,7 @@ -import type { Role, RoleResult, Schema, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { END } from "@uncaged/nerve-core"; -import { compileWorkflowSpec } from "@uncaged/nerve-daemon"; +import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import { createCursorAdapter } from "@uncaged/nerve-adapter-cursor"; -import type { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; import { resolveRepoCwd } from "../../lib/repo-context.js"; @@ -15,13 +13,13 @@ export const planMetaSchema = z.object({ export type PlanMeta = z.infer; export type BuildPlanDeps = { - provider: LlmProvider; + extract: LlmExtractorConfig; nerveRoot: string; }; const CURSOR_TIMEOUT_MS = 300_000; -export function buildPlanRole({ provider, nerveRoot }: BuildPlanDeps): Role { +export function buildPlanRole({ extract, nerveRoot }: BuildPlanDeps): Role { return async (start: StartStep, messages: WorkflowMessage[]): Promise> => { const cwd = resolveRepoCwd(messages); if (cwd === null) { @@ -31,43 +29,29 @@ export function buildPlanRole({ provider, nerveRoot }: BuildPlanDeps): Role + buildPlanPrompt({ + threadId: innerStart.meta.threadId, + nerveRoot, }), - prompt: async (start: StartStep) => - buildPlanPrompt({ - threadId: start.meta.threadId, - nerveRoot, - }), - meta: zodMeta(planMetaSchema), - }, - }; - - const compiled = compileWorkflowSpec( - { - name: "_plan-inner", - roles: innerSpec, - moderator: () => END, - }, - { - extractFn: async (raw: string, schema: Schema, dryRun: boolean) => - createLlmExtractFn({ provider, dryRun })(raw, schema), - createContext: (s, m) => ({ - start: s, - messages: m, - workdir: cwd, - signal: new AbortController().signal, - }), - }, + planMetaSchema, + extract, ); + const innerStart = { + ...start, + meta: { ...start.meta, workdir: cwd }, + } as StartStep; + try { - return await compiled.roles.main(start, messages); + return await innerRole(innerStart, messages); } catch (e) { const msg = e instanceof Error ? e.message : String(e); return { diff --git a/workflows/solve-issue/roles/publish/index.ts b/workflows/solve-issue/roles/publish/index.ts index d42ad18..a314638 100644 --- a/workflows/solve-issue/roles/publish/index.ts +++ b/workflows/solve-issue/roles/publish/index.ts @@ -1,11 +1,9 @@ import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; -import type { Role, RoleResult, Schema, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; -import { END } from "@uncaged/nerve-core"; -import { compileWorkflowSpec } from "@uncaged/nerve-daemon"; +import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core"; import { hermesAdapter } from "@uncaged/nerve-adapter-hermes"; -import type { LlmProvider } from "@uncaged/nerve-workflow-utils"; -import { createLlmExtractFn, isDryRun, zodMeta } from "@uncaged/nerve-workflow-utils"; +import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; +import { createRole, isDryRun } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; import { buildPublishPrompt } from "./prompt.js"; @@ -16,42 +14,22 @@ export const publishMetaSchema = z.object({ export type PublishMeta = z.infer; export type BuildPublishDeps = { - provider: LlmProvider; + extract: LlmExtractorConfig; nerveRoot: string; }; -function defaultAgentCreateContext(nerveRoot: string) { - return (start: StartStep, messages: WorkflowMessage[]) => ({ - start, - messages, - workdir: nerveRoot, - signal: new AbortController().signal, - }); -} - function logPath(nerveRoot: string): string { return join(nerveRoot, "logs", `solve-issue-publish-${Date.now()}.log`); } -export function buildPublishRole({ provider, nerveRoot }: BuildPublishDeps): Role { - const runHermes = compileWorkflowSpec( - { - name: "_publish-inner", - roles: { - main: { - adapter: hermesAdapter, - prompt: async (start: StartStep) => buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }), - meta: zodMeta(publishMetaSchema), - }, - }, - moderator: () => END, - }, - { - extractFn: async (raw: string, schema: Schema, dryRun: boolean) => - createLlmExtractFn({ provider, dryRun })(raw, schema), - createContext: defaultAgentCreateContext(nerveRoot), - }, - ).roles.main; +export function buildPublishRole({ extract, nerveRoot }: BuildPublishDeps): Role { + const innerRole = createRole( + hermesAdapter, + async (start: StartStep) => + buildPublishPrompt({ threadId: start.meta.threadId, nerveRoot }), + publishMetaSchema, + extract, + ); return async (start: StartStep, messages: WorkflowMessage[]): Promise> => { const file = logPath(nerveRoot); @@ -66,8 +44,13 @@ export function buildPublishRole({ provider, nerveRoot }: BuildPublishDeps): Rol }; } + const innerStart = { + ...start, + meta: { ...start.meta, workdir: nerveRoot }, + } as StartStep; + try { - return await runHermes(start, messages); + return await innerRole(innerStart, messages); } catch (e) { const msg = e instanceof Error ? e.message : String(e); const body = `publish failed: ${msg}\n`;