53 lines
1.7 KiB
TypeScript

import type { Role, RoleResult, StartStep, WorkflowMessage } from "@uncaged/nerve-core";
import type { LlmProvider } from "@uncaged/nerve-workflow-utils";
import { createCursorRole } from "@uncaged/nerve-workflow-utils";
import { z } from "zod";
import { resolveRepoCwd } from "../../lib/repo-context.js";
import { buildImplementPrompt } from "./prompt.js";
export const implementMetaSchema = z.object({
done: z.boolean().describe("true when changes are complete and build passes this round"),
});
export type ImplementMeta = z.infer<typeof implementMetaSchema>;
export type BuildImplementDeps = {
provider: LlmProvider;
nerveRoot: string;
};
export function buildImplementRole({ provider, nerveRoot }: BuildImplementDeps): Role<ImplementMeta> {
return async (start: StartStep, messages: WorkflowMessage[]): Promise<RoleResult<ImplementMeta>> => {
const cwd = resolveRepoCwd(messages);
if (cwd === null) {
return {
content: "implement cannot run: missing repo path in thread markers",
meta: { done: false },
};
}
const runRole = createCursorRole<ImplementMeta>({
cwd,
mode: "default",
model: "auto",
env: {},
timeoutMs: 300_000,
prompt: async () =>
buildImplementPrompt({
threadId: (start.meta as { threadId?: string }).threadId ?? "unknown",
nerveRoot,
}),
extract: { provider, schema: implementMetaSchema },
});
try {
return await runRole(start, messages);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
return {
content: `implement failed: ${msg}`,
meta: { done: false },
};
}
};
}