@post-print/agent-test 1.1.1 → 1.1.3
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 +4 -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 +223 -142
- 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 +147 -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 +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-suite.d.ts.map +1 -1
- package/dist/validate-suite.js +4 -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 +37 -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 +848 -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,
|
|
@@ -937,6 +926,7 @@ async function runAgentTestOnce(cwd, suiteName, scenario, defaultHost, defaultCo
|
|
|
937
926
|
outputContract,
|
|
938
927
|
mcpServers,
|
|
939
928
|
allowUserSkills,
|
|
929
|
+
networkAccess: scenario.networkAccess === true,
|
|
940
930
|
authMode: getProcessAuthMode(),
|
|
941
931
|
timeoutMs: liveTimeoutMs,
|
|
942
932
|
failOnUserInput,
|
|
@@ -1073,33 +1063,19 @@ async function runAgentTestOnce(cwd, suiteName, scenario, defaultHost, defaultCo
|
|
|
1073
1063
|
}
|
|
1074
1064
|
worktreeHandle = undefined;
|
|
1075
1065
|
}
|
|
1076
|
-
const
|
|
1077
|
-
const story = buildScenarioStory({
|
|
1078
|
-
rubric: scenario.rubric,
|
|
1079
|
-
trace,
|
|
1080
|
-
passed,
|
|
1081
|
-
failures,
|
|
1082
|
-
judgeVerdicts,
|
|
1083
|
-
});
|
|
1084
|
-
const scenarioResult = {
|
|
1066
|
+
const scenarioResult = finalizeScenarioResult({
|
|
1085
1067
|
suite: suiteName,
|
|
1086
|
-
scenario
|
|
1087
|
-
description: plainDescription(scenario.description),
|
|
1088
|
-
prompt: scenario.prompt,
|
|
1068
|
+
scenario,
|
|
1089
1069
|
contextMode,
|
|
1090
1070
|
contextFiles,
|
|
1091
1071
|
hostInput,
|
|
1092
|
-
passed,
|
|
1093
1072
|
failures,
|
|
1094
1073
|
durationMs,
|
|
1095
1074
|
judgeVerdicts,
|
|
1096
1075
|
trace,
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
judgeVerdicts,
|
|
1101
|
-
}),
|
|
1102
|
-
};
|
|
1076
|
+
agentUsage: session.usage ?? trace?.usage,
|
|
1077
|
+
});
|
|
1078
|
+
const { passed, story } = scenarioResult;
|
|
1103
1079
|
const armMetrics = {
|
|
1104
1080
|
id: runOptions?.compareArm ?? "cell",
|
|
1105
1081
|
label: runOptions?.compareArm ?? "cell",
|
|
@@ -1157,6 +1133,11 @@ async function runAgentTestOnce(cwd, suiteName, scenario, defaultHost, defaultCo
|
|
|
1157
1133
|
authMode: getProcessAuthMode(),
|
|
1158
1134
|
});
|
|
1159
1135
|
scenarioResult.debugBundleDir = debugBundleDir;
|
|
1136
|
+
emitViewerEvent({
|
|
1137
|
+
type: "scenario_result",
|
|
1138
|
+
...viewerEnvelope,
|
|
1139
|
+
result: scenarioResult,
|
|
1140
|
+
});
|
|
1160
1141
|
emitScenarioVerdict({
|
|
1161
1142
|
passed,
|
|
1162
1143
|
index: scenarioIndex,
|
|
@@ -1234,60 +1215,18 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1234
1215
|
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
1216
|
armRuns.push({ id: entry.id, label, scenario: armScenario, result });
|
|
1236
1217
|
}
|
|
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
1218
|
const durationMs = Math.round(performance.now() - started);
|
|
1219
|
+
const scenarioResult = await finalizeCompareArmRuns({
|
|
1220
|
+
cwd,
|
|
1221
|
+
suite: suiteName,
|
|
1222
|
+
scenario,
|
|
1223
|
+
host,
|
|
1224
|
+
armRuns,
|
|
1225
|
+
durationMs,
|
|
1226
|
+
judge: Boolean(judge && !isChildProcess()),
|
|
1227
|
+
evaluateGates: !isChildProcess(),
|
|
1228
|
+
});
|
|
1229
|
+
const { passed, story, failures, trace: firstTrace } = scenarioResult;
|
|
1291
1230
|
if (isChildProcess() && stagingSessionId) {
|
|
1292
1231
|
const sidecarArms = {};
|
|
1293
1232
|
for (const arm of armRuns) {
|
|
@@ -1309,32 +1248,6 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1309
1248
|
},
|
|
1310
1249
|
});
|
|
1311
1250
|
}
|
|
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
1251
|
if (!suppressEmit) {
|
|
1339
1252
|
const debugBundleDir = await maybeWriteDebugBundle({
|
|
1340
1253
|
debug,
|
|
@@ -1356,6 +1269,13 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1356
1269
|
authMode: getProcessAuthMode(),
|
|
1357
1270
|
});
|
|
1358
1271
|
scenarioResult.debugBundleDir = debugBundleDir;
|
|
1272
|
+
emitViewerEvent({
|
|
1273
|
+
type: "scenario_result",
|
|
1274
|
+
suite: suiteName,
|
|
1275
|
+
scenario: scenario.name,
|
|
1276
|
+
host,
|
|
1277
|
+
result: scenarioResult,
|
|
1278
|
+
});
|
|
1359
1279
|
emitScenarioVerdict({
|
|
1360
1280
|
passed,
|
|
1361
1281
|
index: scenarioIndex,
|
|
@@ -1363,7 +1283,7 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1363
1283
|
name: scenario.name,
|
|
1364
1284
|
durationMs,
|
|
1365
1285
|
totalTokens: totalTokensFromScenarioUsage(scenarioResult.usage, firstTrace?.usage),
|
|
1366
|
-
judgeVerdicts,
|
|
1286
|
+
judgeVerdicts: scenarioResult.judgeVerdicts,
|
|
1367
1287
|
failures,
|
|
1368
1288
|
story,
|
|
1369
1289
|
debug,
|
|
@@ -1372,6 +1292,107 @@ async function runCompareAgentTestOnce(cwd, suiteName, scenario, defaultHost, de
|
|
|
1372
1292
|
}
|
|
1373
1293
|
return scenarioResult;
|
|
1374
1294
|
}
|
|
1295
|
+
async function finalizeCompareArmRuns(options) {
|
|
1296
|
+
const resolvedArms = resolveCompareArms(options.scenario.compare);
|
|
1297
|
+
const finalized = finalizeCompareOutcome(options.armRuns.map((arm) => ({
|
|
1298
|
+
id: arm.id,
|
|
1299
|
+
label: arm.label,
|
|
1300
|
+
description: compareArmDescription(resolvedArms.find((entry) => entry.id === arm.id)?.arm),
|
|
1301
|
+
prompt: arm.scenario.prompt,
|
|
1302
|
+
trace: arm.result.trace,
|
|
1303
|
+
contextMode: arm.result.contextMode,
|
|
1304
|
+
contextFiles: arm.result.contextFiles,
|
|
1305
|
+
hostInput: arm.result.hostInput,
|
|
1306
|
+
durationMs: arm.result.durationMs,
|
|
1307
|
+
passed: !arm.result.failures.some((failure) => failure.category === "rubric_miss"),
|
|
1308
|
+
failures: arm.result.failures,
|
|
1309
|
+
})), options.scenario.compare?.gates, { evaluateGates: false });
|
|
1310
|
+
const compareResult = finalized.compare;
|
|
1311
|
+
const failures = finalized.failures;
|
|
1312
|
+
if (options.judge && options.scenario.compare?.judgeMetrics?.length) {
|
|
1313
|
+
for (const arm of compareResult.arms) {
|
|
1314
|
+
if (!arm.trace)
|
|
1315
|
+
continue;
|
|
1316
|
+
const judged = await runJudgeRubric(arm.trace, { judge: options.scenario.compare.judgeMetrics }, options.cwd, options.host);
|
|
1317
|
+
arm.trace = judged.trace;
|
|
1318
|
+
arm.judgeVerdicts = toJudgeVerdictResults(judged.trace, options.scenario.compare.judgeMetrics, judged.verdicts);
|
|
1319
|
+
arm.failures = [...(arm.failures ?? []), ...judged.failures];
|
|
1320
|
+
failures.push(...prefixCompareFailures(arm.label, judged.failures.filter((failure) => failure.category !== "rubric_miss")));
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
if (options.evaluateGates)
|
|
1324
|
+
finalizeCompareGates(compareResult, failures);
|
|
1325
|
+
const compareArms = compareResultArms(compareResult);
|
|
1326
|
+
const firstTrace = compareArms[0]?.trace;
|
|
1327
|
+
let judgeVerdicts;
|
|
1328
|
+
if (options.judge &&
|
|
1329
|
+
failures.every((failure) => failure.category === "rubric_miss") &&
|
|
1330
|
+
compareArms.length > 0 &&
|
|
1331
|
+
compareArms.every((arm) => arm.trace)) {
|
|
1332
|
+
const criteria = collectCompareJudgeCriteria(options.scenario.rubric);
|
|
1333
|
+
if (criteria.length > 0)
|
|
1334
|
+
logPhase(theme.judgePhase(criteria.length), { last: true });
|
|
1335
|
+
const judged = await runCompareJudgeRubric(compareResult, options.scenario.rubric, options.cwd, options.host);
|
|
1336
|
+
failures.push(...judged.failures);
|
|
1337
|
+
if (firstTrace) {
|
|
1338
|
+
judgeVerdicts = toJudgeVerdictResults({ ...firstTrace, judgeVerdicts: judged.verdicts }, criteria, judged.verdicts);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return finalizeScenarioResult({
|
|
1342
|
+
suite: options.suite,
|
|
1343
|
+
scenario: options.scenario,
|
|
1344
|
+
failures,
|
|
1345
|
+
durationMs: options.durationMs,
|
|
1346
|
+
judgeVerdicts,
|
|
1347
|
+
trace: firstTrace,
|
|
1348
|
+
compare: compareResult,
|
|
1349
|
+
storyCompare: attachCompareStoryResults(compareStoryFields(options.scenario), compareResult),
|
|
1350
|
+
agentUsage: sumUsageParts(options.armRuns.map((arm) => arm.result.agentUsage)),
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
/** Finalize viewer-scheduled compare arms through the same domain and judge path as the CLI. */
|
|
1354
|
+
export async function finalizeScheduledCompareScenario(options) {
|
|
1355
|
+
const compareArms = options.scenario.compare ?? [];
|
|
1356
|
+
const scenario = {
|
|
1357
|
+
name: options.scenario.name,
|
|
1358
|
+
description: options.scenario.description,
|
|
1359
|
+
prompt: options.scenario.prompt,
|
|
1360
|
+
rubric: options.scenario.rubric,
|
|
1361
|
+
compare: {
|
|
1362
|
+
arms: compareArms.map((arm) => ({
|
|
1363
|
+
id: arm.id,
|
|
1364
|
+
label: arm.label,
|
|
1365
|
+
description: arm.description,
|
|
1366
|
+
prompt: arm.prompt,
|
|
1367
|
+
})),
|
|
1368
|
+
gates: options.scenario.gates,
|
|
1369
|
+
judgeMetrics: options.scenario.judgeMetrics,
|
|
1370
|
+
},
|
|
1371
|
+
};
|
|
1372
|
+
const armRuns = compareArms.flatMap((arm) => {
|
|
1373
|
+
const result = options.armResults.get(arm.id);
|
|
1374
|
+
return result
|
|
1375
|
+
? [
|
|
1376
|
+
{
|
|
1377
|
+
id: arm.id,
|
|
1378
|
+
label: arm.label,
|
|
1379
|
+
scenario: applyCompareArm(scenario, arm.id),
|
|
1380
|
+
result,
|
|
1381
|
+
},
|
|
1382
|
+
]
|
|
1383
|
+
: [];
|
|
1384
|
+
});
|
|
1385
|
+
return finalizeCompareArmRuns({
|
|
1386
|
+
cwd: options.cwd,
|
|
1387
|
+
suite: options.suite,
|
|
1388
|
+
scenario,
|
|
1389
|
+
host: options.host,
|
|
1390
|
+
armRuns,
|
|
1391
|
+
durationMs: Math.max(0, ...armRuns.map((arm) => arm.result.durationMs)),
|
|
1392
|
+
judge: options.judge !== false,
|
|
1393
|
+
evaluateGates: true,
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1375
1396
|
async function loadCompareResultFromStaging(stagingSessionId, suiteName, scenario) {
|
|
1376
1397
|
const resolved = resolveCompareArms(scenario.compare);
|
|
1377
1398
|
const arms = [];
|