@rallycry/conveyor-agent 7.2.5 → 7.2.6
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-JFWVIDQ2.js → chunk-MFHMYUND.js} +31 -24
- package/dist/chunk-MFHMYUND.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/task-audit-handler-6TZRN3YB.js +885 -0
- package/dist/task-audit-handler-6TZRN3YB.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-JFWVIDQ2.js.map +0 -1
- package/dist/task-audit-handler-7Q7EJENK.js +0 -584
- package/dist/task-audit-handler-7Q7EJENK.js.map +0 -1
|
@@ -1,584 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
textResult
|
|
3
|
-
} from "./chunk-C5YAMQJ2.js";
|
|
4
|
-
import {
|
|
5
|
-
createHarness,
|
|
6
|
-
createServiceLogger,
|
|
7
|
-
defineTool
|
|
8
|
-
} from "./chunk-RRXX6DTB.js";
|
|
9
|
-
|
|
10
|
-
// src/runner/task-audit-handler.ts
|
|
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
|
|
173
|
-
var logger = createServiceLogger("TaskAudit");
|
|
174
|
-
var FALLBACK_MODEL = "claude-sonnet-4-6";
|
|
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.
|
|
176
|
-
|
|
177
|
-
You 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.
|
|
178
|
-
|
|
179
|
-
## Grading Scale
|
|
180
|
-
|
|
181
|
-
- **Correct** (\u265F): Sound moves toward completion \u2014 necessary file reads, proper tool use, following plan steps, logical reasoning, adapting to feedback
|
|
182
|
-
- **Neutral** (\xB7): No significant positive or negative effect \u2014 exploratory reads, clarifying questions, minor tangents that don't waste resources
|
|
183
|
-
- **Blunder** (??): Wasted effort or wrong direction \u2014 incorrect edits, reading irrelevant files repeatedly, ignoring the plan, repeated failures without adapting
|
|
184
|
-
|
|
185
|
-
## Phase Identification
|
|
186
|
-
|
|
187
|
-
Classify each turn into a phase based on the trace context:
|
|
188
|
-
- **planning**: Events before the first file modification (Edit/Write tool use) \u2014 reading files, analyzing requirements, reasoning about approach
|
|
189
|
-
- **building**: File modification events and related reasoning \u2014 writing code, running tests, fixing errors
|
|
190
|
-
- **human**: Turns that are direct responses to user/human chat messages
|
|
191
|
-
|
|
192
|
-
## Specific Blunder Examples
|
|
193
|
-
- Reading the same file 5+ times without making meaningful changes
|
|
194
|
-
- Making edits that are immediately reverted or overwritten
|
|
195
|
-
- Ignoring explicit plan steps or user corrections
|
|
196
|
-
- Repeated failed tool calls (isError: true) without changing approach
|
|
197
|
-
- Using wrong APIs despite project patterns visible in the trace
|
|
198
|
-
- Spending many turns on tangential work not in the plan
|
|
199
|
-
|
|
200
|
-
## Specific Correct Examples
|
|
201
|
-
- Reading context files before implementation
|
|
202
|
-
- Following plan steps in logical sequence
|
|
203
|
-
- Proper error handling and recovery after tool failures
|
|
204
|
-
- Adapting approach based on user feedback
|
|
205
|
-
- Efficient tool usage with clear purpose
|
|
206
|
-
|
|
207
|
-
## Output Format
|
|
208
|
-
|
|
209
|
-
After analyzing all turns, output a JSON block:
|
|
210
|
-
|
|
211
|
-
\`\`\`json
|
|
212
|
-
{
|
|
213
|
-
"turnGrades": [
|
|
214
|
-
{
|
|
215
|
-
"turnIndex": 0,
|
|
216
|
-
"phase": "planning",
|
|
217
|
-
"grade": "correct",
|
|
218
|
-
"reasoning": "Read relevant config files to understand project structure before making changes",
|
|
219
|
-
"eventType": "tool_use",
|
|
220
|
-
"eventSummary": "Read package.json and tsconfig.json"
|
|
221
|
-
}
|
|
222
|
-
],
|
|
223
|
-
"summary": "Brief 2-3 sentence assessment of overall execution quality",
|
|
224
|
-
"planningAccuracy": 0.85,
|
|
225
|
-
"buildingAccuracy": 0.72,
|
|
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
|
-
],
|
|
234
|
-
"macroEvaluation": {
|
|
235
|
-
"instructionsQuality": "Brief assessment",
|
|
236
|
-
"modelSuitability": "Brief assessment",
|
|
237
|
-
"contextAndPlanning": "Brief assessment",
|
|
238
|
-
"overallResult": "Brief assessment"
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
\`\`\`
|
|
242
|
-
|
|
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.
|
|
244
|
-
|
|
245
|
-
## Human Contribution Evaluation
|
|
246
|
-
|
|
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.
|
|
254
|
-
|
|
255
|
-
## Macro Evaluation
|
|
256
|
-
|
|
257
|
-
After grading individual turns, perform a high-level assessment of the overall task execution:
|
|
258
|
-
|
|
259
|
-
- **Instructions Quality**: Were the agent instructions appropriate for this task type? Too vague, too prescriptive, or missing critical guidance?
|
|
260
|
-
- **Model Suitability**: Was the model choice appropriate for the complexity of this task?
|
|
261
|
-
- **Context & Planning**: Was the plan/context sufficient for the agent to succeed? Were there information gaps that caused wasted effort?
|
|
262
|
-
- **Overall Result**: Did the final result meet the task requirements? Was the outcome proportional to the effort spent?
|
|
263
|
-
|
|
264
|
-
Include a "macroEvaluation" object in your JSON output.`;
|
|
265
|
-
function buildSessionInfoSection(info) {
|
|
266
|
-
const lines = ["## Session Info"];
|
|
267
|
-
if (info.model) lines.push(`- Model: ${info.model}`);
|
|
268
|
-
if (info.totalCostUsd !== null) lines.push(`- Total Cost: $${info.totalCostUsd.toFixed(4)}`);
|
|
269
|
-
if (info.planningTurns !== null) lines.push(`- Planning Turns: ${info.planningTurns}`);
|
|
270
|
-
if (info.buildingTurns !== null) lines.push(`- Building Turns: ${info.buildingTurns}`);
|
|
271
|
-
if (info.locDiff !== null) lines.push(`- Lines Changed: ${info.locDiff}`);
|
|
272
|
-
lines.push("");
|
|
273
|
-
return lines.join("\n");
|
|
274
|
-
}
|
|
275
|
-
function buildTraceSection(trace) {
|
|
276
|
-
const lines = ["## Agent Trace\n"];
|
|
277
|
-
if (trace.length === 0) {
|
|
278
|
-
lines.push("No agent trace data available.\n");
|
|
279
|
-
} else {
|
|
280
|
-
for (let i = 0; i < trace.length; i++) {
|
|
281
|
-
const event = trace[i];
|
|
282
|
-
const dataStr = JSON.stringify(event.data);
|
|
283
|
-
const truncated = dataStr.length > 2e3 ? dataStr.slice(0, 2e3) + "..." : dataStr;
|
|
284
|
-
lines.push(`### Turn ${i} [${event.type}] @ ${event.timestamp}`);
|
|
285
|
-
lines.push(truncated);
|
|
286
|
-
lines.push("");
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return lines.join("\n");
|
|
290
|
-
}
|
|
291
|
-
function buildTaskAuditPrompt(task) {
|
|
292
|
-
const parts = [`# Task Audit: ${task.taskTitle}
|
|
293
|
-
`];
|
|
294
|
-
if (task.taskDescription) parts.push(`## Description
|
|
295
|
-
${task.taskDescription}
|
|
296
|
-
`);
|
|
297
|
-
if (task.taskPlan) parts.push(`## Plan
|
|
298
|
-
${task.taskPlan}
|
|
299
|
-
`);
|
|
300
|
-
parts.push(`## Task Status: ${task.taskStatus}`);
|
|
301
|
-
if (task.storyPointValue !== null) parts.push(`## Story Points: ${task.storyPointValue}`);
|
|
302
|
-
parts.push("");
|
|
303
|
-
if (task.sessionInfo) parts.push(buildSessionInfoSection(task.sessionInfo));
|
|
304
|
-
if (task.agentInstructions) parts.push(`## Agent Instructions
|
|
305
|
-
${task.agentInstructions}
|
|
306
|
-
`);
|
|
307
|
-
if (task.humanMessages.length > 0) {
|
|
308
|
-
parts.push("## Human Messages\n");
|
|
309
|
-
for (const msg of task.humanMessages) {
|
|
310
|
-
parts.push(`[${msg.createdAt}] **${msg.role}**: ${msg.content}`);
|
|
311
|
-
}
|
|
312
|
-
parts.push("");
|
|
313
|
-
}
|
|
314
|
-
parts.push(buildTraceSection(task.agentTrace));
|
|
315
|
-
parts.push("Grade each turn above, then output the structured JSON result.");
|
|
316
|
-
return parts.join("\n");
|
|
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.`;
|
|
328
|
-
function buildProjectSuggestionTool(connection, projectId) {
|
|
329
|
-
return defineTool(
|
|
330
|
-
"create_suggestion",
|
|
331
|
-
"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.",
|
|
332
|
-
{
|
|
333
|
-
title: z.string().describe("Short title for the suggestion"),
|
|
334
|
-
description: z.string().optional().describe("Details about the suggestion"),
|
|
335
|
-
tag_names: z.array(z.string()).optional().describe("Tag names to categorize the suggestion")
|
|
336
|
-
},
|
|
337
|
-
async ({ title, description, tag_names }) => {
|
|
338
|
-
try {
|
|
339
|
-
const result = await connection.call("createProjectSuggestion", {
|
|
340
|
-
projectId,
|
|
341
|
-
title,
|
|
342
|
-
description,
|
|
343
|
-
tagNames: tag_names
|
|
344
|
-
});
|
|
345
|
-
if (result.merged) {
|
|
346
|
-
return textResult(
|
|
347
|
-
`Merged into existing suggestion (ID: ${result.mergedIntoId ?? result.id}).`
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
return textResult(`Suggestion created (ID: ${result.id}).`);
|
|
351
|
-
} catch (error) {
|
|
352
|
-
return textResult(
|
|
353
|
-
`Failed to create suggestion: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
async function fetchModel(connection) {
|
|
360
|
-
try {
|
|
361
|
-
const ctx = await connection.call("getProjectAgentContextByRole", {
|
|
362
|
-
projectId: connection.projectId,
|
|
363
|
-
role: "reviewer"
|
|
364
|
-
});
|
|
365
|
-
return ctx.model || FALLBACK_MODEL;
|
|
366
|
-
} catch {
|
|
367
|
-
return FALLBACK_MODEL;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
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
|
-
});
|
|
378
|
-
}
|
|
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));
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
async function collectResponseFromEvents(events, connection, requestId, taskId) {
|
|
399
|
-
const responseParts = [];
|
|
400
|
-
let costUsd = null;
|
|
401
|
-
let model = null;
|
|
402
|
-
const reportedFirstText = { value: false };
|
|
403
|
-
const ctx = { connection, requestId, taskId };
|
|
404
|
-
for await (const event of events) {
|
|
405
|
-
if (event.type === "system") {
|
|
406
|
-
const sysEvent = event;
|
|
407
|
-
if (sysEvent.subtype === "init" && sysEvent.model) {
|
|
408
|
-
model = sysEvent.model;
|
|
409
|
-
reportProgress(
|
|
410
|
-
connection,
|
|
411
|
-
requestId,
|
|
412
|
-
taskId,
|
|
413
|
-
"system",
|
|
414
|
-
`Initialized model: ${sysEvent.model}`
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
if (event.type === "assistant") {
|
|
419
|
-
const { message } = event;
|
|
420
|
-
processAssistantBlocks(message.content, responseParts, ctx, reportedFirstText);
|
|
421
|
-
}
|
|
422
|
-
if (event.type === "result") {
|
|
423
|
-
const resultEvent = event;
|
|
424
|
-
if (resultEvent.subtype === "success" && resultEvent.total_cost_usd !== void 0) {
|
|
425
|
-
costUsd = resultEvent.total_cost_usd;
|
|
426
|
-
}
|
|
427
|
-
const status = resultEvent.subtype === "success" ? "success" : `error: ${resultEvent.subtype}`;
|
|
428
|
-
reportProgress(connection, requestId, taskId, "complete", status);
|
|
429
|
-
break;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
return { text: responseParts.join("\n\n").trim(), costUsd, model };
|
|
433
|
-
}
|
|
434
|
-
function buildTrackedSuggestionTool(connection, projectId, suggestionIds) {
|
|
435
|
-
const suggestionTool = buildProjectSuggestionTool(connection, projectId);
|
|
436
|
-
return defineTool(
|
|
437
|
-
suggestionTool.name,
|
|
438
|
-
suggestionTool.description,
|
|
439
|
-
suggestionTool.schema,
|
|
440
|
-
async (input) => {
|
|
441
|
-
const result = await suggestionTool.handler(input);
|
|
442
|
-
const text = result.content?.[0]?.text ?? "";
|
|
443
|
-
const idMatch = text.match(/ID: ([a-z0-9]+)/i);
|
|
444
|
-
if (idMatch) suggestionIds.push(idMatch[1]);
|
|
445
|
-
return result;
|
|
446
|
-
}
|
|
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);
|
|
458
|
-
const harness = createHarness();
|
|
459
|
-
const mcpServer = harness.createMcpServer({ name: "conveyor", tools: [wrappedSuggestionTool] });
|
|
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({
|
|
489
|
-
prompt: buildTaskAuditPrompt(taskPayload),
|
|
490
|
-
options: {
|
|
491
|
-
model,
|
|
492
|
-
systemPrompt: TASK_AUDIT_SYSTEM_PROMPT,
|
|
493
|
-
cwd: projectDir,
|
|
494
|
-
permissionMode: "bypassPermissions",
|
|
495
|
-
allowDangerouslySkipPermissions: true,
|
|
496
|
-
tools: { type: "preset", preset: "claude_code" },
|
|
497
|
-
mcpServers: {},
|
|
498
|
-
maxTurns: 16,
|
|
499
|
-
maxBudgetUsd: 3,
|
|
500
|
-
disallowedTools: ["Edit", "Write", "Bash", "NotebookEdit", "MultiEdit"]
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
const analysisResponse = await collectResponseFromEvents(
|
|
504
|
-
analysisEvents,
|
|
505
|
-
connection,
|
|
506
|
-
requestId,
|
|
507
|
-
taskPayload.taskId
|
|
508
|
-
);
|
|
509
|
-
if (!analysisResponse.text) throw new Error("No response from Claude");
|
|
510
|
-
const parsed = extractJsonFromResponse(analysisResponse.text);
|
|
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
|
-
}
|
|
532
|
-
logger.info("Task audit complete", {
|
|
533
|
-
requestId,
|
|
534
|
-
taskId: taskPayload.taskId,
|
|
535
|
-
grades: parsed.turnGrades.length,
|
|
536
|
-
suggestions: suggestionIds.length
|
|
537
|
-
});
|
|
538
|
-
await connection.call("reportTaskAuditResult", {
|
|
539
|
-
projectId: connection.projectId,
|
|
540
|
-
requestId,
|
|
541
|
-
taskId: taskPayload.taskId,
|
|
542
|
-
summary: parsed.summary,
|
|
543
|
-
turnGrades: parsed.turnGrades,
|
|
544
|
-
planningAccuracy: parsed.planningAccuracy,
|
|
545
|
-
buildingAccuracy: parsed.buildingAccuracy,
|
|
546
|
-
humanAccuracy: parsed.humanAccuracy,
|
|
547
|
-
humanEvaluations: parsed.humanEvaluations,
|
|
548
|
-
...counts,
|
|
549
|
-
suggestionIds,
|
|
550
|
-
auditCostUsd: totalCostUsd,
|
|
551
|
-
model: analysisResponse.model
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
async function handleTaskAudit(request, connection, projectDir) {
|
|
555
|
-
const { requestId } = request;
|
|
556
|
-
logger.info("Starting task audit", { requestId, taskCount: request.tasks.length });
|
|
557
|
-
const model = await fetchModel(connection);
|
|
558
|
-
for (const taskPayload of request.tasks) {
|
|
559
|
-
try {
|
|
560
|
-
await auditSingleTask(taskPayload, request, connection, projectDir, model);
|
|
561
|
-
} catch (err) {
|
|
562
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
563
|
-
logger.error("Task audit failed for task", {
|
|
564
|
-
requestId,
|
|
565
|
-
taskId: taskPayload.taskId,
|
|
566
|
-
error: msg
|
|
567
|
-
});
|
|
568
|
-
await connection.call(
|
|
569
|
-
"reportTaskAuditResult",
|
|
570
|
-
buildErrorResult(connection.projectId, requestId, taskPayload.taskId, msg)
|
|
571
|
-
).catch(() => {
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
await connection.call("reportTaskAuditBatchComplete", {
|
|
576
|
-
projectId: connection.projectId,
|
|
577
|
-
requestId
|
|
578
|
-
}).catch(() => {
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
export {
|
|
582
|
-
handleTaskAudit
|
|
583
|
-
};
|
|
584
|
-
//# sourceMappingURL=task-audit-handler-7Q7EJENK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|