@rallycry/conveyor-agent 7.2.8 → 7.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7300,7 +7300,7 @@ var ProjectRunner = class {
7300
7300
  async handleAuditTags(request) {
7301
7301
  this.connection.emitStatus("busy");
7302
7302
  try {
7303
- const { handleTagAudit } = await import("./tag-audit-handler-ZJYIOGCJ.js");
7303
+ const { handleTagAudit } = await import("./tag-audit-handler-I54W7ZD7.js");
7304
7304
  await handleTagAudit(request, this.connection, this.projectDir);
7305
7305
  } catch (error) {
7306
7306
  const msg = error instanceof Error ? error.message : String(error);
@@ -7323,7 +7323,7 @@ var ProjectRunner = class {
7323
7323
  async handleAuditTasks(request) {
7324
7324
  this.connection.emitStatus("busy");
7325
7325
  try {
7326
- const { handleTaskAudit } = await import("./task-audit-handler-GAG6XDGJ.js");
7326
+ const { handleTaskAudit } = await import("./task-audit-handler-6XWYK6KZ.js");
7327
7327
  await handleTaskAudit(request, this.connection, this.projectDir);
7328
7328
  } catch (error) {
7329
7329
  const msg = error instanceof Error ? error.message : String(error);
@@ -7768,4 +7768,4 @@ export {
7768
7768
  loadForwardPorts,
7769
7769
  loadConveyorConfig
7770
7770
  };
7771
- //# sourceMappingURL=chunk-M7XPR3PU.js.map
7771
+ //# sourceMappingURL=chunk-PAKPHIMK.js.map
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  loadConveyorConfig,
6
6
  runSetupCommand,
7
7
  runStartCommand
8
- } from "./chunk-M7XPR3PU.js";
8
+ } from "./chunk-PAKPHIMK.js";
9
9
  import "./chunk-C5YAMQJ2.js";
10
10
  import {
11
11
  createServiceLogger
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  runStartCommand,
25
25
  stageAndCommit,
26
26
  updateRemoteToken
27
- } from "./chunk-M7XPR3PU.js";
27
+ } from "./chunk-PAKPHIMK.js";
28
28
  import "./chunk-C5YAMQJ2.js";
29
29
  import "./chunk-RRXX6DTB.js";
30
30
 
@@ -109,12 +109,20 @@ After your analysis, output a JSON block in this exact format:
109
109
  Always provide recommendations. Even well-organized projects have room for improvement \u2014 look for missing context links, stale descriptions, documentation gaps, and tag coverage opportunities. Aim for at least 3-5 recommendations. Be specific, actionable, and concise.`;
110
110
  async function fetchModel(connection) {
111
111
  try {
112
- const ctx = await connection.call("getProjectAgentContext", {
113
- projectId: connection.projectId
112
+ const config = await connection.call("getProjectFunctionConfig", {
113
+ projectId: connection.projectId,
114
+ functionId: "tagAudit"
114
115
  });
115
- return ctx.model || FALLBACK_MODEL;
116
+ return config.model || FALLBACK_MODEL;
116
117
  } catch {
117
- return FALLBACK_MODEL;
118
+ try {
119
+ const ctx = await connection.call("getProjectAgentContext", {
120
+ projectId: connection.projectId
121
+ });
122
+ return ctx.model || FALLBACK_MODEL;
123
+ } catch {
124
+ return FALLBACK_MODEL;
125
+ }
118
126
  }
119
127
  }
120
128
  function extractJsonFromResponse(text) {
@@ -211,4 +219,4 @@ export {
211
219
  buildTagAuditPrompt,
212
220
  handleTagAudit
213
221
  };
214
- //# sourceMappingURL=tag-audit-handler-ZJYIOGCJ.js.map
222
+ //# sourceMappingURL=tag-audit-handler-I54W7ZD7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runner/tag-audit-handler.ts"],"sourcesContent":["import { createHarness } from \"../harness/index.js\";\nimport type { ProjectConnection } from \"../connection/project-connection.js\";\nimport type { TagAuditRunnerRequest } from \"@project/shared\";\nimport { createServiceLogger } from \"../utils/logger.js\";\n\nconst logger = createServiceLogger(\"TagAudit\");\n\nconst FALLBACK_MODEL = \"claude-sonnet-4-6\";\n\n// ── Prompt section builders ────────────────────────────────────────────\n\nfunction buildTagsSection(request: TagAuditRunnerRequest, parts: string[]): void {\n parts.push(\"## Current Tags\\n\");\n if (request.tags.length === 0) {\n parts.push(\"No tags currently exist.\\n\");\n } else {\n for (const tag of request.tags) {\n parts.push(`### ${tag.name} (id: ${tag.id})`);\n parts.push(`- Description: ${tag.description ?? \"(none)\"}`);\n parts.push(`- Active tasks: ${tag.activeTaskCount}`);\n if (tag.contextPaths) {\n parts.push(`- Context paths: ${JSON.stringify(tag.contextPaths)}`);\n }\n parts.push(\"\");\n }\n }\n}\n\nfunction buildContextSections(request: TagAuditRunnerRequest, parts: string[]): void {\n if (request.objectives && request.objectives.length > 0) {\n parts.push(\"## Project Objectives\\n\");\n for (const obj of request.objectives) {\n parts.push(`- **${obj.name}**${obj.description ? `: ${obj.description}` : \"\"}`);\n }\n parts.push(\"\");\n }\n\n if (request.tagRules && request.tagRules.length > 0) {\n parts.push(\"## Tag Rules\\n\");\n parts.push(\"These tags have associated rule files that agents load automatically:\\n\");\n for (const rule of request.tagRules) {\n parts.push(`- **${rule.tagName}** → \\`${rule.rulePath}\\``);\n }\n parts.push(\"\");\n }\n\n if (request.fileHeatmap.length > 0) {\n parts.push(\"## File Access Heatmap\\n\");\n parts.push(\"Files most frequently read by agents, broken down by tag:\\n\");\n for (const entry of request.fileHeatmap.slice(0, 50)) {\n const tagBreakdown = Object.entries(entry.byTag)\n .map(([tag, count]) => `${tag}: ${count}`)\n .join(\", \");\n parts.push(`- \\`${entry.filePath}\\` (total: ${entry.totalReads}) — ${tagBreakdown}`);\n }\n parts.push(\"\");\n }\n\n if (request.recentTaskSamples && request.recentTaskSamples.length > 0) {\n parts.push(\"## Recent Task Samples\\n\");\n parts.push(\"Recent tasks per tag (to understand how tags are used):\\n\");\n for (const sample of request.recentTaskSamples) {\n parts.push(`### ${sample.tagName}`);\n for (const task of sample.tasks) {\n parts.push(`- ${task.title} (${task.status})`);\n }\n parts.push(\"\");\n }\n }\n}\n\n// ── Prompt builder ──────────────────────────────────────────────────────\n\nexport function buildTagAuditPrompt(request: TagAuditRunnerRequest): string {\n const parts: string[] = [];\n\n parts.push(`# Tag Audit for project: ${request.projectName}\\n`);\n buildTagsSection(request, parts);\n buildContextSections(request, parts);\n parts.push(\"Analyze the tags above and the codebase, then output your recommendations.\");\n\n return parts.join(\"\\n\");\n}\n\nconst TAG_AUDIT_SYSTEM_PROMPT = `You are analyzing tags for a software project. Tags are used to organize tasks, associate context paths (files/directories that agents should read), and track work areas.\n\nGiven the current tags (with descriptions, context paths, and active task counts) and a file access heatmap (which files agents read most, broken down by tag), analyze the project and generate recommendations.\n\nYou have full access to the codebase. Read relevant files — especially .claude/rules/, README files, and any context paths referenced by existing tags — to validate your recommendations.\n\nGenerate recommendations of these types:\n- **create_tag**: Suggest new tags for uncovered areas of the codebase\n- **update_description**: Improve a tag's description to be more useful\n- **add_context_link**: Add context paths (files/directories) that agents should read when working on tasks with this tag\n- **documentation_gap**: Identify areas where documentation or context is missing\n- **merge_tags**: Suggest merging overlapping tags\n- **rename_tag**: Suggest a better name for a tag\n\nEach recommendation must include:\n- \\`id\\`: A unique UUID\n- \\`type\\`: One of the types above\n- \\`tagName\\`: The tag name this applies to\n- \\`tagId\\`: The existing tag's ID (if modifying an existing tag, omit for create_tag)\n- \\`suggestion\\`: A short description of the recommendation\n- \\`reasoning\\`: Why this recommendation would help\n- \\`payload\\`: Type-specific data:\n - create_tag: \\`{ name: string, description: string, contextPaths?: string[] }\\`\n - update_description: \\`{ description: string }\\`\n - add_context_link: \\`{ type: \"rule\" | \"doc\" | \"file\" | \"folder\", path: string, label?: string }\\`\n - documentation_gap: \\`{ area: string, suggestedContent?: string }\\`\n - merge_tags: \\`{ sourceTagIds: string[], targetName: string }\\`\n - rename_tag: \\`{ newName: string }\\`\n\nAfter your analysis, output a JSON block in this exact format:\n\n\\`\\`\\`json\n{\n \"recommendations\": [ ...array of recommendations... ],\n \"summary\": \"Brief summary of findings\"\n}\n\\`\\`\\`\n\nAlways provide recommendations. Even well-organized projects have room for improvement — look for missing context links, stale descriptions, documentation gaps, and tag coverage opportunities. Aim for at least 3-5 recommendations. Be specific, actionable, and concise.`;\n\n// ── Fetch agent context ─────────────────────────────────────────────────\n\nasync function fetchModel(connection: ProjectConnection): Promise<string> {\n try {\n const config = await connection.call(\"getProjectFunctionConfig\", {\n projectId: connection.projectId,\n functionId: \"tagAudit\",\n });\n return config.model || FALLBACK_MODEL;\n } catch {\n // Fall back to legacy method for backward compatibility\n try {\n const ctx = await connection.call(\"getProjectAgentContext\", {\n projectId: connection.projectId,\n });\n return ctx.model || FALLBACK_MODEL;\n } catch {\n return FALLBACK_MODEL;\n }\n }\n}\n\n// ── JSON extraction ─────────────────────────────────────────────────────\n\nfunction extractJsonFromResponse(text: string): { recommendations: unknown[]; summary: string } {\n // Try to find a JSON code block first\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const parsed = JSON.parse(jsonStr);\n if (parsed && Array.isArray(parsed.recommendations) && typeof parsed.summary === \"string\") {\n return parsed;\n }\n } catch {\n // Try to find a JSON object in the raw text\n const objectMatch = text.match(/\\{[\\s\\S]*\"recommendations\"[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const parsed = JSON.parse(objectMatch[0]);\n if (parsed && Array.isArray(parsed.recommendations)) {\n return { recommendations: parsed.recommendations, summary: parsed.summary ?? \"\" };\n }\n } catch {\n // Fall through\n }\n }\n }\n\n throw new Error(\"Could not parse tag audit recommendations from Claude response\");\n}\n\n// ── Event stream processing ─────────────────────────────────────────────\n\nasync function collectResponseFromEvents(\n events: AsyncIterable<{ type: string }>,\n connection: ProjectConnection,\n requestId: string,\n): Promise<string> {\n const responseParts: string[] = [];\n for await (const event of events) {\n if (event.type === \"assistant\") {\n const { message } = event as {\n type: string;\n message: {\n content: Array<{ type: string; text?: string; name?: string; input?: unknown }>;\n };\n };\n for (const block of message.content) {\n if (block.type === \"text\" && block.text) {\n responseParts.push(block.text);\n } else if (block.type === \"tool_use\" && block.name) {\n const inputStr =\n typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n await connection\n .call(\"reportTagAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n activity: {\n tool: block.name,\n input: inputStr.slice(0, 10_000),\n timestamp: new Date().toISOString(),\n },\n })\n .catch(() => {});\n }\n }\n }\n if (event.type === \"result\") break;\n }\n return responseParts.join(\"\\n\\n\").trim();\n}\n\n// ── Main handler ────────────────────────────────────────────────────────\n\nexport async function handleTagAudit(\n request: TagAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n): Promise<void> {\n const { requestId } = request;\n\n logger.info(\"Starting tag audit\", { requestId, tagCount: request.tags.length });\n\n await connection\n .call(\"reportTagAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n activity: {\n tool: \"audit\",\n input: \"Starting tag audit...\",\n timestamp: new Date().toISOString(),\n },\n })\n .catch(() => {});\n\n const model = await fetchModel(connection);\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: buildTagAuditPrompt(request),\n options: {\n model,\n systemPrompt: TAG_AUDIT_SYSTEM_PROMPT,\n cwd: projectDir,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: {},\n maxTurns: 8,\n maxBudgetUsd: 5,\n },\n });\n\n const responseText = await collectResponseFromEvents(events, connection, requestId);\n if (!responseText) throw new Error(\"No response from Claude\");\n\n const { recommendations, summary } = extractJsonFromResponse(responseText);\n logger.info(\"Tag audit complete\", { requestId, recommendationCount: recommendations.length });\n\n await connection.call(\"reportTagAuditResult\", {\n projectId: connection.projectId,\n requestId,\n recommendations: recommendations as Array<Record<string, unknown>>,\n summary,\n complete: true,\n });\n}\n"],"mappings":"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","names":[]}
@@ -102,12 +102,17 @@ function extractJsonBlock(text) {
102
102
  }
103
103
  throw new Error("Could not parse JSON from Claude response");
104
104
  }
105
- function extractGradingResult(text, phase) {
105
+ var VALID_GRADING_PHASES = /* @__PURE__ */ new Set(["planning", "building"]);
106
+ function extractCombinedGradingResult(text) {
106
107
  const parsed = extractJsonBlock(text);
107
- const turnGrades = Array.isArray(parsed.turnGrades) ? parsed.turnGrades.map((tg) => ({ ...tg, phase })) : [];
108
+ const turnGrades = Array.isArray(parsed.turnGrades) ? parsed.turnGrades.map((tg) => ({
109
+ ...tg,
110
+ phase: VALID_GRADING_PHASES.has(tg.phase) ? tg.phase : "building"
111
+ })) : [];
108
112
  const summary = parsed.summary ?? "";
109
- const accuracy = typeof parsed.accuracy === "number" ? parsed.accuracy : null;
110
- return { turnGrades, summary, accuracy };
113
+ const planningAccuracy = typeof parsed.planningAccuracy === "number" ? parsed.planningAccuracy : null;
114
+ const buildingAccuracy = typeof parsed.buildingAccuracy === "number" ? parsed.buildingAccuracy : null;
115
+ return { turnGrades, summary, planningAccuracy, buildingAccuracy };
111
116
  }
112
117
  function extractHumanResult(text) {
113
118
  const parsed = extractJsonBlock(text);
@@ -130,13 +135,12 @@ function extractAnalysisResult(text) {
130
135
  } : null
131
136
  };
132
137
  }
133
- function buildMergedSummary(planningResult, buildingResult, humanResult, analysisResult) {
138
+ function buildMergedSummary(gradingResult, humanResult, analysisResult) {
134
139
  const summaryParts = [];
135
140
  if (analysisResult?.summary) {
136
141
  summaryParts.push(analysisResult.summary);
137
142
  } else {
138
- if (planningResult?.summary) summaryParts.push(`Planning: ${planningResult.summary}`);
139
- if (buildingResult?.summary) summaryParts.push(`Building: ${buildingResult.summary}`);
143
+ if (gradingResult?.summary) summaryParts.push(gradingResult.summary);
140
144
  if (humanResult?.summary) summaryParts.push(`Human: ${humanResult.summary}`);
141
145
  }
142
146
  const macroText = analysisResult?.macroEvaluation ? formatMacroEvaluation(analysisResult.macroEvaluation) : null;
@@ -156,130 +160,46 @@ Human Contributions:
156
160
  ${humanEvalText}`;
157
161
  return summary;
158
162
  }
159
- function mergeStepResults(planningResult, buildingResult, humanResult, analysisResult, planningTraceLength) {
160
- const planGrades = planningResult?.turnGrades ?? [];
161
- const buildGrades = (buildingResult?.turnGrades ?? []).map((tg) => ({
162
- ...tg,
163
- turnIndex: tg.turnIndex + planningTraceLength
164
- }));
163
+ function mergeStepResults(gradingResult, humanResult, analysisResult) {
165
164
  return {
166
- turnGrades: [...planGrades, ...buildGrades],
167
- summary: buildMergedSummary(planningResult, buildingResult, humanResult, analysisResult),
168
- planningAccuracy: planningResult?.accuracy ?? null,
169
- buildingAccuracy: buildingResult?.accuracy ?? null,
165
+ turnGrades: gradingResult?.turnGrades ?? [],
166
+ summary: buildMergedSummary(gradingResult, humanResult, analysisResult),
167
+ planningAccuracy: gradingResult?.planningAccuracy ?? null,
168
+ buildingAccuracy: gradingResult?.buildingAccuracy ?? null,
170
169
  humanAccuracy: humanResult?.humanAccuracy ?? null,
171
170
  humanEvaluations: humanResult?.humanEvaluations ?? [],
172
171
  macroEvaluation: analysisResult?.macroEvaluation ?? null
173
172
  };
174
173
  }
175
174
 
176
- // src/runner/task-audit-trace-slicer.ts
177
- var PLAN_UPDATE_PATTERN = /mcp__conveyor__update_task$/;
178
- var PR_CREATION_PATTERN = /mcp__conveyor__create_pull_request$/;
179
- function eventMatchesTool(event, toolPattern) {
180
- if (event.type === "tool_use" && typeof event.data.tool === "string") {
181
- if (toolPattern.test(event.data.tool)) return true;
182
- }
183
- if (event.type === "turn_end" && Array.isArray(event.data.toolCalls)) {
184
- for (const tc of event.data.toolCalls) {
185
- if (typeof tc.tool === "string" && toolPattern.test(tc.tool)) return true;
186
- }
187
- }
188
- return false;
189
- }
190
- function findLastToolCallIndex(trace, toolPattern) {
191
- for (let i = trace.length - 1; i >= 0; i--) {
192
- if (eventMatchesTool(trace[i], toolPattern)) return i;
193
- }
194
- return -1;
195
- }
196
- function sliceTrace(trace) {
197
- const lastPlanUpdateIndex = findLastToolCallIndex(trace, PLAN_UPDATE_PATTERN);
198
- const lastPrCreationIndex = findLastToolCallIndex(trace, PR_CREATION_PATTERN);
199
- const boundaries = { lastPlanUpdateIndex, lastPrCreationIndex };
200
- if (lastPlanUpdateIndex === -1 && lastPrCreationIndex === -1) {
201
- return { planningTrace: [], buildingTrace: trace, boundaries };
202
- }
203
- if (lastPlanUpdateIndex === -1) {
204
- return {
205
- planningTrace: [],
206
- buildingTrace: lastPrCreationIndex >= 0 ? trace.slice(0, lastPrCreationIndex + 1) : trace,
207
- boundaries
208
- };
209
- }
210
- const planEnd = lastPrCreationIndex >= 0 && lastPlanUpdateIndex > lastPrCreationIndex ? lastPrCreationIndex : lastPlanUpdateIndex;
211
- const planningTrace = trace.slice(0, planEnd + 1);
212
- const buildEnd = lastPrCreationIndex >= 0 ? lastPrCreationIndex + 1 : trace.length;
213
- const buildingTrace = trace.slice(planEnd + 1, buildEnd);
214
- return { planningTrace, buildingTrace, boundaries };
215
- }
216
-
217
175
  // src/runner/task-audit-prompts.ts
218
- var PLANNING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the PLANNING phase of an AI agent's task execution. You receive only the planning portion of the agent's trace \u2014 from the start through the last plan update. Grade each turn objectively.
176
+ var COMBINED_GRADING_SYSTEM_PROMPT = `You are a chess-style analysis engine performing a holistic audit of an AI agent's full task execution \u2014 from initial planning through final implementation. You receive the complete agent trace covering all phases and sessions. Grade each turn objectively.
219
177
 
220
- ## Grading Scale
178
+ ## Phase Identification
221
179
 
222
- - **Correct** (\u265F): Sound moves toward understanding the task \u2014 reading relevant files, analyzing requirements, logical reasoning about approach, following project patterns
223
- - **Neutral** (\xB7): No significant positive or negative effect \u2014 exploratory reads, minor tangents
224
- - **Blunder** (??): Wasted effort \u2014 reading irrelevant files repeatedly, ignoring requirements, spending many turns without making progress toward a plan
180
+ Identify the boundary between planning and building phases:
181
+ - **Planning phase**: Turns from the start through the last \`update_task\` (plan save) call. Includes reading requirements, exploring code, analyzing dependencies, and formulating the plan.
182
+ - **Building phase**: Turns after the last plan save through PR creation (or end of trace). Includes implementation, testing, and PR creation.
183
+ - If no \`update_task\` call is found, treat all turns as building phase.
225
184
 
226
- ## Specific Blunder Examples
227
- - Reading the same file 5+ times without advancing understanding
228
- - Ignoring explicit task requirements or project conventions visible in the code
229
- - Spending many turns on tangential investigation not related to the task
230
- - Failing to read key files that are obvious from the task description
185
+ You MUST label each turn with \`"phase": "planning"\` or \`"phase": "building"\`.
231
186
 
232
- ## Specific Correct Examples
233
- - Reading context files before implementation
234
- - Analyzing requirements and dependencies systematically
235
- - Identifying relevant code patterns to follow
236
- - Building understanding incrementally
187
+ ## Multi-Session Awareness
237
188
 
238
- ## Output Format
239
-
240
- Output a JSON block:
241
-
242
- \`\`\`json
243
- {
244
- "turnGrades": [
245
- {
246
- "turnIndex": 0,
247
- "grade": "correct",
248
- "reasoning": "Read relevant config files to understand project structure",
249
- "eventType": "tool_use",
250
- "eventSummary": "Read package.json and tsconfig.json"
251
- }
252
- ],
253
- "summary": "Brief 2-3 sentence assessment of planning quality",
254
- "accuracy": 0.85
255
- }
256
- \`\`\`
257
-
258
- **Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.
259
-
260
- IMPORTANT: Do NOT include a "phase" field in turnGrades \u2014 the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;
261
- var BUILDING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the BUILDING phase of an AI agent's task execution. You receive only the building portion of the agent's trace \u2014 from after the plan was finalized through pull request creation. Grade each turn objectively.
189
+ The trace may contain multiple agent sessions (indicated by \`session_manifest\` events). Grade ALL sessions \u2014 earlier sessions often contain valuable planning work or reflect restart patterns worth evaluating. If an earlier session was abandoned, grade its turns based on quality (exploration reads may be neutral, repeated failures may be blunders).
262
190
 
263
191
  ## Grading Scale
264
192
 
193
+ ### Planning Turns
194
+ - **Correct** (\u265F): Sound moves toward understanding the task \u2014 reading relevant files, analyzing requirements, logical reasoning about approach, following project patterns
195
+ - **Neutral** (\xB7): No significant positive or negative effect \u2014 exploratory reads, minor tangents
196
+ - **Blunder** (??): Wasted effort \u2014 reading irrelevant files repeatedly, ignoring requirements, spending many turns without making progress toward a plan
197
+
198
+ ### Building Turns
265
199
  - **Correct** (\u265F): Sound implementation moves \u2014 proper edits, running tests, fixing errors, following plan steps, adapting to feedback
266
200
  - **Neutral** (\xB7): No significant positive or negative effect \u2014 exploratory reads during implementation, minor tangents
267
201
  - **Blunder** (??): Wasted effort \u2014 incorrect edits immediately reverted, repeated failures without adapting, ignoring the plan, using wrong APIs despite visible patterns
268
202
 
269
- ## Specific Blunder Examples
270
- - Making edits that are immediately reverted or overwritten
271
- - Ignoring explicit plan steps or user corrections
272
- - Repeated failed tool calls (isError: true) without changing approach
273
- - Using wrong APIs despite project patterns visible in the trace
274
- - Spending many turns on tangential work not in the plan
275
-
276
- ## Specific Correct Examples
277
- - Following plan steps in logical sequence
278
- - Proper error handling and recovery after tool failures
279
- - Adapting approach based on test results or errors
280
- - Efficient tool usage with clear purpose
281
- - Running tests to verify changes
282
-
283
203
  ## Output Format
284
204
 
285
205
  Output a JSON block:
@@ -289,20 +209,22 @@ Output a JSON block:
289
209
  "turnGrades": [
290
210
  {
291
211
  "turnIndex": 0,
212
+ "phase": "planning",
292
213
  "grade": "correct",
293
- "reasoning": "Implemented the required changes following the plan",
214
+ "reasoning": "Read relevant config files to understand project structure",
294
215
  "eventType": "tool_use",
295
- "eventSummary": "Edit src/component.tsx"
216
+ "eventSummary": "Read package.json and tsconfig.json"
296
217
  }
297
218
  ],
298
- "summary": "Brief 2-3 sentence assessment of building quality",
299
- "accuracy": 0.72
219
+ "summary": "Brief 2-3 sentence holistic assessment of the full execution",
220
+ "planningAccuracy": 0.85,
221
+ "buildingAccuracy": 0.72
300
222
  }
301
223
  \`\`\`
302
224
 
303
- **Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.
225
+ **Accuracy Calculation**: For each phase separately: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null for a phase if it has no correct or blunder turns.
304
226
 
305
- IMPORTANT: Turn indices are 0-based relative to the trace slice provided. Do NOT include a "phase" field \u2014 the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;
227
+ Turn indices are 0-based relative to the full trace provided. Every turn grade MUST include the phase field.`;
306
228
  var HUMAN_AUDIT_SYSTEM_PROMPT = `You are evaluating human contributions to an AI agent's task execution. For each human message, assess whether it helped, hindered, or had no effect on the agent's work.
307
229
 
308
230
  ## Rating Scale
@@ -410,20 +332,22 @@ ${task.agentInstructions}
410
332
  `);
411
333
  return parts.join("\n");
412
334
  }
413
- function buildPlanningAuditPrompt(task, planningTrace) {
414
- const parts = [`# Planning Audit: ${task.taskTitle}
415
- `];
416
- parts.push(buildTaskContextSection(task));
417
- parts.push(buildTraceSection(planningTrace));
418
- parts.push("Grade each turn above, then output the structured JSON result.");
419
- return parts.join("\n");
335
+ function buildMultiSessionNote(task) {
336
+ const count = task.sessionInfo?.sessionCount;
337
+ if (!count || count <= 1) return null;
338
+ return `> **Note:** This task had ${count} total agent sessions. All sessions are included in the trace below.
339
+ `;
420
340
  }
421
- function buildBuildingAuditPrompt(task, buildingTrace) {
422
- const parts = [`# Building Audit: ${task.taskTitle}
341
+ function buildCombinedGradingPrompt(task) {
342
+ const parts = [`# Full Workflow Audit: ${task.taskTitle}
423
343
  `];
344
+ const sessionNote = buildMultiSessionNote(task);
345
+ if (sessionNote) parts.push(sessionNote);
424
346
  parts.push(buildTaskContextSection(task));
425
- parts.push(buildTraceSection(buildingTrace));
426
- parts.push("Grade each turn above, then output the structured JSON result.");
347
+ parts.push(buildTraceSection(task.agentTrace));
348
+ parts.push(
349
+ "Grade each turn above with its phase (planning or building), then output the structured JSON result."
350
+ );
427
351
  return parts.join("\n");
428
352
  }
429
353
  function buildHumanAuditPrompt(task) {
@@ -447,21 +371,20 @@ ${task.taskPlan}
447
371
  parts.push("Evaluate each human message above, then output the structured JSON result.");
448
372
  return parts.join("\n");
449
373
  }
450
- function buildGradingResultSection(label, result) {
451
- const grades = result.turnGrades;
374
+ function buildPhaseResultSection(label, grades, accuracy, summary) {
452
375
  const correct = grades.filter((g) => g.grade === "correct").length;
453
376
  const neutral = grades.filter((g) => g.grade === "neutral").length;
454
377
  const blunder = grades.filter((g) => g.grade === "blunder").length;
455
- const accuracy = result.accuracy === null ? "N/A" : result.accuracy.toFixed(2);
378
+ const accuracyStr = accuracy === null ? "N/A" : accuracy.toFixed(2);
456
379
  return [
457
380
  `## ${label} Phase Results`,
458
- `- Summary: ${result.summary}`,
459
- `- Accuracy: ${accuracy}`,
381
+ `- Summary: ${summary}`,
382
+ `- Accuracy: ${accuracyStr}`,
460
383
  `- ${grades.length} turns: ${correct} correct, ${neutral} neutral, ${blunder} blunders`,
461
384
  ""
462
385
  ].join("\n");
463
386
  }
464
- function buildAnalysisPrompt(task, planningResult, buildingResult, humanResult) {
387
+ function buildAnalysisPrompt(task, gradingResult, humanResult) {
465
388
  const parts = [`# Task Analysis: ${task.taskTitle}
466
389
  `];
467
390
  if (task.taskDescription) parts.push(`## Description
@@ -474,8 +397,30 @@ ${task.taskPlan}
474
397
  if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);
475
398
  parts.push("");
476
399
  if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));
477
- if (planningResult) parts.push(buildGradingResultSection("Planning", planningResult));
478
- if (buildingResult) parts.push(buildGradingResultSection("Building", buildingResult));
400
+ if (gradingResult) {
401
+ const planGrades = gradingResult.turnGrades.filter((g) => g.phase === "planning");
402
+ const buildGrades = gradingResult.turnGrades.filter((g) => g.phase === "building");
403
+ if (planGrades.length > 0) {
404
+ parts.push(
405
+ buildPhaseResultSection(
406
+ "Planning",
407
+ planGrades,
408
+ gradingResult.planningAccuracy,
409
+ gradingResult.summary
410
+ )
411
+ );
412
+ }
413
+ if (buildGrades.length > 0) {
414
+ parts.push(
415
+ buildPhaseResultSection(
416
+ "Building",
417
+ buildGrades,
418
+ gradingResult.buildingAccuracy,
419
+ gradingResult.summary
420
+ )
421
+ );
422
+ }
423
+ }
479
424
  if (humanResult) {
480
425
  const evals = humanResult.humanEvaluations;
481
426
  const helpful = evals.filter((e) => e.rating > 0).length;
@@ -488,8 +433,7 @@ ${task.taskPlan}
488
433
  );
489
434
  parts.push("");
490
435
  }
491
- const allGrades = [...planningResult?.turnGrades ?? [], ...buildingResult?.turnGrades ?? []];
492
- const blunders = allGrades.filter((g) => g.grade === "blunder");
436
+ const blunders = (gradingResult?.turnGrades ?? []).filter((g) => g.grade === "blunder");
493
437
  if (blunders.length > 0) {
494
438
  parts.push("## Notable Blunders");
495
439
  for (const b of blunders.slice(0, 10)) {
@@ -609,13 +553,21 @@ function buildTrackedSuggestionTool(connection, projectId, suggestionIds) {
609
553
  }
610
554
  async function fetchModel(connection) {
611
555
  try {
612
- const ctx = await connection.call("getProjectAgentContextByRole", {
556
+ const config = await connection.call("getProjectFunctionConfig", {
613
557
  projectId: connection.projectId,
614
- role: "reviewer"
558
+ functionId: "taskAudit"
615
559
  });
616
- return ctx.model || FALLBACK_MODEL;
560
+ return config.model || FALLBACK_MODEL;
617
561
  } catch {
618
- return FALLBACK_MODEL;
562
+ try {
563
+ const ctx = await connection.call("getProjectAgentContextByRole", {
564
+ projectId: connection.projectId,
565
+ role: "reviewer"
566
+ });
567
+ return ctx.model || FALLBACK_MODEL;
568
+ } catch {
569
+ return FALLBACK_MODEL;
570
+ }
619
571
  }
620
572
  }
621
573
  function buildQueryOptions(systemPrompt, opts, limits, mcpServers = {}) {
@@ -632,16 +584,16 @@ function buildQueryOptions(systemPrompt, opts, limits, mcpServers = {}) {
632
584
  disallowedTools: ["Edit", "Write", "Bash", "NotebookEdit", "MultiEdit"]
633
585
  };
634
586
  }
635
- async function runGradingStep(taskId, phase, systemPrompt, userPrompt, limits, opts) {
587
+ async function runCombinedGradingStep(taskId, userPrompt, limits, opts) {
636
588
  const harness = createHarness();
637
589
  const events = harness.executeQuery({
638
590
  prompt: userPrompt,
639
- options: buildQueryOptions(systemPrompt, opts, limits)
591
+ options: buildQueryOptions(COMBINED_GRADING_SYSTEM_PROMPT, opts, limits)
640
592
  });
641
593
  const response = await collectResponseFromEvents(events, opts.connection, opts.requestId, taskId);
642
- if (!response.text) throw new Error(`No response from ${phase} grading step`);
594
+ if (!response.text) throw new Error("No response from combined grading step");
643
595
  return {
644
- result: extractGradingResult(response.text, phase),
596
+ result: extractCombinedGradingResult(response.text),
645
597
  costUsd: response.costUsd,
646
598
  model: response.model
647
599
  };
@@ -656,12 +608,12 @@ async function runHumanStep(taskId, userPrompt, limits, opts) {
656
608
  if (!response.text) throw new Error("No response from human evaluation step");
657
609
  return { result: extractHumanResult(response.text), costUsd: response.costUsd };
658
610
  }
659
- async function runAnalysisStep(task, planningResult, buildingResult, humanResult, projectId, suggestionIds, opts) {
611
+ async function runAnalysisStep(task, gradingResult, humanResult, projectId, suggestionIds, opts) {
660
612
  const wrappedTool = buildTrackedSuggestionTool(opts.connection, projectId, suggestionIds);
661
613
  const harness = createHarness();
662
614
  const mcpServer = harness.createMcpServer({ name: "conveyor", tools: [wrappedTool] });
663
615
  const events = harness.executeQuery({
664
- prompt: buildAnalysisPrompt(task, planningResult, buildingResult, humanResult),
616
+ prompt: buildAnalysisPrompt(task, gradingResult, humanResult),
665
617
  options: buildQueryOptions(
666
618
  ANALYSIS_SYSTEM_PROMPT,
667
619
  opts,
@@ -679,7 +631,7 @@ async function runAnalysisStep(task, planningResult, buildingResult, humanResult
679
631
  return { result: extractAnalysisResult(response.text), costUsd: response.costUsd };
680
632
  }
681
633
  var EMPTY_STEP = { result: null, costUsd: null, model: null };
682
- var GRADING_LIMITS = { maxTurns: 8, maxBudgetUsd: 1 };
634
+ var GRADING_LIMITS = { maxTurns: 24, maxBudgetUsd: 3 };
683
635
  async function executeStepSafely(stepLabel, requestId, taskId, fn) {
684
636
  try {
685
637
  const step = await fn();
@@ -693,47 +645,22 @@ async function executeStepSafely(stepLabel, requestId, taskId, fn) {
693
645
  return EMPTY_STEP;
694
646
  }
695
647
  }
696
- async function executePlanningStep(taskPayload, planningTrace, opts) {
697
- if (planningTrace.length === 0) return EMPTY_STEP;
648
+ async function executeCombinedGradingStep(taskPayload, opts) {
649
+ if (taskPayload.agentTrace.length === 0) return EMPTY_STEP;
698
650
  reportProgress(
699
651
  opts.connection,
700
652
  opts.requestId,
701
653
  taskPayload.taskId,
702
654
  "status",
703
- "Step 1/4: Auditing planning..."
655
+ "Step 1/3: Auditing full workflow..."
704
656
  );
705
657
  return await executeStepSafely(
706
- "Planning audit",
658
+ "Combined grading audit",
707
659
  opts.requestId,
708
660
  taskPayload.taskId,
709
- () => runGradingStep(
661
+ () => runCombinedGradingStep(
710
662
  taskPayload.taskId,
711
- "planning",
712
- PLANNING_AUDIT_SYSTEM_PROMPT,
713
- buildPlanningAuditPrompt(taskPayload, planningTrace),
714
- GRADING_LIMITS,
715
- opts
716
- )
717
- );
718
- }
719
- async function executeBuildingStep(taskPayload, buildingTrace, opts) {
720
- if (buildingTrace.length === 0) return EMPTY_STEP;
721
- reportProgress(
722
- opts.connection,
723
- opts.requestId,
724
- taskPayload.taskId,
725
- "status",
726
- "Step 2/4: Auditing building..."
727
- );
728
- return await executeStepSafely(
729
- "Building audit",
730
- opts.requestId,
731
- taskPayload.taskId,
732
- () => runGradingStep(
733
- taskPayload.taskId,
734
- "building",
735
- BUILDING_AUDIT_SYSTEM_PROMPT,
736
- buildBuildingAuditPrompt(taskPayload, buildingTrace),
663
+ buildCombinedGradingPrompt(taskPayload),
737
664
  GRADING_LIMITS,
738
665
  opts
739
666
  )
@@ -746,7 +673,7 @@ async function executeHumanStep(taskPayload, opts) {
746
673
  opts.requestId,
747
674
  taskPayload.taskId,
748
675
  "status",
749
- "Step 3/4: Auditing human contributions..."
676
+ "Step 2/3: Auditing human contributions..."
750
677
  );
751
678
  return await executeStepSafely(
752
679
  "Human audit",
@@ -760,40 +687,26 @@ async function executeHumanStep(taskPayload, opts) {
760
687
  )
761
688
  );
762
689
  }
763
- async function executeAnalysisStep(taskPayload, planning, building, human, projectId, suggestionIds, opts) {
690
+ async function executeAnalysisStep(taskPayload, grading, human, projectId, suggestionIds, opts) {
764
691
  reportProgress(
765
692
  opts.connection,
766
693
  opts.requestId,
767
694
  taskPayload.taskId,
768
695
  "status",
769
- "Step 4/4: Generating analysis & suggestions..."
696
+ "Step 3/3: Generating analysis & suggestions..."
770
697
  );
771
698
  return await executeStepSafely(
772
699
  "Analysis",
773
700
  opts.requestId,
774
701
  taskPayload.taskId,
775
- () => runAnalysisStep(
776
- taskPayload,
777
- planning.result,
778
- building.result,
779
- human.result,
780
- projectId,
781
- suggestionIds,
782
- opts
783
- )
702
+ () => runAnalysisStep(taskPayload, grading.result, human.result, projectId, suggestionIds, opts)
784
703
  );
785
704
  }
786
- async function reportAuditResult(connection, requestId, taskPayload, steps, planningTraceLength, suggestionIds) {
705
+ async function reportAuditResult(connection, requestId, taskPayload, steps, suggestionIds) {
787
706
  let totalCostUsd = null;
788
- for (const step of [steps.planning, steps.building, steps.human, steps.analysis])
707
+ for (const step of [steps.grading, steps.human, steps.analysis])
789
708
  totalCostUsd = addCosts(totalCostUsd, step.costUsd);
790
- const merged = mergeStepResults(
791
- steps.planning.result,
792
- steps.building.result,
793
- steps.human.result,
794
- steps.analysis.result,
795
- planningTraceLength
796
- );
709
+ const merged = mergeStepResults(steps.grading.result, steps.human.result, steps.analysis.result);
797
710
  await connection.call("reportTaskAuditResult", {
798
711
  projectId: connection.projectId,
799
712
  requestId,
@@ -807,24 +720,21 @@ async function reportAuditResult(connection, requestId, taskPayload, steps, plan
807
720
  ...computeGradeCounts(merged.turnGrades),
808
721
  suggestionIds,
809
722
  auditCostUsd: totalCostUsd,
810
- model: steps.planning.model ?? steps.building.model ?? null
723
+ model: steps.grading.model ?? null
811
724
  });
812
725
  }
813
726
  async function auditSingleTask(taskPayload, request, connection, projectDir, model) {
814
727
  const { requestId, projectId } = request;
815
728
  const suggestionIds = [];
816
729
  const opts = { connection, requestId, projectDir, model };
817
- const { planningTrace, buildingTrace } = sliceTrace(taskPayload.agentTrace);
818
- const planning = await executePlanningStep(taskPayload, planningTrace, opts);
819
- const building = await executeBuildingStep(taskPayload, buildingTrace, opts);
820
- if (!planning.result && !building.result && (planningTrace.length > 0 || buildingTrace.length > 0)) {
821
- throw new Error("All grading audit steps failed");
730
+ const grading = await executeCombinedGradingStep(taskPayload, opts);
731
+ if (!grading.result && taskPayload.agentTrace.length > 0) {
732
+ throw new Error("Grading audit step failed");
822
733
  }
823
734
  const human = await executeHumanStep(taskPayload, opts);
824
735
  const analysis = await executeAnalysisStep(
825
736
  taskPayload,
826
- planning,
827
- building,
737
+ grading,
828
738
  human,
829
739
  projectId,
830
740
  suggestionIds,
@@ -834,8 +744,7 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
834
744
  connection,
835
745
  requestId,
836
746
  taskPayload,
837
- { planning, building, human, analysis },
838
- planningTrace.length,
747
+ { grading, human, analysis },
839
748
  suggestionIds
840
749
  );
841
750
  logger.info("Task audit complete", {
@@ -871,4 +780,4 @@ async function handleTaskAudit(request, connection, projectDir) {
871
780
  export {
872
781
  handleTaskAudit
873
782
  };
874
- //# sourceMappingURL=task-audit-handler-GAG6XDGJ.js.map
783
+ //# sourceMappingURL=task-audit-handler-6XWYK6KZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runner/task-audit-handler.ts","../src/runner/task-audit-parsing.ts","../src/runner/task-audit-prompts.ts","../src/runner/task-audit-progress.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createHarness, defineTool } from \"../harness/index.js\";\nimport type { ProjectConnection } from \"../connection/project-connection.js\";\nimport type { TaskAuditRunnerRequest, TaskAuditPayload } from \"@project/shared\";\nimport { textResult } from \"../tools/helpers.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport {\n type StepCombinedGradingResult,\n type StepHumanResult,\n type StepAnalysisResult,\n extractCombinedGradingResult,\n extractHumanResult,\n extractAnalysisResult,\n mergeStepResults,\n computeGradeCounts,\n addCosts,\n buildErrorResult,\n} from \"./task-audit-parsing.js\";\nimport {\n COMBINED_GRADING_SYSTEM_PROMPT,\n HUMAN_AUDIT_SYSTEM_PROMPT,\n ANALYSIS_SYSTEM_PROMPT,\n buildCombinedGradingPrompt,\n buildHumanAuditPrompt,\n buildAnalysisPrompt,\n} from \"./task-audit-prompts.js\";\nimport { reportProgress, collectResponseFromEvents } from \"./task-audit-progress.js\";\n\nconst logger = createServiceLogger(\"TaskAudit\");\n\nconst FALLBACK_MODEL = \"claude-sonnet-4-6\";\n\n// ── Suggestion MCP tool ─────────────────────────────────────────────────\n\nfunction buildTrackedSuggestionTool(\n connection: ProjectConnection,\n projectId: string,\n suggestionIds: string[],\n) {\n return defineTool(\n \"create_suggestion\",\n \"Suggest a cross-cutting improvement for the project based on patterns found during audit. If a similar suggestion exists, your vote is added instead of creating a duplicate.\",\n {\n title: z.string().describe(\"Short title for the suggestion\"),\n description: z.string().optional().describe(\"Details about the suggestion\"),\n },\n async ({ title, description }) => {\n try {\n const result = await connection.call(\"createProjectSuggestion\", {\n projectId,\n title,\n description,\n });\n // Capture ID directly from the typed response object\n const id = result.mergedIntoId ?? result.id;\n if (id) {\n suggestionIds.push(id);\n logger.info(\"Suggestion tracked\", { id, merged: result.merged });\n }\n if (result.merged) {\n return textResult(`Merged into existing suggestion (ID: ${id}).`);\n }\n return textResult(`Suggestion created (ID: ${result.id}).`);\n } catch (error) {\n logger.warn(\"Suggestion creation failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return textResult(\n `Failed to create suggestion: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\n// ── Fetch model ─────────────────────────────────────────────────────────\n\nasync function fetchModel(connection: ProjectConnection): Promise<string> {\n try {\n const config = await connection.call(\"getProjectFunctionConfig\", {\n projectId: connection.projectId,\n functionId: \"taskAudit\",\n });\n return config.model || FALLBACK_MODEL;\n } catch {\n // Fall back to legacy method for backward compatibility\n try {\n const ctx = await connection.call(\"getProjectAgentContextByRole\", {\n projectId: connection.projectId,\n role: \"reviewer\",\n });\n return ctx.model || FALLBACK_MODEL;\n } catch {\n return FALLBACK_MODEL;\n }\n }\n}\n\n// ── Step runners ────────────────────────────────────────────────────────\n\ninterface StepOptions {\n connection: ProjectConnection;\n requestId: string;\n projectDir: string;\n model: string;\n}\n\nfunction buildQueryOptions(\n systemPrompt: string,\n opts: StepOptions,\n limits: { maxTurns: number; maxBudgetUsd: number },\n mcpServers: Record<string, unknown> = {},\n) {\n return {\n model: opts.model,\n systemPrompt,\n cwd: opts.projectDir,\n permissionMode: \"bypassPermissions\" as const,\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers,\n maxTurns: limits.maxTurns,\n maxBudgetUsd: limits.maxBudgetUsd,\n disallowedTools: [\"Edit\", \"Write\", \"Bash\", \"NotebookEdit\", \"MultiEdit\"],\n };\n}\n\nasync function runCombinedGradingStep(\n taskId: string,\n userPrompt: string,\n limits: { maxTurns: number; maxBudgetUsd: number },\n opts: StepOptions,\n): Promise<{ result: StepCombinedGradingResult; costUsd: number | null; model: string | null }> {\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: userPrompt,\n options: buildQueryOptions(COMBINED_GRADING_SYSTEM_PROMPT, opts, limits),\n });\n const response = await collectResponseFromEvents(events, opts.connection, opts.requestId, taskId);\n if (!response.text) throw new Error(\"No response from combined grading step\");\n return {\n result: extractCombinedGradingResult(response.text),\n costUsd: response.costUsd,\n model: response.model,\n };\n}\n\nasync function runHumanStep(\n taskId: string,\n userPrompt: string,\n limits: { maxTurns: number; maxBudgetUsd: number },\n opts: StepOptions,\n): Promise<{ result: StepHumanResult; costUsd: number | null }> {\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: userPrompt,\n options: buildQueryOptions(HUMAN_AUDIT_SYSTEM_PROMPT, opts, limits),\n });\n const response = await collectResponseFromEvents(events, opts.connection, opts.requestId, taskId);\n if (!response.text) throw new Error(\"No response from human evaluation step\");\n return { result: extractHumanResult(response.text), costUsd: response.costUsd };\n}\n\nasync function runAnalysisStep(\n task: TaskAuditPayload,\n gradingResult: StepCombinedGradingResult | null,\n humanResult: StepHumanResult | null,\n projectId: string,\n suggestionIds: string[],\n opts: StepOptions,\n): Promise<{ result: StepAnalysisResult; costUsd: number | null }> {\n const wrappedTool = buildTrackedSuggestionTool(opts.connection, projectId, suggestionIds);\n const harness = createHarness();\n const mcpServer = harness.createMcpServer({ name: \"conveyor\", tools: [wrappedTool] });\n const events = harness.executeQuery({\n prompt: buildAnalysisPrompt(task, gradingResult, humanResult),\n options: buildQueryOptions(\n ANALYSIS_SYSTEM_PROMPT,\n opts,\n { maxTurns: 6, maxBudgetUsd: 1 },\n { conveyor: mcpServer },\n ),\n });\n const response = await collectResponseFromEvents(\n events,\n opts.connection,\n opts.requestId,\n task.taskId,\n );\n if (!response.text) throw new Error(\"No response from analysis step\");\n return { result: extractAnalysisResult(response.text), costUsd: response.costUsd };\n}\n\n// ── Safe step wrapper ──────────────────────────────────────────────────\n\ninterface StepOutput<T> {\n result: T | null;\n costUsd: number | null;\n model: string | null;\n}\n\nconst EMPTY_STEP: StepOutput<never> = { result: null, costUsd: null, model: null };\nconst GRADING_LIMITS = { maxTurns: 24, maxBudgetUsd: 3 };\n\nasync function executeStepSafely<T>(\n stepLabel: string,\n requestId: string,\n taskId: string,\n fn: () => Promise<{ result: T; costUsd: number | null; model?: string | null }>,\n): Promise<StepOutput<T>> {\n try {\n const step = await fn();\n return { result: step.result, costUsd: step.costUsd, model: step.model ?? null };\n } catch (err) {\n logger.warn(`${stepLabel} failed`, {\n requestId,\n taskId,\n error: err instanceof Error ? err.message : String(err),\n });\n return EMPTY_STEP;\n }\n}\n\n// ── Step orchestration ─────────────────────────────────────────────────\n\nasync function executeCombinedGradingStep(\n taskPayload: TaskAuditPayload,\n opts: StepOptions,\n): Promise<StepOutput<StepCombinedGradingResult>> {\n if (taskPayload.agentTrace.length === 0) return EMPTY_STEP;\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 1/3: Auditing full workflow...\",\n );\n return await executeStepSafely(\"Combined grading audit\", opts.requestId, taskPayload.taskId, () =>\n runCombinedGradingStep(\n taskPayload.taskId,\n buildCombinedGradingPrompt(taskPayload),\n GRADING_LIMITS,\n opts,\n ),\n );\n}\n\nasync function executeHumanStep(\n taskPayload: TaskAuditPayload,\n opts: StepOptions,\n): Promise<StepOutput<StepHumanResult>> {\n if (taskPayload.humanMessages.length === 0) return EMPTY_STEP;\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 2/3: Auditing human contributions...\",\n );\n return await executeStepSafely(\"Human audit\", opts.requestId, taskPayload.taskId, () =>\n runHumanStep(\n taskPayload.taskId,\n buildHumanAuditPrompt(taskPayload),\n { maxTurns: 6, maxBudgetUsd: 0.5 },\n opts,\n ),\n );\n}\n\nasync function executeAnalysisStep(\n taskPayload: TaskAuditPayload,\n grading: StepOutput<StepCombinedGradingResult>,\n human: StepOutput<StepHumanResult>,\n projectId: string,\n suggestionIds: string[],\n opts: StepOptions,\n): Promise<StepOutput<StepAnalysisResult>> {\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 3/3: Generating analysis & suggestions...\",\n );\n return await executeStepSafely(\"Analysis\", opts.requestId, taskPayload.taskId, () =>\n runAnalysisStep(taskPayload, grading.result, human.result, projectId, suggestionIds, opts),\n );\n}\n\n// ── Result reporting ───────────────────────────────────────────────────\n\nasync function reportAuditResult(\n connection: ProjectConnection,\n requestId: string,\n taskPayload: TaskAuditPayload,\n steps: {\n grading: StepOutput<StepCombinedGradingResult>;\n human: StepOutput<StepHumanResult>;\n analysis: StepOutput<StepAnalysisResult>;\n },\n suggestionIds: string[],\n): Promise<void> {\n let totalCostUsd: number | null = null;\n for (const step of [steps.grading, steps.human, steps.analysis])\n totalCostUsd = addCosts(totalCostUsd, step.costUsd);\n\n const merged = mergeStepResults(steps.grading.result, steps.human.result, steps.analysis.result);\n\n await connection.call(\"reportTaskAuditResult\", {\n projectId: connection.projectId,\n requestId,\n taskId: taskPayload.taskId,\n summary: merged.summary,\n turnGrades: merged.turnGrades,\n planningAccuracy: merged.planningAccuracy,\n buildingAccuracy: merged.buildingAccuracy,\n humanAccuracy: merged.humanAccuracy,\n humanEvaluations: merged.humanEvaluations,\n ...computeGradeCounts(merged.turnGrades),\n suggestionIds,\n auditCostUsd: totalCostUsd,\n model: steps.grading.model ?? null,\n });\n}\n\n// ── Per-task audit execution ────────────────────────────────────────────\n\nasync function auditSingleTask(\n taskPayload: TaskAuditPayload,\n request: TaskAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n model: string,\n): Promise<void> {\n const { requestId, projectId } = request;\n const suggestionIds: string[] = [];\n const opts: StepOptions = { connection, requestId, projectDir, model };\n\n const grading = await executeCombinedGradingStep(taskPayload, opts);\n\n if (!grading.result && taskPayload.agentTrace.length > 0) {\n throw new Error(\"Grading audit step failed\");\n }\n\n const human = await executeHumanStep(taskPayload, opts);\n const analysis = await executeAnalysisStep(\n taskPayload,\n grading,\n human,\n projectId,\n suggestionIds,\n opts,\n );\n\n await reportAuditResult(\n connection,\n requestId,\n taskPayload,\n { grading, human, analysis },\n suggestionIds,\n );\n logger.info(\"Task audit complete\", {\n requestId,\n taskId: taskPayload.taskId,\n suggestions: suggestionIds.length,\n });\n}\n\n// ── Main handler ────────────────────────────────────────────────────────\n\nexport async function handleTaskAudit(\n request: TaskAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n): Promise<void> {\n const { requestId } = request;\n\n logger.info(\"Starting task audit\", { requestId, taskCount: request.tasks.length });\n\n const model = await fetchModel(connection);\n\n for (const taskPayload of request.tasks) {\n try {\n await auditSingleTask(taskPayload, request, connection, projectDir, model);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\"Task audit failed for task\", {\n requestId,\n taskId: taskPayload.taskId,\n error: msg,\n });\n await connection\n .call(\n \"reportTaskAuditResult\",\n buildErrorResult(connection.projectId, requestId, taskPayload.taskId, msg),\n )\n .catch(() => {});\n }\n }\n\n await connection\n .call(\"reportTaskAuditBatchComplete\", { projectId: connection.projectId, requestId })\n .catch(() => {});\n}\n","import type {\n TaskAuditTurnGrade,\n TaskAuditHumanEvaluation,\n TaskAuditPayload,\n TaskAuditPhase,\n} from \"@project/shared\";\n\n// ── Types ──────────────────────────────────────────────────────────────\n\nexport interface AuditJsonResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n planningAccuracy: number | null;\n buildingAccuracy: number | null;\n humanAccuracy: number | null;\n humanEvaluations: TaskAuditHumanEvaluation[];\n macroEvaluation?: MacroEvaluation | null;\n}\n\nexport interface MacroEvaluation {\n instructionsQuality?: string;\n modelSuitability?: string;\n contextAndPlanning?: string;\n overallResult?: string;\n}\n\n// ── Step-specific result types ────────────────────────────────────────\n\n/** Output from Steps 1 (Planning) and 2 (Building) — grading a trace slice */\nexport interface StepGradingResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n accuracy: number | null;\n}\n\n/** Output from the combined grading step — holistic assessment of full workflow */\nexport interface StepCombinedGradingResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n planningAccuracy: number | null;\n buildingAccuracy: number | null;\n}\n\n/** Output from Step 3 (Human) — evaluating human messages */\nexport interface StepHumanResult {\n humanEvaluations: TaskAuditHumanEvaluation[];\n summary: string;\n humanAccuracy: number | null;\n}\n\n/** Output from Step 4 (Analysis) — macro evaluation */\nexport interface StepAnalysisResult {\n summary: string;\n macroEvaluation: MacroEvaluation | null;\n}\n\n/** Merged result from all 4 steps, ready for reportTaskAuditResult */\nexport interface MergedAuditResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n planningAccuracy: number | null;\n buildingAccuracy: number | null;\n humanAccuracy: number | null;\n humanEvaluations: TaskAuditHumanEvaluation[];\n macroEvaluation: MacroEvaluation | null;\n}\n\n// ── Formatting helpers ─────────────────────────────────────────────────\n\nfunction formatMacroEvaluation(macro: Record<string, unknown> | null | undefined): string | null {\n if (!macro) return null;\n const lines: string[] = [];\n if (macro.instructionsQuality) lines.push(`- Instructions Quality: ${macro.instructionsQuality}`);\n if (macro.modelSuitability) lines.push(`- Model Suitability: ${macro.modelSuitability}`);\n if (macro.contextAndPlanning) lines.push(`- Context & Planning: ${macro.contextAndPlanning}`);\n if (macro.overallResult) lines.push(`- Overall Result: ${macro.overallResult}`);\n return lines.length > 0 ? lines.join(\"\\n\") : null;\n}\n\nfunction formatHumanEvaluations(evals: TaskAuditHumanEvaluation[]): string | null {\n if (evals.length === 0) return null;\n const total = evals.reduce((sum, e) => sum + e.rating, 0);\n const avg = total / evals.length;\n const label = avg > 0.3 ? \"Helpful\" : avg < -0.3 ? \"Unhelpful\" : \"Neutral\";\n const lines = [\n `- Overall: ${label} (avg ${avg.toFixed(2)}, ${evals.length} message${evals.length === 1 ? \"\" : \"s\"})`,\n ];\n for (const e of evals) {\n const ratingLabel = e.rating > 0 ? \"helpful\" : e.rating < 0 ? \"unhelpful\" : \"neutral\";\n lines.push(` - Message ${e.messageIndex}: ${ratingLabel} — ${e.reasoning}`);\n }\n return lines.join(\"\\n\");\n}\n\n// ── JSON parsing ───────────────────────────────────────────────────────\n\nfunction toAuditResult(parsed: Record<string, unknown>): AuditJsonResult | null {\n if (!parsed || !Array.isArray(parsed.turnGrades)) return null;\n\n const macro = parsed.macroEvaluation as Record<string, unknown> | null | undefined;\n const rawHumanEvals = Array.isArray(parsed.humanEvaluations)\n ? (parsed.humanEvaluations as TaskAuditHumanEvaluation[])\n : [];\n const baseSummary = (parsed.summary as string) ?? \"\";\n\n const macroText = formatMacroEvaluation(macro);\n const humanEvalText = formatHumanEvaluations(rawHumanEvals);\n\n let summary = baseSummary;\n if (macroText) summary += `\\n\\n---\\n\\nMacro Evaluation:\\n${macroText}`;\n if (humanEvalText) summary += `\\n\\n---\\n\\nHuman Contributions:\\n${humanEvalText}`;\n\n return {\n turnGrades: parsed.turnGrades as TaskAuditTurnGrade[],\n summary,\n planningAccuracy: (parsed.planningAccuracy as number) ?? null,\n buildingAccuracy: (parsed.buildingAccuracy as number) ?? null,\n humanAccuracy: (parsed.humanAccuracy as number) ?? null,\n humanEvaluations: rawHumanEvals,\n macroEvaluation: macro\n ? {\n instructionsQuality: (macro.instructionsQuality as string) ?? undefined,\n modelSuitability: (macro.modelSuitability as string) ?? undefined,\n contextAndPlanning: (macro.contextAndPlanning as string) ?? undefined,\n overallResult: (macro.overallResult as string) ?? undefined,\n }\n : null,\n };\n}\n\nexport function extractJsonFromResponse(text: string): AuditJsonResult {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const result = toAuditResult(JSON.parse(jsonStr));\n if (result) return result;\n } catch {\n // Try fallback: find a JSON object in raw text\n }\n\n const objectMatch = text.match(/\\{[\\s\\S]*\"turnGrades\"[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const result = toAuditResult(JSON.parse(objectMatch[0]));\n if (result) return result;\n } catch {\n // Fall through\n }\n }\n\n throw new Error(\"Could not parse task audit grades from Claude response\");\n}\n\n// ── Grade counting ─────────────────────────────────────────────────────\n\nexport function computeGradeCounts(turnGrades: TaskAuditTurnGrade[]) {\n const counts = {\n planningCorrect: 0,\n planningNeutral: 0,\n planningBlunder: 0,\n buildingCorrect: 0,\n buildingNeutral: 0,\n buildingBlunder: 0,\n humanCorrect: 0,\n humanNeutral: 0,\n humanBlunder: 0,\n };\n\n for (const tg of turnGrades) {\n const key =\n `${tg.phase}${tg.grade.charAt(0).toUpperCase()}${tg.grade.slice(1)}` as keyof typeof counts;\n if (key in counts) {\n counts[key]++;\n }\n }\n\n return counts;\n}\n\n// ── Cost helpers ──────────────────────────────────────────────────────\n\nexport function addCosts(base: number | null, addition: number | null): number | null {\n if (base === null) return addition;\n if (addition === null) return base;\n return base + addition;\n}\n\n// ── Error result builder ──────────────────────────────────────────────\n\nexport function buildErrorResult(\n projectId: string,\n requestId: string,\n taskId: string,\n error: string,\n) {\n return {\n projectId,\n requestId,\n taskId,\n summary: \"\",\n turnGrades: [] as TaskAuditTurnGrade[],\n planningAccuracy: null,\n buildingAccuracy: null,\n humanAccuracy: null,\n planningCorrect: 0,\n planningNeutral: 0,\n planningBlunder: 0,\n buildingCorrect: 0,\n buildingNeutral: 0,\n buildingBlunder: 0,\n humanCorrect: 0,\n humanNeutral: 0,\n humanBlunder: 0,\n suggestionIds: [] as string[],\n auditCostUsd: null,\n model: null,\n error,\n };\n}\n\n// ── Step-specific JSON extraction ─────────────────────────────────────\n\nfunction extractJsonBlock(text: string): Record<string, unknown> {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const parsed = JSON.parse(jsonStr);\n if (parsed && typeof parsed === \"object\") return parsed as Record<string, unknown>;\n } catch {\n // Fallback: find a JSON object in raw text\n }\n\n const objectMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const parsed = JSON.parse(objectMatch[0]);\n if (parsed && typeof parsed === \"object\") return parsed as Record<string, unknown>;\n } catch {\n // Fall through\n }\n }\n\n throw new Error(\"Could not parse JSON from Claude response\");\n}\n\n/**\n * Extract grading result from Steps 1 (Planning) or 2 (Building).\n * The phase is hardcoded by the caller, not determined by the LLM.\n */\nexport function extractGradingResult(text: string, phase: TaskAuditPhase): StepGradingResult {\n const parsed = extractJsonBlock(text);\n const turnGrades = Array.isArray(parsed.turnGrades)\n ? (parsed.turnGrades as TaskAuditTurnGrade[]).map((tg) => ({ ...tg, phase }))\n : [];\n const summary = (parsed.summary as string) ?? \"\";\n const accuracy = typeof parsed.accuracy === \"number\" ? parsed.accuracy : null;\n return { turnGrades, summary, accuracy };\n}\n\nconst VALID_GRADING_PHASES = new Set<TaskAuditPhase>([\"planning\", \"building\"]);\n\n/**\n * Extract combined grading result from the holistic audit step.\n * The LLM labels each turn with phase: \"planning\" | \"building\".\n * Falls back to \"building\" if phase is missing or invalid.\n */\nexport function extractCombinedGradingResult(text: string): StepCombinedGradingResult {\n const parsed = extractJsonBlock(text);\n const turnGrades = Array.isArray(parsed.turnGrades)\n ? (parsed.turnGrades as TaskAuditTurnGrade[]).map((tg) => ({\n ...tg,\n phase: VALID_GRADING_PHASES.has(tg.phase as TaskAuditPhase)\n ? (tg.phase as TaskAuditPhase)\n : (\"building\" as const),\n }))\n : [];\n const summary = (parsed.summary as string) ?? \"\";\n const planningAccuracy =\n typeof parsed.planningAccuracy === \"number\" ? parsed.planningAccuracy : null;\n const buildingAccuracy =\n typeof parsed.buildingAccuracy === \"number\" ? parsed.buildingAccuracy : null;\n return { turnGrades, summary, planningAccuracy, buildingAccuracy };\n}\n\n/**\n * Extract human evaluation result from Step 3.\n */\nexport function extractHumanResult(text: string): StepHumanResult {\n const parsed = extractJsonBlock(text);\n const humanEvaluations = Array.isArray(parsed.humanEvaluations)\n ? (parsed.humanEvaluations as TaskAuditHumanEvaluation[])\n : [];\n const summary = (parsed.summary as string) ?? \"\";\n const humanAccuracy = typeof parsed.humanAccuracy === \"number\" ? parsed.humanAccuracy : null;\n return { humanEvaluations, summary, humanAccuracy };\n}\n\n/**\n * Extract analysis result from Step 4.\n */\nexport function extractAnalysisResult(text: string): StepAnalysisResult {\n const parsed = extractJsonBlock(text);\n const summary = (parsed.summary as string) ?? \"\";\n const macro = parsed.macroEvaluation as Record<string, unknown> | null | undefined;\n return {\n summary,\n macroEvaluation: macro\n ? {\n instructionsQuality: (macro.instructionsQuality as string) ?? undefined,\n modelSuitability: (macro.modelSuitability as string) ?? undefined,\n contextAndPlanning: (macro.contextAndPlanning as string) ?? undefined,\n overallResult: (macro.overallResult as string) ?? undefined,\n }\n : null,\n };\n}\n\n/** Build a combined summary from all step results with optional macro/human sections. */\nfunction buildMergedSummary(\n gradingResult: StepCombinedGradingResult | null,\n humanResult: StepHumanResult | null,\n analysisResult: StepAnalysisResult | null,\n): string {\n const summaryParts: string[] = [];\n if (analysisResult?.summary) {\n summaryParts.push(analysisResult.summary);\n } else {\n if (gradingResult?.summary) summaryParts.push(gradingResult.summary);\n if (humanResult?.summary) summaryParts.push(`Human: ${humanResult.summary}`);\n }\n\n const macroText = analysisResult?.macroEvaluation\n ? formatMacroEvaluation(analysisResult.macroEvaluation as Record<string, unknown>)\n : null;\n const humanEvalText = humanResult ? formatHumanEvaluations(humanResult.humanEvaluations) : null;\n\n let summary = summaryParts.join(\"\\n\\n\");\n if (macroText) summary += `\\n\\n---\\n\\nMacro Evaluation:\\n${macroText}`;\n if (humanEvalText) summary += `\\n\\n---\\n\\nHuman Contributions:\\n${humanEvalText}`;\n return summary;\n}\n\n/**\n * Merge results from all 3 steps into a single result ready for reporting.\n * Turn indices are global (no offset needed since the combined step grades the full trace).\n */\nexport function mergeStepResults(\n gradingResult: StepCombinedGradingResult | null,\n humanResult: StepHumanResult | null,\n analysisResult: StepAnalysisResult | null,\n): MergedAuditResult {\n return {\n turnGrades: gradingResult?.turnGrades ?? [],\n summary: buildMergedSummary(gradingResult, humanResult, analysisResult),\n planningAccuracy: gradingResult?.planningAccuracy ?? null,\n buildingAccuracy: gradingResult?.buildingAccuracy ?? null,\n humanAccuracy: humanResult?.humanAccuracy ?? null,\n humanEvaluations: humanResult?.humanEvaluations ?? [],\n macroEvaluation: analysisResult?.macroEvaluation ?? null,\n };\n}\n\n// ── Suggestion prompt builder ─────────────────────────────────────────\n\nexport function buildSuggestionPrompt(parsed: AuditJsonResult, task: TaskAuditPayload): string {\n const parts: string[] = [`# Suggestion Generation for: ${task.taskTitle}\\n`];\n\n parts.push(`## Audit Summary\\n${parsed.summary}\\n`);\n\n if (parsed.macroEvaluation) {\n parts.push(\"## Macro Evaluation\");\n if (parsed.macroEvaluation.instructionsQuality)\n parts.push(`- Instructions Quality: ${parsed.macroEvaluation.instructionsQuality}`);\n if (parsed.macroEvaluation.modelSuitability)\n parts.push(`- Model Suitability: ${parsed.macroEvaluation.modelSuitability}`);\n if (parsed.macroEvaluation.contextAndPlanning)\n parts.push(`- Context & Planning: ${parsed.macroEvaluation.contextAndPlanning}`);\n if (parsed.macroEvaluation.overallResult)\n parts.push(`- Overall Result: ${parsed.macroEvaluation.overallResult}`);\n parts.push(\"\");\n }\n\n const blunders = parsed.turnGrades.filter((tg) => tg.grade === \"blunder\");\n if (blunders.length > 0) {\n parts.push(\"## Notable Blunders\");\n for (const b of blunders.slice(0, 10)) {\n parts.push(`- Turn ${b.turnIndex} (${b.phase}): ${b.reasoning}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\n \"Based on the findings above, call create_suggestion for each actionable cross-cutting improvement.\",\n );\n\n return parts.join(\"\\n\");\n}\n","import type { TaskAuditPayload } from \"@project/shared\";\nimport type { StepHumanResult, StepCombinedGradingResult } from \"./task-audit-parsing.js\";\n\n// ── System prompts (4 focused steps) ────────────────────────────────────\n\nexport const PLANNING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the PLANNING phase of an AI agent's task execution. You receive only the planning portion of the agent's trace — from the start through the last plan update. Grade each turn objectively.\n\n## Grading Scale\n\n- **Correct** (♟): Sound moves toward understanding the task — reading relevant files, analyzing requirements, logical reasoning about approach, following project patterns\n- **Neutral** (·): No significant positive or negative effect — exploratory reads, minor tangents\n- **Blunder** (??): Wasted effort — reading irrelevant files repeatedly, ignoring requirements, spending many turns without making progress toward a plan\n\n## Specific Blunder Examples\n- Reading the same file 5+ times without advancing understanding\n- Ignoring explicit task requirements or project conventions visible in the code\n- Spending many turns on tangential investigation not related to the task\n- Failing to read key files that are obvious from the task description\n\n## Specific Correct Examples\n- Reading context files before implementation\n- Analyzing requirements and dependencies systematically\n- Identifying relevant code patterns to follow\n- Building understanding incrementally\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"turnGrades\": [\n {\n \"turnIndex\": 0,\n \"grade\": \"correct\",\n \"reasoning\": \"Read relevant config files to understand project structure\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Read package.json and tsconfig.json\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of planning quality\",\n \"accuracy\": 0.85\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.\n\nIMPORTANT: Do NOT include a \"phase\" field in turnGrades — the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;\n\nexport const BUILDING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the BUILDING phase of an AI agent's task execution. You receive only the building portion of the agent's trace — from after the plan was finalized through pull request creation. Grade each turn objectively.\n\n## Grading Scale\n\n- **Correct** (♟): Sound implementation moves — proper edits, running tests, fixing errors, following plan steps, adapting to feedback\n- **Neutral** (·): No significant positive or negative effect — exploratory reads during implementation, minor tangents\n- **Blunder** (??): Wasted effort — incorrect edits immediately reverted, repeated failures without adapting, ignoring the plan, using wrong APIs despite visible patterns\n\n## Specific Blunder Examples\n- Making edits that are immediately reverted or overwritten\n- Ignoring explicit plan steps or user corrections\n- Repeated failed tool calls (isError: true) without changing approach\n- Using wrong APIs despite project patterns visible in the trace\n- Spending many turns on tangential work not in the plan\n\n**Multi-session awareness**: If the trace begins with exploration (reads/greps) before any edits, and there is no prior planning trace, these likely represent the agent re-orienting in a new session. Grade initial orientation reads as neutral unless clearly wasteful (e.g., reading the same file 5+ times).\n\n## Specific Correct Examples\n- Following plan steps in logical sequence\n- Proper error handling and recovery after tool failures\n- Adapting approach based on test results or errors\n- Efficient tool usage with clear purpose\n- Running tests to verify changes\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"turnGrades\": [\n {\n \"turnIndex\": 0,\n \"grade\": \"correct\",\n \"reasoning\": \"Implemented the required changes following the plan\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Edit src/component.tsx\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of building quality\",\n \"accuracy\": 0.72\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.\n\nIMPORTANT: Turn indices are 0-based relative to the trace slice provided. Do NOT include a \"phase\" field — the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;\n\nexport const COMBINED_GRADING_SYSTEM_PROMPT = `You are a chess-style analysis engine performing a holistic audit of an AI agent's full task execution — from initial planning through final implementation. You receive the complete agent trace covering all phases and sessions. Grade each turn objectively.\n\n## Phase Identification\n\nIdentify the boundary between planning and building phases:\n- **Planning phase**: Turns from the start through the last \\`update_task\\` (plan save) call. Includes reading requirements, exploring code, analyzing dependencies, and formulating the plan.\n- **Building phase**: Turns after the last plan save through PR creation (or end of trace). Includes implementation, testing, and PR creation.\n- If no \\`update_task\\` call is found, treat all turns as building phase.\n\nYou MUST label each turn with \\`\"phase\": \"planning\"\\` or \\`\"phase\": \"building\"\\`.\n\n## Multi-Session Awareness\n\nThe trace may contain multiple agent sessions (indicated by \\`session_manifest\\` events). Grade ALL sessions — earlier sessions often contain valuable planning work or reflect restart patterns worth evaluating. If an earlier session was abandoned, grade its turns based on quality (exploration reads may be neutral, repeated failures may be blunders).\n\n## Grading Scale\n\n### Planning Turns\n- **Correct** (♟): Sound moves toward understanding the task — reading relevant files, analyzing requirements, logical reasoning about approach, following project patterns\n- **Neutral** (·): No significant positive or negative effect — exploratory reads, minor tangents\n- **Blunder** (??): Wasted effort — reading irrelevant files repeatedly, ignoring requirements, spending many turns without making progress toward a plan\n\n### Building Turns\n- **Correct** (♟): Sound implementation moves — proper edits, running tests, fixing errors, following plan steps, adapting to feedback\n- **Neutral** (·): No significant positive or negative effect — exploratory reads during implementation, minor tangents\n- **Blunder** (??): Wasted effort — incorrect edits immediately reverted, repeated failures without adapting, ignoring the plan, using wrong APIs despite visible patterns\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"turnGrades\": [\n {\n \"turnIndex\": 0,\n \"phase\": \"planning\",\n \"grade\": \"correct\",\n \"reasoning\": \"Read relevant config files to understand project structure\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Read package.json and tsconfig.json\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence holistic assessment of the full execution\",\n \"planningAccuracy\": 0.85,\n \"buildingAccuracy\": 0.72\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: For each phase separately: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null for a phase if it has no correct or blunder turns.\n\nTurn indices are 0-based relative to the full trace provided. Every turn grade MUST include the phase field.`;\n\nexport const HUMAN_AUDIT_SYSTEM_PROMPT = `You are evaluating human contributions to an AI agent's task execution. For each human message, assess whether it helped, hindered, or had no effect on the agent's work.\n\n## Rating Scale\n\n- **Helpful (+1)**: Provided useful context, clear corrections, actionable feedback, or unblocked the agent\n- **Neutral (0)**: Acknowledgements, status checks, or messages with no material impact on execution\n- **Unhelpful (-1)**: Contradictory instructions, incorrect guidance, unnecessary interruptions, or vague requests that caused wasted effort\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"humanEvaluations\": [\n {\n \"messageIndex\": 0,\n \"rating\": 1,\n \"reasoning\": \"Provided clear context about the bug with reproduction steps\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of human contributions\",\n \"humanAccuracy\": 0.75\n}\n\\`\\`\\`\n\n**humanAccuracy Calculation**: humanAccuracy = helpful / (helpful + unhelpful). Neutral messages are excluded. Return null if no helpful or unhelpful messages exist.\n\nEvaluate EVERY human message — do not skip any. Each entry in humanEvaluations must have a messageIndex (0-based index into the Human Messages list), rating (+1, 0, or -1), and reasoning.`;\n\nexport const ANALYSIS_SYSTEM_PROMPT = `You are performing a macro-level analysis of an AI agent's task execution and generating improvement suggestions. You receive grading results from planning, building, and human evaluation phases.\n\n## Your Tasks\n\n1. **Write an overall summary** (2-4 sentences) that synthesizes the planning, building, and human evaluation findings into a cohesive assessment.\n\n2. **Perform a macro evaluation** addressing:\n - **Instructions Quality**: Were the agent instructions appropriate? Too vague, too prescriptive, or missing critical guidance?\n - **Model Suitability**: Was the model choice appropriate for the complexity of this task?\n - **Context & Planning**: Was the plan/context sufficient? Were there information gaps that caused wasted effort?\n - **Overall Result**: Did the final result meet requirements? Was the outcome proportional to effort?\n\n3. **Generate suggestions** using the create_suggestion tool. Focus on:\n - Recurring patterns of wasted effort that could be prevented\n - Missing documentation or context that caused confusion\n - Process improvements to prevent common blunders\n - What worked well that should be replicated\n\nYou MUST call create_suggestion at least once. If the execution was flawless, suggest what made it work well so the pattern can be replicated.\n\n## Output Format\n\nAfter calling create_suggestion, output a JSON block:\n\n\\`\\`\\`json\n{\n \"summary\": \"Overall 2-4 sentence assessment synthesizing all phases\",\n \"macroEvaluation\": {\n \"instructionsQuality\": \"Brief assessment of instruction quality\",\n \"modelSuitability\": \"Brief assessment of model choice\",\n \"contextAndPlanning\": \"Brief assessment of context and planning\",\n \"overallResult\": \"Brief assessment of the outcome\"\n }\n}\n\\`\\`\\``;\n\n// ── Prompt section builders ─────────────────────────────────────────────\n\nfunction buildSessionInfoSection(info: NonNullable<TaskAuditPayload[\"sessionInfo\"]>): string {\n const lines: string[] = [\"## Session Info\"];\n if (info.model) lines.push(`- Model: ${info.model}`);\n if (info.totalCostUsd !== null) lines.push(`- Total Cost: $${info.totalCostUsd.toFixed(4)}`);\n if (info.planningTurns !== null) lines.push(`- Planning Turns: ${info.planningTurns}`);\n if (info.buildingTurns !== null) lines.push(`- Building Turns: ${info.buildingTurns}`);\n if (info.locDiff !== null) lines.push(`- Lines Changed: ${info.locDiff}`);\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\nfunction buildTraceSection(trace: TaskAuditPayload[\"agentTrace\"]): string {\n const lines: string[] = [\"## Agent Trace\\n\"];\n if (trace.length === 0) {\n lines.push(\"No agent trace data available.\\n\");\n } else {\n for (let i = 0; i < trace.length; i++) {\n const event = trace[i];\n const dataStr = JSON.stringify(event.data);\n const truncated = dataStr.length > 2000 ? dataStr.slice(0, 2000) + \"...\" : dataStr;\n lines.push(`### Turn ${i} [${event.type}] @ ${event.timestamp}`);\n lines.push(truncated);\n lines.push(\"\");\n }\n }\n return lines.join(\"\\n\");\n}\n\nfunction buildTaskContextSection(task: TaskAuditPayload): string {\n const parts: string[] = [];\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}`);\n if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);\n parts.push(\"\");\n if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));\n if (task.agentInstructions) parts.push(`## Agent Instructions\\n${task.agentInstructions}\\n`);\n return parts.join(\"\\n\");\n}\n\n// ── Step-specific prompt builders ──────────────────────────────────────\n\nfunction buildMultiSessionNote(task: TaskAuditPayload): string | null {\n const count = task.sessionInfo?.sessionCount;\n if (!count || count <= 1) return null;\n return `> **Note:** This task had ${count} total agent sessions. All sessions are included in the trace below.\\n`;\n}\n\nexport function buildCombinedGradingPrompt(task: TaskAuditPayload): string {\n const parts: string[] = [`# Full Workflow Audit: ${task.taskTitle}\\n`];\n const sessionNote = buildMultiSessionNote(task);\n if (sessionNote) parts.push(sessionNote);\n parts.push(buildTaskContextSection(task));\n parts.push(buildTraceSection(task.agentTrace));\n parts.push(\n \"Grade each turn above with its phase (planning or building), then output the structured JSON result.\",\n );\n return parts.join(\"\\n\");\n}\n\nexport function buildPlanningAuditPrompt(\n task: TaskAuditPayload,\n planningTrace: TaskAuditPayload[\"agentTrace\"],\n): string {\n const parts: string[] = [`# Planning Audit: ${task.taskTitle}\\n`];\n const sessionNote = buildMultiSessionNote(task);\n if (sessionNote) parts.push(sessionNote);\n parts.push(buildTaskContextSection(task));\n parts.push(buildTraceSection(planningTrace));\n parts.push(\"Grade each turn above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nexport function buildBuildingAuditPrompt(\n task: TaskAuditPayload,\n buildingTrace: TaskAuditPayload[\"agentTrace\"],\n): string {\n const parts: string[] = [`# Building Audit: ${task.taskTitle}\\n`];\n const sessionNote = buildMultiSessionNote(task);\n if (sessionNote) parts.push(sessionNote);\n parts.push(buildTaskContextSection(task));\n parts.push(buildTraceSection(buildingTrace));\n parts.push(\"Grade each turn above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nexport function buildHumanAuditPrompt(task: TaskAuditPayload): string {\n const parts: string[] = [`# Human Contribution Evaluation: ${task.taskTitle}\\n`];\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}\\n`);\n\n parts.push(\"## Human Messages\\n\");\n for (let i = 0; i < task.humanMessages.length; i++) {\n const msg = task.humanMessages[i];\n parts.push(`### Message ${i} [${msg.createdAt}]`);\n parts.push(`**${msg.role}**: ${msg.content}\\n`);\n }\n\n parts.push(\"Evaluate each human message above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nfunction buildPhaseResultSection(\n label: string,\n grades: import(\"@project/shared\").TaskAuditTurnGrade[],\n accuracy: number | null,\n summary: string,\n): string {\n const correct = grades.filter((g) => g.grade === \"correct\").length;\n const neutral = grades.filter((g) => g.grade === \"neutral\").length;\n const blunder = grades.filter((g) => g.grade === \"blunder\").length;\n const accuracyStr = accuracy === null ? \"N/A\" : accuracy.toFixed(2);\n return [\n `## ${label} Phase Results`,\n `- Summary: ${summary}`,\n `- Accuracy: ${accuracyStr}`,\n `- ${grades.length} turns: ${correct} correct, ${neutral} neutral, ${blunder} blunders`,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function buildAnalysisPrompt(\n task: TaskAuditPayload,\n gradingResult: StepCombinedGradingResult | null,\n humanResult: StepHumanResult | null,\n): string {\n const parts: string[] = [`# Task Analysis: ${task.taskTitle}\\n`];\n\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}`);\n if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);\n parts.push(\"\");\n if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));\n\n if (gradingResult) {\n const planGrades = gradingResult.turnGrades.filter((g) => g.phase === \"planning\");\n const buildGrades = gradingResult.turnGrades.filter((g) => g.phase === \"building\");\n if (planGrades.length > 0) {\n parts.push(\n buildPhaseResultSection(\n \"Planning\",\n planGrades,\n gradingResult.planningAccuracy,\n gradingResult.summary,\n ),\n );\n }\n if (buildGrades.length > 0) {\n parts.push(\n buildPhaseResultSection(\n \"Building\",\n buildGrades,\n gradingResult.buildingAccuracy,\n gradingResult.summary,\n ),\n );\n }\n }\n\n if (humanResult) {\n const evals = humanResult.humanEvaluations;\n const helpful = evals.filter((e) => e.rating > 0).length;\n const neutralCount = evals.filter((e) => e.rating === 0).length;\n const unhelpful = evals.filter((e) => e.rating < 0).length;\n parts.push(\"## Human Evaluation Results\");\n parts.push(`- Summary: ${humanResult.summary}`);\n parts.push(\n `- ${evals.length} messages: ${helpful} helpful, ${neutralCount} neutral, ${unhelpful} unhelpful`,\n );\n parts.push(\"\");\n }\n\n const blunders = (gradingResult?.turnGrades ?? []).filter((g) => g.grade === \"blunder\");\n if (blunders.length > 0) {\n parts.push(\"## Notable Blunders\");\n for (const b of blunders.slice(0, 10)) {\n parts.push(`- Turn ${b.turnIndex} (${b.phase}): ${b.reasoning}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\n \"Based on the findings above, call create_suggestion for each actionable improvement, then output the JSON result.\",\n );\n\n return parts.join(\"\\n\");\n}\n","import type { ProjectConnection } from \"../connection/project-connection.js\";\n\n// ── Progress reporting ────────────────────────────────────────────────\n\nexport function reportProgress(\n connection: ProjectConnection,\n requestId: string,\n taskId: string,\n tool: string,\n input?: string,\n): void {\n void connection\n .call(\"reportTaskAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n taskId,\n activity: { tool, input, timestamp: new Date().toISOString() },\n })\n .catch(() => {});\n}\n\n// ── Event stream collection ───────────────────────────────────────────\n\ninterface ProgressContext {\n connection: ProjectConnection;\n requestId: string;\n taskId: string;\n}\n\nfunction processAssistantBlocks(\n blocks: Array<{ type: string; text?: string; name?: string; input?: unknown }>,\n responseParts: string[],\n ctx: ProgressContext,\n reportedFirstText: { value: boolean },\n): void {\n for (const block of blocks) {\n if (block.type === \"text\" && block.text) {\n responseParts.push(block.text);\n if (reportedFirstText.value) continue;\n reportedFirstText.value = true;\n reportProgress(\n ctx.connection,\n ctx.requestId,\n ctx.taskId,\n \"thinking\",\n block.text.slice(0, 200),\n );\n } else if (block.type === \"tool_use\" && block.name) {\n const inputStr = typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n reportProgress(ctx.connection, ctx.requestId, ctx.taskId, block.name, inputStr.slice(0, 500));\n }\n }\n}\n\nexport async function collectResponseFromEvents(\n events: AsyncIterable<{ type: string }>,\n connection: ProjectConnection,\n requestId: string,\n taskId: string,\n): Promise<{ text: string; costUsd: number | null; model: string | null }> {\n const responseParts: string[] = [];\n let costUsd: number | null = null;\n let model: string | null = null;\n const reportedFirstText = { value: false };\n const ctx: ProgressContext = { connection, requestId, taskId };\n\n for await (const event of events) {\n if (event.type === \"system\") {\n const sysEvent = event as { type: string; subtype?: string; model?: string };\n if (sysEvent.subtype === \"init\" && sysEvent.model) {\n model = sysEvent.model;\n reportProgress(\n connection,\n requestId,\n taskId,\n \"system\",\n `Initialized model: ${sysEvent.model}`,\n );\n }\n }\n\n if (event.type === \"assistant\") {\n const { message } = event as {\n type: string;\n message: {\n content: Array<{ type: string; text?: string; name?: string; input?: unknown }>;\n };\n };\n processAssistantBlocks(message.content, responseParts, ctx, reportedFirstText);\n }\n\n if (event.type === \"result\") {\n const resultEvent = event as { type: string; subtype?: string; total_cost_usd?: number };\n if (resultEvent.subtype === \"success\" && resultEvent.total_cost_usd !== undefined) {\n costUsd = resultEvent.total_cost_usd;\n }\n const status =\n resultEvent.subtype === \"success\" ? \"success\" : `error: ${resultEvent.subtype}`;\n reportProgress(connection, requestId, taskId, \"complete\", status);\n break;\n }\n }\n\n return { text: responseParts.join(\"\\n\\n\").trim(), costUsd, model };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-agent",
3
- "version": "7.2.8",
3
+ "version": "7.2.10",
4
4
  "description": "Conveyor Agent Runner v7.0 - Agent-as-User architecture with BaseService patterns. Works locally too.",
5
5
  "keywords": [
6
6
  "agent",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runner/tag-audit-handler.ts"],"sourcesContent":["import { createHarness } from \"../harness/index.js\";\nimport type { ProjectConnection } from \"../connection/project-connection.js\";\nimport type { TagAuditRunnerRequest } from \"@project/shared\";\nimport { createServiceLogger } from \"../utils/logger.js\";\n\nconst logger = createServiceLogger(\"TagAudit\");\n\nconst FALLBACK_MODEL = \"claude-sonnet-4-6\";\n\n// ── Prompt section builders ────────────────────────────────────────────\n\nfunction buildTagsSection(request: TagAuditRunnerRequest, parts: string[]): void {\n parts.push(\"## Current Tags\\n\");\n if (request.tags.length === 0) {\n parts.push(\"No tags currently exist.\\n\");\n } else {\n for (const tag of request.tags) {\n parts.push(`### ${tag.name} (id: ${tag.id})`);\n parts.push(`- Description: ${tag.description ?? \"(none)\"}`);\n parts.push(`- Active tasks: ${tag.activeTaskCount}`);\n if (tag.contextPaths) {\n parts.push(`- Context paths: ${JSON.stringify(tag.contextPaths)}`);\n }\n parts.push(\"\");\n }\n }\n}\n\nfunction buildContextSections(request: TagAuditRunnerRequest, parts: string[]): void {\n if (request.objectives && request.objectives.length > 0) {\n parts.push(\"## Project Objectives\\n\");\n for (const obj of request.objectives) {\n parts.push(`- **${obj.name}**${obj.description ? `: ${obj.description}` : \"\"}`);\n }\n parts.push(\"\");\n }\n\n if (request.tagRules && request.tagRules.length > 0) {\n parts.push(\"## Tag Rules\\n\");\n parts.push(\"These tags have associated rule files that agents load automatically:\\n\");\n for (const rule of request.tagRules) {\n parts.push(`- **${rule.tagName}** → \\`${rule.rulePath}\\``);\n }\n parts.push(\"\");\n }\n\n if (request.fileHeatmap.length > 0) {\n parts.push(\"## File Access Heatmap\\n\");\n parts.push(\"Files most frequently read by agents, broken down by tag:\\n\");\n for (const entry of request.fileHeatmap.slice(0, 50)) {\n const tagBreakdown = Object.entries(entry.byTag)\n .map(([tag, count]) => `${tag}: ${count}`)\n .join(\", \");\n parts.push(`- \\`${entry.filePath}\\` (total: ${entry.totalReads}) — ${tagBreakdown}`);\n }\n parts.push(\"\");\n }\n\n if (request.recentTaskSamples && request.recentTaskSamples.length > 0) {\n parts.push(\"## Recent Task Samples\\n\");\n parts.push(\"Recent tasks per tag (to understand how tags are used):\\n\");\n for (const sample of request.recentTaskSamples) {\n parts.push(`### ${sample.tagName}`);\n for (const task of sample.tasks) {\n parts.push(`- ${task.title} (${task.status})`);\n }\n parts.push(\"\");\n }\n }\n}\n\n// ── Prompt builder ──────────────────────────────────────────────────────\n\nexport function buildTagAuditPrompt(request: TagAuditRunnerRequest): string {\n const parts: string[] = [];\n\n parts.push(`# Tag Audit for project: ${request.projectName}\\n`);\n buildTagsSection(request, parts);\n buildContextSections(request, parts);\n parts.push(\"Analyze the tags above and the codebase, then output your recommendations.\");\n\n return parts.join(\"\\n\");\n}\n\nconst TAG_AUDIT_SYSTEM_PROMPT = `You are analyzing tags for a software project. Tags are used to organize tasks, associate context paths (files/directories that agents should read), and track work areas.\n\nGiven the current tags (with descriptions, context paths, and active task counts) and a file access heatmap (which files agents read most, broken down by tag), analyze the project and generate recommendations.\n\nYou have full access to the codebase. Read relevant files — especially .claude/rules/, README files, and any context paths referenced by existing tags — to validate your recommendations.\n\nGenerate recommendations of these types:\n- **create_tag**: Suggest new tags for uncovered areas of the codebase\n- **update_description**: Improve a tag's description to be more useful\n- **add_context_link**: Add context paths (files/directories) that agents should read when working on tasks with this tag\n- **documentation_gap**: Identify areas where documentation or context is missing\n- **merge_tags**: Suggest merging overlapping tags\n- **rename_tag**: Suggest a better name for a tag\n\nEach recommendation must include:\n- \\`id\\`: A unique UUID\n- \\`type\\`: One of the types above\n- \\`tagName\\`: The tag name this applies to\n- \\`tagId\\`: The existing tag's ID (if modifying an existing tag, omit for create_tag)\n- \\`suggestion\\`: A short description of the recommendation\n- \\`reasoning\\`: Why this recommendation would help\n- \\`payload\\`: Type-specific data:\n - create_tag: \\`{ name: string, description: string, contextPaths?: string[] }\\`\n - update_description: \\`{ description: string }\\`\n - add_context_link: \\`{ type: \"rule\" | \"doc\" | \"file\" | \"folder\", path: string, label?: string }\\`\n - documentation_gap: \\`{ area: string, suggestedContent?: string }\\`\n - merge_tags: \\`{ sourceTagIds: string[], targetName: string }\\`\n - rename_tag: \\`{ newName: string }\\`\n\nAfter your analysis, output a JSON block in this exact format:\n\n\\`\\`\\`json\n{\n \"recommendations\": [ ...array of recommendations... ],\n \"summary\": \"Brief summary of findings\"\n}\n\\`\\`\\`\n\nAlways provide recommendations. Even well-organized projects have room for improvement — look for missing context links, stale descriptions, documentation gaps, and tag coverage opportunities. Aim for at least 3-5 recommendations. Be specific, actionable, and concise.`;\n\n// ── Fetch agent context ─────────────────────────────────────────────────\n\nasync function fetchModel(connection: ProjectConnection): Promise<string> {\n try {\n const ctx = await connection.call(\"getProjectAgentContext\", {\n projectId: connection.projectId,\n });\n return ctx.model || FALLBACK_MODEL;\n } catch {\n return FALLBACK_MODEL;\n }\n}\n\n// ── JSON extraction ─────────────────────────────────────────────────────\n\nfunction extractJsonFromResponse(text: string): { recommendations: unknown[]; summary: string } {\n // Try to find a JSON code block first\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const parsed = JSON.parse(jsonStr);\n if (parsed && Array.isArray(parsed.recommendations) && typeof parsed.summary === \"string\") {\n return parsed;\n }\n } catch {\n // Try to find a JSON object in the raw text\n const objectMatch = text.match(/\\{[\\s\\S]*\"recommendations\"[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const parsed = JSON.parse(objectMatch[0]);\n if (parsed && Array.isArray(parsed.recommendations)) {\n return { recommendations: parsed.recommendations, summary: parsed.summary ?? \"\" };\n }\n } catch {\n // Fall through\n }\n }\n }\n\n throw new Error(\"Could not parse tag audit recommendations from Claude response\");\n}\n\n// ── Event stream processing ─────────────────────────────────────────────\n\nasync function collectResponseFromEvents(\n events: AsyncIterable<{ type: string }>,\n connection: ProjectConnection,\n requestId: string,\n): Promise<string> {\n const responseParts: string[] = [];\n for await (const event of events) {\n if (event.type === \"assistant\") {\n const { message } = event as {\n type: string;\n message: {\n content: Array<{ type: string; text?: string; name?: string; input?: unknown }>;\n };\n };\n for (const block of message.content) {\n if (block.type === \"text\" && block.text) {\n responseParts.push(block.text);\n } else if (block.type === \"tool_use\" && block.name) {\n const inputStr =\n typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n await connection\n .call(\"reportTagAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n activity: {\n tool: block.name,\n input: inputStr.slice(0, 10_000),\n timestamp: new Date().toISOString(),\n },\n })\n .catch(() => {});\n }\n }\n }\n if (event.type === \"result\") break;\n }\n return responseParts.join(\"\\n\\n\").trim();\n}\n\n// ── Main handler ────────────────────────────────────────────────────────\n\nexport async function handleTagAudit(\n request: TagAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n): Promise<void> {\n const { requestId } = request;\n\n logger.info(\"Starting tag audit\", { requestId, tagCount: request.tags.length });\n\n await connection\n .call(\"reportTagAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n activity: {\n tool: \"audit\",\n input: \"Starting tag audit...\",\n timestamp: new Date().toISOString(),\n },\n })\n .catch(() => {});\n\n const model = await fetchModel(connection);\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: buildTagAuditPrompt(request),\n options: {\n model,\n systemPrompt: TAG_AUDIT_SYSTEM_PROMPT,\n cwd: projectDir,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: {},\n maxTurns: 8,\n maxBudgetUsd: 5,\n },\n });\n\n const responseText = await collectResponseFromEvents(events, connection, requestId);\n if (!responseText) throw new Error(\"No response from Claude\");\n\n const { recommendations, summary } = extractJsonFromResponse(responseText);\n logger.info(\"Tag audit complete\", { requestId, recommendationCount: recommendations.length });\n\n await connection.call(\"reportTagAuditResult\", {\n projectId: connection.projectId,\n requestId,\n recommendations: recommendations as Array<Record<string, unknown>>,\n summary,\n complete: true,\n });\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runner/task-audit-handler.ts","../src/runner/task-audit-parsing.ts","../src/runner/task-audit-trace-slicer.ts","../src/runner/task-audit-prompts.ts","../src/runner/task-audit-progress.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { createHarness, defineTool } from \"../harness/index.js\";\nimport type { ProjectConnection } from \"../connection/project-connection.js\";\nimport type { TaskAuditRunnerRequest, TaskAuditPayload, TaskAuditPhase } from \"@project/shared\";\nimport { textResult } from \"../tools/helpers.js\";\nimport { createServiceLogger } from \"../utils/logger.js\";\nimport {\n type StepGradingResult,\n type StepHumanResult,\n type StepAnalysisResult,\n extractGradingResult,\n extractHumanResult,\n extractAnalysisResult,\n mergeStepResults,\n computeGradeCounts,\n addCosts,\n buildErrorResult,\n} from \"./task-audit-parsing.js\";\nimport { sliceTrace } from \"./task-audit-trace-slicer.js\";\nimport {\n PLANNING_AUDIT_SYSTEM_PROMPT,\n BUILDING_AUDIT_SYSTEM_PROMPT,\n HUMAN_AUDIT_SYSTEM_PROMPT,\n ANALYSIS_SYSTEM_PROMPT,\n buildPlanningAuditPrompt,\n buildBuildingAuditPrompt,\n buildHumanAuditPrompt,\n buildAnalysisPrompt,\n} from \"./task-audit-prompts.js\";\nimport { reportProgress, collectResponseFromEvents } from \"./task-audit-progress.js\";\n\nconst logger = createServiceLogger(\"TaskAudit\");\n\nconst FALLBACK_MODEL = \"claude-sonnet-4-6\";\n\n// ── Suggestion MCP tool ─────────────────────────────────────────────────\n\nfunction buildTrackedSuggestionTool(\n connection: ProjectConnection,\n projectId: string,\n suggestionIds: string[],\n) {\n return defineTool(\n \"create_suggestion\",\n \"Suggest a cross-cutting improvement for the project based on patterns found during audit. If a similar suggestion exists, your vote is added instead of creating a duplicate.\",\n {\n title: z.string().describe(\"Short title for the suggestion\"),\n description: z.string().optional().describe(\"Details about the suggestion\"),\n },\n async ({ title, description }) => {\n try {\n const result = await connection.call(\"createProjectSuggestion\", {\n projectId,\n title,\n description,\n });\n // Capture ID directly from the typed response object\n const id = result.mergedIntoId ?? result.id;\n if (id) {\n suggestionIds.push(id);\n logger.info(\"Suggestion tracked\", { id, merged: result.merged });\n }\n if (result.merged) {\n return textResult(`Merged into existing suggestion (ID: ${id}).`);\n }\n return textResult(`Suggestion created (ID: ${result.id}).`);\n } catch (error) {\n logger.warn(\"Suggestion creation failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return textResult(\n `Failed to create suggestion: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n },\n );\n}\n\n// ── Fetch model ─────────────────────────────────────────────────────────\n\nasync function fetchModel(connection: ProjectConnection): Promise<string> {\n try {\n const ctx = await connection.call(\"getProjectAgentContextByRole\", {\n projectId: connection.projectId,\n role: \"reviewer\",\n });\n return ctx.model || FALLBACK_MODEL;\n } catch {\n return FALLBACK_MODEL;\n }\n}\n\n// ── Step runners ────────────────────────────────────────────────────────\n\ninterface StepOptions {\n connection: ProjectConnection;\n requestId: string;\n projectDir: string;\n model: string;\n}\n\nfunction buildQueryOptions(\n systemPrompt: string,\n opts: StepOptions,\n limits: { maxTurns: number; maxBudgetUsd: number },\n mcpServers: Record<string, unknown> = {},\n) {\n return {\n model: opts.model,\n systemPrompt,\n cwd: opts.projectDir,\n permissionMode: \"bypassPermissions\" as const,\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers,\n maxTurns: limits.maxTurns,\n maxBudgetUsd: limits.maxBudgetUsd,\n disallowedTools: [\"Edit\", \"Write\", \"Bash\", \"NotebookEdit\", \"MultiEdit\"],\n };\n}\n\nasync function runGradingStep(\n taskId: string,\n phase: TaskAuditPhase,\n systemPrompt: string,\n userPrompt: string,\n limits: { maxTurns: number; maxBudgetUsd: number },\n opts: StepOptions,\n): Promise<{ result: StepGradingResult; costUsd: number | null; model: string | null }> {\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: userPrompt,\n options: buildQueryOptions(systemPrompt, opts, limits),\n });\n const response = await collectResponseFromEvents(events, opts.connection, opts.requestId, taskId);\n if (!response.text) throw new Error(`No response from ${phase} grading step`);\n return {\n result: extractGradingResult(response.text, phase),\n costUsd: response.costUsd,\n model: response.model,\n };\n}\n\nasync function runHumanStep(\n taskId: string,\n userPrompt: string,\n limits: { maxTurns: number; maxBudgetUsd: number },\n opts: StepOptions,\n): Promise<{ result: StepHumanResult; costUsd: number | null }> {\n const harness = createHarness();\n const events = harness.executeQuery({\n prompt: userPrompt,\n options: buildQueryOptions(HUMAN_AUDIT_SYSTEM_PROMPT, opts, limits),\n });\n const response = await collectResponseFromEvents(events, opts.connection, opts.requestId, taskId);\n if (!response.text) throw new Error(\"No response from human evaluation step\");\n return { result: extractHumanResult(response.text), costUsd: response.costUsd };\n}\n\nasync function runAnalysisStep(\n task: TaskAuditPayload,\n planningResult: StepGradingResult | null,\n buildingResult: StepGradingResult | null,\n humanResult: StepHumanResult | null,\n projectId: string,\n suggestionIds: string[],\n opts: StepOptions,\n): Promise<{ result: StepAnalysisResult; costUsd: number | null }> {\n const wrappedTool = buildTrackedSuggestionTool(opts.connection, projectId, suggestionIds);\n const harness = createHarness();\n const mcpServer = harness.createMcpServer({ name: \"conveyor\", tools: [wrappedTool] });\n const events = harness.executeQuery({\n prompt: buildAnalysisPrompt(task, planningResult, buildingResult, humanResult),\n options: buildQueryOptions(\n ANALYSIS_SYSTEM_PROMPT,\n opts,\n { maxTurns: 6, maxBudgetUsd: 1 },\n { conveyor: mcpServer },\n ),\n });\n const response = await collectResponseFromEvents(\n events,\n opts.connection,\n opts.requestId,\n task.taskId,\n );\n if (!response.text) throw new Error(\"No response from analysis step\");\n return { result: extractAnalysisResult(response.text), costUsd: response.costUsd };\n}\n\n// ── Safe step wrapper ──────────────────────────────────────────────────\n\ninterface StepOutput<T> {\n result: T | null;\n costUsd: number | null;\n model: string | null;\n}\n\nconst EMPTY_STEP: StepOutput<never> = { result: null, costUsd: null, model: null };\nconst GRADING_LIMITS = { maxTurns: 8, maxBudgetUsd: 1 };\n\nasync function executeStepSafely<T>(\n stepLabel: string,\n requestId: string,\n taskId: string,\n fn: () => Promise<{ result: T; costUsd: number | null; model?: string | null }>,\n): Promise<StepOutput<T>> {\n try {\n const step = await fn();\n return { result: step.result, costUsd: step.costUsd, model: step.model ?? null };\n } catch (err) {\n logger.warn(`${stepLabel} failed`, {\n requestId,\n taskId,\n error: err instanceof Error ? err.message : String(err),\n });\n return EMPTY_STEP;\n }\n}\n\n// ── Step orchestration ─────────────────────────────────────────────────\n\nasync function executePlanningStep(\n taskPayload: TaskAuditPayload,\n planningTrace: TaskAuditPayload[\"agentTrace\"],\n opts: StepOptions,\n): Promise<StepOutput<StepGradingResult>> {\n if (planningTrace.length === 0) return EMPTY_STEP;\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 1/4: Auditing planning...\",\n );\n return await executeStepSafely(\"Planning audit\", opts.requestId, taskPayload.taskId, () =>\n runGradingStep(\n taskPayload.taskId,\n \"planning\",\n PLANNING_AUDIT_SYSTEM_PROMPT,\n buildPlanningAuditPrompt(taskPayload, planningTrace),\n GRADING_LIMITS,\n opts,\n ),\n );\n}\n\nasync function executeBuildingStep(\n taskPayload: TaskAuditPayload,\n buildingTrace: TaskAuditPayload[\"agentTrace\"],\n opts: StepOptions,\n): Promise<StepOutput<StepGradingResult>> {\n if (buildingTrace.length === 0) return EMPTY_STEP;\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 2/4: Auditing building...\",\n );\n return await executeStepSafely(\"Building audit\", opts.requestId, taskPayload.taskId, () =>\n runGradingStep(\n taskPayload.taskId,\n \"building\",\n BUILDING_AUDIT_SYSTEM_PROMPT,\n buildBuildingAuditPrompt(taskPayload, buildingTrace),\n GRADING_LIMITS,\n opts,\n ),\n );\n}\n\nasync function executeHumanStep(\n taskPayload: TaskAuditPayload,\n opts: StepOptions,\n): Promise<StepOutput<StepHumanResult>> {\n if (taskPayload.humanMessages.length === 0) return EMPTY_STEP;\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 3/4: Auditing human contributions...\",\n );\n return await executeStepSafely(\"Human audit\", opts.requestId, taskPayload.taskId, () =>\n runHumanStep(\n taskPayload.taskId,\n buildHumanAuditPrompt(taskPayload),\n { maxTurns: 6, maxBudgetUsd: 0.5 },\n opts,\n ),\n );\n}\n\nasync function executeAnalysisStep(\n taskPayload: TaskAuditPayload,\n planning: StepOutput<StepGradingResult>,\n building: StepOutput<StepGradingResult>,\n human: StepOutput<StepHumanResult>,\n projectId: string,\n suggestionIds: string[],\n opts: StepOptions,\n): Promise<StepOutput<StepAnalysisResult>> {\n reportProgress(\n opts.connection,\n opts.requestId,\n taskPayload.taskId,\n \"status\",\n \"Step 4/4: Generating analysis & suggestions...\",\n );\n return await executeStepSafely(\"Analysis\", opts.requestId, taskPayload.taskId, () =>\n runAnalysisStep(\n taskPayload,\n planning.result,\n building.result,\n human.result,\n projectId,\n suggestionIds,\n opts,\n ),\n );\n}\n\n// ── Result reporting ───────────────────────────────────────────────────\n\nasync function reportAuditResult(\n connection: ProjectConnection,\n requestId: string,\n taskPayload: TaskAuditPayload,\n steps: {\n planning: StepOutput<StepGradingResult>;\n building: StepOutput<StepGradingResult>;\n human: StepOutput<StepHumanResult>;\n analysis: StepOutput<StepAnalysisResult>;\n },\n planningTraceLength: number,\n suggestionIds: string[],\n): Promise<void> {\n let totalCostUsd: number | null = null;\n for (const step of [steps.planning, steps.building, steps.human, steps.analysis])\n totalCostUsd = addCosts(totalCostUsd, step.costUsd);\n\n const merged = mergeStepResults(\n steps.planning.result,\n steps.building.result,\n steps.human.result,\n steps.analysis.result,\n planningTraceLength,\n );\n\n await connection.call(\"reportTaskAuditResult\", {\n projectId: connection.projectId,\n requestId,\n taskId: taskPayload.taskId,\n summary: merged.summary,\n turnGrades: merged.turnGrades,\n planningAccuracy: merged.planningAccuracy,\n buildingAccuracy: merged.buildingAccuracy,\n humanAccuracy: merged.humanAccuracy,\n humanEvaluations: merged.humanEvaluations,\n ...computeGradeCounts(merged.turnGrades),\n suggestionIds,\n auditCostUsd: totalCostUsd,\n model: steps.planning.model ?? steps.building.model ?? null,\n });\n}\n\n// ── Per-task audit execution ────────────────────────────────────────────\n\nasync function auditSingleTask(\n taskPayload: TaskAuditPayload,\n request: TaskAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n model: string,\n): Promise<void> {\n const { requestId, projectId } = request;\n const suggestionIds: string[] = [];\n const opts: StepOptions = { connection, requestId, projectDir, model };\n\n const { planningTrace, buildingTrace } = sliceTrace(taskPayload.agentTrace);\n\n const planning = await executePlanningStep(taskPayload, planningTrace, opts);\n const building = await executeBuildingStep(taskPayload, buildingTrace, opts);\n\n if (\n !planning.result &&\n !building.result &&\n (planningTrace.length > 0 || buildingTrace.length > 0)\n ) {\n throw new Error(\"All grading audit steps failed\");\n }\n\n const human = await executeHumanStep(taskPayload, opts);\n const analysis = await executeAnalysisStep(\n taskPayload,\n planning,\n building,\n human,\n projectId,\n suggestionIds,\n opts,\n );\n\n await reportAuditResult(\n connection,\n requestId,\n taskPayload,\n { planning, building, human, analysis },\n planningTrace.length,\n suggestionIds,\n );\n logger.info(\"Task audit complete\", {\n requestId,\n taskId: taskPayload.taskId,\n suggestions: suggestionIds.length,\n });\n}\n\n// ── Main handler ────────────────────────────────────────────────────────\n\nexport async function handleTaskAudit(\n request: TaskAuditRunnerRequest,\n connection: ProjectConnection,\n projectDir: string,\n): Promise<void> {\n const { requestId } = request;\n\n logger.info(\"Starting task audit\", { requestId, taskCount: request.tasks.length });\n\n const model = await fetchModel(connection);\n\n for (const taskPayload of request.tasks) {\n try {\n await auditSingleTask(taskPayload, request, connection, projectDir, model);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(\"Task audit failed for task\", {\n requestId,\n taskId: taskPayload.taskId,\n error: msg,\n });\n await connection\n .call(\n \"reportTaskAuditResult\",\n buildErrorResult(connection.projectId, requestId, taskPayload.taskId, msg),\n )\n .catch(() => {});\n }\n }\n\n await connection\n .call(\"reportTaskAuditBatchComplete\", { projectId: connection.projectId, requestId })\n .catch(() => {});\n}\n","import type {\n TaskAuditTurnGrade,\n TaskAuditHumanEvaluation,\n TaskAuditPayload,\n TaskAuditPhase,\n} from \"@project/shared\";\n\n// ── Types ──────────────────────────────────────────────────────────────\n\nexport interface AuditJsonResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n planningAccuracy: number | null;\n buildingAccuracy: number | null;\n humanAccuracy: number | null;\n humanEvaluations: TaskAuditHumanEvaluation[];\n macroEvaluation?: MacroEvaluation | null;\n}\n\nexport interface MacroEvaluation {\n instructionsQuality?: string;\n modelSuitability?: string;\n contextAndPlanning?: string;\n overallResult?: string;\n}\n\n// ── Step-specific result types ────────────────────────────────────────\n\n/** Output from Steps 1 (Planning) and 2 (Building) — grading a trace slice */\nexport interface StepGradingResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n accuracy: number | null;\n}\n\n/** Output from Step 3 (Human) — evaluating human messages */\nexport interface StepHumanResult {\n humanEvaluations: TaskAuditHumanEvaluation[];\n summary: string;\n humanAccuracy: number | null;\n}\n\n/** Output from Step 4 (Analysis) — macro evaluation */\nexport interface StepAnalysisResult {\n summary: string;\n macroEvaluation: MacroEvaluation | null;\n}\n\n/** Merged result from all 4 steps, ready for reportTaskAuditResult */\nexport interface MergedAuditResult {\n turnGrades: TaskAuditTurnGrade[];\n summary: string;\n planningAccuracy: number | null;\n buildingAccuracy: number | null;\n humanAccuracy: number | null;\n humanEvaluations: TaskAuditHumanEvaluation[];\n macroEvaluation: MacroEvaluation | null;\n}\n\n// ── Formatting helpers ─────────────────────────────────────────────────\n\nfunction formatMacroEvaluation(macro: Record<string, unknown> | null | undefined): string | null {\n if (!macro) return null;\n const lines: string[] = [];\n if (macro.instructionsQuality) lines.push(`- Instructions Quality: ${macro.instructionsQuality}`);\n if (macro.modelSuitability) lines.push(`- Model Suitability: ${macro.modelSuitability}`);\n if (macro.contextAndPlanning) lines.push(`- Context & Planning: ${macro.contextAndPlanning}`);\n if (macro.overallResult) lines.push(`- Overall Result: ${macro.overallResult}`);\n return lines.length > 0 ? lines.join(\"\\n\") : null;\n}\n\nfunction formatHumanEvaluations(evals: TaskAuditHumanEvaluation[]): string | null {\n if (evals.length === 0) return null;\n const total = evals.reduce((sum, e) => sum + e.rating, 0);\n const avg = total / evals.length;\n const label = avg > 0.3 ? \"Helpful\" : avg < -0.3 ? \"Unhelpful\" : \"Neutral\";\n const lines = [\n `- Overall: ${label} (avg ${avg.toFixed(2)}, ${evals.length} message${evals.length === 1 ? \"\" : \"s\"})`,\n ];\n for (const e of evals) {\n const ratingLabel = e.rating > 0 ? \"helpful\" : e.rating < 0 ? \"unhelpful\" : \"neutral\";\n lines.push(` - Message ${e.messageIndex}: ${ratingLabel} — ${e.reasoning}`);\n }\n return lines.join(\"\\n\");\n}\n\n// ── JSON parsing ───────────────────────────────────────────────────────\n\nfunction toAuditResult(parsed: Record<string, unknown>): AuditJsonResult | null {\n if (!parsed || !Array.isArray(parsed.turnGrades)) return null;\n\n const macro = parsed.macroEvaluation as Record<string, unknown> | null | undefined;\n const rawHumanEvals = Array.isArray(parsed.humanEvaluations)\n ? (parsed.humanEvaluations as TaskAuditHumanEvaluation[])\n : [];\n const baseSummary = (parsed.summary as string) ?? \"\";\n\n const macroText = formatMacroEvaluation(macro);\n const humanEvalText = formatHumanEvaluations(rawHumanEvals);\n\n let summary = baseSummary;\n if (macroText) summary += `\\n\\n---\\n\\nMacro Evaluation:\\n${macroText}`;\n if (humanEvalText) summary += `\\n\\n---\\n\\nHuman Contributions:\\n${humanEvalText}`;\n\n return {\n turnGrades: parsed.turnGrades as TaskAuditTurnGrade[],\n summary,\n planningAccuracy: (parsed.planningAccuracy as number) ?? null,\n buildingAccuracy: (parsed.buildingAccuracy as number) ?? null,\n humanAccuracy: (parsed.humanAccuracy as number) ?? null,\n humanEvaluations: rawHumanEvals,\n macroEvaluation: macro\n ? {\n instructionsQuality: (macro.instructionsQuality as string) ?? undefined,\n modelSuitability: (macro.modelSuitability as string) ?? undefined,\n contextAndPlanning: (macro.contextAndPlanning as string) ?? undefined,\n overallResult: (macro.overallResult as string) ?? undefined,\n }\n : null,\n };\n}\n\nexport function extractJsonFromResponse(text: string): AuditJsonResult {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const result = toAuditResult(JSON.parse(jsonStr));\n if (result) return result;\n } catch {\n // Try fallback: find a JSON object in raw text\n }\n\n const objectMatch = text.match(/\\{[\\s\\S]*\"turnGrades\"[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const result = toAuditResult(JSON.parse(objectMatch[0]));\n if (result) return result;\n } catch {\n // Fall through\n }\n }\n\n throw new Error(\"Could not parse task audit grades from Claude response\");\n}\n\n// ── Grade counting ─────────────────────────────────────────────────────\n\nexport function computeGradeCounts(turnGrades: TaskAuditTurnGrade[]) {\n const counts = {\n planningCorrect: 0,\n planningNeutral: 0,\n planningBlunder: 0,\n buildingCorrect: 0,\n buildingNeutral: 0,\n buildingBlunder: 0,\n humanCorrect: 0,\n humanNeutral: 0,\n humanBlunder: 0,\n };\n\n for (const tg of turnGrades) {\n const key =\n `${tg.phase}${tg.grade.charAt(0).toUpperCase()}${tg.grade.slice(1)}` as keyof typeof counts;\n if (key in counts) {\n counts[key]++;\n }\n }\n\n return counts;\n}\n\n// ── Cost helpers ──────────────────────────────────────────────────────\n\nexport function addCosts(base: number | null, addition: number | null): number | null {\n if (base === null) return addition;\n if (addition === null) return base;\n return base + addition;\n}\n\n// ── Error result builder ──────────────────────────────────────────────\n\nexport function buildErrorResult(\n projectId: string,\n requestId: string,\n taskId: string,\n error: string,\n) {\n return {\n projectId,\n requestId,\n taskId,\n summary: \"\",\n turnGrades: [] as TaskAuditTurnGrade[],\n planningAccuracy: null,\n buildingAccuracy: null,\n humanAccuracy: null,\n planningCorrect: 0,\n planningNeutral: 0,\n planningBlunder: 0,\n buildingCorrect: 0,\n buildingNeutral: 0,\n buildingBlunder: 0,\n humanCorrect: 0,\n humanNeutral: 0,\n humanBlunder: 0,\n suggestionIds: [] as string[],\n auditCostUsd: null,\n model: null,\n error,\n };\n}\n\n// ── Step-specific JSON extraction ─────────────────────────────────────\n\nfunction extractJsonBlock(text: string): Record<string, unknown> {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;\n\n try {\n const parsed = JSON.parse(jsonStr);\n if (parsed && typeof parsed === \"object\") return parsed as Record<string, unknown>;\n } catch {\n // Fallback: find a JSON object in raw text\n }\n\n const objectMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (objectMatch) {\n try {\n const parsed = JSON.parse(objectMatch[0]);\n if (parsed && typeof parsed === \"object\") return parsed as Record<string, unknown>;\n } catch {\n // Fall through\n }\n }\n\n throw new Error(\"Could not parse JSON from Claude response\");\n}\n\n/**\n * Extract grading result from Steps 1 (Planning) or 2 (Building).\n * The phase is hardcoded by the caller, not determined by the LLM.\n */\nexport function extractGradingResult(text: string, phase: TaskAuditPhase): StepGradingResult {\n const parsed = extractJsonBlock(text);\n const turnGrades = Array.isArray(parsed.turnGrades)\n ? (parsed.turnGrades as TaskAuditTurnGrade[]).map((tg) => ({ ...tg, phase }))\n : [];\n const summary = (parsed.summary as string) ?? \"\";\n const accuracy = typeof parsed.accuracy === \"number\" ? parsed.accuracy : null;\n return { turnGrades, summary, accuracy };\n}\n\n/**\n * Extract human evaluation result from Step 3.\n */\nexport function extractHumanResult(text: string): StepHumanResult {\n const parsed = extractJsonBlock(text);\n const humanEvaluations = Array.isArray(parsed.humanEvaluations)\n ? (parsed.humanEvaluations as TaskAuditHumanEvaluation[])\n : [];\n const summary = (parsed.summary as string) ?? \"\";\n const humanAccuracy = typeof parsed.humanAccuracy === \"number\" ? parsed.humanAccuracy : null;\n return { humanEvaluations, summary, humanAccuracy };\n}\n\n/**\n * Extract analysis result from Step 4.\n */\nexport function extractAnalysisResult(text: string): StepAnalysisResult {\n const parsed = extractJsonBlock(text);\n const summary = (parsed.summary as string) ?? \"\";\n const macro = parsed.macroEvaluation as Record<string, unknown> | null | undefined;\n return {\n summary,\n macroEvaluation: macro\n ? {\n instructionsQuality: (macro.instructionsQuality as string) ?? undefined,\n modelSuitability: (macro.modelSuitability as string) ?? undefined,\n contextAndPlanning: (macro.contextAndPlanning as string) ?? undefined,\n overallResult: (macro.overallResult as string) ?? undefined,\n }\n : null,\n };\n}\n\n/** Build a combined summary from all step results with optional macro/human sections. */\nfunction buildMergedSummary(\n planningResult: StepGradingResult | null,\n buildingResult: StepGradingResult | null,\n humanResult: StepHumanResult | null,\n analysisResult: StepAnalysisResult | null,\n): string {\n const summaryParts: string[] = [];\n if (analysisResult?.summary) {\n summaryParts.push(analysisResult.summary);\n } else {\n if (planningResult?.summary) summaryParts.push(`Planning: ${planningResult.summary}`);\n if (buildingResult?.summary) summaryParts.push(`Building: ${buildingResult.summary}`);\n if (humanResult?.summary) summaryParts.push(`Human: ${humanResult.summary}`);\n }\n\n const macroText = analysisResult?.macroEvaluation\n ? formatMacroEvaluation(analysisResult.macroEvaluation as Record<string, unknown>)\n : null;\n const humanEvalText = humanResult ? formatHumanEvaluations(humanResult.humanEvaluations) : null;\n\n let summary = summaryParts.join(\"\\n\\n\");\n if (macroText) summary += `\\n\\n---\\n\\nMacro Evaluation:\\n${macroText}`;\n if (humanEvalText) summary += `\\n\\n---\\n\\nHuman Contributions:\\n${humanEvalText}`;\n return summary;\n}\n\n/**\n * Merge results from all 4 steps into a single result ready for reporting.\n * Building turn indices are offset by planningTraceLength so they reference\n * the original global trace positions.\n */\nexport function mergeStepResults(\n planningResult: StepGradingResult | null,\n buildingResult: StepGradingResult | null,\n humanResult: StepHumanResult | null,\n analysisResult: StepAnalysisResult | null,\n planningTraceLength: number,\n): MergedAuditResult {\n const planGrades = planningResult?.turnGrades ?? [];\n const buildGrades = (buildingResult?.turnGrades ?? []).map((tg) => ({\n ...tg,\n turnIndex: tg.turnIndex + planningTraceLength,\n }));\n\n return {\n turnGrades: [...planGrades, ...buildGrades],\n summary: buildMergedSummary(planningResult, buildingResult, humanResult, analysisResult),\n planningAccuracy: planningResult?.accuracy ?? null,\n buildingAccuracy: buildingResult?.accuracy ?? null,\n humanAccuracy: humanResult?.humanAccuracy ?? null,\n humanEvaluations: humanResult?.humanEvaluations ?? [],\n macroEvaluation: analysisResult?.macroEvaluation ?? null,\n };\n}\n\n// ── Suggestion prompt builder ─────────────────────────────────────────\n\nexport function buildSuggestionPrompt(parsed: AuditJsonResult, task: TaskAuditPayload): string {\n const parts: string[] = [`# Suggestion Generation for: ${task.taskTitle}\\n`];\n\n parts.push(`## Audit Summary\\n${parsed.summary}\\n`);\n\n if (parsed.macroEvaluation) {\n parts.push(\"## Macro Evaluation\");\n if (parsed.macroEvaluation.instructionsQuality)\n parts.push(`- Instructions Quality: ${parsed.macroEvaluation.instructionsQuality}`);\n if (parsed.macroEvaluation.modelSuitability)\n parts.push(`- Model Suitability: ${parsed.macroEvaluation.modelSuitability}`);\n if (parsed.macroEvaluation.contextAndPlanning)\n parts.push(`- Context & Planning: ${parsed.macroEvaluation.contextAndPlanning}`);\n if (parsed.macroEvaluation.overallResult)\n parts.push(`- Overall Result: ${parsed.macroEvaluation.overallResult}`);\n parts.push(\"\");\n }\n\n const blunders = parsed.turnGrades.filter((tg) => tg.grade === \"blunder\");\n if (blunders.length > 0) {\n parts.push(\"## Notable Blunders\");\n for (const b of blunders.slice(0, 10)) {\n parts.push(`- Turn ${b.turnIndex} (${b.phase}): ${b.reasoning}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\n \"Based on the findings above, call create_suggestion for each actionable cross-cutting improvement.\",\n );\n\n return parts.join(\"\\n\");\n}\n","import type { TaskAuditPayload } from \"@project/shared\";\n\n// ── Tool name patterns ────────────────────────────────────────────────\n// MCP tools in agent traces use the mcp__conveyor__ prefix.\n// The $ anchor prevents matching update_task_properties or force_update_task_status.\n\nexport const PLAN_UPDATE_PATTERN = /mcp__conveyor__update_task$/;\nexport const PR_CREATION_PATTERN = /mcp__conveyor__create_pull_request$/;\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface TraceBoundaries {\n /** Index of last update_task event, or -1 if none found */\n lastPlanUpdateIndex: number;\n /** Index of last create_pull_request event, or -1 if none found */\n lastPrCreationIndex: number;\n}\n\nexport interface TraceSlices {\n /** Events from start through last plan update (inclusive). Empty if no plan update found. */\n planningTrace: TaskAuditPayload[\"agentTrace\"];\n /** Events after last plan update through last PR creation (inclusive), or to end of trace. */\n buildingTrace: TaskAuditPayload[\"agentTrace\"];\n /** Boundary info for diagnostics/logging */\n boundaries: TraceBoundaries;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────\n\n/**\n * Check whether an event contains a tool call matching the given pattern.\n *\n * Handles two event shapes:\n * - `tool_use` events: check `data.tool`\n * - `turn_end` events: check each entry in `data.toolCalls[].tool`\n */\nfunction eventMatchesTool(\n event: TaskAuditPayload[\"agentTrace\"][number],\n toolPattern: RegExp,\n): boolean {\n // tool_use events store the tool name in data.tool\n if (event.type === \"tool_use\" && typeof event.data.tool === \"string\") {\n if (toolPattern.test(event.data.tool)) return true;\n }\n\n // turn_end events store an array of tool calls in data.toolCalls\n if (event.type === \"turn_end\" && Array.isArray(event.data.toolCalls)) {\n for (const tc of event.data.toolCalls as Array<{ tool?: string }>) {\n if (typeof tc.tool === \"string\" && toolPattern.test(tc.tool)) return true;\n }\n }\n\n return false;\n}\n\n// ── Public API ────────────────────────────────────────────────────────\n\n/**\n * Find the last index in agentTrace where a tool matching the given pattern was used.\n * Returns -1 if no match found.\n */\nexport function findLastToolCallIndex(\n trace: TaskAuditPayload[\"agentTrace\"],\n toolPattern: RegExp,\n): number {\n for (let i = trace.length - 1; i >= 0; i--) {\n if (eventMatchesTool(trace[i], toolPattern)) return i;\n }\n return -1;\n}\n\n/**\n * Compute stage boundaries and slice the trace into planning and building segments.\n *\n * Rules:\n * - Planning = [0, lastPlanUpdate] inclusive\n * - Building = (lastPlanUpdate, lastPrCreation] inclusive (or to end if no PR)\n * - If plan update occurs after PR creation, clamp planning end to PR index\n * - If no plan update found, planning is empty, all pre-PR events go to building\n * - If neither found, everything goes to building\n */\nexport function sliceTrace(trace: TaskAuditPayload[\"agentTrace\"]): TraceSlices {\n const lastPlanUpdateIndex = findLastToolCallIndex(trace, PLAN_UPDATE_PATTERN);\n const lastPrCreationIndex = findLastToolCallIndex(trace, PR_CREATION_PATTERN);\n\n const boundaries: TraceBoundaries = { lastPlanUpdateIndex, lastPrCreationIndex };\n\n // No boundaries at all — everything is building\n if (lastPlanUpdateIndex === -1 && lastPrCreationIndex === -1) {\n return { planningTrace: [], buildingTrace: trace, boundaries };\n }\n\n // No plan update — everything up to (and including) PR creation is building\n if (lastPlanUpdateIndex === -1) {\n return {\n planningTrace: [],\n buildingTrace: lastPrCreationIndex >= 0 ? trace.slice(0, lastPrCreationIndex + 1) : trace,\n boundaries,\n };\n }\n\n // Clamp: if plan update is after PR creation, use PR index as the planning end\n const planEnd =\n lastPrCreationIndex >= 0 && lastPlanUpdateIndex > lastPrCreationIndex\n ? lastPrCreationIndex\n : lastPlanUpdateIndex;\n\n const planningTrace = trace.slice(0, planEnd + 1);\n\n // Building starts after planning end\n const buildEnd = lastPrCreationIndex >= 0 ? lastPrCreationIndex + 1 : trace.length;\n const buildingTrace = trace.slice(planEnd + 1, buildEnd);\n\n return { planningTrace, buildingTrace, boundaries };\n}\n","import type { TaskAuditPayload } from \"@project/shared\";\nimport type { StepGradingResult, StepHumanResult } from \"./task-audit-parsing.js\";\n\n// ── System prompts (4 focused steps) ────────────────────────────────────\n\nexport const PLANNING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the PLANNING phase of an AI agent's task execution. You receive only the planning portion of the agent's trace — from the start through the last plan update. Grade each turn objectively.\n\n## Grading Scale\n\n- **Correct** (♟): Sound moves toward understanding the task — reading relevant files, analyzing requirements, logical reasoning about approach, following project patterns\n- **Neutral** (·): No significant positive or negative effect — exploratory reads, minor tangents\n- **Blunder** (??): Wasted effort — reading irrelevant files repeatedly, ignoring requirements, spending many turns without making progress toward a plan\n\n## Specific Blunder Examples\n- Reading the same file 5+ times without advancing understanding\n- Ignoring explicit task requirements or project conventions visible in the code\n- Spending many turns on tangential investigation not related to the task\n- Failing to read key files that are obvious from the task description\n\n## Specific Correct Examples\n- Reading context files before implementation\n- Analyzing requirements and dependencies systematically\n- Identifying relevant code patterns to follow\n- Building understanding incrementally\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"turnGrades\": [\n {\n \"turnIndex\": 0,\n \"grade\": \"correct\",\n \"reasoning\": \"Read relevant config files to understand project structure\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Read package.json and tsconfig.json\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of planning quality\",\n \"accuracy\": 0.85\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.\n\nIMPORTANT: Do NOT include a \"phase\" field in turnGrades — the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;\n\nexport const BUILDING_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine grading the BUILDING phase of an AI agent's task execution. You receive only the building portion of the agent's trace — from after the plan was finalized through pull request creation. Grade each turn objectively.\n\n## Grading Scale\n\n- **Correct** (♟): Sound implementation moves — proper edits, running tests, fixing errors, following plan steps, adapting to feedback\n- **Neutral** (·): No significant positive or negative effect — exploratory reads during implementation, minor tangents\n- **Blunder** (??): Wasted effort — incorrect edits immediately reverted, repeated failures without adapting, ignoring the plan, using wrong APIs despite visible patterns\n\n## Specific Blunder Examples\n- Making edits that are immediately reverted or overwritten\n- Ignoring explicit plan steps or user corrections\n- Repeated failed tool calls (isError: true) without changing approach\n- Using wrong APIs despite project patterns visible in the trace\n- Spending many turns on tangential work not in the plan\n\n## Specific Correct Examples\n- Following plan steps in logical sequence\n- Proper error handling and recovery after tool failures\n- Adapting approach based on test results or errors\n- Efficient tool usage with clear purpose\n- Running tests to verify changes\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"turnGrades\": [\n {\n \"turnIndex\": 0,\n \"grade\": \"correct\",\n \"reasoning\": \"Implemented the required changes following the plan\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Edit src/component.tsx\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of building quality\",\n \"accuracy\": 0.72\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: accuracy = correct / (correct + blunder). Neutral turns are excluded. Return null if no correct or blunder turns exist.\n\nIMPORTANT: Turn indices are 0-based relative to the trace slice provided. Do NOT include a \"phase\" field — the phase is set programmatically. Only include turnIndex, grade, reasoning, eventType, and eventSummary.`;\n\nexport const HUMAN_AUDIT_SYSTEM_PROMPT = `You are evaluating human contributions to an AI agent's task execution. For each human message, assess whether it helped, hindered, or had no effect on the agent's work.\n\n## Rating Scale\n\n- **Helpful (+1)**: Provided useful context, clear corrections, actionable feedback, or unblocked the agent\n- **Neutral (0)**: Acknowledgements, status checks, or messages with no material impact on execution\n- **Unhelpful (-1)**: Contradictory instructions, incorrect guidance, unnecessary interruptions, or vague requests that caused wasted effort\n\n## Output Format\n\nOutput a JSON block:\n\n\\`\\`\\`json\n{\n \"humanEvaluations\": [\n {\n \"messageIndex\": 0,\n \"rating\": 1,\n \"reasoning\": \"Provided clear context about the bug with reproduction steps\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of human contributions\",\n \"humanAccuracy\": 0.75\n}\n\\`\\`\\`\n\n**humanAccuracy Calculation**: humanAccuracy = helpful / (helpful + unhelpful). Neutral messages are excluded. Return null if no helpful or unhelpful messages exist.\n\nEvaluate EVERY human message — do not skip any. Each entry in humanEvaluations must have a messageIndex (0-based index into the Human Messages list), rating (+1, 0, or -1), and reasoning.`;\n\nexport const ANALYSIS_SYSTEM_PROMPT = `You are performing a macro-level analysis of an AI agent's task execution and generating improvement suggestions. You receive grading results from planning, building, and human evaluation phases.\n\n## Your Tasks\n\n1. **Write an overall summary** (2-4 sentences) that synthesizes the planning, building, and human evaluation findings into a cohesive assessment.\n\n2. **Perform a macro evaluation** addressing:\n - **Instructions Quality**: Were the agent instructions appropriate? Too vague, too prescriptive, or missing critical guidance?\n - **Model Suitability**: Was the model choice appropriate for the complexity of this task?\n - **Context & Planning**: Was the plan/context sufficient? Were there information gaps that caused wasted effort?\n - **Overall Result**: Did the final result meet requirements? Was the outcome proportional to effort?\n\n3. **Generate suggestions** using the create_suggestion tool. Focus on:\n - Recurring patterns of wasted effort that could be prevented\n - Missing documentation or context that caused confusion\n - Process improvements to prevent common blunders\n - What worked well that should be replicated\n\nYou MUST call create_suggestion at least once. If the execution was flawless, suggest what made it work well so the pattern can be replicated.\n\n## Output Format\n\nAfter calling create_suggestion, output a JSON block:\n\n\\`\\`\\`json\n{\n \"summary\": \"Overall 2-4 sentence assessment synthesizing all phases\",\n \"macroEvaluation\": {\n \"instructionsQuality\": \"Brief assessment of instruction quality\",\n \"modelSuitability\": \"Brief assessment of model choice\",\n \"contextAndPlanning\": \"Brief assessment of context and planning\",\n \"overallResult\": \"Brief assessment of the outcome\"\n }\n}\n\\`\\`\\``;\n\n// ── Prompt section builders ─────────────────────────────────────────────\n\nfunction buildSessionInfoSection(info: NonNullable<TaskAuditPayload[\"sessionInfo\"]>): string {\n const lines: string[] = [\"## Session Info\"];\n if (info.model) lines.push(`- Model: ${info.model}`);\n if (info.totalCostUsd !== null) lines.push(`- Total Cost: $${info.totalCostUsd.toFixed(4)}`);\n if (info.planningTurns !== null) lines.push(`- Planning Turns: ${info.planningTurns}`);\n if (info.buildingTurns !== null) lines.push(`- Building Turns: ${info.buildingTurns}`);\n if (info.locDiff !== null) lines.push(`- Lines Changed: ${info.locDiff}`);\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\nfunction buildTraceSection(trace: TaskAuditPayload[\"agentTrace\"]): string {\n const lines: string[] = [\"## Agent Trace\\n\"];\n if (trace.length === 0) {\n lines.push(\"No agent trace data available.\\n\");\n } else {\n for (let i = 0; i < trace.length; i++) {\n const event = trace[i];\n const dataStr = JSON.stringify(event.data);\n const truncated = dataStr.length > 2000 ? dataStr.slice(0, 2000) + \"...\" : dataStr;\n lines.push(`### Turn ${i} [${event.type}] @ ${event.timestamp}`);\n lines.push(truncated);\n lines.push(\"\");\n }\n }\n return lines.join(\"\\n\");\n}\n\nfunction buildTaskContextSection(task: TaskAuditPayload): string {\n const parts: string[] = [];\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}`);\n if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);\n parts.push(\"\");\n if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));\n if (task.agentInstructions) parts.push(`## Agent Instructions\\n${task.agentInstructions}\\n`);\n return parts.join(\"\\n\");\n}\n\n// ── Step-specific prompt builders ──────────────────────────────────────\n\nexport function buildPlanningAuditPrompt(\n task: TaskAuditPayload,\n planningTrace: TaskAuditPayload[\"agentTrace\"],\n): string {\n const parts: string[] = [`# Planning Audit: ${task.taskTitle}\\n`];\n parts.push(buildTaskContextSection(task));\n parts.push(buildTraceSection(planningTrace));\n parts.push(\"Grade each turn above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nexport function buildBuildingAuditPrompt(\n task: TaskAuditPayload,\n buildingTrace: TaskAuditPayload[\"agentTrace\"],\n): string {\n const parts: string[] = [`# Building Audit: ${task.taskTitle}\\n`];\n parts.push(buildTaskContextSection(task));\n parts.push(buildTraceSection(buildingTrace));\n parts.push(\"Grade each turn above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nexport function buildHumanAuditPrompt(task: TaskAuditPayload): string {\n const parts: string[] = [`# Human Contribution Evaluation: ${task.taskTitle}\\n`];\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}\\n`);\n\n parts.push(\"## Human Messages\\n\");\n for (let i = 0; i < task.humanMessages.length; i++) {\n const msg = task.humanMessages[i];\n parts.push(`### Message ${i} [${msg.createdAt}]`);\n parts.push(`**${msg.role}**: ${msg.content}\\n`);\n }\n\n parts.push(\"Evaluate each human message above, then output the structured JSON result.\");\n return parts.join(\"\\n\");\n}\n\nfunction buildGradingResultSection(label: string, result: StepGradingResult): string {\n const grades = result.turnGrades;\n const correct = grades.filter((g) => g.grade === \"correct\").length;\n const neutral = grades.filter((g) => g.grade === \"neutral\").length;\n const blunder = grades.filter((g) => g.grade === \"blunder\").length;\n const accuracy = result.accuracy === null ? \"N/A\" : result.accuracy.toFixed(2);\n return [\n `## ${label} Phase Results`,\n `- Summary: ${result.summary}`,\n `- Accuracy: ${accuracy}`,\n `- ${grades.length} turns: ${correct} correct, ${neutral} neutral, ${blunder} blunders`,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function buildAnalysisPrompt(\n task: TaskAuditPayload,\n planningResult: StepGradingResult | null,\n buildingResult: StepGradingResult | null,\n humanResult: StepHumanResult | null,\n): string {\n const parts: string[] = [`# Task Analysis: ${task.taskTitle}\\n`];\n\n if (task.taskDescription) parts.push(`## Description\\n${task.taskDescription}\\n`);\n if (task.taskPlan) parts.push(`## Plan\\n${task.taskPlan}\\n`);\n parts.push(`## Task Status: ${task.taskStatus}`);\n if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);\n parts.push(\"\");\n if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));\n\n if (planningResult) parts.push(buildGradingResultSection(\"Planning\", planningResult));\n if (buildingResult) parts.push(buildGradingResultSection(\"Building\", buildingResult));\n\n if (humanResult) {\n const evals = humanResult.humanEvaluations;\n const helpful = evals.filter((e) => e.rating > 0).length;\n const neutralCount = evals.filter((e) => e.rating === 0).length;\n const unhelpful = evals.filter((e) => e.rating < 0).length;\n parts.push(\"## Human Evaluation Results\");\n parts.push(`- Summary: ${humanResult.summary}`);\n parts.push(\n `- ${evals.length} messages: ${helpful} helpful, ${neutralCount} neutral, ${unhelpful} unhelpful`,\n );\n parts.push(\"\");\n }\n\n const allGrades = [...(planningResult?.turnGrades ?? []), ...(buildingResult?.turnGrades ?? [])];\n const blunders = allGrades.filter((g) => g.grade === \"blunder\");\n if (blunders.length > 0) {\n parts.push(\"## Notable Blunders\");\n for (const b of blunders.slice(0, 10)) {\n parts.push(`- Turn ${b.turnIndex} (${b.phase}): ${b.reasoning}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\n \"Based on the findings above, call create_suggestion for each actionable improvement, then output the JSON result.\",\n );\n\n return parts.join(\"\\n\");\n}\n","import type { ProjectConnection } from \"../connection/project-connection.js\";\n\n// ── Progress reporting ────────────────────────────────────────────────\n\nexport function reportProgress(\n connection: ProjectConnection,\n requestId: string,\n taskId: string,\n tool: string,\n input?: string,\n): void {\n void connection\n .call(\"reportTaskAuditProgress\", {\n projectId: connection.projectId,\n requestId,\n taskId,\n activity: { tool, input, timestamp: new Date().toISOString() },\n })\n .catch(() => {});\n}\n\n// ── Event stream collection ───────────────────────────────────────────\n\ninterface ProgressContext {\n connection: ProjectConnection;\n requestId: string;\n taskId: string;\n}\n\nfunction processAssistantBlocks(\n blocks: Array<{ type: string; text?: string; name?: string; input?: unknown }>,\n responseParts: string[],\n ctx: ProgressContext,\n reportedFirstText: { value: boolean },\n): void {\n for (const block of blocks) {\n if (block.type === \"text\" && block.text) {\n responseParts.push(block.text);\n if (reportedFirstText.value) continue;\n reportedFirstText.value = true;\n reportProgress(\n ctx.connection,\n ctx.requestId,\n ctx.taskId,\n \"thinking\",\n block.text.slice(0, 200),\n );\n } else if (block.type === \"tool_use\" && block.name) {\n const inputStr = typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n reportProgress(ctx.connection, ctx.requestId, ctx.taskId, block.name, inputStr.slice(0, 500));\n }\n }\n}\n\nexport async function collectResponseFromEvents(\n events: AsyncIterable<{ type: string }>,\n connection: ProjectConnection,\n requestId: string,\n taskId: string,\n): Promise<{ text: string; costUsd: number | null; model: string | null }> {\n const responseParts: string[] = [];\n let costUsd: number | null = null;\n let model: string | null = null;\n const reportedFirstText = { value: false };\n const ctx: ProgressContext = { connection, requestId, taskId };\n\n for await (const event of events) {\n if (event.type === \"system\") {\n const sysEvent = event as { type: string; subtype?: string; model?: string };\n if (sysEvent.subtype === \"init\" && sysEvent.model) {\n model = sysEvent.model;\n reportProgress(\n connection,\n requestId,\n taskId,\n \"system\",\n `Initialized model: ${sysEvent.model}`,\n );\n }\n }\n\n if (event.type === \"assistant\") {\n const { message } = event as {\n type: string;\n message: {\n content: Array<{ type: string; text?: string; name?: string; input?: unknown }>;\n };\n };\n processAssistantBlocks(message.content, responseParts, ctx, reportedFirstText);\n }\n\n if (event.type === \"result\") {\n const resultEvent = event as { type: string; subtype?: string; total_cost_usd?: number };\n if (resultEvent.subtype === \"success\" && resultEvent.total_cost_usd !== undefined) {\n costUsd = resultEvent.total_cost_usd;\n }\n const status =\n resultEvent.subtype === \"success\" ? \"success\" : `error: ${resultEvent.subtype}`;\n reportProgress(connection, requestId, taskId, \"complete\", status);\n break;\n }\n }\n\n return { text: responseParts.join(\"\\n\\n\").trim(), costUsd, model };\n}\n"],"mappings":"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","names":[]}