The previous commit incorrectly deleted all workflows. Only restart-gateway should be removed (replaced by direct shell trigger). Other workflows (solve-issue, extract-knowledge, develop-sense, develop-workflow) are CLI-triggered and independent of sense coupling.
89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import type { AgentFn, Role, RoleResult, ThreadContext, WorkflowMessage } from "@uncaged/nerve-core";
|
|
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";
|
|
|
|
function buildPlanPrompt({ threadId, nerveRoot }: { threadId: string; nerveRoot: string }): string {
|
|
return `You are the **plan** agent (analysis only — ask mode). You produce an implementation plan for fixing the issue.
|
|
|
|
Read workflow context: \`nerve thread show ${threadId}\`
|
|
|
|
Read Nerve workspace conventions (coding rules for agents): \`cat ${nerveRoot}/CONVENTIONS.md\`
|
|
|
|
In the **target repository** (your cwd), skim relevant files and read \`CONVENTIONS.md\` **if it exists** there.
|
|
|
|
## Output
|
|
|
|
Write an implementation plan in **markdown** with:
|
|
|
|
1. Problem understanding
|
|
2. Change strategy
|
|
3. Target files (paths)
|
|
4. **Test commands** to run (explicit shell commands, e.g. \`pnpm test\`, \`pnpm vitest run\`)
|
|
5. Risks
|
|
|
|
End your reply with a JSON code block (meta signal):
|
|
\`\`\`json
|
|
{ "ready": true }
|
|
\`\`\`
|
|
Use \`{ "ready": false }\` if the plan cannot be made actionable.
|
|
|
|
**ready=true** only when the plan is clear and actionable.`;
|
|
}
|
|
|
|
export const planMetaSchema = z.object({
|
|
ready: z.boolean().describe("true if plan is clear and actionable"),
|
|
});
|
|
export type PlanMeta = z.infer<typeof planMetaSchema>;
|
|
|
|
export type CreatePlanRoleDeps = {
|
|
extract: LlmExtractorConfig;
|
|
nerveRoot: string;
|
|
};
|
|
|
|
export function createPlanRole(
|
|
adapter: AgentFn,
|
|
{ extract, nerveRoot }: CreatePlanRoleDeps,
|
|
): Role<PlanMeta> {
|
|
return async (ctx: ThreadContext): Promise<RoleResult<PlanMeta>> => {
|
|
const messages = ctx.steps as unknown as WorkflowMessage[];
|
|
const cwd = resolveRepoCwd(messages);
|
|
if (cwd === null) {
|
|
return {
|
|
content: "plan cannot run: missing ---SOLVE_ISSUE_REPO--- or ---SOLVE_ISSUE_PARSE--- in thread",
|
|
meta: { ready: false },
|
|
};
|
|
}
|
|
|
|
const innerRole = createRole(
|
|
adapter,
|
|
async (innerCtx: ThreadContext) =>
|
|
buildPlanPrompt({
|
|
threadId: innerCtx.start.meta.threadId,
|
|
nerveRoot,
|
|
}),
|
|
planMetaSchema,
|
|
extract,
|
|
);
|
|
|
|
const innerCtx: ThreadContext = {
|
|
...ctx,
|
|
start: {
|
|
...ctx.start,
|
|
meta: { ...ctx.start.meta, workdir: cwd },
|
|
},
|
|
};
|
|
try {
|
|
return await innerRole(innerCtx);
|
|
} catch (e) {
|
|
const msg = e instanceof Error ? e.message : String(e);
|
|
return {
|
|
content: `plan failed: ${msg}`,
|
|
meta: { ready: false },
|
|
};
|
|
}
|
|
};
|
|
}
|