小橘 🍊(NEKO Team) 70fd064bad Refactor workflows to use compileWorkflowSpec from nerve-daemon
Remove workflows/_shared; wire createLlmExtractFn, zodMeta, and createCursorAdapter(mode ask). Plan/implement/publish compile inner specs via daemon.

Made-with: Cursor
2026-04-29 09:35:13 +00:00

110 lines
3.5 KiB
TypeScript

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 { hermesAdapter } from "@uncaged/nerve-adapter-hermes";
import type { LlmProvider } from "@uncaged/nerve-workflow-utils";
import { createLlmExtractFn, zodMeta } from "@uncaged/nerve-workflow-utils";
import { coderPrompt } from "./roles/coder/prompt.js";
import { coderMetaSchema } from "./roles/coder/index.js";
import { plannerPrompt } from "./roles/planner/prompt.js";
import { plannerMetaSchema } from "./roles/planner/index.js";
import { reviewerPrompt } from "./roles/reviewer/prompt.js";
import { reviewerMetaSchema } from "./roles/reviewer/index.js";
import { testerPrompt } from "./roles/tester/prompt.js";
import { testerMetaSchema } from "./roles/tester/index.js";
import { buildCommitterRole } from "./roles/committer/index.js";
import { moderator } from "./moderator.js";
import type { SenseMeta } from "./moderator.js";
export type BuildSenseGeneratorDeps = {
provider: LlmProvider;
cwd: string;
};
const CURSOR_TIMEOUT_MS = 300_000;
type SenseAgentMeta = Pick<SenseMeta, "planner" | "coder" | "reviewer" | "tester">;
function defaultAgentCreateContext(
workdir: string,
): (start: StartStep, messages: WorkflowMessage[]) => WorkflowContext {
return (start, messages) => ({
start,
messages,
workdir,
signal: new AbortController().signal,
});
}
export function buildSenseGenerator({
provider,
cwd,
}: BuildSenseGeneratorDeps): WorkflowDefinition<SenseMeta> {
const compileDeps: CompileWorkflowSpecDeps = {
extractFn: async <T>(raw: string, schema: Schema<T>, dryRun: boolean) =>
createLlmExtractFn<T>({ provider, dryRun })(raw, schema),
createContext: defaultAgentCreateContext(cwd),
};
const agentSpec: WorkflowSpec<SenseAgentMeta> = {
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 }),
},
moderator,
};
}