@rallycry/conveyor-agent 7.2.3 → 7.2.5
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.
- package/dist/{chunk-N66QQFXY.js → chunk-JFWVIDQ2.js} +93 -66
- package/dist/chunk-JFWVIDQ2.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{task-audit-handler-UL4HXCE4.js → task-audit-handler-7Q7EJENK.js} +297 -140
- package/dist/task-audit-handler-7Q7EJENK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-N66QQFXY.js.map +0 -1
- package/dist/task-audit-handler-UL4HXCE4.js.map +0 -1
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -9,6 +9,167 @@ import {
|
|
|
9
9
|
|
|
10
10
|
// src/runner/task-audit-handler.ts
|
|
11
11
|
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
// src/runner/task-audit-parsing.ts
|
|
14
|
+
function formatMacroEvaluation(macro) {
|
|
15
|
+
if (!macro) return null;
|
|
16
|
+
const lines = [];
|
|
17
|
+
if (macro.instructionsQuality) lines.push(`- Instructions Quality: ${macro.instructionsQuality}`);
|
|
18
|
+
if (macro.modelSuitability) lines.push(`- Model Suitability: ${macro.modelSuitability}`);
|
|
19
|
+
if (macro.contextAndPlanning) lines.push(`- Context & Planning: ${macro.contextAndPlanning}`);
|
|
20
|
+
if (macro.overallResult) lines.push(`- Overall Result: ${macro.overallResult}`);
|
|
21
|
+
return lines.length > 0 ? lines.join("\n") : null;
|
|
22
|
+
}
|
|
23
|
+
function formatHumanEvaluations(evals) {
|
|
24
|
+
if (evals.length === 0) return null;
|
|
25
|
+
const total = evals.reduce((sum, e) => sum + e.rating, 0);
|
|
26
|
+
const avg = total / evals.length;
|
|
27
|
+
const label = avg > 0.3 ? "Helpful" : avg < -0.3 ? "Unhelpful" : "Neutral";
|
|
28
|
+
const lines = [
|
|
29
|
+
`- Overall: ${label} (avg ${avg.toFixed(2)}, ${evals.length} message${evals.length === 1 ? "" : "s"})`
|
|
30
|
+
];
|
|
31
|
+
for (const e of evals) {
|
|
32
|
+
const ratingLabel = e.rating > 0 ? "helpful" : e.rating < 0 ? "unhelpful" : "neutral";
|
|
33
|
+
lines.push(` - Message ${e.messageIndex}: ${ratingLabel} \u2014 ${e.reasoning}`);
|
|
34
|
+
}
|
|
35
|
+
return lines.join("\n");
|
|
36
|
+
}
|
|
37
|
+
function toAuditResult(parsed) {
|
|
38
|
+
if (!parsed || !Array.isArray(parsed.turnGrades)) return null;
|
|
39
|
+
const macro = parsed.macroEvaluation;
|
|
40
|
+
const rawHumanEvals = Array.isArray(parsed.humanEvaluations) ? parsed.humanEvaluations : [];
|
|
41
|
+
const baseSummary = parsed.summary ?? "";
|
|
42
|
+
const macroText = formatMacroEvaluation(macro);
|
|
43
|
+
const humanEvalText = formatHumanEvaluations(rawHumanEvals);
|
|
44
|
+
let summary = baseSummary;
|
|
45
|
+
if (macroText) summary += `
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
Macro Evaluation:
|
|
50
|
+
${macroText}`;
|
|
51
|
+
if (humanEvalText) summary += `
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
Human Contributions:
|
|
56
|
+
${humanEvalText}`;
|
|
57
|
+
return {
|
|
58
|
+
turnGrades: parsed.turnGrades,
|
|
59
|
+
summary,
|
|
60
|
+
planningAccuracy: parsed.planningAccuracy ?? null,
|
|
61
|
+
buildingAccuracy: parsed.buildingAccuracy ?? null,
|
|
62
|
+
humanAccuracy: parsed.humanAccuracy ?? null,
|
|
63
|
+
humanEvaluations: rawHumanEvals,
|
|
64
|
+
macroEvaluation: macro ? {
|
|
65
|
+
instructionsQuality: macro.instructionsQuality ?? void 0,
|
|
66
|
+
modelSuitability: macro.modelSuitability ?? void 0,
|
|
67
|
+
contextAndPlanning: macro.contextAndPlanning ?? void 0,
|
|
68
|
+
overallResult: macro.overallResult ?? void 0
|
|
69
|
+
} : null
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function extractJsonFromResponse(text) {
|
|
73
|
+
const codeBlockMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
74
|
+
const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;
|
|
75
|
+
try {
|
|
76
|
+
const result = toAuditResult(JSON.parse(jsonStr));
|
|
77
|
+
if (result) return result;
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
const objectMatch = text.match(/\{[\s\S]*"turnGrades"[\s\S]*\}/);
|
|
81
|
+
if (objectMatch) {
|
|
82
|
+
try {
|
|
83
|
+
const result = toAuditResult(JSON.parse(objectMatch[0]));
|
|
84
|
+
if (result) return result;
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw new Error("Could not parse task audit grades from Claude response");
|
|
89
|
+
}
|
|
90
|
+
function computeGradeCounts(turnGrades) {
|
|
91
|
+
const counts = {
|
|
92
|
+
planningCorrect: 0,
|
|
93
|
+
planningNeutral: 0,
|
|
94
|
+
planningBlunder: 0,
|
|
95
|
+
buildingCorrect: 0,
|
|
96
|
+
buildingNeutral: 0,
|
|
97
|
+
buildingBlunder: 0,
|
|
98
|
+
humanCorrect: 0,
|
|
99
|
+
humanNeutral: 0,
|
|
100
|
+
humanBlunder: 0
|
|
101
|
+
};
|
|
102
|
+
for (const tg of turnGrades) {
|
|
103
|
+
const key = `${tg.phase}${tg.grade.charAt(0).toUpperCase()}${tg.grade.slice(1)}`;
|
|
104
|
+
if (key in counts) {
|
|
105
|
+
counts[key]++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return counts;
|
|
109
|
+
}
|
|
110
|
+
function addCosts(base, addition) {
|
|
111
|
+
if (base === null) return addition;
|
|
112
|
+
if (addition === null) return base;
|
|
113
|
+
return base + addition;
|
|
114
|
+
}
|
|
115
|
+
function buildErrorResult(projectId, requestId, taskId, error) {
|
|
116
|
+
return {
|
|
117
|
+
projectId,
|
|
118
|
+
requestId,
|
|
119
|
+
taskId,
|
|
120
|
+
summary: "",
|
|
121
|
+
turnGrades: [],
|
|
122
|
+
planningAccuracy: null,
|
|
123
|
+
buildingAccuracy: null,
|
|
124
|
+
humanAccuracy: null,
|
|
125
|
+
planningCorrect: 0,
|
|
126
|
+
planningNeutral: 0,
|
|
127
|
+
planningBlunder: 0,
|
|
128
|
+
buildingCorrect: 0,
|
|
129
|
+
buildingNeutral: 0,
|
|
130
|
+
buildingBlunder: 0,
|
|
131
|
+
humanCorrect: 0,
|
|
132
|
+
humanNeutral: 0,
|
|
133
|
+
humanBlunder: 0,
|
|
134
|
+
suggestionIds: [],
|
|
135
|
+
auditCostUsd: null,
|
|
136
|
+
model: null,
|
|
137
|
+
error
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function buildSuggestionPrompt(parsed, task) {
|
|
141
|
+
const parts = [`# Suggestion Generation for: ${task.taskTitle}
|
|
142
|
+
`];
|
|
143
|
+
parts.push(`## Audit Summary
|
|
144
|
+
${parsed.summary}
|
|
145
|
+
`);
|
|
146
|
+
if (parsed.macroEvaluation) {
|
|
147
|
+
parts.push("## Macro Evaluation");
|
|
148
|
+
if (parsed.macroEvaluation.instructionsQuality)
|
|
149
|
+
parts.push(`- Instructions Quality: ${parsed.macroEvaluation.instructionsQuality}`);
|
|
150
|
+
if (parsed.macroEvaluation.modelSuitability)
|
|
151
|
+
parts.push(`- Model Suitability: ${parsed.macroEvaluation.modelSuitability}`);
|
|
152
|
+
if (parsed.macroEvaluation.contextAndPlanning)
|
|
153
|
+
parts.push(`- Context & Planning: ${parsed.macroEvaluation.contextAndPlanning}`);
|
|
154
|
+
if (parsed.macroEvaluation.overallResult)
|
|
155
|
+
parts.push(`- Overall Result: ${parsed.macroEvaluation.overallResult}`);
|
|
156
|
+
parts.push("");
|
|
157
|
+
}
|
|
158
|
+
const blunders = parsed.turnGrades.filter((tg) => tg.grade === "blunder");
|
|
159
|
+
if (blunders.length > 0) {
|
|
160
|
+
parts.push("## Notable Blunders");
|
|
161
|
+
for (const b of blunders.slice(0, 10)) {
|
|
162
|
+
parts.push(`- Turn ${b.turnIndex} (${b.phase}): ${b.reasoning}`);
|
|
163
|
+
}
|
|
164
|
+
parts.push("");
|
|
165
|
+
}
|
|
166
|
+
parts.push(
|
|
167
|
+
"Based on the findings above, call create_suggestion for each actionable cross-cutting improvement."
|
|
168
|
+
);
|
|
169
|
+
return parts.join("\n");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/runner/task-audit-handler.ts
|
|
12
173
|
var logger = createServiceLogger("TaskAudit");
|
|
13
174
|
var FALLBACK_MODEL = "claude-sonnet-4-6";
|
|
14
175
|
var TASK_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine for AI agent task execution. You grade each turn of an agent's work trace like a chess engine grades moves: Correct, Neutral, or Blunder.
|
|
@@ -63,6 +224,13 @@ After analyzing all turns, output a JSON block:
|
|
|
63
224
|
"planningAccuracy": 0.85,
|
|
64
225
|
"buildingAccuracy": 0.72,
|
|
65
226
|
"humanAccuracy": 1.0,
|
|
227
|
+
"humanEvaluations": [
|
|
228
|
+
{
|
|
229
|
+
"messageIndex": 0,
|
|
230
|
+
"rating": 1,
|
|
231
|
+
"reasoning": "Provided clear context about the bug with reproduction steps"
|
|
232
|
+
}
|
|
233
|
+
],
|
|
66
234
|
"macroEvaluation": {
|
|
67
235
|
"instructionsQuality": "Brief assessment",
|
|
68
236
|
"modelSuitability": "Brief assessment",
|
|
@@ -74,13 +242,15 @@ After analyzing all turns, output a JSON block:
|
|
|
74
242
|
|
|
75
243
|
**Accuracy Calculation**: For each phase, accuracy = correct / (correct + blunder). Neutral turns are excluded from the ratio. Return null if a phase has no correct or blunder turns.
|
|
76
244
|
|
|
77
|
-
##
|
|
245
|
+
## Human Contribution Evaluation
|
|
78
246
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
247
|
+
For each human message in the trace, evaluate whether the human's contribution was helpful, neutral, or unhelpful to the agent's success:
|
|
248
|
+
|
|
249
|
+
- **Helpful (+1)**: Provided useful context, clear corrections, actionable feedback, or unblocked the agent
|
|
250
|
+
- **Neutral (0)**: Acknowledgements, status checks, or messages with no material impact on execution
|
|
251
|
+
- **Unhelpful (-1)**: Contradictory instructions, incorrect guidance, unnecessary interruptions, or vague requests that caused wasted effort
|
|
252
|
+
|
|
253
|
+
Include a \`humanEvaluations\` array in your JSON output. Each entry has: \`messageIndex\` (0-based index into the Human Messages list), \`rating\` (+1, 0, or -1), and \`reasoning\` (brief explanation). If there are no human messages, return an empty array.
|
|
84
254
|
|
|
85
255
|
## Macro Evaluation
|
|
86
256
|
|
|
@@ -91,7 +261,7 @@ After grading individual turns, perform a high-level assessment of the overall t
|
|
|
91
261
|
- **Context & Planning**: Was the plan/context sufficient for the agent to succeed? Were there information gaps that caused wasted effort?
|
|
92
262
|
- **Overall Result**: Did the final result meet the task requirements? Was the outcome proportional to the effort spent?
|
|
93
263
|
|
|
94
|
-
Include a "macroEvaluation" object in your JSON output
|
|
264
|
+
Include a "macroEvaluation" object in your JSON output.`;
|
|
95
265
|
function buildSessionInfoSection(info) {
|
|
96
266
|
const lines = ["## Session Info"];
|
|
97
267
|
if (info.model) lines.push(`- Model: ${info.model}`);
|
|
@@ -145,6 +315,16 @@ ${task.agentInstructions}
|
|
|
145
315
|
parts.push("Grade each turn above, then output the structured JSON result.");
|
|
146
316
|
return parts.join("\n");
|
|
147
317
|
}
|
|
318
|
+
var SUGGESTION_SYSTEM_PROMPT = `You are a suggestion generator for an AI task audit system. Based on the audit findings below, create actionable project-level suggestions using the create_suggestion tool.
|
|
319
|
+
|
|
320
|
+
Focus on:
|
|
321
|
+
- Recurring patterns of wasted effort that could be prevented
|
|
322
|
+
- Missing documentation or context that caused agent confusion
|
|
323
|
+
- Process improvements that would prevent common blunders
|
|
324
|
+
- Tool or workflow optimizations
|
|
325
|
+
- Actionable macro findings that would improve future task execution
|
|
326
|
+
|
|
327
|
+
You MUST call create_suggestion at least once. If the execution was flawless, suggest what made it work well so the pattern can be replicated.`;
|
|
148
328
|
function buildProjectSuggestionTool(connection, projectId) {
|
|
149
329
|
return defineTool(
|
|
150
330
|
"create_suggestion",
|
|
@@ -178,161 +358,82 @@ function buildProjectSuggestionTool(connection, projectId) {
|
|
|
178
358
|
}
|
|
179
359
|
async function fetchModel(connection) {
|
|
180
360
|
try {
|
|
181
|
-
const ctx = await connection.call("
|
|
182
|
-
projectId: connection.projectId
|
|
361
|
+
const ctx = await connection.call("getProjectAgentContextByRole", {
|
|
362
|
+
projectId: connection.projectId,
|
|
363
|
+
role: "reviewer"
|
|
183
364
|
});
|
|
184
365
|
return ctx.model || FALLBACK_MODEL;
|
|
185
366
|
} catch {
|
|
186
367
|
return FALLBACK_MODEL;
|
|
187
368
|
}
|
|
188
369
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
function toAuditResult(parsed) {
|
|
199
|
-
if (!parsed || !Array.isArray(parsed.turnGrades)) return null;
|
|
200
|
-
const macro = parsed.macroEvaluation;
|
|
201
|
-
const baseSummary = parsed.summary ?? "";
|
|
202
|
-
const macroText = formatMacroEvaluation(macro);
|
|
203
|
-
const summary = macroText ? `${baseSummary}
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
Macro Evaluation:
|
|
208
|
-
${macroText}` : baseSummary;
|
|
209
|
-
return {
|
|
210
|
-
turnGrades: parsed.turnGrades,
|
|
211
|
-
summary,
|
|
212
|
-
planningAccuracy: parsed.planningAccuracy ?? null,
|
|
213
|
-
buildingAccuracy: parsed.buildingAccuracy ?? null,
|
|
214
|
-
humanAccuracy: parsed.humanAccuracy ?? null,
|
|
215
|
-
macroEvaluation: macro ? {
|
|
216
|
-
instructionsQuality: macro.instructionsQuality ?? void 0,
|
|
217
|
-
modelSuitability: macro.modelSuitability ?? void 0,
|
|
218
|
-
contextAndPlanning: macro.contextAndPlanning ?? void 0,
|
|
219
|
-
overallResult: macro.overallResult ?? void 0
|
|
220
|
-
} : null
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function extractJsonFromResponse(text) {
|
|
224
|
-
const codeBlockMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
225
|
-
const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;
|
|
226
|
-
try {
|
|
227
|
-
const result = toAuditResult(JSON.parse(jsonStr));
|
|
228
|
-
if (result) return result;
|
|
229
|
-
} catch {
|
|
230
|
-
}
|
|
231
|
-
const objectMatch = text.match(/\{[\s\S]*"turnGrades"[\s\S]*\}/);
|
|
232
|
-
if (objectMatch) {
|
|
233
|
-
try {
|
|
234
|
-
const result = toAuditResult(JSON.parse(objectMatch[0]));
|
|
235
|
-
if (result) return result;
|
|
236
|
-
} catch {
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
throw new Error("Could not parse task audit grades from Claude response");
|
|
370
|
+
function reportProgress(connection, requestId, taskId, tool, input) {
|
|
371
|
+
void connection.call("reportTaskAuditProgress", {
|
|
372
|
+
projectId: connection.projectId,
|
|
373
|
+
requestId,
|
|
374
|
+
taskId,
|
|
375
|
+
activity: { tool, input, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
|
|
376
|
+
}).catch(() => {
|
|
377
|
+
});
|
|
240
378
|
}
|
|
241
|
-
function
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
379
|
+
function processAssistantBlocks(blocks, responseParts, ctx, reportedFirstText) {
|
|
380
|
+
for (const block of blocks) {
|
|
381
|
+
if (block.type === "text" && block.text) {
|
|
382
|
+
responseParts.push(block.text);
|
|
383
|
+
if (reportedFirstText.value) continue;
|
|
384
|
+
reportedFirstText.value = true;
|
|
385
|
+
reportProgress(
|
|
386
|
+
ctx.connection,
|
|
387
|
+
ctx.requestId,
|
|
388
|
+
ctx.taskId,
|
|
389
|
+
"thinking",
|
|
390
|
+
block.text.slice(0, 200)
|
|
391
|
+
);
|
|
392
|
+
} else if (block.type === "tool_use" && block.name) {
|
|
393
|
+
const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
|
|
394
|
+
reportProgress(ctx.connection, ctx.requestId, ctx.taskId, block.name, inputStr.slice(0, 500));
|
|
257
395
|
}
|
|
258
396
|
}
|
|
259
|
-
return counts;
|
|
260
397
|
}
|
|
261
398
|
async function collectResponseFromEvents(events, connection, requestId, taskId) {
|
|
262
399
|
const responseParts = [];
|
|
263
400
|
let costUsd = null;
|
|
264
401
|
let model = null;
|
|
402
|
+
const reportedFirstText = { value: false };
|
|
403
|
+
const ctx = { connection, requestId, taskId };
|
|
265
404
|
for await (const event of events) {
|
|
266
405
|
if (event.type === "system") {
|
|
267
406
|
const sysEvent = event;
|
|
268
407
|
if (sysEvent.subtype === "init" && sysEvent.model) {
|
|
269
408
|
model = sysEvent.model;
|
|
409
|
+
reportProgress(
|
|
410
|
+
connection,
|
|
411
|
+
requestId,
|
|
412
|
+
taskId,
|
|
413
|
+
"system",
|
|
414
|
+
`Initialized model: ${sysEvent.model}`
|
|
415
|
+
);
|
|
270
416
|
}
|
|
271
417
|
}
|
|
272
418
|
if (event.type === "assistant") {
|
|
273
419
|
const { message } = event;
|
|
274
|
-
|
|
275
|
-
if (block.type === "text" && block.text) {
|
|
276
|
-
responseParts.push(block.text);
|
|
277
|
-
} else if (block.type === "tool_use" && block.name) {
|
|
278
|
-
const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
|
|
279
|
-
await connection.call("reportTaskAuditProgress", {
|
|
280
|
-
projectId: connection.projectId,
|
|
281
|
-
requestId,
|
|
282
|
-
taskId,
|
|
283
|
-
activity: `${block.name}: ${inputStr.slice(0, 500)}`
|
|
284
|
-
}).catch(() => {
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
}
|
|
420
|
+
processAssistantBlocks(message.content, responseParts, ctx, reportedFirstText);
|
|
288
421
|
}
|
|
289
422
|
if (event.type === "result") {
|
|
290
423
|
const resultEvent = event;
|
|
291
424
|
if (resultEvent.subtype === "success" && resultEvent.total_cost_usd !== void 0) {
|
|
292
425
|
costUsd = resultEvent.total_cost_usd;
|
|
293
426
|
}
|
|
427
|
+
const status = resultEvent.subtype === "success" ? "success" : `error: ${resultEvent.subtype}`;
|
|
428
|
+
reportProgress(connection, requestId, taskId, "complete", status);
|
|
294
429
|
break;
|
|
295
430
|
}
|
|
296
431
|
}
|
|
297
432
|
return { text: responseParts.join("\n\n").trim(), costUsd, model };
|
|
298
433
|
}
|
|
299
|
-
function
|
|
300
|
-
return {
|
|
301
|
-
projectId,
|
|
302
|
-
requestId,
|
|
303
|
-
taskId,
|
|
304
|
-
summary: "",
|
|
305
|
-
turnGrades: [],
|
|
306
|
-
planningAccuracy: null,
|
|
307
|
-
buildingAccuracy: null,
|
|
308
|
-
humanAccuracy: null,
|
|
309
|
-
planningCorrect: 0,
|
|
310
|
-
planningNeutral: 0,
|
|
311
|
-
planningBlunder: 0,
|
|
312
|
-
buildingCorrect: 0,
|
|
313
|
-
buildingNeutral: 0,
|
|
314
|
-
buildingBlunder: 0,
|
|
315
|
-
humanCorrect: 0,
|
|
316
|
-
humanNeutral: 0,
|
|
317
|
-
humanBlunder: 0,
|
|
318
|
-
suggestionIds: [],
|
|
319
|
-
auditCostUsd: null,
|
|
320
|
-
model: null,
|
|
321
|
-
error
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
async function auditSingleTask(taskPayload, request, connection, projectDir, model) {
|
|
325
|
-
const { requestId, projectId } = request;
|
|
326
|
-
await connection.call("reportTaskAuditProgress", {
|
|
327
|
-
projectId: connection.projectId,
|
|
328
|
-
requestId,
|
|
329
|
-
taskId: taskPayload.taskId,
|
|
330
|
-
activity: "Starting task audit..."
|
|
331
|
-
}).catch(() => {
|
|
332
|
-
});
|
|
333
|
-
const suggestionIds = [];
|
|
434
|
+
function buildTrackedSuggestionTool(connection, projectId, suggestionIds) {
|
|
334
435
|
const suggestionTool = buildProjectSuggestionTool(connection, projectId);
|
|
335
|
-
|
|
436
|
+
return defineTool(
|
|
336
437
|
suggestionTool.name,
|
|
337
438
|
suggestionTool.description,
|
|
338
439
|
suggestionTool.schema,
|
|
@@ -344,12 +445,47 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
|
|
|
344
445
|
return result;
|
|
345
446
|
}
|
|
346
447
|
);
|
|
448
|
+
}
|
|
449
|
+
async function runSuggestionPhase(parsed, taskPayload, connection, requestId, projectId, projectDir, model, suggestionIds) {
|
|
450
|
+
reportProgress(
|
|
451
|
+
connection,
|
|
452
|
+
requestId,
|
|
453
|
+
taskPayload.taskId,
|
|
454
|
+
"status",
|
|
455
|
+
"Creating suggestions from findings..."
|
|
456
|
+
);
|
|
457
|
+
const wrappedSuggestionTool = buildTrackedSuggestionTool(connection, projectId, suggestionIds);
|
|
347
458
|
const harness = createHarness();
|
|
348
|
-
const mcpServer = harness.createMcpServer({
|
|
349
|
-
name: "task-audit",
|
|
350
|
-
tools: [wrappedSuggestionTool]
|
|
351
|
-
});
|
|
459
|
+
const mcpServer = harness.createMcpServer({ name: "conveyor", tools: [wrappedSuggestionTool] });
|
|
352
460
|
const events = harness.executeQuery({
|
|
461
|
+
prompt: buildSuggestionPrompt(parsed, taskPayload),
|
|
462
|
+
options: {
|
|
463
|
+
model,
|
|
464
|
+
systemPrompt: SUGGESTION_SYSTEM_PROMPT,
|
|
465
|
+
cwd: projectDir,
|
|
466
|
+
permissionMode: "bypassPermissions",
|
|
467
|
+
allowDangerouslySkipPermissions: true,
|
|
468
|
+
tools: { type: "preset", preset: "claude_code" },
|
|
469
|
+
mcpServers: { conveyor: mcpServer },
|
|
470
|
+
maxTurns: 4,
|
|
471
|
+
maxBudgetUsd: 0.5,
|
|
472
|
+
disallowedTools: ["Edit", "Write", "Bash", "NotebookEdit", "MultiEdit"]
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
const response = await collectResponseFromEvents(
|
|
476
|
+
events,
|
|
477
|
+
connection,
|
|
478
|
+
requestId,
|
|
479
|
+
taskPayload.taskId
|
|
480
|
+
);
|
|
481
|
+
return response.costUsd;
|
|
482
|
+
}
|
|
483
|
+
async function auditSingleTask(taskPayload, request, connection, projectDir, model) {
|
|
484
|
+
const { requestId, projectId } = request;
|
|
485
|
+
const suggestionIds = [];
|
|
486
|
+
reportProgress(connection, requestId, taskPayload.taskId, "status", "Generating audit grades...");
|
|
487
|
+
const analysisHarness = createHarness();
|
|
488
|
+
const analysisEvents = analysisHarness.executeQuery({
|
|
353
489
|
prompt: buildTaskAuditPrompt(taskPayload),
|
|
354
490
|
options: {
|
|
355
491
|
model,
|
|
@@ -358,21 +494,41 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
|
|
|
358
494
|
permissionMode: "bypassPermissions",
|
|
359
495
|
allowDangerouslySkipPermissions: true,
|
|
360
496
|
tools: { type: "preset", preset: "claude_code" },
|
|
361
|
-
mcpServers: {
|
|
362
|
-
maxTurns:
|
|
497
|
+
mcpServers: {},
|
|
498
|
+
maxTurns: 16,
|
|
363
499
|
maxBudgetUsd: 3,
|
|
364
500
|
disallowedTools: ["Edit", "Write", "Bash", "NotebookEdit", "MultiEdit"]
|
|
365
501
|
}
|
|
366
502
|
});
|
|
367
|
-
const
|
|
368
|
-
|
|
503
|
+
const analysisResponse = await collectResponseFromEvents(
|
|
504
|
+
analysisEvents,
|
|
369
505
|
connection,
|
|
370
506
|
requestId,
|
|
371
507
|
taskPayload.taskId
|
|
372
508
|
);
|
|
373
|
-
if (!
|
|
374
|
-
const parsed = extractJsonFromResponse(
|
|
509
|
+
if (!analysisResponse.text) throw new Error("No response from Claude");
|
|
510
|
+
const parsed = extractJsonFromResponse(analysisResponse.text);
|
|
375
511
|
const counts = computeGradeCounts(parsed.turnGrades);
|
|
512
|
+
let totalCostUsd = analysisResponse.costUsd;
|
|
513
|
+
try {
|
|
514
|
+
const suggestionCost = await runSuggestionPhase(
|
|
515
|
+
parsed,
|
|
516
|
+
taskPayload,
|
|
517
|
+
connection,
|
|
518
|
+
requestId,
|
|
519
|
+
projectId,
|
|
520
|
+
projectDir,
|
|
521
|
+
model,
|
|
522
|
+
suggestionIds
|
|
523
|
+
);
|
|
524
|
+
totalCostUsd = addCosts(totalCostUsd, suggestionCost);
|
|
525
|
+
} catch (err) {
|
|
526
|
+
logger.warn("Suggestion phase failed, proceeding without suggestions", {
|
|
527
|
+
requestId,
|
|
528
|
+
taskId: taskPayload.taskId,
|
|
529
|
+
error: err instanceof Error ? err.message : String(err)
|
|
530
|
+
});
|
|
531
|
+
}
|
|
376
532
|
logger.info("Task audit complete", {
|
|
377
533
|
requestId,
|
|
378
534
|
taskId: taskPayload.taskId,
|
|
@@ -388,10 +544,11 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
|
|
|
388
544
|
planningAccuracy: parsed.planningAccuracy,
|
|
389
545
|
buildingAccuracy: parsed.buildingAccuracy,
|
|
390
546
|
humanAccuracy: parsed.humanAccuracy,
|
|
547
|
+
humanEvaluations: parsed.humanEvaluations,
|
|
391
548
|
...counts,
|
|
392
549
|
suggestionIds,
|
|
393
|
-
auditCostUsd:
|
|
394
|
-
model:
|
|
550
|
+
auditCostUsd: totalCostUsd,
|
|
551
|
+
model: analysisResponse.model
|
|
395
552
|
});
|
|
396
553
|
}
|
|
397
554
|
async function handleTaskAudit(request, connection, projectDir) {
|
|
@@ -424,4 +581,4 @@ async function handleTaskAudit(request, connection, projectDir) {
|
|
|
424
581
|
export {
|
|
425
582
|
handleTaskAudit
|
|
426
583
|
};
|
|
427
|
-
//# sourceMappingURL=task-audit-handler-
|
|
584
|
+
//# sourceMappingURL=task-audit-handler-7Q7EJENK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runner/task-audit-handler.ts","../src/runner/task-audit-parsing.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 AuditJsonResult,\n extractJsonFromResponse,\n computeGradeCounts,\n addCosts,\n buildErrorResult,\n buildSuggestionPrompt,\n} from \"./task-audit-parsing.js\";\n\nconst logger = createServiceLogger(\"TaskAudit\");\n\nconst FALLBACK_MODEL = \"claude-sonnet-4-6\";\n\n// ── System prompt ────────────────────────────────────────────────────────\n\nconst TASK_AUDIT_SYSTEM_PROMPT = `You are a chess-style analysis engine for AI agent task execution. You grade each turn of an agent's work trace like a chess engine grades moves: Correct, Neutral, or Blunder.\n\nYou receive the agent's full execution trace (tool calls, reasoning, errors) along with the task plan, description, and human messages. Your job is to objectively assess the quality of the agent's work.\n\n## Grading Scale\n\n- **Correct** (♟): Sound moves toward completion — necessary file reads, proper tool use, following plan steps, logical reasoning, adapting to feedback\n- **Neutral** (·): No significant positive or negative effect — exploratory reads, clarifying questions, minor tangents that don't waste resources\n- **Blunder** (??): Wasted effort or wrong direction — incorrect edits, reading irrelevant files repeatedly, ignoring the plan, repeated failures without adapting\n\n## Phase Identification\n\nClassify each turn into a phase based on the trace context:\n- **planning**: Events before the first file modification (Edit/Write tool use) — reading files, analyzing requirements, reasoning about approach\n- **building**: File modification events and related reasoning — writing code, running tests, fixing errors\n- **human**: Turns that are direct responses to user/human chat messages\n\n## Specific Blunder Examples\n- Reading the same file 5+ times without making meaningful changes\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- Reading context files before implementation\n- Following plan steps in logical sequence\n- Proper error handling and recovery after tool failures\n- Adapting approach based on user feedback\n- Efficient tool usage with clear purpose\n\n## Output Format\n\nAfter analyzing all turns, output 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 before making changes\",\n \"eventType\": \"tool_use\",\n \"eventSummary\": \"Read package.json and tsconfig.json\"\n }\n ],\n \"summary\": \"Brief 2-3 sentence assessment of overall execution quality\",\n \"planningAccuracy\": 0.85,\n \"buildingAccuracy\": 0.72,\n \"humanAccuracy\": 1.0,\n \"humanEvaluations\": [\n {\n \"messageIndex\": 0,\n \"rating\": 1,\n \"reasoning\": \"Provided clear context about the bug with reproduction steps\"\n }\n ],\n \"macroEvaluation\": {\n \"instructionsQuality\": \"Brief assessment\",\n \"modelSuitability\": \"Brief assessment\",\n \"contextAndPlanning\": \"Brief assessment\",\n \"overallResult\": \"Brief assessment\"\n }\n}\n\\`\\`\\`\n\n**Accuracy Calculation**: For each phase, accuracy = correct / (correct + blunder). Neutral turns are excluded from the ratio. Return null if a phase has no correct or blunder turns.\n\n## Human Contribution Evaluation\n\nFor each human message in the trace, evaluate whether the human's contribution was helpful, neutral, or unhelpful to the agent's success:\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\nInclude a \\`humanEvaluations\\` array in your JSON output. Each entry has: \\`messageIndex\\` (0-based index into the Human Messages list), \\`rating\\` (+1, 0, or -1), and \\`reasoning\\` (brief explanation). If there are no human messages, return an empty array.\n\n## Macro Evaluation\n\nAfter grading individual turns, perform a high-level assessment of the overall task execution:\n\n- **Instructions Quality**: Were the agent instructions appropriate for this task type? 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 for the agent to succeed? Were there information gaps that caused wasted effort?\n- **Overall Result**: Did the final result meet the task requirements? Was the outcome proportional to the effort spent?\n\nInclude a \"macroEvaluation\" object in your JSON output.`;\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\n// ── Prompt builder ──────────────────────────────────────────────────────\n\nfunction buildTaskAuditPrompt(task: TaskAuditPayload): string {\n const parts: string[] = [`# Task Audit: ${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\n parts.push(`## Task Status: ${task.taskStatus}`);\n if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);\n parts.push(\"\");\n\n if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));\n if (task.agentInstructions) parts.push(`## Agent Instructions\\n${task.agentInstructions}\\n`);\n\n if (task.humanMessages.length > 0) {\n parts.push(\"## Human Messages\\n\");\n for (const msg of task.humanMessages) {\n parts.push(`[${msg.createdAt}] **${msg.role}**: ${msg.content}`);\n }\n parts.push(\"\");\n }\n\n parts.push(buildTraceSection(task.agentTrace));\n parts.push(\"Grade each turn above, then output the structured JSON result.\");\n\n return parts.join(\"\\n\");\n}\n\n// ── Suggestion phase prompt ──────────────────────────────────────────────\n\nconst SUGGESTION_SYSTEM_PROMPT = `You are a suggestion generator for an AI task audit system. Based on the audit findings below, create actionable project-level suggestions using the create_suggestion tool.\n\nFocus on:\n- Recurring patterns of wasted effort that could be prevented\n- Missing documentation or context that caused agent confusion\n- Process improvements that would prevent common blunders\n- Tool or workflow optimizations\n- Actionable macro findings that would improve future task execution\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// ── Suggestion MCP tool ─────────────────────────────────────────────────\n\nfunction buildProjectSuggestionTool(connection: ProjectConnection, projectId: string) {\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 tag_names: z.array(z.string()).optional().describe(\"Tag names to categorize the suggestion\"),\n },\n async ({ title, description, tag_names }) => {\n try {\n const result = await connection.call(\"createProjectSuggestion\", {\n projectId,\n title,\n description,\n tagNames: tag_names,\n });\n if (result.merged) {\n return textResult(\n `Merged into existing suggestion (ID: ${result.mergedIntoId ?? result.id}).`,\n );\n }\n return textResult(`Suggestion created (ID: ${result.id}).`);\n } catch (error) {\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// ── Event stream processing ─────────────────────────────────────────────\n\nfunction 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\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\nasync 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\n// ── Suggestion tool with ID capture ───────────────────────────────────\n\nfunction buildTrackedSuggestionTool(\n connection: ProjectConnection,\n projectId: string,\n suggestionIds: string[],\n) {\n const suggestionTool = buildProjectSuggestionTool(connection, projectId);\n return defineTool(\n suggestionTool.name,\n suggestionTool.description,\n suggestionTool.schema as z.ZodRawShape,\n async (input: Record<string, unknown>) => {\n const result = await suggestionTool.handler(input);\n const text = result.content?.[0]?.text ?? \"\";\n const idMatch = text.match(/ID: ([a-z0-9]+)/i);\n if (idMatch) suggestionIds.push(idMatch[1]);\n return result;\n },\n );\n}\n\n// ── Suggestion phase ───────────────────────────────────────────────────\n\nasync function runSuggestionPhase(\n parsed: AuditJsonResult,\n taskPayload: TaskAuditPayload,\n connection: ProjectConnection,\n requestId: string,\n projectId: string,\n projectDir: string,\n model: string,\n suggestionIds: string[],\n): Promise<number | null> {\n reportProgress(\n connection,\n requestId,\n taskPayload.taskId,\n \"status\",\n \"Creating suggestions from findings...\",\n );\n\n const wrappedSuggestionTool = buildTrackedSuggestionTool(connection, projectId, suggestionIds);\n const harness = createHarness();\n const mcpServer = harness.createMcpServer({ name: \"conveyor\", tools: [wrappedSuggestionTool] });\n\n const events = harness.executeQuery({\n prompt: buildSuggestionPrompt(parsed, taskPayload),\n options: {\n model,\n systemPrompt: SUGGESTION_SYSTEM_PROMPT,\n cwd: projectDir,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: { conveyor: mcpServer },\n maxTurns: 4,\n maxBudgetUsd: 0.5,\n disallowedTools: [\"Edit\", \"Write\", \"Bash\", \"NotebookEdit\", \"MultiEdit\"],\n },\n });\n\n const response = await collectResponseFromEvents(\n events,\n connection,\n requestId,\n taskPayload.taskId,\n );\n return response.costUsd;\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\n // Phase 1: Analysis (no MCP tools — pure grading)\n reportProgress(connection, requestId, taskPayload.taskId, \"status\", \"Generating audit grades...\");\n\n const analysisHarness = createHarness();\n const analysisEvents = analysisHarness.executeQuery({\n prompt: buildTaskAuditPrompt(taskPayload),\n options: {\n model,\n systemPrompt: TASK_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: 16,\n maxBudgetUsd: 3,\n disallowedTools: [\"Edit\", \"Write\", \"Bash\", \"NotebookEdit\", \"MultiEdit\"],\n },\n });\n\n const analysisResponse = await collectResponseFromEvents(\n analysisEvents,\n connection,\n requestId,\n taskPayload.taskId,\n );\n if (!analysisResponse.text) throw new Error(\"No response from Claude\");\n\n const parsed = extractJsonFromResponse(analysisResponse.text);\n const counts = computeGradeCounts(parsed.turnGrades);\n\n // Phase 2: Suggestions (dedicated MCP query)\n let totalCostUsd = analysisResponse.costUsd;\n try {\n const suggestionCost = await runSuggestionPhase(\n parsed,\n taskPayload,\n connection,\n requestId,\n projectId,\n projectDir,\n model,\n suggestionIds,\n );\n totalCostUsd = addCosts(totalCostUsd, suggestionCost);\n } catch (err) {\n logger.warn(\"Suggestion phase failed, proceeding without suggestions\", {\n requestId,\n taskId: taskPayload.taskId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n logger.info(\"Task audit complete\", {\n requestId,\n taskId: taskPayload.taskId,\n grades: parsed.turnGrades.length,\n suggestions: suggestionIds.length,\n });\n\n await connection.call(\"reportTaskAuditResult\", {\n projectId: connection.projectId,\n requestId,\n taskId: taskPayload.taskId,\n summary: parsed.summary,\n turnGrades: parsed.turnGrades,\n planningAccuracy: parsed.planningAccuracy,\n buildingAccuracy: parsed.buildingAccuracy,\n humanAccuracy: parsed.humanAccuracy,\n humanEvaluations: parsed.humanEvaluations,\n ...counts,\n suggestionIds,\n auditCostUsd: totalCostUsd,\n model: analysisResponse.model,\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 // Signal batch completion to API/UI\n await connection\n .call(\"reportTaskAuditBatchComplete\", {\n projectId: connection.projectId,\n requestId,\n })\n .catch(() => {});\n}\n","import type {\n TaskAuditTurnGrade,\n TaskAuditHumanEvaluation,\n TaskAuditPayload,\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?: {\n instructionsQuality?: string;\n modelSuitability?: string;\n contextAndPlanning?: string;\n overallResult?: string;\n } | 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// ── 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"],"mappings":"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","names":[]}
|