import type { AgentFn, Role, ThreadContext } from "@uncaged/nerve-core"; import type { LlmExtractorConfig } from "@uncaged/nerve-workflow-utils"; import { createRole } from "@uncaged/nerve-workflow-utils"; import { z } from "zod"; function testPrompt({ threadId }: { threadId: string }): string { return `You are the **test** agent (Hermes). You execute automated tests for the change. Read workflow context: \`nerve thread show ${threadId}\` Find **repo path** from \`---SOLVE_ISSUE_REPO--- path:\` in the thread. From the **plan** step output, locate **Test commands** (explicit shell commands). Run each command with cwd = repo path, in order. If the plan lists **no** test commands, try **pnpm test**, then **npm test** if pnpm is unavailable; if neither applies, explain skip. Collect stdout/stderr snippets on failure. End with JSON only: \`\`\`json { "passed": true } \`\`\` or \`{ "passed": false }\` **passed=true** only if every executed command exited 0 (or skip was justified with no failing command).`; } export const testMetaSchema = z.object({ passed: z.boolean().describe("true if all test commands passed"), }); export type TestMeta = z.infer; export function createTestRole(adapter: AgentFn, extract: LlmExtractorConfig): Role { return createRole( adapter, async (ctx: ThreadContext) => testPrompt({ threadId: ctx.start.meta.threadId }), testMetaSchema, extract, ); }