@post-print/agent-test 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -127
- package/dist/compare-scenario.d.ts +8 -0
- package/dist/compare-scenario.d.ts.map +1 -1
- package/dist/compare-scenario.js +66 -0
- package/dist/compare-scenario.js.map +1 -1
- package/dist/html-report.d.ts.map +1 -1
- package/dist/html-report.js +141 -23
- package/dist/html-report.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/run-suite.d.ts.map +1 -1
- package/dist/run-suite.js +40 -3
- package/dist/run-suite.js.map +1 -1
- package/dist/scenario-story.d.ts +2 -0
- package/dist/scenario-story.d.ts.map +1 -1
- package/dist/scenario-story.js +17 -0
- package/dist/scenario-story.js.map +1 -1
- package/dist/theme.d.ts +3 -2
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +6 -3
- package/dist/theme.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-suite.d.ts.map +1 -1
- package/dist/validate-suite.js +10 -0
- package/dist/validate-suite.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ const result = await runAgentTest({
|
|
|
21
21
|
cwd: process.cwd(),
|
|
22
22
|
scenario: {
|
|
23
23
|
name: "uses the project instructions",
|
|
24
|
+
description: "Checks that the agent reads AGENTS.md.",
|
|
24
25
|
prompt: "Review the current change.",
|
|
25
26
|
rubric: { mustReadPath: ["AGENTS.md"] },
|
|
26
27
|
},
|
|
@@ -31,141 +32,17 @@ The default host is Cursor. Set `scenario.host`, `defaults.host`, or the top-lev
|
|
|
31
32
|
|
|
32
33
|
## JSON suites and CLI
|
|
33
34
|
|
|
34
|
-
JSON is an authoring adapter, not a stored answer. This repository keeps host-agent suites under `agent-suites/<suite>/scenarios.json`.
|
|
35
|
+
JSON is an authoring adapter, not a stored answer. This repository keeps host-agent suites under `agent-suites/<suite>/scenarios.json`.
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
|
-
npx agent-test --suites-dir agent-suites
|
|
38
|
-
npx agent-test --suites-dir agent-suites --host cursor
|
|
39
|
-
npx agent-test --suites-dir agent-suites --suite smoke
|
|
40
|
-
npx agent-test --suites-dir agent-suites --suite tools
|
|
41
|
-
npx agent-test --suites-dir agent-suites --suite mcp
|
|
42
|
-
npx agent-test --suites-dir agent-suites --suite judge
|
|
43
|
-
npx agent-test --suites-dir agent-suites --suite depth
|
|
44
38
|
npx agent-test --check --suites-dir agent-suites
|
|
39
|
+
npx agent-test --suites-dir agent-suites --host cursor --suite smoke
|
|
45
40
|
```
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
`smoke` is the short host proof. `tools` checks Read and Write. `mcp` checks echo invoke and a lookup read. `judge` starts a second host call that scores the reply. One judge scenario runs two workspace arms and scores both transcripts together. `depth` checks workspace roots, seed patches, injected context, mustRun, and skill invoke. `bun run test:smoke` stays on Cursor.
|
|
50
|
-
|
|
51
|
-
`scenario.host` pins that scenario to one host. A matrix run skips it on the other hosts.
|
|
52
|
-
|
|
53
|
-
## Custom hosts
|
|
54
|
-
|
|
55
|
-
A consumer repo can register its own adapter.
|
|
56
|
-
|
|
57
|
-
```js
|
|
58
|
-
// agent-test.config.mjs
|
|
59
|
-
import { defineConfig } from "@post-print/agent-test";
|
|
60
|
-
|
|
61
|
-
export default defineConfig({
|
|
62
|
-
adapters: [
|
|
63
|
-
{
|
|
64
|
-
host: "gemini",
|
|
65
|
-
missingAuth() {
|
|
66
|
-
return process.env.GEMINI_API_KEY ? undefined : "GEMINI_API_KEY not set";
|
|
67
|
-
},
|
|
68
|
-
classifierHost: "cursor",
|
|
69
|
-
async run(options) {
|
|
70
|
-
return {
|
|
71
|
-
host: "gemini",
|
|
72
|
-
status: "completed",
|
|
73
|
-
durationMs: 0,
|
|
74
|
-
trace: {
|
|
75
|
-
messages: [{ role: "assistant", content: options.prompt }],
|
|
76
|
-
toolCalls: [],
|
|
77
|
-
shellCommands: [],
|
|
78
|
-
artifacts: {},
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
});
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Then `--host gemini` and a suite `hosts` list can include `gemini`. You can also pass `--adapter ./hosts/gemini.mjs`. The module can export `{ adapters: [...] }` or call `registerHostAdapter` as a side effect.
|
|
88
|
-
|
|
89
|
-
Do not reuse `cursor`, `claude`, `openai`, `replay`, or `all` as the slug.
|
|
90
|
-
|
|
91
|
-
Direct runs need host auth. Cursor uses `CURSOR_API_KEY`, or `CURSOR_AUTH_MODE=subscription` after `Cursor.auth.login()`. The Cursor app login does not count. Claude uses `CLAUDE_AUTH_MODE` plus `ANTHROPIC_API_KEY` or a Claude Code login. OpenAI uses `OPENAI_API_KEY` or `CODEX_API_KEY`, or `OPENAI_AUTH_MODE=subscription` after `codex login`. The judge uses the same host family. It runs when a rubric has judge questions or `mustInvokeSkill`. A `compare` scenario runs two arms. `compare.faster` and `compare.cheaper` pick a metric winner. `rubric.judge` is optional and scores both transcripts. `--no-judge` turns the judge off. The CLI does not load `.env`.
|
|
92
|
-
|
|
93
|
-
`--allow-user-input` starts a second classifier as the user. That user agent answers AskQuestion-style tools. The test agent then continues with the original task plus the transcript.
|
|
94
|
-
|
|
95
|
-
## Check, rubrics, and compare
|
|
96
|
-
|
|
97
|
-
`--check` inspects the suite, seeds, package, and host. It does not launch an agent. A live run runs the same check first, then starts the host.
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
npx agent-test --check --suites-dir agent-suites
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
A compare scenario sets `compare.a` and `compare.b`. Each arm can override workspace, prompt, host, skills, or extra rubric checks. Arm rubric arrays append onto the scenario rubric. Do not put `judge` on an arm. `compare.faster` and `compare.cheaper` name the arm that must win on time or tokens. Add `rubric.judge` when you want a pairwise judge. Omit it for a metric-only compare. `--no-judge` skips the judge.
|
|
104
|
-
|
|
105
|
-
```json
|
|
106
|
-
{
|
|
107
|
-
"name": "cheaper prompt",
|
|
108
|
-
"prompt": "Read README.txt. Reply with one sentence.",
|
|
109
|
-
"compare": {
|
|
110
|
-
"a": { "label": "verbose", "prompt": "Read README.txt. Write a long summary." },
|
|
111
|
-
"b": { "label": "short" },
|
|
112
|
-
"cheaper": "b"
|
|
113
|
-
},
|
|
114
|
-
"rubric": { "mustReadPath": ["README.txt"] }
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Use two workspaces when one arm has a skill and the other does not. Put `mustInvokeSkill` on the skill arm only.
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
{
|
|
122
|
-
"name": "skill vs no skill",
|
|
123
|
-
"prompt": "Read every markdown file. Write a detailed shipping plan.",
|
|
124
|
-
"compare": {
|
|
125
|
-
"a": {
|
|
126
|
-
"label": "no skill",
|
|
127
|
-
"workspace": "workspaces/skill-off",
|
|
128
|
-
"rubric": { "mustNotInvokeSkill": ["brief-ship"] }
|
|
129
|
-
},
|
|
130
|
-
"b": {
|
|
131
|
-
"label": "with skill",
|
|
132
|
-
"workspace": "workspaces/skill-on",
|
|
133
|
-
"skills": [".agents/skills/brief-ship/SKILL.md"],
|
|
134
|
-
"rubric": { "mustInvokeSkill": ["brief-ship"] }
|
|
135
|
-
},
|
|
136
|
-
"cheaper": "b"
|
|
137
|
-
},
|
|
138
|
-
"rubric": {
|
|
139
|
-
"mustReadPath": ["note.md"],
|
|
140
|
-
"judge": ["Did the skill arm stay closer to the note?"]
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
42
|
+
First run: [docs/getting-started.md](../../docs/getting-started.md). Flags: [docs/cli.md](../../docs/cli.md). Suite fields, rubric, compare, and MCP: [docs/suites.md](../../docs/suites.md). Auth and adapters: [docs/hosts.md](../../docs/hosts.md). Sealed workspace and debug: [docs/isolation.md](../../docs/isolation.md).
|
|
144
43
|
|
|
145
44
|
`--doctor`, `--validate-only`, `--validate-paths`, and `--validate-seeds` are aliases for `--check`.
|
|
146
45
|
|
|
147
|
-
`scenarios.json` can omit inline rubric keys when a sibling `rubrics.json` / `scenarios.rubric.json` or `--rubrics-dir` supplies them.
|
|
148
|
-
|
|
149
|
-
## Isolation and diagnostics
|
|
150
|
-
|
|
151
|
-
In-repo suites set `workspace` on every scenario. The runner copies that folder into a temp repo. Omit `workspace`, or set `"."`, to copy HEAD plus caller context instead. The folder gets its own `.git`. The runner fails the scenario when tool paths leave that folder. A leftover caller-tree check still restores leaked caller edits.
|
|
152
|
-
|
|
153
|
-
Host-global user skills stay out of the run by default. Those trees live under `~/.cursor/skills`, `~/.claude/skills`, `~/.codex/skills`, and `~/.agents/skills`. A custom `workspace` is a fixture. Keep `allowUserSkills` false for that case. Set `allowUserSkills` to true on the scenario or suite defaults when the test needs the machine skill set. The `skills` field only overlays repo-relative folders into the sealed workspace.
|
|
154
|
-
|
|
155
|
-
`contextSources` and `skills` are relative to the workspace root when `workspace` is a subfolder. A bare `contextSources` name is a file in that root. `seedPatch` stays a caller-repo path. Its hunks are relative to that workspace.
|
|
156
|
-
|
|
157
|
-
`--debug` retains an evidence bundle under `$TMPDIR/agent-spec/sessions/<id>/` by default. Use `--debug-dir` to override the parent directory.
|
|
158
|
-
|
|
159
|
-
Host SDK INFO lines stay hidden. Set `AGENT_TEST_HOST_LOGS=1` or `--debug` to print them.
|
|
160
|
-
|
|
161
|
-
A TTY run prints `agent started`, then updates an `agent` clock every 0.1s. Tool names and a short reply preview print as the host streams them. The clock line stays one row so the terminal can overwrite it. The HTML report line is a localhost link. A click opens the browser. The preview exits after 30 minutes idle. Set `AGENT_TEST_NO_REPORT_PREVIEW=1` to skip the preview.
|
|
162
|
-
|
|
163
|
-
`Ctrl+C` cancels active host work and deletes the temp folder. `--no-worktree` requires `AGENT_TEST_ALLOW_IN_PLACE=1` because agent edits will persist in the caller checkout.
|
|
164
|
-
|
|
165
|
-
## MCP servers
|
|
166
|
-
|
|
167
|
-
Scenarios can attach inline stdio or HTTP/SSE MCP servers through suite defaults or scenario overrides. Ambient project/user MCP configuration is not loaded. When `workspace` is a subfolder, stdio MCP cwd is the caller repo. Script args stay caller-relative.
|
|
168
|
-
|
|
169
46
|
## In-repo package checks
|
|
170
47
|
|
|
171
48
|
Default CI does not launch a paid agent:
|
|
@@ -6,6 +6,9 @@ export declare function isCompareScenario(scenario: Pick<AgentScenario, "compare
|
|
|
6
6
|
};
|
|
7
7
|
export declare function parseCompareArmId(value: unknown): CompareArmId | undefined;
|
|
8
8
|
export declare function compareArmLabel(arm: CompareArm | undefined, side: CompareArmId): string;
|
|
9
|
+
/** Trim a description. Empty text becomes undefined. */
|
|
10
|
+
export declare function plainDescription(value?: string): string | undefined;
|
|
11
|
+
export declare function compareArmDescription(arm: CompareArm | undefined): string | undefined;
|
|
9
12
|
export declare function compareArmTokens(arm: CompareArmResult): number | undefined;
|
|
10
13
|
/** Apply one compare arm onto the shared scenario. Drops `compare` so the arm is a normal run. */
|
|
11
14
|
export declare function applyCompareArm(scenario: AgentScenario, side: CompareArmId): AgentScenario;
|
|
@@ -18,6 +21,11 @@ export declare function compareStoryFields(scenario: AgentScenario): {
|
|
|
18
21
|
bRubric?: ScenarioRubric;
|
|
19
22
|
};
|
|
20
23
|
export declare function prefixCompareFailures(label: string, failures: AssertionFailure[]): AssertionFailure[];
|
|
24
|
+
/**
|
|
25
|
+
* Plain-language winners after both arms finish.
|
|
26
|
+
* Lower duration, token count, and tool count win.
|
|
27
|
+
*/
|
|
28
|
+
export declare function describeCompareOutcome(compare: ScenarioCompareResult): string[];
|
|
21
29
|
export declare function applySidecarCompareDurations(compare: ScenarioCompareResult, sidecar?: {
|
|
22
30
|
compare?: {
|
|
23
31
|
a?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-scenario.d.ts","sourceRoot":"","sources":["../src/compare-scenario.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,MAAM,YAAY,CAAC;AAcpB,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAmB7F;AAED,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GACtC,QAAQ,IAAI,aAAa,GAAG;IAAE,OAAO,EAAE,eAAe,CAAA;CAAE,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAE1E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAMvF;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CAoB1F;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,cAAc,CAAC;CACzB,CASA;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,EAAE,GAC1B,gBAAgB,EAAE,CAKpB;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE;QAAE,CAAC,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,CAAC,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GAClF,qBAAqB,CAQvB;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,SAAS,CAAC,EACjD,MAAM,EAAE,qBAAqB,GAC3B,gBAAgB,EAAE,CA+CpB"}
|
|
1
|
+
{"version":3,"file":"compare-scenario.d.ts","sourceRoot":"","sources":["../src/compare-scenario.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,MAAM,YAAY,CAAC;AAcpB,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAmB7F;AAED,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GACtC,QAAQ,IAAI,aAAa,GAAG;IAAE,OAAO,EAAE,eAAe,CAAA;CAAE,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAE1E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAMvF;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGnE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAErF;AAMD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CAoB1F;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,CAAC,EAAE,cAAc,CAAC;CACzB,CASA;AAED,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,gBAAgB,EAAE,GAC1B,gBAAgB,EAAE,CAKpB;AAaD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAgD/E;AAED,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE;QAAE,CAAC,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,CAAC,CAAC,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GAClF,qBAAqB,CAQvB;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,CACnC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,SAAS,CAAC,EACjD,MAAM,EAAE,qBAAqB,GAC3B,gBAAgB,EAAE,CA+CpB"}
|
package/dist/compare-scenario.js
CHANGED
|
@@ -44,6 +44,14 @@ export function compareArmLabel(arm, side) {
|
|
|
44
44
|
}
|
|
45
45
|
return side === "a" ? "A" : "B";
|
|
46
46
|
}
|
|
47
|
+
/** Trim a description. Empty text becomes undefined. */
|
|
48
|
+
export function plainDescription(value) {
|
|
49
|
+
const text = value?.trim();
|
|
50
|
+
return text ? text : undefined;
|
|
51
|
+
}
|
|
52
|
+
export function compareArmDescription(arm) {
|
|
53
|
+
return plainDescription(arm?.description);
|
|
54
|
+
}
|
|
47
55
|
function otherArm(side) {
|
|
48
56
|
return side === "a" ? "b" : "a";
|
|
49
57
|
}
|
|
@@ -89,6 +97,64 @@ export function prefixCompareFailures(label, failures) {
|
|
|
89
97
|
message: `${label}: ${failure.message}`,
|
|
90
98
|
}));
|
|
91
99
|
}
|
|
100
|
+
function formatCompareDuration(ms) {
|
|
101
|
+
if (ms < 1000) {
|
|
102
|
+
return `${Math.round(ms)}ms`;
|
|
103
|
+
}
|
|
104
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
105
|
+
}
|
|
106
|
+
function armToolCount(arm) {
|
|
107
|
+
return arm.trace ? arm.trace.toolCalls.length : undefined;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Plain-language winners after both arms finish.
|
|
111
|
+
* Lower duration, token count, and tool count win.
|
|
112
|
+
*/
|
|
113
|
+
export function describeCompareOutcome(compare) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
const aLabel = compare.a.label;
|
|
116
|
+
const bLabel = compare.b.label;
|
|
117
|
+
const aMs = compare.a.durationMs;
|
|
118
|
+
const bMs = compare.b.durationMs;
|
|
119
|
+
if (typeof aMs === "number" && typeof bMs === "number") {
|
|
120
|
+
if (aMs === bMs) {
|
|
121
|
+
lines.push(`both arms took ${formatCompareDuration(aMs)}`);
|
|
122
|
+
}
|
|
123
|
+
else if (aMs < bMs) {
|
|
124
|
+
lines.push(`${aLabel} is faster than ${bLabel} (${formatCompareDuration(aMs)} vs ${formatCompareDuration(bMs)})`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
lines.push(`${bLabel} is faster than ${aLabel} (${formatCompareDuration(bMs)} vs ${formatCompareDuration(aMs)})`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const aTokens = compareArmTokens(compare.a);
|
|
131
|
+
const bTokens = compareArmTokens(compare.b);
|
|
132
|
+
if (typeof aTokens === "number" && typeof bTokens === "number") {
|
|
133
|
+
if (aTokens === bTokens) {
|
|
134
|
+
lines.push(`both arms use ${aTokens} tokens`);
|
|
135
|
+
}
|
|
136
|
+
else if (aTokens < bTokens) {
|
|
137
|
+
lines.push(`${aLabel} uses fewer tokens than ${bLabel} (${aTokens} vs ${bTokens})`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
lines.push(`${bLabel} uses fewer tokens than ${aLabel} (${bTokens} vs ${aTokens})`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const aTools = armToolCount(compare.a);
|
|
144
|
+
const bTools = armToolCount(compare.b);
|
|
145
|
+
if (typeof aTools === "number" && typeof bTools === "number") {
|
|
146
|
+
if (aTools === bTools) {
|
|
147
|
+
lines.push(aTools === 1 ? "both arms make 1 tool call" : `both arms make ${aTools} tool calls`);
|
|
148
|
+
}
|
|
149
|
+
else if (aTools < bTools) {
|
|
150
|
+
lines.push(`${aLabel} makes fewer tool calls than ${bLabel} (${aTools} vs ${bTools})`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
lines.push(`${bLabel} makes fewer tool calls than ${aLabel} (${bTools} vs ${aTools})`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return lines;
|
|
157
|
+
}
|
|
92
158
|
export function applySidecarCompareDurations(compare, sidecar) {
|
|
93
159
|
if (!sidecar?.compare) {
|
|
94
160
|
return compare;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-scenario.js","sourceRoot":"","sources":["../src/compare-scenario.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compare-scenario.js","sourceRoot":"","sources":["../src/compare-scenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-report.d.ts","sourceRoot":"","sources":["../src/html-report.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"html-report.d.ts","sourceRoot":"","sources":["../src/html-report.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAoC,cAAc,EAAc,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,cAAc;IAC9B,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AA6gCD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,IAAI,GAAE,cAAmB,GAAG,MAAM,CAkD7F;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,cAAc,EAAE,EACzB,IAAI,GAAE,cAAmB,EACzB,OAAO,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAQjB"}
|
package/dist/html-report.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
+
import { describeCompareOutcome } from "./compare-scenario.js";
|
|
4
5
|
import { summarizeReports } from "./suite-summary.js";
|
|
5
6
|
function escapeHtml(value) {
|
|
6
7
|
return value
|
|
@@ -446,11 +447,20 @@ function tokenDelta(a, b, key) {
|
|
|
446
447
|
}
|
|
447
448
|
return bValue - aValue;
|
|
448
449
|
}
|
|
450
|
+
function winnerCellClass(delta, side) {
|
|
451
|
+
if (delta === undefined || delta === 0) {
|
|
452
|
+
return "";
|
|
453
|
+
}
|
|
454
|
+
if (side === "a") {
|
|
455
|
+
return delta > 0 ? "is-better" : "is-worse";
|
|
456
|
+
}
|
|
457
|
+
return delta < 0 ? "is-better" : "is-worse";
|
|
458
|
+
}
|
|
449
459
|
function renderCompareMetricRow(label, aText, bText, delta, deltaText) {
|
|
450
460
|
return `<tr>
|
|
451
461
|
<th scope="row">${escapeHtml(label)}</th>
|
|
452
|
-
<td>${escapeHtml(aText)}</td>
|
|
453
|
-
<td>${escapeHtml(bText)}</td>
|
|
462
|
+
<td class="${winnerCellClass(delta, "a")}">${escapeHtml(aText)}</td>
|
|
463
|
+
<td class="${winnerCellClass(delta, "b")}">${escapeHtml(bText)}</td>
|
|
454
464
|
<td class="${deltaClass(delta)}">${escapeHtml(deltaText)}</td>
|
|
455
465
|
</tr>`;
|
|
456
466
|
}
|
|
@@ -466,12 +476,17 @@ function renderCompareMetrics(result) {
|
|
|
466
476
|
const bTools = armToolCount(compare.b);
|
|
467
477
|
const toolDelta = aTools !== undefined && bTools !== undefined ? bTools - aTools : undefined;
|
|
468
478
|
const totalDelta = tokenDelta(compare.a, compare.b, "total");
|
|
479
|
+
const callouts = describeCompareOutcome(compare);
|
|
480
|
+
const calloutList = callouts.length > 0
|
|
481
|
+
? `<ul class="compare-callouts">${callouts.map((line) => `<li>${escapeHtml(line)}</li>`).join("")}</ul>`
|
|
482
|
+
: "";
|
|
469
483
|
return `
|
|
470
484
|
<section class="compare">
|
|
471
485
|
<header class="compare-header">
|
|
472
486
|
<h3>Comparison</h3>
|
|
473
487
|
<p class="muted">${escapeHtml(compare.a.label)} vs ${escapeHtml(compare.b.label)}. Δ is B minus A. A lower time and a lower token count is better.</p>
|
|
474
488
|
</header>
|
|
489
|
+
${calloutList}
|
|
475
490
|
<div class="compare-table-wrap">
|
|
476
491
|
<table class="compare-table">
|
|
477
492
|
<thead>
|
|
@@ -493,6 +508,57 @@ function renderCompareMetrics(result) {
|
|
|
493
508
|
</div>
|
|
494
509
|
</section>`;
|
|
495
510
|
}
|
|
511
|
+
function renderArmMetrics(arm) {
|
|
512
|
+
const parts = [];
|
|
513
|
+
const ms = armDurationMs(arm);
|
|
514
|
+
if (ms !== undefined) {
|
|
515
|
+
parts.push(formatDuration(ms));
|
|
516
|
+
}
|
|
517
|
+
const tokens = formatArmTokens(arm, "total");
|
|
518
|
+
if (tokens !== "n/a") {
|
|
519
|
+
parts.push(`${tokens} tokens`);
|
|
520
|
+
}
|
|
521
|
+
const tools = armToolCount(arm);
|
|
522
|
+
if (tools !== undefined) {
|
|
523
|
+
parts.push(tools === 1 ? "1 tool" : `${formatInteger(tools)} tools`);
|
|
524
|
+
}
|
|
525
|
+
if (parts.length === 0) {
|
|
526
|
+
return "";
|
|
527
|
+
}
|
|
528
|
+
return `<p class="compare-arm-metrics">${escapeHtml(parts.join(" · "))}</p>`;
|
|
529
|
+
}
|
|
530
|
+
function renderArmColumn(arm, side) {
|
|
531
|
+
const description = arm.description
|
|
532
|
+
? `<p class="compare-arm-description">${escapeHtml(arm.description)}</p>`
|
|
533
|
+
: "";
|
|
534
|
+
return `
|
|
535
|
+
<article class="compare-arm compare-arm-${side}">
|
|
536
|
+
<header class="compare-arm-header">
|
|
537
|
+
<p class="compare-arm-kicker">${side === "a" ? "Arm A" : "Arm B"}</p>
|
|
538
|
+
<h3>${escapeHtml(arm.label)}</h3>
|
|
539
|
+
${description}
|
|
540
|
+
${renderArmMetrics(arm)}
|
|
541
|
+
</header>
|
|
542
|
+
${renderChat(arm.trace, arm.prompt)}
|
|
543
|
+
</article>`;
|
|
544
|
+
}
|
|
545
|
+
function renderCompareConversations(result) {
|
|
546
|
+
const compare = result.compare;
|
|
547
|
+
if (!compare) {
|
|
548
|
+
return `<section class="conversation">
|
|
549
|
+
<h3>Conversation</h3>
|
|
550
|
+
${renderChat(result.trace, result.prompt)}
|
|
551
|
+
</section>`;
|
|
552
|
+
}
|
|
553
|
+
return `
|
|
554
|
+
<div class="compare-layout">
|
|
555
|
+
<div class="compare-arms">
|
|
556
|
+
${renderArmColumn(compare.a, "a")}
|
|
557
|
+
${renderArmColumn(compare.b, "b")}
|
|
558
|
+
</div>
|
|
559
|
+
${renderCompareMetrics(result)}
|
|
560
|
+
</div>`;
|
|
561
|
+
}
|
|
496
562
|
function renderStoryList(title, lines) {
|
|
497
563
|
if (!lines || lines.length === 0) {
|
|
498
564
|
return "";
|
|
@@ -511,12 +577,12 @@ function renderStory(result) {
|
|
|
511
577
|
</div>`;
|
|
512
578
|
}
|
|
513
579
|
function renderScenario(result) {
|
|
514
|
-
const open = result.passed || result.
|
|
580
|
+
const open = result.skipped ? "" : !result.passed || result.compare ? " open" : "";
|
|
515
581
|
const failures = result.story ? "" : renderFailures(result);
|
|
516
582
|
const judgeVerdicts = renderJudgeVerdicts(result);
|
|
517
583
|
const tokens = formatTokensBadge(result);
|
|
518
|
-
const usageDetail = renderUsageDetail(usageOf(result));
|
|
519
|
-
const traceMeta = renderTraceMeta(result);
|
|
584
|
+
const usageDetail = result.compare ? "" : renderUsageDetail(usageOf(result));
|
|
585
|
+
const traceMeta = result.compare ? "" : renderTraceMeta(result);
|
|
520
586
|
const story = renderStory(result);
|
|
521
587
|
const diagnostics = story || failures || judgeVerdicts
|
|
522
588
|
? `<div class="diagnostics">
|
|
@@ -528,31 +594,25 @@ function renderScenario(result) {
|
|
|
528
594
|
const metaRow = usageDetail || traceMeta
|
|
529
595
|
? `<div class="diagnostics meta-row">${usageDetail}${traceMeta}</div>`
|
|
530
596
|
: "";
|
|
597
|
+
const compareClass = result.compare ? " compare-scenario" : "";
|
|
598
|
+
const description = result.description
|
|
599
|
+
? `<span class="scenario-lede">${escapeHtml(result.description)}</span>`
|
|
600
|
+
: "";
|
|
531
601
|
return `
|
|
532
|
-
<details class="scenario ${statusClass(result)}"${open}>
|
|
602
|
+
<details class="scenario ${statusClass(result)}${compareClass}"${open}>
|
|
533
603
|
<summary>
|
|
534
604
|
<span class="badge ${statusClass(result)}">${statusLabel(result)}</span>
|
|
535
|
-
<span class="scenario-
|
|
605
|
+
<span class="scenario-heading">
|
|
606
|
+
<span class="scenario-name">${escapeHtml(result.scenario)}</span>
|
|
607
|
+
${description}
|
|
608
|
+
</span>
|
|
536
609
|
${tokens ? `<span class="tokens">${escapeHtml(tokens)}</span>` : ""}
|
|
537
610
|
<span class="duration">${escapeHtml(formatDuration(result.durationMs))}</span>
|
|
538
611
|
</summary>
|
|
539
612
|
<div class="scenario-body">
|
|
540
613
|
${diagnostics}
|
|
541
614
|
${metaRow}
|
|
542
|
-
${
|
|
543
|
-
${result.compare
|
|
544
|
-
? `<section class="conversation">
|
|
545
|
-
<h3>Conversation · ${escapeHtml(result.compare.a.label)}</h3>
|
|
546
|
-
${renderChat(result.compare.a.trace, result.compare.a.prompt)}
|
|
547
|
-
</section>
|
|
548
|
-
<section class="conversation">
|
|
549
|
-
<h3>Conversation · ${escapeHtml(result.compare.b.label)}</h3>
|
|
550
|
-
${renderChat(result.compare.b.trace, result.compare.b.prompt)}
|
|
551
|
-
</section>`
|
|
552
|
-
: `<section class="conversation">
|
|
553
|
-
<h3>Conversation</h3>
|
|
554
|
-
${renderChat(result.trace, result.prompt)}
|
|
555
|
-
</section>`}
|
|
615
|
+
${renderCompareConversations(result)}
|
|
556
616
|
</div>
|
|
557
617
|
</details>`;
|
|
558
618
|
}
|
|
@@ -589,6 +649,8 @@ function sharedReportCss() {
|
|
|
589
649
|
--system-bubble: oklch(0.26 0.04 300);
|
|
590
650
|
--tool: oklch(0.82 0.12 80);
|
|
591
651
|
--tool-bubble: oklch(0.26 0.04 80);
|
|
652
|
+
--arm-a: oklch(0.72 0.12 250);
|
|
653
|
+
--arm-b: oklch(0.78 0.14 75);
|
|
592
654
|
}
|
|
593
655
|
@layer reset {
|
|
594
656
|
* { box-sizing: border-box; }
|
|
@@ -605,6 +667,7 @@ function sharedReportCss() {
|
|
|
605
667
|
word-spacing: 0.16em;
|
|
606
668
|
}
|
|
607
669
|
main { max-width: 68rem; margin-inline: auto; padding: 1.5rem 1.25rem 3rem; }
|
|
670
|
+
main:has(.compare-layout) { max-width: 96rem; }
|
|
608
671
|
h1 { font-size: 1.7rem; font-weight: 650; letter-spacing: -0.02em; }
|
|
609
672
|
h2 { font-size: 1.05rem; font-weight: 650; }
|
|
610
673
|
h3 { font-size: 0.8rem; color: var(--muted); font-weight: 650; }
|
|
@@ -693,7 +756,9 @@ function sharedReportCss() {
|
|
|
693
756
|
}
|
|
694
757
|
details.scenario[open] summary { border-bottom: 1px solid var(--border); background: #17202d; }
|
|
695
758
|
details.scenario summary::-webkit-details-marker { display: none; }
|
|
759
|
+
.scenario-heading { display: grid; gap: 0.1rem; min-width: 12rem; flex: 1 1 16rem; }
|
|
696
760
|
.scenario-name { font-weight: 600; font-size: 0.9rem; }
|
|
761
|
+
.scenario-lede { color: var(--muted); font-size: 0.78rem; font-weight: 400; }
|
|
697
762
|
.duration { color: var(--muted); margin-left: auto; font-variant-numeric: tabular-nums; }
|
|
698
763
|
.badge {
|
|
699
764
|
display: inline-block;
|
|
@@ -784,8 +849,47 @@ function sharedReportCss() {
|
|
|
784
849
|
.shell-commands li { font-size: 0.8rem; background: #0b1017; border: 1px solid var(--border); border-radius: 6px; padding: 0.3rem 0.5rem; }
|
|
785
850
|
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.85em; }
|
|
786
851
|
|
|
852
|
+
.compare-layout {
|
|
853
|
+
container-type: inline-size;
|
|
854
|
+
display: grid;
|
|
855
|
+
gap: 0.9rem;
|
|
856
|
+
}
|
|
857
|
+
.compare-arms {
|
|
858
|
+
display: grid;
|
|
859
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
860
|
+
gap: 0.85rem;
|
|
861
|
+
align-items: stretch;
|
|
862
|
+
}
|
|
863
|
+
.compare-arm {
|
|
864
|
+
min-width: 0;
|
|
865
|
+
display: grid;
|
|
866
|
+
align-content: start;
|
|
867
|
+
gap: 0.65rem;
|
|
868
|
+
background: var(--panel-2);
|
|
869
|
+
border: 1px solid var(--border);
|
|
870
|
+
border-radius: 10px;
|
|
871
|
+
padding: 0.75rem 0.8rem 0.85rem;
|
|
872
|
+
border-block-start-width: 3px;
|
|
873
|
+
}
|
|
874
|
+
.compare-arm-a { border-block-start-color: var(--arm-a); }
|
|
875
|
+
.compare-arm-b { border-block-start-color: var(--arm-b); }
|
|
876
|
+
.compare-arm-header { display: grid; gap: 0.15rem; padding-bottom: 0.55rem; border-bottom: 1px solid var(--border); }
|
|
877
|
+
.compare-arm-kicker {
|
|
878
|
+
color: var(--muted);
|
|
879
|
+
font-size: 0.66rem;
|
|
880
|
+
font-weight: 700;
|
|
881
|
+
letter-spacing: 0.06em;
|
|
882
|
+
text-transform: uppercase;
|
|
883
|
+
}
|
|
884
|
+
.compare-arm-a .compare-arm-kicker { color: var(--arm-a); }
|
|
885
|
+
.compare-arm-b .compare-arm-kicker { color: var(--arm-b); }
|
|
886
|
+
.compare-arm-header h3 { color: var(--text); font-size: 0.95rem; }
|
|
887
|
+
.compare-arm-description { color: var(--muted); font-size: 0.8rem; }
|
|
888
|
+
.compare-arm-metrics { color: var(--muted); font-size: 0.78rem; font-variant-numeric: tabular-nums; }
|
|
889
|
+
.compare-arm .bubble, .compare-arm .tool-card { max-width: 100%; }
|
|
890
|
+
|
|
787
891
|
.compare {
|
|
788
|
-
margin-top:
|
|
892
|
+
margin-top: 0;
|
|
789
893
|
background: var(--panel);
|
|
790
894
|
border: 1px solid var(--border);
|
|
791
895
|
border-radius: 10px;
|
|
@@ -793,6 +897,13 @@ function sharedReportCss() {
|
|
|
793
897
|
}
|
|
794
898
|
.compare-header { margin-bottom: 0.65rem; }
|
|
795
899
|
.compare-header h3 { margin-bottom: 0.2rem; }
|
|
900
|
+
.compare-callouts {
|
|
901
|
+
margin: 0 0 0.75rem;
|
|
902
|
+
padding-left: 1.1rem;
|
|
903
|
+
display: grid;
|
|
904
|
+
gap: 0.25rem;
|
|
905
|
+
font-size: 0.85rem;
|
|
906
|
+
}
|
|
796
907
|
.compare-table-wrap { overflow-x: auto; }
|
|
797
908
|
.compare-table {
|
|
798
909
|
width: 100%;
|
|
@@ -810,12 +921,19 @@ function sharedReportCss() {
|
|
|
810
921
|
.delta-up { color: var(--fail); }
|
|
811
922
|
.delta-down { color: var(--pass); }
|
|
812
923
|
.delta-flat { color: var(--muted); }
|
|
924
|
+
.is-better { color: var(--pass); font-weight: 650; }
|
|
925
|
+
.is-worse { color: var(--muted); }
|
|
926
|
+
|
|
927
|
+
@container (max-width: 44rem) {
|
|
928
|
+
.compare-arms { grid-template-columns: minmax(0, 1fr); }
|
|
929
|
+
}
|
|
813
930
|
|
|
814
931
|
@media (max-width: 720px) {
|
|
815
932
|
main { padding: 0.75rem; }
|
|
816
933
|
.suite-header { align-items: flex-start; flex-direction: column; gap: 0.2rem; }
|
|
817
934
|
.diagnostics { grid-template-columns: 1fr; }
|
|
818
935
|
.bubble, .tool-card { max-width: 92%; }
|
|
936
|
+
.compare-arms { grid-template-columns: minmax(0, 1fr); }
|
|
819
937
|
}
|
|
820
938
|
}
|
|
821
939
|
`;
|
|
@@ -858,7 +976,7 @@ export function renderHtmlReport(reports, meta = {}) {
|
|
|
858
976
|
<h2 id="guide-heading">How to read this report</h2>
|
|
859
977
|
<ol>
|
|
860
978
|
<li>The verdict is pass or fail. Tokens are cost, not the score.</li>
|
|
861
|
-
<li>Open a scenario for the criteria and the result. A compare scenario shows
|
|
979
|
+
<li>Open a scenario for the criteria and the result. A compare scenario shows the two arms side by side, then a comparison of time, tokens, and tools.</li>
|
|
862
980
|
<li>Typical is the middle scenario cost. Largest is the heaviest scenario.</li>
|
|
863
981
|
<li>In is prompt and context. Out is generated text.</li>
|
|
864
982
|
</ol>
|