@prismatic-io/lux 0.0.1 → 0.0.2-preview.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/answerers/persona/index.d.ts +2 -1
- package/lib/answerers/persona/index.d.ts.map +1 -1
- package/lib/answerers/persona/index.js +19 -5
- package/lib/answerers/persona/index.js.map +1 -1
- package/lib/answerers/terminal/index.js +1 -1
- package/lib/answerers/terminal/index.js.map +1 -1
- package/lib/assertions/authoring.d.ts +14 -0
- package/lib/assertions/authoring.d.ts.map +1 -0
- package/lib/assertions/authoring.js +3 -0
- package/lib/assertions/authoring.js.map +1 -0
- package/lib/assertions/core/helpers.d.ts +2 -7
- package/lib/assertions/core/helpers.d.ts.map +1 -1
- package/lib/assertions/core/helpers.js +2 -6
- package/lib/assertions/core/helpers.js.map +1 -1
- package/lib/assertions/core/index.d.ts.map +1 -1
- package/lib/assertions/core/index.js +2 -1
- package/lib/assertions/core/index.js.map +1 -1
- package/lib/assertions/core/resource-checks.d.ts +19 -0
- package/lib/assertions/core/resource-checks.d.ts.map +1 -1
- package/lib/assertions/core/resource-checks.js +32 -0
- package/lib/assertions/core/resource-checks.js.map +1 -1
- package/lib/authoring.d.ts +1 -0
- package/lib/authoring.d.ts.map +1 -1
- package/lib/authoring.js +1 -0
- package/lib/authoring.js.map +1 -1
- package/lib/cli/program.d.ts.map +1 -1
- package/lib/cli/program.js +12 -67
- package/lib/cli/program.js.map +1 -1
- package/lib/cli/render/reporter.d.ts.map +1 -1
- package/lib/cli/render/reporter.js +16 -3
- package/lib/cli/render/reporter.js.map +1 -1
- package/lib/cli/run-options.d.ts +1 -0
- package/lib/cli/run-options.d.ts.map +1 -1
- package/lib/cli/run-options.js.map +1 -1
- package/lib/cli/view.d.ts +13 -0
- package/lib/cli/view.d.ts.map +1 -0
- package/lib/cli/view.js +126 -0
- package/lib/cli/view.js.map +1 -0
- package/lib/core/action-events.d.ts +29 -0
- package/lib/core/action-events.d.ts.map +1 -0
- package/lib/core/action-events.js +51 -0
- package/lib/core/action-events.js.map +1 -0
- package/lib/core/agent-activity.d.ts +49 -0
- package/lib/core/agent-activity.d.ts.map +1 -0
- package/lib/core/agent-activity.js +206 -0
- package/lib/core/agent-activity.js.map +1 -0
- package/lib/core/agent-events.d.ts +26 -0
- package/lib/core/agent-events.d.ts.map +1 -0
- package/lib/core/agent-events.js +13 -0
- package/lib/core/agent-events.js.map +1 -0
- package/lib/core/artifact-evidence.d.ts +8 -0
- package/lib/core/artifact-evidence.d.ts.map +1 -1
- package/lib/core/artifact-evidence.js +36 -4
- package/lib/core/artifact-evidence.js.map +1 -1
- package/lib/core/assertion.d.ts +19 -9
- package/lib/core/assertion.d.ts.map +1 -1
- package/lib/core/assertion.js +26 -0
- package/lib/core/assertion.js.map +1 -1
- package/lib/core/case-authoring-state.d.ts +12 -0
- package/lib/core/case-authoring-state.d.ts.map +1 -0
- package/lib/core/case-authoring-state.js +43 -0
- package/lib/core/case-authoring-state.js.map +1 -0
- package/lib/core/case.d.ts +29 -1
- package/lib/core/case.d.ts.map +1 -1
- package/lib/core/case.js +14 -6
- package/lib/core/case.js.map +1 -1
- package/lib/core/driver-metrics.d.ts +98 -0
- package/lib/core/driver-metrics.d.ts.map +1 -0
- package/lib/core/driver-metrics.js +36 -0
- package/lib/core/driver-metrics.js.map +1 -0
- package/lib/core/driver.d.ts +3 -0
- package/lib/core/driver.d.ts.map +1 -1
- package/lib/core/driver.js.map +1 -1
- package/lib/core/events.d.ts +36 -0
- package/lib/core/events.d.ts.map +1 -1
- package/lib/core/events.js +12 -2
- package/lib/core/events.js.map +1 -1
- package/lib/core/experiment.d.ts +19 -0
- package/lib/core/experiment.d.ts.map +1 -1
- package/lib/core/experiment.js +2 -0
- package/lib/core/experiment.js.map +1 -1
- package/lib/core/index.d.ts +4 -0
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +4 -0
- package/lib/core/index.js.map +1 -1
- package/lib/core/lifecycle-fixtures.d.ts +3 -1
- package/lib/core/lifecycle-fixtures.d.ts.map +1 -1
- package/lib/core/lifecycle-fixtures.js +4 -2
- package/lib/core/lifecycle-fixtures.js.map +1 -1
- package/lib/core/lifecycle-hooks.d.ts +9 -0
- package/lib/core/lifecycle-hooks.d.ts.map +1 -1
- package/lib/core/lifecycle-hooks.js +8 -2
- package/lib/core/lifecycle-hooks.js.map +1 -1
- package/lib/core/run.d.ts +150 -0
- package/lib/core/run.d.ts.map +1 -1
- package/lib/core/run.js +9 -0
- package/lib/core/run.js.map +1 -1
- package/lib/core/wire.d.ts +12 -0
- package/lib/core/wire.d.ts.map +1 -1
- package/lib/core/wire.js +5 -1
- package/lib/core/wire.js.map +1 -1
- package/lib/drivers/claude-code/parse-events.d.ts.map +1 -1
- package/lib/drivers/claude-code/parse-events.js +73 -8
- package/lib/drivers/claude-code/parse-events.js.map +1 -1
- package/lib/drivers/codex/app-events.d.ts +9 -2
- package/lib/drivers/codex/app-events.d.ts.map +1 -1
- package/lib/drivers/codex/app-events.js +93 -12
- package/lib/drivers/codex/app-events.js.map +1 -1
- package/lib/drivers/codex/index.d.ts.map +1 -1
- package/lib/drivers/codex/index.js +10 -14
- package/lib/drivers/codex/index.js.map +1 -1
- package/lib/drivers/subprocess/index.d.ts.map +1 -1
- package/lib/drivers/subprocess/index.js +6 -0
- package/lib/drivers/subprocess/index.js.map +1 -1
- package/lib/index.d.ts +10 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +10 -6
- package/lib/index.js.map +1 -1
- package/lib/orchestrator/annotation-store.d.ts.map +1 -1
- package/lib/orchestrator/annotation-store.js +6 -2
- package/lib/orchestrator/annotation-store.js.map +1 -1
- package/lib/orchestrator/case-extensions.d.ts +6 -0
- package/lib/orchestrator/case-extensions.d.ts.map +1 -0
- package/lib/orchestrator/case-extensions.js +28 -0
- package/lib/orchestrator/case-extensions.js.map +1 -0
- package/lib/orchestrator/compare.d.ts +13 -1
- package/lib/orchestrator/compare.d.ts.map +1 -1
- package/lib/orchestrator/compare.js +12 -0
- package/lib/orchestrator/compare.js.map +1 -1
- package/lib/orchestrator/config.d.ts.map +1 -1
- package/lib/orchestrator/config.js +0 -2
- package/lib/orchestrator/config.js.map +1 -1
- package/lib/orchestrator/doctor.d.ts.map +1 -1
- package/lib/orchestrator/doctor.js +5 -3
- package/lib/orchestrator/doctor.js.map +1 -1
- package/lib/orchestrator/experiment-contracts.d.ts +19 -0
- package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.js +17 -0
- package/lib/orchestrator/experiment-evaluation.js.map +1 -1
- package/lib/orchestrator/experiment-report.d.ts +19 -0
- package/lib/orchestrator/experiment-report.d.ts.map +1 -1
- package/lib/orchestrator/experiment-runs.d.ts +38 -0
- package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
- package/lib/orchestrator/grader-experiment.d.ts +12 -0
- package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
- package/lib/orchestrator/grading.d.ts +2 -1
- package/lib/orchestrator/grading.d.ts.map +1 -1
- package/lib/orchestrator/grading.js +16 -4
- package/lib/orchestrator/grading.js.map +1 -1
- package/lib/orchestrator/index.d.ts +1 -1
- package/lib/orchestrator/index.d.ts.map +1 -1
- package/lib/orchestrator/index.js +1 -1
- package/lib/orchestrator/index.js.map +1 -1
- package/lib/orchestrator/list-runs.d.ts +7 -1
- package/lib/orchestrator/list-runs.d.ts.map +1 -1
- package/lib/orchestrator/list-runs.js +50 -6
- package/lib/orchestrator/list-runs.js.map +1 -1
- package/lib/orchestrator/loader.d.ts.map +1 -1
- package/lib/orchestrator/loader.js +2 -0
- package/lib/orchestrator/loader.js.map +1 -1
- package/lib/orchestrator/orchestrator.d.ts +3 -0
- package/lib/orchestrator/orchestrator.d.ts.map +1 -1
- package/lib/orchestrator/orchestrator.js +42 -14
- package/lib/orchestrator/orchestrator.js.map +1 -1
- package/lib/orchestrator/owned-lock.d.ts.map +1 -1
- package/lib/orchestrator/owned-lock.js +52 -38
- package/lib/orchestrator/owned-lock.js.map +1 -1
- package/lib/orchestrator/regrade.d.ts +6 -0
- package/lib/orchestrator/regrade.d.ts.map +1 -1
- package/lib/orchestrator/regrade.js +8 -4
- package/lib/orchestrator/regrade.js.map +1 -1
- package/lib/orchestrator/run-execution.d.ts +2 -1
- package/lib/orchestrator/run-execution.d.ts.map +1 -1
- package/lib/orchestrator/run-execution.js +20 -5
- package/lib/orchestrator/run-execution.js.map +1 -1
- package/lib/orchestrator/suite-compare.d.ts +34 -0
- package/lib/orchestrator/suite-compare.d.ts.map +1 -1
- package/lib/orchestrator/suite-summary.d.ts +68 -0
- package/lib/orchestrator/suite-summary.d.ts.map +1 -1
- package/lib/orchestrator/suite-summary.js +45 -7
- package/lib/orchestrator/suite-summary.js.map +1 -1
- package/lib/previewer/artifacts.d.ts +25 -0
- package/lib/previewer/artifacts.d.ts.map +1 -0
- package/lib/previewer/artifacts.js +180 -0
- package/lib/previewer/artifacts.js.map +1 -0
- package/lib/previewer/server.d.ts +105 -0
- package/lib/previewer/server.d.ts.map +1 -0
- package/lib/previewer/server.js +542 -0
- package/lib/previewer/server.js.map +1 -0
- package/package.json +2 -2
- package/skills/lux/SKILL.md +7 -3
- package/skills/lux/references/cli.md +25 -2
- package/skills/lux/references/eval-authoring.md +158 -4
- package/skills/lux-answerer/SKILL.md +1 -1
- package/src/answerers/persona/index.ts +20 -4
- package/src/answerers/terminal/index.ts +1 -1
- package/src/assertions/authoring.ts +81 -0
- package/src/assertions/core/helpers.ts +3 -6
- package/src/assertions/core/index.ts +2 -0
- package/src/assertions/core/resource-checks.ts +35 -0
- package/src/authoring.ts +1 -0
- package/src/cli/program.ts +14 -93
- package/src/cli/render/reporter.ts +18 -3
- package/src/cli/run-options.ts +1 -0
- package/src/cli/view.ts +168 -0
- package/src/core/action-events.ts +59 -0
- package/src/core/agent-activity.ts +236 -0
- package/src/core/agent-events.ts +17 -0
- package/src/core/artifact-evidence.ts +47 -4
- package/src/core/assertion.ts +41 -22
- package/src/core/case-authoring-state.ts +65 -0
- package/src/core/case.ts +57 -6
- package/src/core/driver-metrics.ts +51 -0
- package/src/core/driver.ts +3 -0
- package/src/core/events.ts +14 -2
- package/src/core/experiment.ts +2 -0
- package/src/core/index.ts +4 -0
- package/src/core/lifecycle-fixtures.ts +7 -2
- package/src/core/lifecycle-hooks.ts +16 -2
- package/src/core/run.ts +9 -0
- package/src/core/wire.ts +5 -1
- package/src/drivers/claude-code/parse-events.ts +98 -12
- package/src/drivers/codex/app-events.ts +116 -16
- package/src/drivers/codex/index.ts +16 -14
- package/src/drivers/subprocess/index.ts +6 -0
- package/src/index.ts +50 -6
- package/src/orchestrator/annotation-store.ts +5 -1
- package/src/orchestrator/case-extensions.ts +44 -0
- package/src/orchestrator/compare.ts +18 -0
- package/src/orchestrator/config.ts +0 -2
- package/src/orchestrator/doctor.ts +5 -3
- package/src/orchestrator/experiment-evaluation.ts +23 -0
- package/src/orchestrator/grading.ts +21 -2
- package/src/orchestrator/index.ts +1 -0
- package/src/orchestrator/list-runs.ts +66 -5
- package/src/orchestrator/loader.ts +2 -0
- package/src/orchestrator/orchestrator.ts +86 -40
- package/src/orchestrator/owned-lock.ts +54 -34
- package/src/orchestrator/regrade.ts +8 -7
- package/src/orchestrator/run-execution.ts +24 -3
- package/src/orchestrator/suite-summary.ts +101 -8
- package/src/previewer/artifacts.ts +221 -0
- package/src/previewer/server.ts +765 -0
- package/viewer/app.css +2075 -0
- package/viewer/app.js +606 -0
- package/viewer/artifact-view.js +48 -0
- package/viewer/charts.js +86 -0
- package/viewer/detail.js +1214 -0
- package/viewer/format.js +129 -0
- package/viewer/index.html +151 -0
- package/lib/answerers/scripted/index.d.ts +0 -8
- package/lib/answerers/scripted/index.d.ts.map +0 -1
- package/lib/answerers/scripted/index.js +0 -163
- package/lib/answerers/scripted/index.js.map +0 -1
- package/src/answerers/scripted/index.ts +0 -186
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import {
|
|
3
|
+
type AgentAttribution,
|
|
3
4
|
type Interrupt,
|
|
4
5
|
type ParsedDriverEvent,
|
|
5
6
|
parseAgentUsage,
|
|
@@ -8,6 +9,39 @@ import {
|
|
|
8
9
|
toolResultProgress,
|
|
9
10
|
} from "../../core/index.js";
|
|
10
11
|
|
|
12
|
+
const claudeAgent = (parentToolUseId?: string): AgentAttribution =>
|
|
13
|
+
parentToolUseId
|
|
14
|
+
? {
|
|
15
|
+
id: `claude-code:${parentToolUseId}`,
|
|
16
|
+
role: "subagent",
|
|
17
|
+
parentId: "claude-code",
|
|
18
|
+
spawnToolUseId: parentToolUseId,
|
|
19
|
+
}
|
|
20
|
+
: { id: "claude-code", role: "main" };
|
|
21
|
+
|
|
22
|
+
const isSubagentTool = (name: string): boolean => name === "Agent" || name === "Task";
|
|
23
|
+
|
|
24
|
+
const spawnedClaudeAgent = (
|
|
25
|
+
toolUseId: string,
|
|
26
|
+
input: unknown,
|
|
27
|
+
parentToolUseId?: string,
|
|
28
|
+
): AgentAttribution => {
|
|
29
|
+
const details =
|
|
30
|
+
typeof input === "object" && input !== null ? (input as Record<string, unknown>) : {};
|
|
31
|
+
const name = [details.name, details.subagent_type, details.agent, details.role].find(
|
|
32
|
+
(value): value is string => typeof value === "string" && value.length > 0,
|
|
33
|
+
);
|
|
34
|
+
const model = typeof details.model === "string" && details.model ? details.model : undefined;
|
|
35
|
+
return {
|
|
36
|
+
id: `claude-code:${toolUseId}`,
|
|
37
|
+
role: "subagent",
|
|
38
|
+
parentId: claudeAgent(parentToolUseId).id,
|
|
39
|
+
spawnToolUseId: toolUseId,
|
|
40
|
+
...(name ? { name } : {}),
|
|
41
|
+
...(model ? { model } : {}),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
11
45
|
const ContentBlockSchema = z.discriminatedUnion("type", [
|
|
12
46
|
z.object({ type: z.literal("text"), text: z.string() }),
|
|
13
47
|
z.object({ type: z.literal("tool_use"), id: z.string(), name: z.string(), input: z.unknown() }),
|
|
@@ -88,6 +122,7 @@ type PendingTurn = {
|
|
|
88
122
|
asked: boolean;
|
|
89
123
|
thought: boolean;
|
|
90
124
|
text?: string;
|
|
125
|
+
agent: AgentAttribution;
|
|
91
126
|
};
|
|
92
127
|
|
|
93
128
|
type AssistantContent = {
|
|
@@ -96,6 +131,7 @@ type AssistantContent = {
|
|
|
96
131
|
asked: boolean;
|
|
97
132
|
thought: boolean;
|
|
98
133
|
firstText?: string;
|
|
134
|
+
agent: AgentAttribution;
|
|
99
135
|
};
|
|
100
136
|
|
|
101
137
|
const questionTextOf = (raw: unknown): string =>
|
|
@@ -225,6 +261,30 @@ class ClaudeEventParser {
|
|
|
225
261
|
if (!block) continue;
|
|
226
262
|
events.push(block);
|
|
227
263
|
if (block.tag !== "progress") continue;
|
|
264
|
+
const resultPayload = block.progress.payload as {
|
|
265
|
+
name?: unknown;
|
|
266
|
+
toolUseId?: unknown;
|
|
267
|
+
isError?: unknown;
|
|
268
|
+
};
|
|
269
|
+
if (
|
|
270
|
+
typeof resultPayload.name === "string" &&
|
|
271
|
+
isSubagentTool(resultPayload.name) &&
|
|
272
|
+
typeof resultPayload.toolUseId === "string"
|
|
273
|
+
) {
|
|
274
|
+
events.push({
|
|
275
|
+
tag: "progress",
|
|
276
|
+
progress: {
|
|
277
|
+
id: `agent-completed-${resultPayload.toolUseId}`,
|
|
278
|
+
kind: "agent-completed",
|
|
279
|
+
payload: {
|
|
280
|
+
agentId: `claude-code:${resultPayload.toolUseId}`,
|
|
281
|
+
status: resultPayload.isError === true ? "failed" : "completed",
|
|
282
|
+
},
|
|
283
|
+
agent: claudeAgent(),
|
|
284
|
+
ts: block.progress.ts,
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
}
|
|
228
288
|
const text = (block.progress.payload as { text?: unknown }).text;
|
|
229
289
|
const failure = typeof text === "string" ? toolInfrastructureFailure(text) : null;
|
|
230
290
|
if (failure) {
|
|
@@ -244,20 +304,21 @@ class ClaudeEventParser {
|
|
|
244
304
|
|
|
245
305
|
const toolUseId = block.tool_use_id;
|
|
246
306
|
const content = block.content ?? [];
|
|
307
|
+
const progress = toolResultProgress(
|
|
308
|
+
this.eventSequence++,
|
|
309
|
+
{
|
|
310
|
+
name: this.toolNames.get(toolUseId) ?? "unknown",
|
|
311
|
+
toolUseId,
|
|
312
|
+
content,
|
|
313
|
+
isError: block.is_error === true,
|
|
314
|
+
text: toolResultText(content),
|
|
315
|
+
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
316
|
+
},
|
|
317
|
+
Date.now(),
|
|
318
|
+
);
|
|
247
319
|
return {
|
|
248
320
|
tag: "progress",
|
|
249
|
-
progress:
|
|
250
|
-
this.eventSequence++,
|
|
251
|
-
{
|
|
252
|
-
name: this.toolNames.get(toolUseId) ?? "unknown",
|
|
253
|
-
toolUseId,
|
|
254
|
-
content,
|
|
255
|
-
isError: block.is_error === true,
|
|
256
|
-
text: toolResultText(content),
|
|
257
|
-
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
258
|
-
},
|
|
259
|
-
Date.now(),
|
|
260
|
-
),
|
|
321
|
+
progress: { ...progress, agent: claudeAgent(parentToolUseId) },
|
|
261
322
|
};
|
|
262
323
|
}
|
|
263
324
|
|
|
@@ -284,6 +345,7 @@ class ClaudeEventParser {
|
|
|
284
345
|
tools: [],
|
|
285
346
|
asked: false,
|
|
286
347
|
thought: false,
|
|
348
|
+
agent: claudeAgent(event.parent_tool_use_id),
|
|
287
349
|
};
|
|
288
350
|
for (const rawBlock of event.message.content) {
|
|
289
351
|
const block = ContentBlockSchema.safeParse(rawBlock).data;
|
|
@@ -323,6 +385,7 @@ class ClaudeEventParser {
|
|
|
323
385
|
kind: "agent-message",
|
|
324
386
|
payload: { text, ...(parentToolUseId ? { parentToolUseId } : {}) },
|
|
325
387
|
ts: Date.now(),
|
|
388
|
+
agent: claudeAgent(parentToolUseId),
|
|
326
389
|
},
|
|
327
390
|
});
|
|
328
391
|
}
|
|
@@ -354,8 +417,29 @@ class ClaudeEventParser {
|
|
|
354
417
|
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
355
418
|
},
|
|
356
419
|
ts: Date.now(),
|
|
420
|
+
agent: claudeAgent(parentToolUseId),
|
|
357
421
|
},
|
|
358
422
|
});
|
|
423
|
+
if (isSubagentTool(block.name)) {
|
|
424
|
+
const agent = spawnedClaudeAgent(block.id, block.input, parentToolUseId);
|
|
425
|
+
const details =
|
|
426
|
+
typeof block.input === "object" && block.input !== null
|
|
427
|
+
? (block.input as Record<string, unknown>)
|
|
428
|
+
: {};
|
|
429
|
+
content.events.push({
|
|
430
|
+
tag: "progress",
|
|
431
|
+
progress: {
|
|
432
|
+
id: `agent-spawn-${block.id}`,
|
|
433
|
+
kind: "agent-spawn",
|
|
434
|
+
payload: {
|
|
435
|
+
agent,
|
|
436
|
+
...(typeof details.prompt === "string" ? { prompt: details.prompt } : {}),
|
|
437
|
+
},
|
|
438
|
+
agent: claudeAgent(parentToolUseId),
|
|
439
|
+
ts: Date.now(),
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
}
|
|
359
443
|
}
|
|
360
444
|
|
|
361
445
|
private recordTurn(
|
|
@@ -376,6 +460,7 @@ class ClaudeEventParser {
|
|
|
376
460
|
tools: [],
|
|
377
461
|
asked: false,
|
|
378
462
|
thought: false,
|
|
463
|
+
agent: content.agent,
|
|
379
464
|
};
|
|
380
465
|
this.pendingTurn.usage = usage;
|
|
381
466
|
this.pendingTurn.asked ||= content.asked;
|
|
@@ -451,6 +536,7 @@ class ClaudeEventParser {
|
|
|
451
536
|
kind: "usage",
|
|
452
537
|
payload: { ...this.pendingTurn.usage, ...(label ? { label } : {}) },
|
|
453
538
|
ts: Date.now(),
|
|
539
|
+
agent: this.pendingTurn.agent,
|
|
454
540
|
},
|
|
455
541
|
};
|
|
456
542
|
this.pendingTurn = null;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type AgentAttribution,
|
|
2
3
|
type ParsedDriverEvent,
|
|
4
|
+
type Progress,
|
|
3
5
|
type TokenUsage,
|
|
4
6
|
TURN_GLYPHS,
|
|
5
7
|
toolResultProgress,
|
|
@@ -20,8 +22,98 @@ const resultText = (content: unknown): string => {
|
|
|
20
22
|
.join("\n");
|
|
21
23
|
};
|
|
22
24
|
|
|
25
|
+
const agentCompletionStatus = (status: unknown): "completed" | "failed" | "cancelled" => {
|
|
26
|
+
if (status === "failed") return "failed";
|
|
27
|
+
if (status === "cancelled" || status === "interrupted") return "cancelled";
|
|
28
|
+
return "completed";
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const appAgentLifecycleProgress = (
|
|
32
|
+
item: RpcRecord,
|
|
33
|
+
phase: "started" | "completed",
|
|
34
|
+
actor?: AgentAttribution,
|
|
35
|
+
ts = Date.now(),
|
|
36
|
+
): Progress[] => {
|
|
37
|
+
if (item.type !== "collabAgentToolCall" || typeof item.id !== "string") return [];
|
|
38
|
+
const receiverThreadIds = Array.isArray(item.receiverThreadIds)
|
|
39
|
+
? item.receiverThreadIds.filter((value): value is string => typeof value === "string")
|
|
40
|
+
: [];
|
|
41
|
+
const completionStatus = agentCompletionStatus(item.status);
|
|
42
|
+
return receiverThreadIds.map((receiverThreadId) =>
|
|
43
|
+
phase === "started"
|
|
44
|
+
? {
|
|
45
|
+
id: `agent-spawn-${item.id}-${receiverThreadId}`,
|
|
46
|
+
kind: "agent-spawn",
|
|
47
|
+
payload: {
|
|
48
|
+
agent: {
|
|
49
|
+
id: receiverThreadId,
|
|
50
|
+
role: "subagent",
|
|
51
|
+
parentId: actor?.id ?? "codex",
|
|
52
|
+
spawnToolUseId: item.id as string,
|
|
53
|
+
...(typeof item.model === "string" ? { model: item.model } : {}),
|
|
54
|
+
},
|
|
55
|
+
...(typeof item.prompt === "string" ? { prompt: item.prompt } : {}),
|
|
56
|
+
},
|
|
57
|
+
...(actor ? { agent: actor } : {}),
|
|
58
|
+
ts,
|
|
59
|
+
}
|
|
60
|
+
: {
|
|
61
|
+
id: `agent-completed-${item.id}-${receiverThreadId}`,
|
|
62
|
+
kind: "agent-completed",
|
|
63
|
+
payload: {
|
|
64
|
+
agentId: receiverThreadId,
|
|
65
|
+
status: completionStatus,
|
|
66
|
+
},
|
|
67
|
+
...(actor ? { agent: actor } : {}),
|
|
68
|
+
ts,
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
23
73
|
export type RpcId = string | number;
|
|
24
74
|
export type RpcRecord = Record<string, unknown>;
|
|
75
|
+
|
|
76
|
+
export class CodexSubagentTracker {
|
|
77
|
+
private readonly spawnToolByThread = new Map<string, string>();
|
|
78
|
+
private readonly parentAgentByThread = new Map<string, string>();
|
|
79
|
+
|
|
80
|
+
record(
|
|
81
|
+
item: RpcRecord | null,
|
|
82
|
+
spawningThreadId: string | undefined,
|
|
83
|
+
mainThreadId: string | null,
|
|
84
|
+
): void {
|
|
85
|
+
if (item?.type !== "collabAgentToolCall" || typeof item.id !== "string") return;
|
|
86
|
+
const receiverThreadIds = Array.isArray(item.receiverThreadIds)
|
|
87
|
+
? item.receiverThreadIds.filter((value): value is string => typeof value === "string")
|
|
88
|
+
: [];
|
|
89
|
+
for (const receiverThreadId of receiverThreadIds) {
|
|
90
|
+
this.spawnToolByThread.set(receiverThreadId, item.id);
|
|
91
|
+
if (spawningThreadId) {
|
|
92
|
+
this.parentAgentByThread.set(
|
|
93
|
+
receiverThreadId,
|
|
94
|
+
spawningThreadId === mainThreadId ? "codex" : spawningThreadId,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
attribution(
|
|
101
|
+
threadId: string | undefined,
|
|
102
|
+
mainThreadId: string | null,
|
|
103
|
+
): AgentAttribution | undefined {
|
|
104
|
+
if (!threadId) return undefined;
|
|
105
|
+
const spawnToolUseId = this.spawnToolByThread.get(threadId);
|
|
106
|
+
if (!spawnToolUseId) {
|
|
107
|
+
return { id: threadId === mainThreadId ? "codex" : threadId, role: "main" };
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
id: threadId,
|
|
111
|
+
role: "subagent",
|
|
112
|
+
parentId: this.parentAgentByThread.get(threadId) ?? mainThreadId ?? "codex",
|
|
113
|
+
spawnToolUseId,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
25
117
|
export type AppTurnFacets = {
|
|
26
118
|
tools: string[];
|
|
27
119
|
asked: boolean;
|
|
@@ -131,8 +223,10 @@ const appItemResultText = (item: RpcRecord, error: RpcRecord | null, content: un
|
|
|
131
223
|
export const appItemProgress = (
|
|
132
224
|
item: RpcRecord,
|
|
133
225
|
phase: "started" | "completed",
|
|
134
|
-
|
|
226
|
+
attribution?: AgentAttribution | string,
|
|
135
227
|
): ParsedDriverEvent | null => {
|
|
228
|
+
const agent = typeof attribution === "string" ? undefined : attribution;
|
|
229
|
+
const parentToolUseId = typeof attribution === "string" ? attribution : agent?.spawnToolUseId;
|
|
136
230
|
const id = typeof item.id === "string" ? item.id : `${String(item.type)}-${Date.now()}`;
|
|
137
231
|
if (item.type === "agentMessage" && phase === "completed" && typeof item.text === "string") {
|
|
138
232
|
return {
|
|
@@ -142,6 +236,7 @@ export const appItemProgress = (
|
|
|
142
236
|
kind: "agent-message",
|
|
143
237
|
payload: { text: item.text, ...(parentToolUseId ? { parentToolUseId } : {}) },
|
|
144
238
|
ts: Date.now(),
|
|
239
|
+
...(agent ? { agent } : {}),
|
|
145
240
|
},
|
|
146
241
|
};
|
|
147
242
|
}
|
|
@@ -162,6 +257,7 @@ export const appItemProgress = (
|
|
|
162
257
|
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
163
258
|
},
|
|
164
259
|
ts: Date.now(),
|
|
260
|
+
...(agent ? { agent } : {}),
|
|
165
261
|
},
|
|
166
262
|
};
|
|
167
263
|
}
|
|
@@ -184,6 +280,7 @@ export const appItemProgress = (
|
|
|
184
280
|
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
185
281
|
},
|
|
186
282
|
ts: Date.now(),
|
|
283
|
+
...(agent ? { agent } : {}),
|
|
187
284
|
},
|
|
188
285
|
};
|
|
189
286
|
}
|
|
@@ -199,20 +296,23 @@ export const appItemProgress = (
|
|
|
199
296
|
error !== null;
|
|
200
297
|
return {
|
|
201
298
|
tag: "progress",
|
|
202
|
-
progress:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
299
|
+
progress: {
|
|
300
|
+
...toolResultProgress(
|
|
301
|
+
0,
|
|
302
|
+
{
|
|
303
|
+
name: tool,
|
|
304
|
+
toolUseId: id,
|
|
305
|
+
content,
|
|
306
|
+
...(asRecord(structuredContent)
|
|
307
|
+
? { structuredContent: asRecord(structuredContent) ?? {} }
|
|
308
|
+
: {}),
|
|
309
|
+
isError,
|
|
310
|
+
text: appItemResultText(item, error, content),
|
|
311
|
+
...(parentToolUseId ? { parentToolUseId } : {}),
|
|
312
|
+
},
|
|
313
|
+
Date.now(),
|
|
314
|
+
),
|
|
315
|
+
...(agent ? { agent } : {}),
|
|
316
|
+
},
|
|
217
317
|
};
|
|
218
318
|
};
|
|
@@ -24,11 +24,13 @@ import { copyRegularFileNoFollow } from "../shared/secure-copy.js";
|
|
|
24
24
|
import { subprocessDriver } from "../subprocess/index.js";
|
|
25
25
|
import {
|
|
26
26
|
type AppTurnFacets,
|
|
27
|
+
appAgentLifecycleProgress,
|
|
27
28
|
appItemProgress,
|
|
28
29
|
appItemToolName,
|
|
29
30
|
appTurnLabel,
|
|
30
31
|
appUsage,
|
|
31
32
|
asRecord,
|
|
33
|
+
CodexSubagentTracker,
|
|
32
34
|
messageOf,
|
|
33
35
|
type RpcId,
|
|
34
36
|
type RpcRecord,
|
|
@@ -316,7 +318,7 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
316
318
|
{ resolve: (result: RpcRecord) => void; reject: (error: Error) => void }
|
|
317
319
|
>();
|
|
318
320
|
private readonly interrupts = new Map<string, { id: RpcId; method: string; params: RpcRecord }>();
|
|
319
|
-
private readonly
|
|
321
|
+
private readonly subagents = new CodexSubagentTracker();
|
|
320
322
|
private readonly turnFacets = new Map<string, AppTurnFacets>();
|
|
321
323
|
private interruptCount = 0;
|
|
322
324
|
private idleTimer: NodeJS.Timeout | null = null;
|
|
@@ -702,22 +704,22 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
702
704
|
const toolName = item ? appItemToolName(item) : null;
|
|
703
705
|
if (toolName && !facets.tools.includes(toolName)) facets.tools.push(toolName);
|
|
704
706
|
if (turnId) this.turnFacets.set(turnId, facets);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
707
|
+
const threadId = typeof params.threadId === "string" ? params.threadId : undefined;
|
|
708
|
+
this.subagents.record(item, threadId, this.threadId);
|
|
709
|
+
const agent = this.subagents.attribution(threadId, this.threadId);
|
|
708
710
|
const event = item
|
|
709
|
-
? appItemProgress(item, method === "item/started" ? "started" : "completed",
|
|
711
|
+
? appItemProgress(item, method === "item/started" ? "started" : "completed", agent)
|
|
710
712
|
: null;
|
|
711
713
|
if (event?.tag === "progress") await this.emitter.emit("progress", event.progress);
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
714
|
+
if (item) {
|
|
715
|
+
for (const lifecycle of appAgentLifecycleProgress(
|
|
716
|
+
item,
|
|
717
|
+
method === "item/started" ? "started" : "completed",
|
|
718
|
+
agent,
|
|
719
|
+
event?.tag === "progress" ? event.progress.ts : Date.now(),
|
|
720
|
+
)) {
|
|
721
|
+
await this.emitter.emit("progress", lifecycle);
|
|
722
|
+
}
|
|
721
723
|
}
|
|
722
724
|
}
|
|
723
725
|
|
|
@@ -82,6 +82,7 @@ const KILL_GRACE_MS = 5_000;
|
|
|
82
82
|
const DEFAULT_MAX_LINE_BYTES = 10_000_000;
|
|
83
83
|
const MAX_STDERR_TAIL_CHARS = 8_192;
|
|
84
84
|
const DEFAULT_MAX_ARTIFACT_FILES = 500;
|
|
85
|
+
const MAX_FIXTURE_VALUES_BYTES = 64 * 1024;
|
|
85
86
|
const ARTIFACT_SNAPSHOT_MODULE = fileURLToPath(
|
|
86
87
|
new URL("../../core/artifact-snapshot.js", import.meta.url),
|
|
87
88
|
);
|
|
@@ -139,6 +140,10 @@ class SubprocessDriverImpl implements AgentDriver {
|
|
|
139
140
|
|
|
140
141
|
async start(ctx: StartContext): Promise<ReadyState> {
|
|
141
142
|
this.artifactsDir = ctx.artifactsDir;
|
|
143
|
+
const fixtureValues = JSON.stringify(ctx.fixtureValues ?? []);
|
|
144
|
+
if (Buffer.byteLength(fixtureValues) > MAX_FIXTURE_VALUES_BYTES) {
|
|
145
|
+
throw new Error(`subprocess fixture values exceed ${MAX_FIXTURE_VALUES_BYTES} bytes`);
|
|
146
|
+
}
|
|
142
147
|
const managed = spawnManagedProcess(this.config.command, this.config.args ?? [], {
|
|
143
148
|
cwd: this.config.cwd ?? ctx.runDir,
|
|
144
149
|
env: {
|
|
@@ -147,6 +152,7 @@ class SubprocessDriverImpl implements AgentDriver {
|
|
|
147
152
|
...(ctx.caseId ? { LUX_CASE_ID: ctx.caseId } : {}),
|
|
148
153
|
LUX_RUN_DIR: ctx.runDir,
|
|
149
154
|
LUX_ARTIFACTS_DIR: ctx.artifactsDir,
|
|
155
|
+
LUX_FIXTURE_VALUES: fixtureValues,
|
|
150
156
|
LUX_PROMPT: ctx.prompt,
|
|
151
157
|
LUX_ARTIFACT_SNAPSHOT_MODULE: ARTIFACT_SNAPSHOT_MODULE,
|
|
152
158
|
},
|
package/src/index.ts
CHANGED
|
@@ -16,16 +16,15 @@ export {
|
|
|
16
16
|
PersonaAnswererConfigSchema,
|
|
17
17
|
personaAnswerer,
|
|
18
18
|
} from "./answerers/persona/index.js";
|
|
19
|
-
export {
|
|
20
|
-
type ScriptedAnswererConfig,
|
|
21
|
-
ScriptedAnswererConfigSchema,
|
|
22
|
-
scriptedAnswerer,
|
|
23
|
-
} from "./answerers/scripted/index.js";
|
|
24
19
|
export {
|
|
25
20
|
type TerminalAnswererConfig,
|
|
26
21
|
TerminalAnswererConfigSchema,
|
|
27
22
|
terminalAnswerer,
|
|
28
23
|
} from "./answerers/terminal/index.js";
|
|
24
|
+
export {
|
|
25
|
+
type BuiltinAssertion,
|
|
26
|
+
defineEvalCase,
|
|
27
|
+
} from "./assertions/authoring.js";
|
|
29
28
|
// Bundled deterministic and judge assertions.
|
|
30
29
|
export {
|
|
31
30
|
type AgentScope,
|
|
@@ -88,6 +87,8 @@ export {
|
|
|
88
87
|
registerCoreAssertions,
|
|
89
88
|
runSucceededAssertion,
|
|
90
89
|
subagentToolCalls,
|
|
90
|
+
type TimeToFirstActionUnderConfig,
|
|
91
|
+
TimeToFirstActionUnderConfigSchema,
|
|
91
92
|
type TokensUnderConfig,
|
|
92
93
|
TokensUnderConfigSchema,
|
|
93
94
|
type ToolCall,
|
|
@@ -105,6 +106,7 @@ export {
|
|
|
105
106
|
ToolResultIsErrorConfigSchema,
|
|
106
107
|
type ToolResultJsonPointerEqualsConfig,
|
|
107
108
|
ToolResultJsonPointerEqualsConfigSchema,
|
|
109
|
+
timeToFirstActionUnderAssertion,
|
|
108
110
|
tokensUnderAssertion,
|
|
109
111
|
toolCallCountAssertion,
|
|
110
112
|
toolCalledAssertion,
|
|
@@ -142,6 +144,28 @@ export {
|
|
|
142
144
|
rubricAssertion,
|
|
143
145
|
} from "./assertions/rubric/index.js";
|
|
144
146
|
// Authoring and extension contracts.
|
|
147
|
+
export {
|
|
148
|
+
type ActionCategory,
|
|
149
|
+
ActionCategorySchema,
|
|
150
|
+
type ActionProgressPayload,
|
|
151
|
+
ActionProgressPayloadSchema,
|
|
152
|
+
type ActionTiming,
|
|
153
|
+
ActionTimingSchema,
|
|
154
|
+
actionTiming,
|
|
155
|
+
} from "./core/action-events.js";
|
|
156
|
+
export {
|
|
157
|
+
type AgentActivity,
|
|
158
|
+
AgentActivitySchema,
|
|
159
|
+
summarizeAgentActivity,
|
|
160
|
+
} from "./core/agent-activity.js";
|
|
161
|
+
export {
|
|
162
|
+
AGENT_COMPLETED_KIND,
|
|
163
|
+
AGENT_SPAWN_KIND,
|
|
164
|
+
type AgentCompletedPayload,
|
|
165
|
+
AgentCompletedPayloadSchema,
|
|
166
|
+
type AgentSpawnPayload,
|
|
167
|
+
AgentSpawnPayloadSchema,
|
|
168
|
+
} from "./core/agent-events.js";
|
|
145
169
|
export {
|
|
146
170
|
defineGraderAnnotations,
|
|
147
171
|
type GraderAnnotation,
|
|
@@ -185,6 +209,7 @@ export {
|
|
|
185
209
|
type AssertionResult,
|
|
186
210
|
AssertionResultSchema,
|
|
187
211
|
defineAssertion,
|
|
212
|
+
defineAssertionRegistry,
|
|
188
213
|
type EvaluateContext,
|
|
189
214
|
type GradingAssertionEntry,
|
|
190
215
|
GradingAssertionEntrySchema,
|
|
@@ -198,8 +223,9 @@ export {
|
|
|
198
223
|
AssertionSchema,
|
|
199
224
|
type DriverRef,
|
|
200
225
|
DriverRefSchema,
|
|
201
|
-
defineEvalCase,
|
|
202
226
|
type EvalCase,
|
|
227
|
+
type EvalCaseAuthoringOptions,
|
|
228
|
+
type EvalCaseDefinition,
|
|
203
229
|
EvalCaseSchema,
|
|
204
230
|
type FixturesRef,
|
|
205
231
|
FixturesRefSchema,
|
|
@@ -226,8 +252,23 @@ export {
|
|
|
226
252
|
ResolvedFixturesSchema,
|
|
227
253
|
type StartContext,
|
|
228
254
|
} from "./core/driver.js";
|
|
255
|
+
export {
|
|
256
|
+
type DriverMetric,
|
|
257
|
+
type DriverMetricDescriptor,
|
|
258
|
+
DriverMetricDescriptorSchema,
|
|
259
|
+
DriverMetricSchema,
|
|
260
|
+
type DriverMetrics,
|
|
261
|
+
DriverMetricsSchema,
|
|
262
|
+
type DriverMetricUnit,
|
|
263
|
+
DriverMetricUnitSchema,
|
|
264
|
+
normalizeDriverMetrics,
|
|
265
|
+
type ReportedDriverMetrics,
|
|
266
|
+
ReportedDriverMetricsSchema,
|
|
267
|
+
} from "./core/driver-metrics.js";
|
|
229
268
|
export { type EventHandler, TypedEmitter } from "./core/emitter.js";
|
|
230
269
|
export {
|
|
270
|
+
type AgentAttribution,
|
|
271
|
+
AgentAttributionSchema,
|
|
231
272
|
type Answer,
|
|
232
273
|
AnswerSchema,
|
|
233
274
|
ApproveAnswerSchema,
|
|
@@ -300,6 +341,9 @@ export {
|
|
|
300
341
|
export {
|
|
301
342
|
type CaseLifecycleHookContext,
|
|
302
343
|
defineLifecycleHooks,
|
|
344
|
+
type FixtureValue,
|
|
345
|
+
type FixtureValueBinding,
|
|
346
|
+
FixtureValueSchema,
|
|
303
347
|
type LifecycleHookCleanup,
|
|
304
348
|
type LifecycleHookSetupResult,
|
|
305
349
|
type LifecycleHooksPlugin,
|
|
@@ -57,6 +57,7 @@ const recoverStaleLock = async (lockPath: string): Promise<boolean> => {
|
|
|
57
57
|
const acquireAnnotationLock = async (path: string): Promise<() => Promise<void>> => {
|
|
58
58
|
const lockPath = `${path}.lock`;
|
|
59
59
|
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
60
|
+
let attemptedRecovery = false;
|
|
60
61
|
while (true) {
|
|
61
62
|
try {
|
|
62
63
|
const owner = await publishOwnedLock(lockPath, {
|
|
@@ -69,7 +70,10 @@ const acquireAnnotationLock = async (path: string): Promise<() => Promise<void>>
|
|
|
69
70
|
};
|
|
70
71
|
} catch (error) {
|
|
71
72
|
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
72
|
-
if (
|
|
73
|
+
if (!attemptedRecovery) {
|
|
74
|
+
attemptedRecovery = true;
|
|
75
|
+
if (await recoverStaleLock(lockPath)) continue;
|
|
76
|
+
}
|
|
73
77
|
if (Date.now() >= deadline) {
|
|
74
78
|
throw new Error(`timed out waiting to update grader annotations: ${path}`);
|
|
75
79
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { evalCaseExtensions } from "../core/case-authoring-state.js";
|
|
2
|
+
import type {
|
|
3
|
+
EvalCase,
|
|
4
|
+
FixtureValueBinding,
|
|
5
|
+
LifecycleHooksPlugin,
|
|
6
|
+
Registry,
|
|
7
|
+
} from "../core/index.js";
|
|
8
|
+
|
|
9
|
+
export const registryForEvalCase = (registry: Registry, evalCase: EvalCase): Registry => {
|
|
10
|
+
let resolved = registry;
|
|
11
|
+
for (const plugin of evalCaseExtensions(evalCase).assertions) {
|
|
12
|
+
const existing = resolved.getAssertion(plugin.type);
|
|
13
|
+
if (existing === plugin) continue;
|
|
14
|
+
if (existing) {
|
|
15
|
+
throw new TypeError(
|
|
16
|
+
`case-local assertion '${plugin.type}' conflicts with a registered implementation`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
resolved = resolved.withAssertion(plugin);
|
|
20
|
+
}
|
|
21
|
+
return resolved;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const fixturesForEvalCase = (evalCase: EvalCase): readonly LifecycleHooksPlugin[] =>
|
|
25
|
+
evalCaseExtensions(evalCase).fixtures;
|
|
26
|
+
|
|
27
|
+
export const valuesForFixtures = (
|
|
28
|
+
fixtures: readonly LifecycleHooksPlugin[],
|
|
29
|
+
): FixtureValueBinding[] =>
|
|
30
|
+
fixtures.flatMap(({ name, value }) => (value === undefined ? [] : [{ name, value }]));
|
|
31
|
+
|
|
32
|
+
export const mergeLifecycleFixtures = (
|
|
33
|
+
...groups: readonly (readonly LifecycleHooksPlugin[])[]
|
|
34
|
+
): LifecycleHooksPlugin[] => {
|
|
35
|
+
const fixtures = new Map<string, LifecycleHooksPlugin>();
|
|
36
|
+
for (const fixture of groups.flat()) {
|
|
37
|
+
const existing = fixtures.get(fixture.name);
|
|
38
|
+
if (existing && existing !== fixture) {
|
|
39
|
+
throw new TypeError(`conflicting lifecycle fixture definitions for '${fixture.name}'`);
|
|
40
|
+
}
|
|
41
|
+
fixtures.set(fixture.name, fixture);
|
|
42
|
+
}
|
|
43
|
+
return [...fixtures.values()];
|
|
44
|
+
};
|
|
@@ -2,6 +2,9 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import {
|
|
5
|
+
type ActionTiming,
|
|
6
|
+
type AgentActivity,
|
|
7
|
+
type DriverMetrics,
|
|
5
8
|
emptyRunUsage,
|
|
6
9
|
type GradingReport,
|
|
7
10
|
GradingReportSchema,
|
|
@@ -48,6 +51,9 @@ export type RunComparison = {
|
|
|
48
51
|
exitReason: { a: string; b: string };
|
|
49
52
|
durationMsA: number | null;
|
|
50
53
|
durationMsB: number | null;
|
|
54
|
+
actionTiming: { a: ActionTiming; b: ActionTiming };
|
|
55
|
+
driverMetrics: { a: DriverMetrics; b: DriverMetrics };
|
|
56
|
+
agentActivity: { a: AgentActivity[]; b: AgentActivity[] };
|
|
51
57
|
interruptCounts: {
|
|
52
58
|
a: { ask: number; approve: number; custom: number };
|
|
53
59
|
b: { ask: number; approve: number; custom: number };
|
|
@@ -260,6 +266,18 @@ export const compareRuns = async (input: ComparisonInput): Promise<RunComparison
|
|
|
260
266
|
},
|
|
261
267
|
durationMsA: durationFromMeta(a.runJson),
|
|
262
268
|
durationMsB: durationFromMeta(b.runJson),
|
|
269
|
+
actionTiming: {
|
|
270
|
+
a: a.runJson?.actionTiming ?? {},
|
|
271
|
+
b: b.runJson?.actionTiming ?? {},
|
|
272
|
+
},
|
|
273
|
+
driverMetrics: {
|
|
274
|
+
a: a.runJson?.driverMetrics ?? {},
|
|
275
|
+
b: b.runJson?.driverMetrics ?? {},
|
|
276
|
+
},
|
|
277
|
+
agentActivity: {
|
|
278
|
+
a: a.runJson?.agentActivity ?? [],
|
|
279
|
+
b: b.runJson?.agentActivity ?? [],
|
|
280
|
+
},
|
|
263
281
|
interruptCounts: {
|
|
264
282
|
a: a.runJson?.interruptCounts ?? { ask: 0, approve: 0, custom: 0 },
|
|
265
283
|
b: b.runJson?.interruptCounts ?? { ask: 0, approve: 0, custom: 0 },
|
|
@@ -4,7 +4,6 @@ import { pathToFileURL } from "node:url";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { claudeCodeAnswerer } from "../answerers/claude-code/index.js";
|
|
6
6
|
import { personaAnswerer } from "../answerers/persona/index.js";
|
|
7
|
-
import { scriptedAnswerer } from "../answerers/scripted/index.js";
|
|
8
7
|
import { terminalAnswerer } from "../answerers/terminal/index.js";
|
|
9
8
|
import { allCoreAssertions } from "../assertions/core/index.js";
|
|
10
9
|
import { allMcpAssertions } from "../assertions/mcp/index.js";
|
|
@@ -182,7 +181,6 @@ const builtinDrivers: DriverPlugin<never>[] = [
|
|
|
182
181
|
const builtinAnswerers: AnswererPlugin<never>[] = [
|
|
183
182
|
personaAnswerer,
|
|
184
183
|
claudeCodeAnswerer,
|
|
185
|
-
scriptedAnswerer,
|
|
186
184
|
terminalAnswerer,
|
|
187
185
|
];
|
|
188
186
|
export const buildRegistryFromConfig = (config: ResolvedLuxConfig): Registry => {
|