@post-print/agent-test 1.1.0 → 1.1.2
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/README.md +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +34 -6
- package/dist/cli.js.map +1 -1
- package/dist/compare-scenario.d.ts +10 -0
- package/dist/compare-scenario.d.ts.map +1 -1
- package/dist/compare-scenario.js +48 -3
- package/dist/compare-scenario.js.map +1 -1
- package/dist/expect.d.ts +1 -0
- package/dist/expect.d.ts.map +1 -1
- package/dist/expect.js +24 -0
- package/dist/expect.js.map +1 -1
- package/dist/html-report.d.ts +4 -1
- package/dist/html-report.d.ts.map +1 -1
- package/dist/html-report.js +224 -143
- package/dist/html-report.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/live-isolation.d.ts +2 -0
- package/dist/live-isolation.d.ts.map +1 -1
- package/dist/live-isolation.js +8 -2
- package/dist/live-isolation.js.map +1 -1
- package/dist/report-preview.d.ts +24 -0
- package/dist/report-preview.d.ts.map +1 -1
- package/dist/report-preview.js +46 -2
- package/dist/report-preview.js.map +1 -1
- package/dist/run-suite.d.ts +10 -0
- package/dist/run-suite.d.ts.map +1 -1
- package/dist/run-suite.js +146 -126
- package/dist/run-suite.js.map +1 -1
- package/dist/scenario-finalizer.d.ts +27 -0
- package/dist/scenario-finalizer.d.ts.map +1 -0
- package/dist/scenario-finalizer.js +39 -0
- package/dist/scenario-finalizer.js.map +1 -0
- package/dist/scenario-story.d.ts.map +1 -1
- package/dist/scenario-story.js +14 -8
- package/dist/scenario-story.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-suite.d.ts.map +1 -1
- package/dist/validate-suite.js +1 -0
- package/dist/validate-suite.js.map +1 -1
- package/dist/viewer/catalog.d.ts +14 -3
- package/dist/viewer/catalog.d.ts.map +1 -1
- package/dist/viewer/catalog.js +33 -6
- package/dist/viewer/catalog.js.map +1 -1
- package/dist/viewer/compare-metrics.d.ts.map +1 -1
- package/dist/viewer/compare-metrics.js +8 -9
- package/dist/viewer/compare-metrics.js.map +1 -1
- package/dist/viewer/events.d.ts +22 -1
- package/dist/viewer/events.d.ts.map +1 -1
- package/dist/viewer/events.js +1 -0
- package/dist/viewer/events.js.map +1 -1
- package/dist/viewer/live-runner.d.ts +7 -0
- package/dist/viewer/live-runner.d.ts.map +1 -1
- package/dist/viewer/live-runner.js +36 -23
- package/dist/viewer/live-runner.js.map +1 -1
- package/dist/viewer/page.d.ts +14 -1
- package/dist/viewer/page.d.ts.map +1 -1
- package/dist/viewer/page.js +758 -141
- package/dist/viewer/page.js.map +1 -1
- package/dist/viewer/run-controller.d.ts +13 -6
- package/dist/viewer/run-controller.d.ts.map +1 -1
- package/dist/viewer/run-controller.js +246 -74
- package/dist/viewer/run-controller.js.map +1 -1
- package/dist/viewer/server.d.ts +5 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +72 -17
- package/dist/viewer/server.js.map +1 -1
- package/dist/viewer/session-server.d.ts +2 -0
- package/dist/viewer/session-server.d.ts.map +1 -0
- package/dist/viewer/session-server.js +71 -0
- package/dist/viewer/session-server.js.map +1 -0
- package/package.json +2 -2
package/dist/run-suite.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { basename, dirname, join, resolve } from "node:path";
|
|
3
3
|
import { buildHostPrompt, cancelActiveClaudeRun, cancelActiveCursorRun, cancelActiveOpenaiRun, captureWorkingTreeStatus, createSealedWorkspace, defaultSealedOverlayPaths, enrichTrace, filterWorkingTreeLeaks, findWorkingTreeLeak, formatWorkingTreeLeak, getProcessAuthMode, isBuiltinAgentHost, judgeCompareTraces, judgeTrace, loadContext, loadUnifiedDiffPaths, mergeMcpServers, parseScenarioWorkspace, partitionSeedCollateralLeaks, porcelainPathsFromLines, resolveAllowUserSkills, resolveHarnessArtifactIgnoreRoots, restoreWorkingTreePaths, runAgent, setProcessAuthMode, skillInvokeJudgeCriteria, skillPathsFromSetting, sumUsageParts, toolPathsOutsideWorkspace, traceEditsOutsideWorktree, traceHasUserInputTool, } from "@post-print/agent-harness";
|
|
4
|
-
import { applyCompareArm, applySidecarCompareDurations, assertCompareGates, attachCompareStoryResults, buildCompareResult, compareArmDescription, compareArmLabel, compareArmTokens, compareArmTurns, compareResultArms, compareStoryFields, evaluateCompareGates, plainDescription, prefixCompareFailures, requireCompareArm, resolveCompareArms, } from "./compare-scenario.js";
|
|
4
|
+
import { applyCompareArm, applySidecarCompareDurations, assertCompareGates, attachCompareStoryResults, buildCompareResult, compareArmDescription, compareArmLabel, compareArmTokens, compareArmTurns, compareResultArms, compareStoryFields, evaluateCompareGates, finalizeCompareGates, finalizeCompareOutcome, plainDescription, prefixCompareFailures, requireCompareArm, resolveCompareArms, } from "./compare-scenario.js";
|
|
5
5
|
import { collectDebugEnvironment, getDebugBundleDir, writeDebugBundle } from "./debug-bundle.js";
|
|
6
6
|
import { discoverSuites } from "./discover-suites.js";
|
|
7
7
|
import { assertRubric } from "./expect.js";
|
|
@@ -13,10 +13,11 @@ import { loadSuiteFile } from "./load-suite.js";
|
|
|
13
13
|
import { bindMcpServersToCaller, mcpStdioScriptPaths } from "./mcp-config.js";
|
|
14
14
|
import { formatDuration, logLive, logPhase, logProgress, logVerdict, refreshHeartbeat, withHeartbeat, } from "./progress.js";
|
|
15
15
|
import { cleanupStagingSession, createLiveStagingSessionId, getLiveStagingRootOverride, getLiveStagingSessionRoot, getStagingAgentStartPath, getStagingResultPath, getStagingTracePath, loadStagingResult, loadStagingTrace, recordTrace, resolveRecordingPath, setLiveStagingRootOverride, writeAgentStartMarker, writeStagingResult, } from "./record-trace.js";
|
|
16
|
+
import { finalizeScenarioResult } from "./scenario-finalizer.js";
|
|
16
17
|
import { resolveScenarioRetryMaxAttempts, shouldRetryAnnounceStopFlake } from "./scenario-retry.js";
|
|
17
18
|
import { captureCallerHead, restoreCallerHeadIfSeedCommit, seedScenarioWorktree, } from "./scenario-seed.js";
|
|
18
19
|
import { buildScenarioStory, pathFromArgs, quoteExcerpt } from "./scenario-story.js";
|
|
19
|
-
import {
|
|
20
|
+
import { totalTokensFromScenarioUsage } from "./scenario-usage.js";
|
|
20
21
|
import { summarizeReportResults } from "./suite-summary.js";
|
|
21
22
|
import { theme } from "./theme.js";
|
|
22
23
|
import { validateSuiteFile } from "./validate-suite.js";
|
|
@@ -190,6 +191,9 @@ function toJudgeVerdictResults(trace, criteria, verdictsFromJudge) {
|
|
|
190
191
|
question: questionForCriterion(criteria, extended.id),
|
|
191
192
|
pass: extended.pass,
|
|
192
193
|
rationale: extended.rationale,
|
|
194
|
+
evidence: extended.evidence,
|
|
195
|
+
prompt: extended.prompt,
|
|
196
|
+
response: extended.response,
|
|
193
197
|
infraError: extended.infraError,
|
|
194
198
|
parseError: extended.parseError,
|
|
195
199
|
rawSdkStatus: extended.rawSdkStatus,
|
|
@@ -529,44 +533,29 @@ async function runSuiteBody(options) {
|
|
|
529
533
|
}
|
|
530
534
|
}
|
|
531
535
|
const durationMs = Math.round(performance.now() - started);
|
|
532
|
-
const
|
|
533
|
-
const usageFields = buildScenarioResultUsage({
|
|
534
|
-
agentUsage: compareResult
|
|
535
|
-
? sumUsageParts(compareResultArms(compareResult).map((arm) => arm.trace?.usage))
|
|
536
|
-
: scenarioTrace?.usage,
|
|
537
|
-
judgeVerdicts,
|
|
538
|
-
});
|
|
539
|
-
const story = buildScenarioStory({
|
|
540
|
-
rubric: scenario.rubric,
|
|
541
|
-
trace: scenarioTrace,
|
|
542
|
-
passed,
|
|
543
|
-
failures,
|
|
544
|
-
judgeVerdicts,
|
|
545
|
-
compare: compareResult
|
|
546
|
-
? attachCompareStoryResults(compareStoryFields(scenario), compareResult)
|
|
547
|
-
: undefined,
|
|
548
|
-
});
|
|
549
|
-
const scenarioResult = {
|
|
536
|
+
const scenarioResult = finalizeScenarioResult({
|
|
550
537
|
suite: suite.name,
|
|
551
|
-
scenario
|
|
552
|
-
description: plainDescription(scenario.description),
|
|
553
|
-
prompt: scenario.prompt,
|
|
538
|
+
scenario,
|
|
554
539
|
contextMode: childSidecar?.contextMode ??
|
|
555
540
|
scenario.contextMode ??
|
|
556
541
|
suite.defaults?.contextMode ??
|
|
557
542
|
"harness-preamble",
|
|
558
543
|
contextFiles: childSidecar?.contextFiles,
|
|
559
544
|
hostInput: childSidecar?.hostInput,
|
|
560
|
-
passed,
|
|
561
545
|
failures,
|
|
562
546
|
durationMs,
|
|
563
547
|
attempts,
|
|
564
548
|
judgeVerdicts,
|
|
565
549
|
trace: scenarioTrace,
|
|
566
550
|
compare: compareResult,
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
551
|
+
storyCompare: compareResult
|
|
552
|
+
? attachCompareStoryResults(compareStoryFields(scenario), compareResult)
|
|
553
|
+
: undefined,
|
|
554
|
+
agentUsage: compareResult
|
|
555
|
+
? sumUsageParts(compareResultArms(compareResult).map((arm) => arm.trace?.usage))
|
|
556
|
+
: scenarioTrace?.usage,
|
|
557
|
+
});
|
|
558
|
+
const { passed, story } = scenarioResult;
|
|
570
559
|
const debugBundleDir = await maybeWriteDebugBundle({
|
|
571
560
|
debug,
|
|
572
561
|
cwd: options.cwd,
|
|
@@ -1073,33 +1062,19 @@ async function runAgentTestOnce(cwd, suiteName, scenario, defaultHost, defaultCo
|
|
|
1073
1062
|
}
|
|
1074
1063
|
worktreeHandle = undefined;
|
|
1075
1064
|
}
|
|
1076
|
-
const
|
|
1077
|
-
const story = buildScenarioStory({
|
|
1078
|
-
rubric: scenario.rubric,
|
|
1079
|
-
trace,
|
|
1080
|
-
passed,
|
|
1081
|
-
failures,
|
|
1082
|
-
judgeVerdicts,
|
|
1083
|
-
});
|
|
1084
|
-
const scenarioResult = {
|
|
1065
|
+
const scenarioResult = finalizeScenarioResult({
|
|
1085
1066
|
suite: suiteName,
|
|
1086
|
-
scenario
|
|
1087
|
-
description: plainDescription(scenario.description),
|
|
1088
|
-
prompt: scenario.prompt,
|
|
1067
|
+
scenario,
|
|
1089
1068
|
contextMode,
|
|
1090
1069
|
contextFiles,
|
|
1091
1070
|
hostInput,
|
|
1092
|
-
passed,
|
|
1093
1071
|
failures,
|
|
1094
1072
|
durationMs,
|
|
1095
1073
|
judgeVerdicts,
|
|
1096
1074
|
trace,
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
judgeVerdicts,
|
|
1101
|
-
}),
|
|
1102
|
-
};
|
|
1075
|
+
agentUsage: session.usage ?? trace?.usage,
|
|
1076
|
+
});
|
|
1077
|
+
const { passed, story } = scenarioResult;
|
|
1103
1078
|
const armMetrics = {
|
|
1104
1079
|
id: runOptions?.compareArm ?? "cell",
|
|
1105
1080
|
label: runOptions?.compareArm ?? "cell",
|
|
@@ -1157,6 +1132,11 @@ async function runAgentTestOnce(cwd, suiteName, scenario, defaultHost, defaultCo
|
|
|
1157
1132
|
authMode: getProcessAuthMode(),
|
|
1158
1133
|
});
|
|
1159
1134
|
scenarioResult.debugBundleDir = debugBundleDir;
|
|
1135
|
+
emitViewerEvent({
|
|
1136
|
+
type: "scenario_result",
|
|
1137
|
+
...viewerEnvelope,
|
|
1138
|
+
result: scenarioResult,
|
|
1139
|
+
});
|
|
1160
1140
|
emitScenarioVerdict({
|
|
1161
1141
|
passed,
|
|
1162
1142
|
index: scenarioIndex,
|
|
@@ -1234,60 +1214,18 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1234
1214
|
const result = await runAgentTestOnce(shared.cwd, shared.suiteName, armScenario, shared.defaultHost, shared.defaultContextMode, shared.defaultProfile, shared.defaultSkills, shared.defaultContextSources, shared.defaultMcpServers, shared.defaultWorkspace, shared.defaultAllowUserSkills, false, shared.worktree, shared.stagingSessionId, undefined, undefined, shared.timeoutMs, shared.allowUserInput, shared.debugFlag, shared.debugDir, shared.suitesDir, shared.keepRecordings, shared.rubricsDir, { suppressEmit: true, compareArm: entry.id, writeSidecar: false });
|
|
1235
1215
|
armRuns.push({ id: entry.id, label, scenario: armScenario, result });
|
|
1236
1216
|
}
|
|
1237
|
-
const experimentMode = (scenario.compare?.gates?.length ?? 0) > 0;
|
|
1238
|
-
const failures = armRuns.flatMap((arm) => prefixCompareFailures(arm.label, experimentMode
|
|
1239
|
-
? arm.result.failures.filter((failure) => failure.category !== "rubric_miss")
|
|
1240
|
-
: arm.result.failures));
|
|
1241
|
-
const compareResult = buildCompareResult(armRuns.map((arm) => ({
|
|
1242
|
-
id: arm.id,
|
|
1243
|
-
label: arm.label,
|
|
1244
|
-
description: compareArmDescription(resolvedArms.find((entry) => entry.id === arm.id)?.arm),
|
|
1245
|
-
prompt: arm.scenario.prompt,
|
|
1246
|
-
trace: arm.result.trace,
|
|
1247
|
-
contextMode: arm.result.contextMode,
|
|
1248
|
-
contextFiles: arm.result.contextFiles,
|
|
1249
|
-
hostInput: arm.result.hostInput,
|
|
1250
|
-
durationMs: arm.result.durationMs,
|
|
1251
|
-
passed: !arm.result.failures.some((failure) => failure.category === "rubric_miss"),
|
|
1252
|
-
failures: arm.result.failures,
|
|
1253
|
-
})), scenario.compare?.gates);
|
|
1254
|
-
if (judge && !isChildProcess() && scenario.compare?.judgeMetrics?.length) {
|
|
1255
|
-
for (const arm of compareResult.arms) {
|
|
1256
|
-
if (!arm.trace)
|
|
1257
|
-
continue;
|
|
1258
|
-
const judged = await runJudgeRubric(arm.trace, { judge: scenario.compare.judgeMetrics }, cwd, host);
|
|
1259
|
-
arm.trace = judged.trace;
|
|
1260
|
-
arm.judgeVerdicts = toJudgeVerdictResults(judged.trace, scenario.compare.judgeMetrics, judged.verdicts);
|
|
1261
|
-
arm.failures = [...(arm.failures ?? []), ...judged.failures];
|
|
1262
|
-
failures.push(...prefixCompareFailures(arm.label, judged.failures.filter((failure) => failure.category !== "rubric_miss")));
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
if (!isChildProcess()) {
|
|
1266
|
-
compareResult.gateResults = evaluateCompareGates(compareResult.gates, compareResult);
|
|
1267
|
-
if (failures.every((failure) => failure.category === "rubric_miss")) {
|
|
1268
|
-
failures.push(...assertCompareGates(compareResult.gates, compareResult));
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
const deferJudgeToParent = isChildProcess();
|
|
1272
|
-
const compareArms = compareResultArms(compareResult);
|
|
1273
|
-
const firstTrace = compareArms[0]?.trace;
|
|
1274
|
-
let judgeVerdicts;
|
|
1275
|
-
if (judge &&
|
|
1276
|
-
!deferJudgeToParent &&
|
|
1277
|
-
failures.every((failure) => failure.category === "rubric_miss") &&
|
|
1278
|
-
compareArms.length > 0 &&
|
|
1279
|
-
compareArms.every((arm) => arm.trace)) {
|
|
1280
|
-
const criteria = collectCompareJudgeCriteria(scenario.rubric);
|
|
1281
|
-
if (criteria.length > 0) {
|
|
1282
|
-
logPhase(theme.judgePhase(criteria.length), { last: true });
|
|
1283
|
-
}
|
|
1284
|
-
const judged = await runCompareJudgeRubric(compareResult, scenario.rubric, cwd, host);
|
|
1285
|
-
failures.push(...judged.failures);
|
|
1286
|
-
if (firstTrace) {
|
|
1287
|
-
judgeVerdicts = toJudgeVerdictResults({ ...firstTrace, judgeVerdicts: judged.verdicts }, criteria, judged.verdicts);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
1217
|
const durationMs = Math.round(performance.now() - started);
|
|
1218
|
+
const scenarioResult = await finalizeCompareArmRuns({
|
|
1219
|
+
cwd,
|
|
1220
|
+
suite: suiteName,
|
|
1221
|
+
scenario,
|
|
1222
|
+
host,
|
|
1223
|
+
armRuns,
|
|
1224
|
+
durationMs,
|
|
1225
|
+
judge: Boolean(judge && !isChildProcess()),
|
|
1226
|
+
evaluateGates: !isChildProcess(),
|
|
1227
|
+
});
|
|
1228
|
+
const { passed, story, failures, trace: firstTrace } = scenarioResult;
|
|
1291
1229
|
if (isChildProcess() && stagingSessionId) {
|
|
1292
1230
|
const sidecarArms = {};
|
|
1293
1231
|
for (const arm of armRuns) {
|
|
@@ -1309,32 +1247,6 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1309
1247
|
},
|
|
1310
1248
|
});
|
|
1311
1249
|
}
|
|
1312
|
-
const passed = failures.length === 0;
|
|
1313
|
-
const story = buildScenarioStory({
|
|
1314
|
-
rubric: scenario.rubric,
|
|
1315
|
-
trace: firstTrace,
|
|
1316
|
-
passed,
|
|
1317
|
-
failures,
|
|
1318
|
-
judgeVerdicts,
|
|
1319
|
-
compare: attachCompareStoryResults(compareStoryFields(scenario), compareResult),
|
|
1320
|
-
});
|
|
1321
|
-
const scenarioResult = {
|
|
1322
|
-
suite: suiteName,
|
|
1323
|
-
scenario: scenario.name,
|
|
1324
|
-
description: plainDescription(scenario.description),
|
|
1325
|
-
prompt: scenario.prompt,
|
|
1326
|
-
passed,
|
|
1327
|
-
failures,
|
|
1328
|
-
durationMs,
|
|
1329
|
-
judgeVerdicts,
|
|
1330
|
-
trace: firstTrace,
|
|
1331
|
-
compare: compareResult,
|
|
1332
|
-
story,
|
|
1333
|
-
...buildScenarioResultUsage({
|
|
1334
|
-
agentUsage: sumUsageParts(armRuns.map((arm) => arm.result.agentUsage)),
|
|
1335
|
-
judgeVerdicts,
|
|
1336
|
-
}),
|
|
1337
|
-
};
|
|
1338
1250
|
if (!suppressEmit) {
|
|
1339
1251
|
const debugBundleDir = await maybeWriteDebugBundle({
|
|
1340
1252
|
debug,
|
|
@@ -1356,6 +1268,13 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1356
1268
|
authMode: getProcessAuthMode(),
|
|
1357
1269
|
});
|
|
1358
1270
|
scenarioResult.debugBundleDir = debugBundleDir;
|
|
1271
|
+
emitViewerEvent({
|
|
1272
|
+
type: "scenario_result",
|
|
1273
|
+
suite: suiteName,
|
|
1274
|
+
scenario: scenario.name,
|
|
1275
|
+
host,
|
|
1276
|
+
result: scenarioResult,
|
|
1277
|
+
});
|
|
1359
1278
|
emitScenarioVerdict({
|
|
1360
1279
|
passed,
|
|
1361
1280
|
index: scenarioIndex,
|
|
@@ -1363,7 +1282,7 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1363
1282
|
name: scenario.name,
|
|
1364
1283
|
durationMs,
|
|
1365
1284
|
totalTokens: totalTokensFromScenarioUsage(scenarioResult.usage, firstTrace?.usage),
|
|
1366
|
-
judgeVerdicts,
|
|
1285
|
+
judgeVerdicts: scenarioResult.judgeVerdicts,
|
|
1367
1286
|
failures,
|
|
1368
1287
|
story,
|
|
1369
1288
|
debug,
|
|
@@ -1372,6 +1291,107 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1372
1291
|
}
|
|
1373
1292
|
return scenarioResult;
|
|
1374
1293
|
}
|
|
1294
|
+
async function finalizeCompareArmRuns(options) {
|
|
1295
|
+
const resolvedArms = resolveCompareArms(options.scenario.compare);
|
|
1296
|
+
const finalized = finalizeCompareOutcome(options.armRuns.map((arm) => ({
|
|
1297
|
+
id: arm.id,
|
|
1298
|
+
label: arm.label,
|
|
1299
|
+
description: compareArmDescription(resolvedArms.find((entry) => entry.id === arm.id)?.arm),
|
|
1300
|
+
prompt: arm.scenario.prompt,
|
|
1301
|
+
trace: arm.result.trace,
|
|
1302
|
+
contextMode: arm.result.contextMode,
|
|
1303
|
+
contextFiles: arm.result.contextFiles,
|
|
1304
|
+
hostInput: arm.result.hostInput,
|
|
1305
|
+
durationMs: arm.result.durationMs,
|
|
1306
|
+
passed: !arm.result.failures.some((failure) => failure.category === "rubric_miss"),
|
|
1307
|
+
failures: arm.result.failures,
|
|
1308
|
+
})), options.scenario.compare?.gates, { evaluateGates: false });
|
|
1309
|
+
const compareResult = finalized.compare;
|
|
1310
|
+
const failures = finalized.failures;
|
|
1311
|
+
if (options.judge && options.scenario.compare?.judgeMetrics?.length) {
|
|
1312
|
+
for (const arm of compareResult.arms) {
|
|
1313
|
+
if (!arm.trace)
|
|
1314
|
+
continue;
|
|
1315
|
+
const judged = await runJudgeRubric(arm.trace, { judge: options.scenario.compare.judgeMetrics }, options.cwd, options.host);
|
|
1316
|
+
arm.trace = judged.trace;
|
|
1317
|
+
arm.judgeVerdicts = toJudgeVerdictResults(judged.trace, options.scenario.compare.judgeMetrics, judged.verdicts);
|
|
1318
|
+
arm.failures = [...(arm.failures ?? []), ...judged.failures];
|
|
1319
|
+
failures.push(...prefixCompareFailures(arm.label, judged.failures.filter((failure) => failure.category !== "rubric_miss")));
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
if (options.evaluateGates)
|
|
1323
|
+
finalizeCompareGates(compareResult, failures);
|
|
1324
|
+
const compareArms = compareResultArms(compareResult);
|
|
1325
|
+
const firstTrace = compareArms[0]?.trace;
|
|
1326
|
+
let judgeVerdicts;
|
|
1327
|
+
if (options.judge &&
|
|
1328
|
+
failures.every((failure) => failure.category === "rubric_miss") &&
|
|
1329
|
+
compareArms.length > 0 &&
|
|
1330
|
+
compareArms.every((arm) => arm.trace)) {
|
|
1331
|
+
const criteria = collectCompareJudgeCriteria(options.scenario.rubric);
|
|
1332
|
+
if (criteria.length > 0)
|
|
1333
|
+
logPhase(theme.judgePhase(criteria.length), { last: true });
|
|
1334
|
+
const judged = await runCompareJudgeRubric(compareResult, options.scenario.rubric, options.cwd, options.host);
|
|
1335
|
+
failures.push(...judged.failures);
|
|
1336
|
+
if (firstTrace) {
|
|
1337
|
+
judgeVerdicts = toJudgeVerdictResults({ ...firstTrace, judgeVerdicts: judged.verdicts }, criteria, judged.verdicts);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
return finalizeScenarioResult({
|
|
1341
|
+
suite: options.suite,
|
|
1342
|
+
scenario: options.scenario,
|
|
1343
|
+
failures,
|
|
1344
|
+
durationMs: options.durationMs,
|
|
1345
|
+
judgeVerdicts,
|
|
1346
|
+
trace: firstTrace,
|
|
1347
|
+
compare: compareResult,
|
|
1348
|
+
storyCompare: attachCompareStoryResults(compareStoryFields(options.scenario), compareResult),
|
|
1349
|
+
agentUsage: sumUsageParts(options.armRuns.map((arm) => arm.result.agentUsage)),
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
/** Finalize viewer-scheduled compare arms through the same domain and judge path as the CLI. */
|
|
1353
|
+
export async function finalizeScheduledCompareScenario(options) {
|
|
1354
|
+
const compareArms = options.scenario.compare ?? [];
|
|
1355
|
+
const scenario = {
|
|
1356
|
+
name: options.scenario.name,
|
|
1357
|
+
description: options.scenario.description,
|
|
1358
|
+
prompt: options.scenario.prompt,
|
|
1359
|
+
rubric: options.scenario.rubric,
|
|
1360
|
+
compare: {
|
|
1361
|
+
arms: compareArms.map((arm) => ({
|
|
1362
|
+
id: arm.id,
|
|
1363
|
+
label: arm.label,
|
|
1364
|
+
description: arm.description,
|
|
1365
|
+
prompt: arm.prompt,
|
|
1366
|
+
})),
|
|
1367
|
+
gates: options.scenario.gates,
|
|
1368
|
+
judgeMetrics: options.scenario.judgeMetrics,
|
|
1369
|
+
},
|
|
1370
|
+
};
|
|
1371
|
+
const armRuns = compareArms.flatMap((arm) => {
|
|
1372
|
+
const result = options.armResults.get(arm.id);
|
|
1373
|
+
return result
|
|
1374
|
+
? [
|
|
1375
|
+
{
|
|
1376
|
+
id: arm.id,
|
|
1377
|
+
label: arm.label,
|
|
1378
|
+
scenario: applyCompareArm(scenario, arm.id),
|
|
1379
|
+
result,
|
|
1380
|
+
},
|
|
1381
|
+
]
|
|
1382
|
+
: [];
|
|
1383
|
+
});
|
|
1384
|
+
return finalizeCompareArmRuns({
|
|
1385
|
+
cwd: options.cwd,
|
|
1386
|
+
suite: options.suite,
|
|
1387
|
+
scenario,
|
|
1388
|
+
host: options.host,
|
|
1389
|
+
armRuns,
|
|
1390
|
+
durationMs: Math.max(0, ...armRuns.map((arm) => arm.result.durationMs)),
|
|
1391
|
+
judge: options.judge !== false,
|
|
1392
|
+
evaluateGates: true,
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1375
1395
|
async function loadCompareResultFromStaging(stagingSessionId, suiteName, scenario) {
|
|
1376
1396
|
const resolved = resolveCompareArms(scenario.compare);
|
|
1377
1397
|
const arms = [];
|