@rallycry/conveyor-agent 7.2.4 → 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-AS3FYEBJ.js → chunk-JFWVIDQ2.js} +23 -10
- 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-LH35J3TX.js → task-audit-handler-7Q7EJENK.js} +276 -169
- package/dist/task-audit-handler-7Q7EJENK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-AS3FYEBJ.js.map +0 -1
- package/dist/task-audit-handler-LH35J3TX.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.
|
|
@@ -100,18 +261,7 @@ After grading individual turns, perform a high-level assessment of the overall t
|
|
|
100
261
|
- **Context & Planning**: Was the plan/context sufficient for the agent to succeed? Were there information gaps that caused wasted effort?
|
|
101
262
|
- **Overall Result**: Did the final result meet the task requirements? Was the outcome proportional to the effort spent?
|
|
102
263
|
|
|
103
|
-
Include a "macroEvaluation" object in your JSON output
|
|
104
|
-
|
|
105
|
-
## Suggestion Creation (MANDATORY)
|
|
106
|
-
|
|
107
|
-
After outputting the JSON block above, you MUST call the \`create_suggestion\` tool for each actionable cross-cutting improvement. Do NOT stop after the JSON block \u2014 you must continue and call the tool. Focus on:
|
|
108
|
-
- Recurring patterns of wasted effort
|
|
109
|
-
- Missing documentation or context that caused confusion
|
|
110
|
-
- Process improvements that would prevent common blunders
|
|
111
|
-
- Tool or workflow optimizations
|
|
112
|
-
- Actionable macro findings that would improve future task execution
|
|
113
|
-
|
|
114
|
-
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.`;
|
|
264
|
+
Include a "macroEvaluation" object in your JSON output.`;
|
|
115
265
|
function buildSessionInfoSection(info) {
|
|
116
266
|
const lines = ["## Session Info"];
|
|
117
267
|
if (info.model) lines.push(`- Model: ${info.model}`);
|
|
@@ -162,11 +312,19 @@ ${task.agentInstructions}
|
|
|
162
312
|
parts.push("");
|
|
163
313
|
}
|
|
164
314
|
parts.push(buildTraceSection(task.agentTrace));
|
|
165
|
-
parts.push(
|
|
166
|
-
"Grade each turn above, then output the structured JSON result, then call create_suggestion for each cross-cutting improvement. You must call create_suggestion at least once."
|
|
167
|
-
);
|
|
315
|
+
parts.push("Grade each turn above, then output the structured JSON result.");
|
|
168
316
|
return parts.join("\n");
|
|
169
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.`;
|
|
170
328
|
function buildProjectSuggestionTool(connection, projectId) {
|
|
171
329
|
return defineTool(
|
|
172
330
|
"create_suggestion",
|
|
@@ -200,173 +358,79 @@ function buildProjectSuggestionTool(connection, projectId) {
|
|
|
200
358
|
}
|
|
201
359
|
async function fetchModel(connection) {
|
|
202
360
|
try {
|
|
203
|
-
const ctx = await connection.call("
|
|
204
|
-
projectId: connection.projectId
|
|
361
|
+
const ctx = await connection.call("getProjectAgentContextByRole", {
|
|
362
|
+
projectId: connection.projectId,
|
|
363
|
+
role: "reviewer"
|
|
205
364
|
});
|
|
206
365
|
return ctx.model || FALLBACK_MODEL;
|
|
207
366
|
} catch {
|
|
208
367
|
return FALLBACK_MODEL;
|
|
209
368
|
}
|
|
210
369
|
}
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
function formatHumanEvaluations(evals) {
|
|
221
|
-
if (evals.length === 0) return null;
|
|
222
|
-
const total = evals.reduce((sum, e) => sum + e.rating, 0);
|
|
223
|
-
const avg = total / evals.length;
|
|
224
|
-
const label = avg > 0.3 ? "Helpful" : avg < -0.3 ? "Unhelpful" : "Neutral";
|
|
225
|
-
const lines = [
|
|
226
|
-
`- Overall: ${label} (avg ${avg.toFixed(2)}, ${evals.length} message${evals.length === 1 ? "" : "s"})`
|
|
227
|
-
];
|
|
228
|
-
for (const e of evals) {
|
|
229
|
-
const ratingLabel = e.rating > 0 ? "helpful" : e.rating < 0 ? "unhelpful" : "neutral";
|
|
230
|
-
lines.push(` - Message ${e.messageIndex}: ${ratingLabel} \u2014 ${e.reasoning}`);
|
|
231
|
-
}
|
|
232
|
-
return lines.join("\n");
|
|
233
|
-
}
|
|
234
|
-
function toAuditResult(parsed) {
|
|
235
|
-
if (!parsed || !Array.isArray(parsed.turnGrades)) return null;
|
|
236
|
-
const macro = parsed.macroEvaluation;
|
|
237
|
-
const rawHumanEvals = Array.isArray(parsed.humanEvaluations) ? parsed.humanEvaluations : [];
|
|
238
|
-
const baseSummary = parsed.summary ?? "";
|
|
239
|
-
const macroText = formatMacroEvaluation(macro);
|
|
240
|
-
const humanEvalText = formatHumanEvaluations(rawHumanEvals);
|
|
241
|
-
let summary = baseSummary;
|
|
242
|
-
if (macroText) summary += `
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
Macro Evaluation:
|
|
247
|
-
${macroText}`;
|
|
248
|
-
if (humanEvalText) summary += `
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
Human Contributions:
|
|
253
|
-
${humanEvalText}`;
|
|
254
|
-
return {
|
|
255
|
-
turnGrades: parsed.turnGrades,
|
|
256
|
-
summary,
|
|
257
|
-
planningAccuracy: parsed.planningAccuracy ?? null,
|
|
258
|
-
buildingAccuracy: parsed.buildingAccuracy ?? null,
|
|
259
|
-
humanAccuracy: parsed.humanAccuracy ?? null,
|
|
260
|
-
humanEvaluations: rawHumanEvals,
|
|
261
|
-
macroEvaluation: macro ? {
|
|
262
|
-
instructionsQuality: macro.instructionsQuality ?? void 0,
|
|
263
|
-
modelSuitability: macro.modelSuitability ?? void 0,
|
|
264
|
-
contextAndPlanning: macro.contextAndPlanning ?? void 0,
|
|
265
|
-
overallResult: macro.overallResult ?? void 0
|
|
266
|
-
} : null
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
function extractJsonFromResponse(text) {
|
|
270
|
-
const codeBlockMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
271
|
-
const jsonStr = codeBlockMatch ? codeBlockMatch[1].trim() : text;
|
|
272
|
-
try {
|
|
273
|
-
const result = toAuditResult(JSON.parse(jsonStr));
|
|
274
|
-
if (result) return result;
|
|
275
|
-
} catch {
|
|
276
|
-
}
|
|
277
|
-
const objectMatch = text.match(/\{[\s\S]*"turnGrades"[\s\S]*\}/);
|
|
278
|
-
if (objectMatch) {
|
|
279
|
-
try {
|
|
280
|
-
const result = toAuditResult(JSON.parse(objectMatch[0]));
|
|
281
|
-
if (result) return result;
|
|
282
|
-
} catch {
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
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
|
+
});
|
|
286
378
|
}
|
|
287
|
-
function
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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));
|
|
303
395
|
}
|
|
304
396
|
}
|
|
305
|
-
return counts;
|
|
306
397
|
}
|
|
307
398
|
async function collectResponseFromEvents(events, connection, requestId, taskId) {
|
|
308
399
|
const responseParts = [];
|
|
309
400
|
let costUsd = null;
|
|
310
401
|
let model = null;
|
|
402
|
+
const reportedFirstText = { value: false };
|
|
403
|
+
const ctx = { connection, requestId, taskId };
|
|
311
404
|
for await (const event of events) {
|
|
312
405
|
if (event.type === "system") {
|
|
313
406
|
const sysEvent = event;
|
|
314
407
|
if (sysEvent.subtype === "init" && sysEvent.model) {
|
|
315
408
|
model = sysEvent.model;
|
|
409
|
+
reportProgress(
|
|
410
|
+
connection,
|
|
411
|
+
requestId,
|
|
412
|
+
taskId,
|
|
413
|
+
"system",
|
|
414
|
+
`Initialized model: ${sysEvent.model}`
|
|
415
|
+
);
|
|
316
416
|
}
|
|
317
417
|
}
|
|
318
418
|
if (event.type === "assistant") {
|
|
319
419
|
const { message } = event;
|
|
320
|
-
|
|
321
|
-
if (block.type === "text" && block.text) {
|
|
322
|
-
responseParts.push(block.text);
|
|
323
|
-
} else if (block.type === "tool_use" && block.name) {
|
|
324
|
-
const inputStr = typeof block.input === "string" ? block.input : JSON.stringify(block.input);
|
|
325
|
-
await connection.call("reportTaskAuditProgress", {
|
|
326
|
-
projectId: connection.projectId,
|
|
327
|
-
requestId,
|
|
328
|
-
taskId,
|
|
329
|
-
activity: `${block.name}: ${inputStr.slice(0, 500)}`
|
|
330
|
-
}).catch(() => {
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
420
|
+
processAssistantBlocks(message.content, responseParts, ctx, reportedFirstText);
|
|
334
421
|
}
|
|
335
422
|
if (event.type === "result") {
|
|
336
423
|
const resultEvent = event;
|
|
337
424
|
if (resultEvent.subtype === "success" && resultEvent.total_cost_usd !== void 0) {
|
|
338
425
|
costUsd = resultEvent.total_cost_usd;
|
|
339
426
|
}
|
|
427
|
+
const status = resultEvent.subtype === "success" ? "success" : `error: ${resultEvent.subtype}`;
|
|
428
|
+
reportProgress(connection, requestId, taskId, "complete", status);
|
|
340
429
|
break;
|
|
341
430
|
}
|
|
342
431
|
}
|
|
343
432
|
return { text: responseParts.join("\n\n").trim(), costUsd, model };
|
|
344
433
|
}
|
|
345
|
-
function buildErrorResult(projectId, requestId, taskId, error) {
|
|
346
|
-
return {
|
|
347
|
-
projectId,
|
|
348
|
-
requestId,
|
|
349
|
-
taskId,
|
|
350
|
-
summary: "",
|
|
351
|
-
turnGrades: [],
|
|
352
|
-
planningAccuracy: null,
|
|
353
|
-
buildingAccuracy: null,
|
|
354
|
-
humanAccuracy: null,
|
|
355
|
-
planningCorrect: 0,
|
|
356
|
-
planningNeutral: 0,
|
|
357
|
-
planningBlunder: 0,
|
|
358
|
-
buildingCorrect: 0,
|
|
359
|
-
buildingNeutral: 0,
|
|
360
|
-
buildingBlunder: 0,
|
|
361
|
-
humanCorrect: 0,
|
|
362
|
-
humanNeutral: 0,
|
|
363
|
-
humanBlunder: 0,
|
|
364
|
-
suggestionIds: [],
|
|
365
|
-
auditCostUsd: null,
|
|
366
|
-
model: null,
|
|
367
|
-
error
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
434
|
function buildTrackedSuggestionTool(connection, projectId, suggestionIds) {
|
|
371
435
|
const suggestionTool = buildProjectSuggestionTool(connection, projectId);
|
|
372
436
|
return defineTool(
|
|
@@ -382,23 +446,46 @@ function buildTrackedSuggestionTool(connection, projectId, suggestionIds) {
|
|
|
382
446
|
}
|
|
383
447
|
);
|
|
384
448
|
}
|
|
385
|
-
async function
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
projectId: connection.projectId,
|
|
449
|
+
async function runSuggestionPhase(parsed, taskPayload, connection, requestId, projectId, projectDir, model, suggestionIds) {
|
|
450
|
+
reportProgress(
|
|
451
|
+
connection,
|
|
389
452
|
requestId,
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const suggestionIds = [];
|
|
453
|
+
taskPayload.taskId,
|
|
454
|
+
"status",
|
|
455
|
+
"Creating suggestions from findings..."
|
|
456
|
+
);
|
|
395
457
|
const wrappedSuggestionTool = buildTrackedSuggestionTool(connection, projectId, suggestionIds);
|
|
396
458
|
const harness = createHarness();
|
|
397
|
-
const mcpServer = harness.createMcpServer({
|
|
398
|
-
name: "conveyor",
|
|
399
|
-
tools: [wrappedSuggestionTool]
|
|
400
|
-
});
|
|
459
|
+
const mcpServer = harness.createMcpServer({ name: "conveyor", tools: [wrappedSuggestionTool] });
|
|
401
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({
|
|
402
489
|
prompt: buildTaskAuditPrompt(taskPayload),
|
|
403
490
|
options: {
|
|
404
491
|
model,
|
|
@@ -407,21 +494,41 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
|
|
|
407
494
|
permissionMode: "bypassPermissions",
|
|
408
495
|
allowDangerouslySkipPermissions: true,
|
|
409
496
|
tools: { type: "preset", preset: "claude_code" },
|
|
410
|
-
mcpServers: {
|
|
497
|
+
mcpServers: {},
|
|
411
498
|
maxTurns: 16,
|
|
412
499
|
maxBudgetUsd: 3,
|
|
413
500
|
disallowedTools: ["Edit", "Write", "Bash", "NotebookEdit", "MultiEdit"]
|
|
414
501
|
}
|
|
415
502
|
});
|
|
416
|
-
const
|
|
417
|
-
|
|
503
|
+
const analysisResponse = await collectResponseFromEvents(
|
|
504
|
+
analysisEvents,
|
|
418
505
|
connection,
|
|
419
506
|
requestId,
|
|
420
507
|
taskPayload.taskId
|
|
421
508
|
);
|
|
422
|
-
if (!
|
|
423
|
-
const parsed = extractJsonFromResponse(
|
|
509
|
+
if (!analysisResponse.text) throw new Error("No response from Claude");
|
|
510
|
+
const parsed = extractJsonFromResponse(analysisResponse.text);
|
|
424
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
|
+
}
|
|
425
532
|
logger.info("Task audit complete", {
|
|
426
533
|
requestId,
|
|
427
534
|
taskId: taskPayload.taskId,
|
|
@@ -440,8 +547,8 @@ async function auditSingleTask(taskPayload, request, connection, projectDir, mod
|
|
|
440
547
|
humanEvaluations: parsed.humanEvaluations,
|
|
441
548
|
...counts,
|
|
442
549
|
suggestionIds,
|
|
443
|
-
auditCostUsd:
|
|
444
|
-
model:
|
|
550
|
+
auditCostUsd: totalCostUsd,
|
|
551
|
+
model: analysisResponse.model
|
|
445
552
|
});
|
|
446
553
|
}
|
|
447
554
|
async function handleTaskAudit(request, connection, projectDir) {
|
|
@@ -474,4 +581,4 @@ async function handleTaskAudit(request, connection, projectDir) {
|
|
|
474
581
|
export {
|
|
475
582
|
handleTaskAudit
|
|
476
583
|
};
|
|
477
|
-
//# 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":";;;;;;;;;;AAAA,SAAS,SAAS;;;ACyBlB,SAAS,sBAAsB,OAAkE;AAC/F,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,oBAAqB,OAAM,KAAK,2BAA2B,MAAM,mBAAmB,EAAE;AAChG,MAAI,MAAM,iBAAkB,OAAM,KAAK,wBAAwB,MAAM,gBAAgB,EAAE;AACvF,MAAI,MAAM,mBAAoB,OAAM,KAAK,yBAAyB,MAAM,kBAAkB,EAAE;AAC5F,MAAI,MAAM,cAAe,OAAM,KAAK,qBAAqB,MAAM,aAAa,EAAE;AAC9E,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;AAEA,SAAS,uBAAuB,OAAkD;AAChF,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,CAAC;AACxD,QAAM,MAAM,QAAQ,MAAM;AAC1B,QAAM,QAAQ,MAAM,MAAM,YAAY,MAAM,OAAO,cAAc;AACjE,QAAM,QAAQ;AAAA,IACZ,cAAc,KAAK,SAAS,IAAI,QAAQ,CAAC,CAAC,KAAK,MAAM,MAAM,WAAW,MAAM,WAAW,IAAI,KAAK,GAAG;AAAA,EACrG;AACA,aAAW,KAAK,OAAO;AACrB,UAAM,cAAc,EAAE,SAAS,IAAI,YAAY,EAAE,SAAS,IAAI,cAAc;AAC5E,UAAM,KAAK,eAAe,EAAE,YAAY,KAAK,WAAW,WAAM,EAAE,SAAS,EAAE;AAAA,EAC7E;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,SAAS,cAAc,QAAyD;AAC9E,MAAI,CAAC,UAAU,CAAC,MAAM,QAAQ,OAAO,UAAU,EAAG,QAAO;AAEzD,QAAM,QAAQ,OAAO;AACrB,QAAM,gBAAgB,MAAM,QAAQ,OAAO,gBAAgB,IACtD,OAAO,mBACR,CAAC;AACL,QAAM,cAAe,OAAO,WAAsB;AAElD,QAAM,YAAY,sBAAsB,KAAK;AAC7C,QAAM,gBAAgB,uBAAuB,aAAa;AAE1D,MAAI,UAAU;AACd,MAAI,UAAW,YAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAAiC,SAAS;AACpE,MAAI,cAAe,YAAW;AAAA;AAAA;AAAA;AAAA;AAAA,EAAoC,aAAa;AAE/E,SAAO;AAAA,IACL,YAAY,OAAO;AAAA,IACnB;AAAA,IACA,kBAAmB,OAAO,oBAA+B;AAAA,IACzD,kBAAmB,OAAO,oBAA+B;AAAA,IACzD,eAAgB,OAAO,iBAA4B;AAAA,IACnD,kBAAkB;AAAA,IAClB,iBAAiB,QACb;AAAA,MACE,qBAAsB,MAAM,uBAAkC;AAAA,MAC9D,kBAAmB,MAAM,oBAA+B;AAAA,MACxD,oBAAqB,MAAM,sBAAiC;AAAA,MAC5D,eAAgB,MAAM,iBAA4B;AAAA,IACpD,IACA;AAAA,EACN;AACF;AAEO,SAAS,wBAAwB,MAA+B;AACrE,QAAM,iBAAiB,KAAK,MAAM,iCAAiC;AACnE,QAAM,UAAU,iBAAiB,eAAe,CAAC,EAAE,KAAK,IAAI;AAE5D,MAAI;AACF,UAAM,SAAS,cAAc,KAAK,MAAM,OAAO,CAAC;AAChD,QAAI,OAAQ,QAAO;AAAA,EACrB,QAAQ;AAAA,EAER;AAEA,QAAM,cAAc,KAAK,MAAM,gCAAgC;AAC/D,MAAI,aAAa;AACf,QAAI;AACF,YAAM,SAAS,cAAc,KAAK,MAAM,YAAY,CAAC,CAAC,CAAC;AACvD,UAAI,OAAQ,QAAO;AAAA,IACrB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,wDAAwD;AAC1E;AAIO,SAAS,mBAAmB,YAAkC;AACnE,QAAM,SAAS;AAAA,IACb,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,EAChB;AAEA,aAAW,MAAM,YAAY;AAC3B,UAAM,MACJ,GAAG,GAAG,KAAK,GAAG,GAAG,MAAM,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG,GAAG,MAAM,MAAM,CAAC,CAAC;AACpE,QAAI,OAAO,QAAQ;AACjB,aAAO,GAAG;AAAA,IACZ;AAAA,EACF;AAEA,SAAO;AACT;AAIO,SAAS,SAAS,MAAqB,UAAwC;AACpF,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,aAAa,KAAM,QAAO;AAC9B,SAAO,OAAO;AAChB;AAIO,SAAS,iBACd,WACA,WACA,QACA,OACA;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,YAAY,CAAC;AAAA,IACb,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,cAAc;AAAA,IACd,OAAO;AAAA,IACP;AAAA,EACF;AACF;AAIO,SAAS,sBAAsB,QAAyB,MAAgC;AAC7F,QAAM,QAAkB,CAAC,gCAAgC,KAAK,SAAS;AAAA,CAAI;AAE3E,QAAM,KAAK;AAAA,EAAqB,OAAO,OAAO;AAAA,CAAI;AAElD,MAAI,OAAO,iBAAiB;AAC1B,UAAM,KAAK,qBAAqB;AAChC,QAAI,OAAO,gBAAgB;AACzB,YAAM,KAAK,2BAA2B,OAAO,gBAAgB,mBAAmB,EAAE;AACpF,QAAI,OAAO,gBAAgB;AACzB,YAAM,KAAK,wBAAwB,OAAO,gBAAgB,gBAAgB,EAAE;AAC9E,QAAI,OAAO,gBAAgB;AACzB,YAAM,KAAK,yBAAyB,OAAO,gBAAgB,kBAAkB,EAAE;AACjF,QAAI,OAAO,gBAAgB;AACzB,YAAM,KAAK,qBAAqB,OAAO,gBAAgB,aAAa,EAAE;AACxE,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,WAAW,OAAO,WAAW,OAAO,CAAC,OAAO,GAAG,UAAU,SAAS;AACxE,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,qBAAqB;AAChC,eAAW,KAAK,SAAS,MAAM,GAAG,EAAE,GAAG;AACrC,YAAM,KAAK,UAAU,EAAE,SAAS,KAAK,EAAE,KAAK,MAAM,EAAE,SAAS,EAAE;AAAA,IACjE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ADpMA,IAAM,SAAS,oBAAoB,WAAW;AAE9C,IAAM,iBAAiB;AAIvB,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6FjC,SAAS,wBAAwB,MAA4D;AAC3F,QAAM,QAAkB,CAAC,iBAAiB;AAC1C,MAAI,KAAK,MAAO,OAAM,KAAK,YAAY,KAAK,KAAK,EAAE;AACnD,MAAI,KAAK,iBAAiB,KAAM,OAAM,KAAK,kBAAkB,KAAK,aAAa,QAAQ,CAAC,CAAC,EAAE;AAC3F,MAAI,KAAK,kBAAkB,KAAM,OAAM,KAAK,qBAAqB,KAAK,aAAa,EAAE;AACrF,MAAI,KAAK,kBAAkB,KAAM,OAAM,KAAK,qBAAqB,KAAK,aAAa,EAAE;AACrF,MAAI,KAAK,YAAY,KAAM,OAAM,KAAK,oBAAoB,KAAK,OAAO,EAAE;AACxE,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,kBAAkB,OAA+C;AACxE,QAAM,QAAkB,CAAC,kBAAkB;AAC3C,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,kCAAkC;AAAA,EAC/C,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,QAAQ,MAAM,CAAC;AACrB,YAAM,UAAU,KAAK,UAAU,MAAM,IAAI;AACzC,YAAM,YAAY,QAAQ,SAAS,MAAO,QAAQ,MAAM,GAAG,GAAI,IAAI,QAAQ;AAC3E,YAAM,KAAK,YAAY,CAAC,KAAK,MAAM,IAAI,OAAO,MAAM,SAAS,EAAE;AAC/D,YAAM,KAAK,SAAS;AACpB,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,SAAS,qBAAqB,MAAgC;AAC5D,QAAM,QAAkB,CAAC,iBAAiB,KAAK,SAAS;AAAA,CAAI;AAE5D,MAAI,KAAK,gBAAiB,OAAM,KAAK;AAAA,EAAmB,KAAK,eAAe;AAAA,CAAI;AAChF,MAAI,KAAK,SAAU,OAAM,KAAK;AAAA,EAAY,KAAK,QAAQ;AAAA,CAAI;AAE3D,QAAM,KAAK,mBAAmB,KAAK,UAAU,EAAE;AAC/C,MAAI,KAAK,oBAAoB,KAAM,OAAM,KAAK,oBAAoB,KAAK,eAAe,EAAE;AACxF,QAAM,KAAK,EAAE;AAEb,MAAI,KAAK,YAAa,OAAM,KAAK,wBAAwB,KAAK,WAAW,CAAC;AAC1E,MAAI,KAAK,kBAAmB,OAAM,KAAK;AAAA,EAA0B,KAAK,iBAAiB;AAAA,CAAI;AAE3F,MAAI,KAAK,cAAc,SAAS,GAAG;AACjC,UAAM,KAAK,qBAAqB;AAChC,eAAW,OAAO,KAAK,eAAe;AACpC,YAAM,KAAK,IAAI,IAAI,SAAS,OAAO,IAAI,IAAI,OAAO,IAAI,OAAO,EAAE;AAAA,IACjE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,kBAAkB,KAAK,UAAU,CAAC;AAC7C,QAAM,KAAK,gEAAgE;AAE3E,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAajC,SAAS,2BAA2B,YAA+B,WAAmB;AACpF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EAAE,OAAO,EAAE,SAAS,gCAAgC;AAAA,MAC3D,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAA8B;AAAA,MAC1E,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,wCAAwC;AAAA,IAC7F;AAAA,IACA,OAAO,EAAE,OAAO,aAAa,UAAU,MAAM;AAC3C,UAAI;AACF,cAAM,SAAS,MAAM,WAAW,KAAK,2BAA2B;AAAA,UAC9D;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,QACZ,CAAC;AACD,YAAI,OAAO,QAAQ;AACjB,iBAAO;AAAA,YACL,wCAAwC,OAAO,gBAAgB,OAAO,EAAE;AAAA,UAC1E;AAAA,QACF;AACA,eAAO,WAAW,2BAA2B,OAAO,EAAE,IAAI;AAAA,MAC5D,SAAS,OAAO;AACd,eAAO;AAAA,UACL,gCAAgC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC1F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAIA,eAAe,WAAW,YAAgD;AACxE,MAAI;AACF,UAAM,MAAM,MAAM,WAAW,KAAK,gCAAgC;AAAA,MAChE,WAAW,WAAW;AAAA,MACtB,MAAM;AAAA,IACR,CAAC;AACD,WAAO,IAAI,SAAS;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,SAAS,eACP,YACA,WACA,QACA,MACA,OACM;AACN,OAAK,WACF,KAAK,2BAA2B;AAAA,IAC/B,WAAW,WAAW;AAAA,IACtB;AAAA,IACA;AAAA,IACA,UAAU,EAAE,MAAM,OAAO,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,EAC/D,CAAC,EACA,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAQA,SAAS,uBACP,QACA,eACA,KACA,mBACM;AACN,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,UAAU,MAAM,MAAM;AACvC,oBAAc,KAAK,MAAM,IAAI;AAC7B,UAAI,kBAAkB,MAAO;AAC7B,wBAAkB,QAAQ;AAC1B;AAAA,QACE,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ;AAAA,QACA,MAAM,KAAK,MAAM,GAAG,GAAG;AAAA,MACzB;AAAA,IACF,WAAW,MAAM,SAAS,cAAc,MAAM,MAAM;AAClD,YAAM,WAAW,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK;AAC3F,qBAAe,IAAI,YAAY,IAAI,WAAW,IAAI,QAAQ,MAAM,MAAM,SAAS,MAAM,GAAG,GAAG,CAAC;AAAA,IAC9F;AAAA,EACF;AACF;AAEA,eAAe,0BACb,QACA,YACA,WACA,QACyE;AACzE,QAAM,gBAA0B,CAAC;AACjC,MAAI,UAAyB;AAC7B,MAAI,QAAuB;AAC3B,QAAM,oBAAoB,EAAE,OAAO,MAAM;AACzC,QAAM,MAAuB,EAAE,YAAY,WAAW,OAAO;AAE7D,mBAAiB,SAAS,QAAQ;AAChC,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,WAAW;AACjB,UAAI,SAAS,YAAY,UAAU,SAAS,OAAO;AACjD,gBAAQ,SAAS;AACjB;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,sBAAsB,SAAS,KAAK;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,aAAa;AAC9B,YAAM,EAAE,QAAQ,IAAI;AAMpB,6BAAuB,QAAQ,SAAS,eAAe,KAAK,iBAAiB;AAAA,IAC/E;AAEA,QAAI,MAAM,SAAS,UAAU;AAC3B,YAAM,cAAc;AACpB,UAAI,YAAY,YAAY,aAAa,YAAY,mBAAmB,QAAW;AACjF,kBAAU,YAAY;AAAA,MACxB;AACA,YAAM,SACJ,YAAY,YAAY,YAAY,YAAY,UAAU,YAAY,OAAO;AAC/E,qBAAe,YAAY,WAAW,QAAQ,YAAY,MAAM;AAChE;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,cAAc,KAAK,MAAM,EAAE,KAAK,GAAG,SAAS,MAAM;AACnE;AAIA,SAAS,2BACP,YACA,WACA,eACA;AACA,QAAM,iBAAiB,2BAA2B,YAAY,SAAS;AACvE,SAAO;AAAA,IACL,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,OAAO,UAAmC;AACxC,YAAM,SAAS,MAAM,eAAe,QAAQ,KAAK;AACjD,YAAM,OAAO,OAAO,UAAU,CAAC,GAAG,QAAQ;AAC1C,YAAM,UAAU,KAAK,MAAM,kBAAkB;AAC7C,UAAI,QAAS,eAAc,KAAK,QAAQ,CAAC,CAAC;AAC1C,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAIA,eAAe,mBACb,QACA,aACA,YACA,WACA,WACA,YACA,OACA,eACwB;AACxB;AAAA,IACE;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,EACF;AAEA,QAAM,wBAAwB,2BAA2B,YAAY,WAAW,aAAa;AAC7F,QAAM,UAAU,cAAc;AAC9B,QAAM,YAAY,QAAQ,gBAAgB,EAAE,MAAM,YAAY,OAAO,CAAC,qBAAqB,EAAE,CAAC;AAE9F,QAAM,SAAS,QAAQ,aAAa;AAAA,IAClC,QAAQ,sBAAsB,QAAQ,WAAW;AAAA,IACjD,SAAS;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,KAAK;AAAA,MACL,gBAAgB;AAAA,MAChB,iCAAiC;AAAA,MACjC,OAAO,EAAE,MAAM,UAAmB,QAAQ,cAAuB;AAAA,MACjE,YAAY,EAAE,UAAU,UAAU;AAAA,MAClC,UAAU;AAAA,MACV,cAAc;AAAA,MACd,iBAAiB,CAAC,QAAQ,SAAS,QAAQ,gBAAgB,WAAW;AAAA,IACxE;AAAA,EACF,CAAC;AAED,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACA,SAAO,SAAS;AAClB;AAIA,eAAe,gBACb,aACA,SACA,YACA,YACA,OACe;AACf,QAAM,EAAE,WAAW,UAAU,IAAI;AACjC,QAAM,gBAA0B,CAAC;AAGjC,iBAAe,YAAY,WAAW,YAAY,QAAQ,UAAU,4BAA4B;AAEhG,QAAM,kBAAkB,cAAc;AACtC,QAAM,iBAAiB,gBAAgB,aAAa;AAAA,IAClD,QAAQ,qBAAqB,WAAW;AAAA,IACxC,SAAS;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,KAAK;AAAA,MACL,gBAAgB;AAAA,MAChB,iCAAiC;AAAA,MACjC,OAAO,EAAE,MAAM,UAAmB,QAAQ,cAAuB;AAAA,MACjE,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,cAAc;AAAA,MACd,iBAAiB,CAAC,QAAQ,SAAS,QAAQ,gBAAgB,WAAW;AAAA,IACxE;AAAA,EACF,CAAC;AAED,QAAM,mBAAmB,MAAM;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACA,MAAI,CAAC,iBAAiB,KAAM,OAAM,IAAI,MAAM,yBAAyB;AAErE,QAAM,SAAS,wBAAwB,iBAAiB,IAAI;AAC5D,QAAM,SAAS,mBAAmB,OAAO,UAAU;AAGnD,MAAI,eAAe,iBAAiB;AACpC,MAAI;AACF,UAAM,iBAAiB,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,mBAAe,SAAS,cAAc,cAAc;AAAA,EACtD,SAAS,KAAK;AACZ,WAAO,KAAK,2DAA2D;AAAA,MACrE;AAAA,MACA,QAAQ,YAAY;AAAA,MACpB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,SAAO,KAAK,uBAAuB;AAAA,IACjC;AAAA,IACA,QAAQ,YAAY;AAAA,IACpB,QAAQ,OAAO,WAAW;AAAA,IAC1B,aAAa,cAAc;AAAA,EAC7B,CAAC;AAED,QAAM,WAAW,KAAK,yBAAyB;AAAA,IAC7C,WAAW,WAAW;AAAA,IACtB;AAAA,IACA,QAAQ,YAAY;AAAA,IACpB,SAAS,OAAO;AAAA,IAChB,YAAY,OAAO;AAAA,IACnB,kBAAkB,OAAO;AAAA,IACzB,kBAAkB,OAAO;AAAA,IACzB,eAAe,OAAO;AAAA,IACtB,kBAAkB,OAAO;AAAA,IACzB,GAAG;AAAA,IACH;AAAA,IACA,cAAc;AAAA,IACd,OAAO,iBAAiB;AAAA,EAC1B,CAAC;AACH;AAIA,eAAsB,gBACpB,SACA,YACA,YACe;AACf,QAAM,EAAE,UAAU,IAAI;AAEtB,SAAO,KAAK,uBAAuB,EAAE,WAAW,WAAW,QAAQ,MAAM,OAAO,CAAC;AAEjF,QAAM,QAAQ,MAAM,WAAW,UAAU;AAEzC,aAAW,eAAe,QAAQ,OAAO;AACvC,QAAI;AACF,YAAM,gBAAgB,aAAa,SAAS,YAAY,YAAY,KAAK;AAAA,IAC3E,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,MAAM,8BAA8B;AAAA,QACzC;AAAA,QACA,QAAQ,YAAY;AAAA,QACpB,OAAO;AAAA,MACT,CAAC;AACD,YAAM,WACH;AAAA,QACC;AAAA,QACA,iBAAiB,WAAW,WAAW,WAAW,YAAY,QAAQ,GAAG;AAAA,MAC3E,EACC,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB;AAAA,EACF;AAGA,QAAM,WACH,KAAK,gCAAgC;AAAA,IACpC,WAAW,WAAW;AAAA,IACtB;AAAA,EACF,CAAC,EACA,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;","names":[]}
|