import type { AgentRunLog } from "@/lib/agent-run-log-types"; /** Markdown export for pasting into an LLM — safe for client bundles (no Redis). */ export function buildDebugTrace(run: AgentRunLog): string { const lines: string[] = []; const ts = new Date(run.startedAt).toISOString(); lines.push("# Job Scorer Agent Debug Trace"); lines.push(`Run ID: \`${run.runId}\``); lines.push(`User: \`${run.userId}\``); if (run.sessionId) lines.push(`Session: \`${run.sessionId}\``); lines.push(`Started: ${ts}`); lines.push(`Duration: ${(run.durationMs / 1000).toFixed(1)}s`); lines.push(`Stopped because: **${run.stoppedBecause}**`); lines.push(`Credit cost: ${run.creditCost}`); lines.push(`Result: ${run.finalResultSummary ?? "none"}`); if (run.errorMessage) lines.push(`Run error: ${run.errorMessage}`); lines.push(""); lines.push("## Completion Steps (LLM decisions)"); for (const step of run.completionSteps) { lines.push(`### Step ${step.stepIndex + 1} — ${step.model || "?"} (${step.provider})`); lines.push(`Duration: ${step.durationMs}ms`); if (step.assistantReasoningText) { lines.push("**Model reasoning before tool call:**"); lines.push(`> ${step.assistantReasoningText.replace(/\n/g, "\n> ")}`); } if (step.toolCalls?.length) { lines.push("**Tool calls chosen:**"); for (const tc of step.toolCalls) { lines.push(`- \`${tc.name}\`: \`${JSON.stringify(tc.input).slice(0, 200)}\``); } } else if (!step.errorMessage) { lines.push("*No tool call — final response turn*"); } if (step.errorMessage) { lines.push(`**Error:** ${step.errorMessage}`); } if (step.messages?.length) { lines.push(`
Full message array (${step.messages.length} messages)`); lines.push(""); lines.push("```json"); lines.push(JSON.stringify(step.messages, null, 2).slice(0, 8000)); lines.push("```"); lines.push("
"); } lines.push(""); } lines.push("## Tool Timeline"); for (const t of run.tools) { const status = t.status === "ok" ? "✓" : t.status === "error" ? "✗" : "⚠"; lines.push(`${status} **${t.tool}** — ${t.durationMs}ms — ${t.provider ?? "unknown provider"}`); if (t.resultSummary) lines.push(` Result: ${t.resultSummary}`); if (t.creditCost !== undefined && t.creditCost > 0) lines.push(` Credits: ${t.creditCost}`); if (t.input && Object.keys(t.input).length > 0) { lines.push(` Input: \`${JSON.stringify(t.input).slice(0, 300)}\``); } } lines.push(""); lines.push("---"); lines.push("*Job Scorer debug trace — paste into Claude for diagnosis*"); return lines.join("\n"); }