@rudderjs/ai 1.4.0 → 1.6.0

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.
Files changed (179) hide show
  1. package/README.md +484 -7
  2. package/boost/guidelines.md +62 -2
  3. package/boost/skills/ai-tools/SKILL.md +14 -5
  4. package/dist/agent.d.ts +66 -15
  5. package/dist/agent.d.ts.map +1 -1
  6. package/dist/agent.js +529 -58
  7. package/dist/agent.js.map +1 -1
  8. package/dist/budget/pricing.d.ts +124 -0
  9. package/dist/budget/pricing.d.ts.map +1 -0
  10. package/dist/budget/pricing.js +175 -0
  11. package/dist/budget/pricing.js.map +1 -0
  12. package/dist/budget/storage.d.ts +104 -0
  13. package/dist/budget/storage.d.ts.map +1 -0
  14. package/dist/budget/storage.js +0 -0
  15. package/dist/budget/storage.js.map +1 -0
  16. package/dist/budget/with-budget.d.ts +119 -0
  17. package/dist/budget/with-budget.d.ts.map +1 -0
  18. package/dist/budget/with-budget.js +175 -0
  19. package/dist/budget/with-budget.js.map +1 -0
  20. package/dist/budget-orm/index.d.ts +96 -0
  21. package/dist/budget-orm/index.d.ts.map +1 -0
  22. package/dist/budget-orm/index.js +177 -0
  23. package/dist/budget-orm/index.js.map +1 -0
  24. package/dist/commands/ai-eval.d.ts +93 -0
  25. package/dist/commands/ai-eval.d.ts.map +1 -0
  26. package/dist/commands/ai-eval.js +378 -0
  27. package/dist/commands/ai-eval.js.map +1 -0
  28. package/dist/computer-use/actions.d.ts +214 -0
  29. package/dist/computer-use/actions.d.ts.map +1 -0
  30. package/dist/computer-use/actions.js +48 -0
  31. package/dist/computer-use/actions.js.map +1 -0
  32. package/dist/computer-use/errors.d.ts +57 -0
  33. package/dist/computer-use/errors.d.ts.map +1 -0
  34. package/dist/computer-use/errors.js +76 -0
  35. package/dist/computer-use/errors.js.map +1 -0
  36. package/dist/computer-use/index.d.ts +53 -0
  37. package/dist/computer-use/index.d.ts.map +1 -0
  38. package/dist/computer-use/index.js +51 -0
  39. package/dist/computer-use/index.js.map +1 -0
  40. package/dist/computer-use/playwright.d.ts +76 -0
  41. package/dist/computer-use/playwright.d.ts.map +1 -0
  42. package/dist/computer-use/playwright.js +270 -0
  43. package/dist/computer-use/playwright.js.map +1 -0
  44. package/dist/computer-use/tool.d.ts +154 -0
  45. package/dist/computer-use/tool.d.ts.map +1 -0
  46. package/dist/computer-use/tool.js +210 -0
  47. package/dist/computer-use/tool.js.map +1 -0
  48. package/dist/eval/fixtures.d.ts +65 -0
  49. package/dist/eval/fixtures.d.ts.map +1 -0
  50. package/dist/eval/fixtures.js +110 -0
  51. package/dist/eval/fixtures.js.map +1 -0
  52. package/dist/eval/html-reporter.d.ts +25 -0
  53. package/dist/eval/html-reporter.d.ts.map +1 -0
  54. package/dist/eval/html-reporter.js +209 -0
  55. package/dist/eval/html-reporter.js.map +1 -0
  56. package/dist/eval/index.d.ts +271 -0
  57. package/dist/eval/index.d.ts.map +1 -0
  58. package/dist/eval/index.js +510 -0
  59. package/dist/eval/index.js.map +1 -0
  60. package/dist/eval/json-reporter.d.ts +43 -0
  61. package/dist/eval/json-reporter.d.ts.map +1 -0
  62. package/dist/eval/json-reporter.js +40 -0
  63. package/dist/eval/json-reporter.js.map +1 -0
  64. package/dist/fake.d.ts +36 -1
  65. package/dist/fake.d.ts.map +1 -1
  66. package/dist/fake.js +49 -2
  67. package/dist/fake.js.map +1 -1
  68. package/dist/file-search.d.ts +168 -0
  69. package/dist/file-search.d.ts.map +1 -0
  70. package/dist/file-search.js +158 -0
  71. package/dist/file-search.js.map +1 -0
  72. package/dist/handoff.d.ts +95 -0
  73. package/dist/handoff.d.ts.map +1 -0
  74. package/dist/handoff.js +78 -0
  75. package/dist/handoff.js.map +1 -0
  76. package/dist/index.d.ts +29 -5
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +22 -2
  79. package/dist/index.js.map +1 -1
  80. package/dist/mcp/client-tools.d.ts +39 -0
  81. package/dist/mcp/client-tools.d.ts.map +1 -0
  82. package/dist/mcp/client-tools.js +147 -0
  83. package/dist/mcp/client-tools.js.map +1 -0
  84. package/dist/mcp/index.d.ts +16 -0
  85. package/dist/mcp/index.d.ts.map +1 -0
  86. package/dist/mcp/index.js +15 -0
  87. package/dist/mcp/index.js.map +1 -0
  88. package/dist/mcp/server-from-agent.d.ts +24 -0
  89. package/dist/mcp/server-from-agent.d.ts.map +1 -0
  90. package/dist/mcp/server-from-agent.js +113 -0
  91. package/dist/mcp/server-from-agent.js.map +1 -0
  92. package/dist/mcp/types.d.ts +64 -0
  93. package/dist/mcp/types.d.ts.map +1 -0
  94. package/dist/mcp/types.js +6 -0
  95. package/dist/mcp/types.js.map +1 -0
  96. package/dist/memory-embedding/index.d.ts +121 -0
  97. package/dist/memory-embedding/index.d.ts.map +1 -0
  98. package/dist/memory-embedding/index.js +229 -0
  99. package/dist/memory-embedding/index.js.map +1 -0
  100. package/dist/memory-extract.d.ts +60 -0
  101. package/dist/memory-extract.d.ts.map +1 -0
  102. package/dist/memory-extract.js +163 -0
  103. package/dist/memory-extract.js.map +1 -0
  104. package/dist/memory-inject.d.ts +39 -0
  105. package/dist/memory-inject.d.ts.map +1 -0
  106. package/dist/memory-inject.js +135 -0
  107. package/dist/memory-inject.js.map +1 -0
  108. package/dist/memory-orm/index.d.ts +118 -0
  109. package/dist/memory-orm/index.d.ts.map +1 -0
  110. package/dist/memory-orm/index.js +187 -0
  111. package/dist/memory-orm/index.js.map +1 -0
  112. package/dist/memory.d.ts +55 -0
  113. package/dist/memory.d.ts.map +1 -0
  114. package/dist/memory.js +132 -0
  115. package/dist/memory.js.map +1 -0
  116. package/dist/observers.d.ts +22 -0
  117. package/dist/observers.d.ts.map +1 -1
  118. package/dist/observers.js.map +1 -1
  119. package/dist/provider-tools.d.ts +15 -1
  120. package/dist/provider-tools.d.ts.map +1 -1
  121. package/dist/provider-tools.js +21 -1
  122. package/dist/provider-tools.js.map +1 -1
  123. package/dist/providers/anthropic.d.ts +9 -1
  124. package/dist/providers/anthropic.d.ts.map +1 -1
  125. package/dist/providers/anthropic.js +66 -11
  126. package/dist/providers/anthropic.js.map +1 -1
  127. package/dist/providers/bedrock.d.ts +60 -0
  128. package/dist/providers/bedrock.d.ts.map +1 -0
  129. package/dist/providers/bedrock.js +167 -0
  130. package/dist/providers/bedrock.js.map +1 -0
  131. package/dist/providers/elevenlabs.d.ts +98 -0
  132. package/dist/providers/elevenlabs.d.ts.map +1 -0
  133. package/dist/providers/elevenlabs.js +229 -0
  134. package/dist/providers/elevenlabs.js.map +1 -0
  135. package/dist/providers/google.d.ts +83 -1
  136. package/dist/providers/google.d.ts.map +1 -1
  137. package/dist/providers/google.js +491 -8
  138. package/dist/providers/google.js.map +1 -1
  139. package/dist/providers/openai.d.ts +8 -1
  140. package/dist/providers/openai.d.ts.map +1 -1
  141. package/dist/providers/openai.js +215 -5
  142. package/dist/providers/openai.js.map +1 -1
  143. package/dist/providers/openrouter.d.ts +43 -0
  144. package/dist/providers/openrouter.d.ts.map +1 -0
  145. package/dist/providers/openrouter.js +21 -0
  146. package/dist/providers/openrouter.js.map +1 -0
  147. package/dist/providers/voyage.d.ts +91 -0
  148. package/dist/providers/voyage.d.ts.map +1 -0
  149. package/dist/providers/voyage.js +166 -0
  150. package/dist/providers/voyage.js.map +1 -0
  151. package/dist/queue-job.d.ts +69 -4
  152. package/dist/queue-job.d.ts.map +1 -1
  153. package/dist/queue-job.js +114 -11
  154. package/dist/queue-job.js.map +1 -1
  155. package/dist/registry.d.ts +3 -1
  156. package/dist/registry.d.ts.map +1 -1
  157. package/dist/registry.js +10 -0
  158. package/dist/registry.js.map +1 -1
  159. package/dist/server/provider.d.ts.map +1 -1
  160. package/dist/server/provider.js +38 -1
  161. package/dist/server/provider.js.map +1 -1
  162. package/dist/similarity-search.d.ts +163 -0
  163. package/dist/similarity-search.d.ts.map +1 -0
  164. package/dist/similarity-search.js +147 -0
  165. package/dist/similarity-search.js.map +1 -0
  166. package/dist/sub-agent-run-store.d.ts +40 -3
  167. package/dist/sub-agent-run-store.d.ts.map +1 -1
  168. package/dist/sub-agent-run-store.js.map +1 -1
  169. package/dist/tool.d.ts +59 -0
  170. package/dist/tool.d.ts.map +1 -1
  171. package/dist/tool.js +45 -4
  172. package/dist/tool.js.map +1 -1
  173. package/dist/types.d.ts +285 -1
  174. package/dist/types.d.ts.map +1 -1
  175. package/dist/vector-stores/index.d.ts +96 -0
  176. package/dist/vector-stores/index.d.ts.map +1 -0
  177. package/dist/vector-stores/index.js +153 -0
  178. package/dist/vector-stores/index.js.map +1 -0
  179. package/package.json +43 -4
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Fixture I/O for `pnpm rudder ai:eval --record` / `--replay` (#A5
3
+ * Phase 4). Each case writes one JSON file under
4
+ * `evals/__fixtures__/<suite>/<case>.json` carrying the assistant
5
+ * turns from a real provider run, normalized into the
6
+ * {@link AiFakeStep} shape so `--replay` can re-feed them via
7
+ * `AiFake.respondWithSequence` for zero-API regression tests.
8
+ *
9
+ * The fixture format is versioned. Bumping `version` forces a
10
+ * re-record on stale fixtures rather than silently mis-replaying.
11
+ */
12
+ import type { AgentResponse } from '../types.js';
13
+ import type { AiFakeStep } from '../fake.js';
14
+ /** Fixture format. Bump `version` when the shape changes incompatibly. */
15
+ export interface EvalFixture {
16
+ version: 1;
17
+ suite: string;
18
+ case: string;
19
+ input: string;
20
+ recordedAt: string;
21
+ steps: AiFakeStep[];
22
+ }
23
+ /**
24
+ * Convert an `AgentResponse` into the assistant-turn `AiFakeStep[]`
25
+ * sequence that `AiFake.respondWithSequence` expects.
26
+ *
27
+ * - Drops user/tool turns — those are framework-generated during a
28
+ * replayed run, not provider output.
29
+ * - Multi-modal assistant content collapses to its concatenated text
30
+ * parts (the fake's transport is text-only; image/document parts
31
+ * wouldn't replay meaningfully).
32
+ * - `toolCalls` carry through verbatim so multi-step tool loops
33
+ * replay deterministically.
34
+ */
35
+ export declare function stepsFromResponse(response: AgentResponse): AiFakeStep[];
36
+ /**
37
+ * Default fixtures directory: `<cwd>/evals/__fixtures__`. Override
38
+ * via the CLI handler's options for tests / non-standard layouts.
39
+ */
40
+ export declare function defaultFixturesDir(cwd: string): string;
41
+ /**
42
+ * Filesystem-safe slug for `<suite>/<case>` segments. Letters,
43
+ * digits, dot, dash, underscore pass through; everything else
44
+ * collapses to `-`. Multiple consecutive `-` collapse to one.
45
+ *
46
+ * Pure function; tested directly so suite/case rename diffs stay
47
+ * predictable across editors.
48
+ */
49
+ export declare function slugify(s: string): string;
50
+ export declare function fixturePath(dir: string, suite: string, caseName: string): string;
51
+ /**
52
+ * Read a fixture file. Returns `null` when the fixture is missing
53
+ * (replay falls back to running normally with a clear stderr line).
54
+ *
55
+ * Throws on parse / version errors — corruption is not a passing
56
+ * case and silently ignoring it would mask real regressions.
57
+ */
58
+ export declare function readFixture(dir: string, suite: string, caseName: string): Promise<EvalFixture | null>;
59
+ /**
60
+ * Write a fixture, creating intermediate directories as needed.
61
+ * Pretty-printed (2-space) so PR diffs remain readable when the
62
+ * model output evolves.
63
+ */
64
+ export declare function writeFixture(dir: string, suite: string, caseName: string, payload: Omit<EvalFixture, 'version' | 'suite' | 'case' | 'recordedAt'>): Promise<string>;
65
+ //# sourceMappingURL=fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/eval/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,aAAa,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAK,CAAC,CAAA;IACb,KAAK,EAAO,MAAM,CAAA;IAClB,IAAI,EAAQ,MAAM,CAAA;IAClB,KAAK,EAAO,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAO,UAAU,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,GAAG,UAAU,EAAE,CAWvE;AASD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhF;AAID;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAO,MAAM,EAChB,KAAK,EAAK,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAiB7B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAO,MAAM,EAChB,KAAK,EAAK,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAG,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC,GACvE,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Fixture I/O for `pnpm rudder ai:eval --record` / `--replay` (#A5
3
+ * Phase 4). Each case writes one JSON file under
4
+ * `evals/__fixtures__/<suite>/<case>.json` carrying the assistant
5
+ * turns from a real provider run, normalized into the
6
+ * {@link AiFakeStep} shape so `--replay` can re-feed them via
7
+ * `AiFake.respondWithSequence` for zero-API regression tests.
8
+ *
9
+ * The fixture format is versioned. Bumping `version` forces a
10
+ * re-record on stale fixtures rather than silently mis-replaying.
11
+ */
12
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
13
+ import path from 'node:path';
14
+ /**
15
+ * Convert an `AgentResponse` into the assistant-turn `AiFakeStep[]`
16
+ * sequence that `AiFake.respondWithSequence` expects.
17
+ *
18
+ * - Drops user/tool turns — those are framework-generated during a
19
+ * replayed run, not provider output.
20
+ * - Multi-modal assistant content collapses to its concatenated text
21
+ * parts (the fake's transport is text-only; image/document parts
22
+ * wouldn't replay meaningfully).
23
+ * - `toolCalls` carry through verbatim so multi-step tool loops
24
+ * replay deterministically.
25
+ */
26
+ export function stepsFromResponse(response) {
27
+ return response.steps
28
+ .filter(step => step.message.role === 'assistant')
29
+ .map(step => {
30
+ const out = {
31
+ text: contentToText(step.message.content),
32
+ finishReason: step.finishReason,
33
+ };
34
+ if (step.toolCalls.length > 0)
35
+ out.toolCalls = step.toolCalls;
36
+ return out;
37
+ });
38
+ }
39
+ function contentToText(content) {
40
+ if (typeof content === 'string')
41
+ return content;
42
+ return content.filter(p => p.type === 'text').map(p => p.text).join('');
43
+ }
44
+ // ─── Fixture path conventions ─────────────────────────────
45
+ /**
46
+ * Default fixtures directory: `<cwd>/evals/__fixtures__`. Override
47
+ * via the CLI handler's options for tests / non-standard layouts.
48
+ */
49
+ export function defaultFixturesDir(cwd) {
50
+ return path.join(cwd, 'evals', '__fixtures__');
51
+ }
52
+ /**
53
+ * Filesystem-safe slug for `<suite>/<case>` segments. Letters,
54
+ * digits, dot, dash, underscore pass through; everything else
55
+ * collapses to `-`. Multiple consecutive `-` collapse to one.
56
+ *
57
+ * Pure function; tested directly so suite/case rename diffs stay
58
+ * predictable across editors.
59
+ */
60
+ export function slugify(s) {
61
+ return s.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || '_';
62
+ }
63
+ export function fixturePath(dir, suite, caseName) {
64
+ return path.join(dir, slugify(suite), `${slugify(caseName)}.json`);
65
+ }
66
+ // ─── Read / write ─────────────────────────────────────────
67
+ /**
68
+ * Read a fixture file. Returns `null` when the fixture is missing
69
+ * (replay falls back to running normally with a clear stderr line).
70
+ *
71
+ * Throws on parse / version errors — corruption is not a passing
72
+ * case and silently ignoring it would mask real regressions.
73
+ */
74
+ export async function readFixture(dir, suite, caseName) {
75
+ const file = fixturePath(dir, suite, caseName);
76
+ let raw;
77
+ try {
78
+ raw = await readFile(file, 'utf8');
79
+ }
80
+ catch (err) {
81
+ if (err.code === 'ENOENT')
82
+ return null;
83
+ throw err;
84
+ }
85
+ const parsed = JSON.parse(raw);
86
+ if (parsed.version !== 1) {
87
+ throw new Error(`[RudderJS AI] Fixture ${file} is version ${String(parsed.version)}; expected 1. ` +
88
+ `Re-record with \`pnpm rudder ai:eval --record\`.`);
89
+ }
90
+ return parsed;
91
+ }
92
+ /**
93
+ * Write a fixture, creating intermediate directories as needed.
94
+ * Pretty-printed (2-space) so PR diffs remain readable when the
95
+ * model output evolves.
96
+ */
97
+ export async function writeFixture(dir, suite, caseName, payload) {
98
+ const file = fixturePath(dir, suite, caseName);
99
+ await mkdir(path.dirname(file), { recursive: true });
100
+ const fixture = {
101
+ version: 1,
102
+ suite,
103
+ case: caseName,
104
+ recordedAt: new Date().toISOString(),
105
+ ...payload,
106
+ };
107
+ await writeFile(file, `${JSON.stringify(fixture, null, 2)}\n`);
108
+ return file;
109
+ }
110
+ //# sourceMappingURL=fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/eval/fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Self-contained HTML reporter for `pnpm rudder ai:eval --html`
3
+ * (#A5 Phase 5). Renders one or more {@link SuiteReport}s into a
4
+ * single HTML string with inline styles and minimal vanilla JS for
5
+ * row expand/collapse — no framework deps, no external assets, safe
6
+ * to paste into a PR comment or open offline.
7
+ *
8
+ * Defensive HTML-escape on every piece of user content (suite name,
9
+ * case name, input, response, metadata). Long responses get a
10
+ * `<pre>` block with `white-space: pre-wrap` so output stays
11
+ * scannable without a horizontal scroll.
12
+ */
13
+ import type { SuiteReport } from './index.js';
14
+ export interface HtmlReportOptions {
15
+ /** Document `<title>`. Defaults to `"Eval Report"`. */
16
+ title?: string;
17
+ /** ISO timestamp shown in the header. Defaults to `new Date().toISOString()`. */
18
+ generatedAt?: string;
19
+ }
20
+ /**
21
+ * Render an array of {@link SuiteReport}s as a single self-contained
22
+ * HTML document.
23
+ */
24
+ export declare function reportHtml(reports: SuiteReport[], opts?: HtmlReportOptions): string;
25
+ //# sourceMappingURL=html-reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-reporter.d.ts","sourceRoot":"","sources":["../../src/eval/html-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAA;AAE3D,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,KAAK,CAAC,EAAQ,MAAM,CAAA;IACpB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,GAAE,iBAAsB,GAAG,MAAM,CA6CvF"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Self-contained HTML reporter for `pnpm rudder ai:eval --html`
3
+ * (#A5 Phase 5). Renders one or more {@link SuiteReport}s into a
4
+ * single HTML string with inline styles and minimal vanilla JS for
5
+ * row expand/collapse — no framework deps, no external assets, safe
6
+ * to paste into a PR comment or open offline.
7
+ *
8
+ * Defensive HTML-escape on every piece of user content (suite name,
9
+ * case name, input, response, metadata). Long responses get a
10
+ * `<pre>` block with `white-space: pre-wrap` so output stays
11
+ * scannable without a horizontal scroll.
12
+ */
13
+ /**
14
+ * Render an array of {@link SuiteReport}s as a single self-contained
15
+ * HTML document.
16
+ */
17
+ export function reportHtml(reports, opts = {}) {
18
+ const title = opts.title ?? 'Eval Report';
19
+ const generatedAt = opts.generatedAt ?? new Date().toISOString();
20
+ const totals = reports.reduce((a, r) => ({
21
+ cases: a.cases + r.cases.length,
22
+ passed: a.passed + r.passed,
23
+ failed: a.failed + r.failed,
24
+ skipped: a.skipped + r.skipped,
25
+ cost: a.cost + r.cost,
26
+ tokens: a.tokens + r.tokens,
27
+ duration: a.duration + r.duration,
28
+ }), { cases: 0, passed: 0, failed: 0, skipped: 0, cost: 0, tokens: 0, duration: 0 });
29
+ const passRate = totals.cases > 0 ? Math.round((totals.passed / totals.cases) * 100) : 0;
30
+ return `<!DOCTYPE html>
31
+ <html lang="en">
32
+ <head>
33
+ <meta charset="UTF-8">
34
+ <meta name="viewport" content="width=device-width,initial-scale=1">
35
+ <title>${escapeHtml(title)}</title>
36
+ <style>${STYLE}</style>
37
+ </head>
38
+ <body>
39
+ <header class="page-header">
40
+ <h1>${escapeHtml(title)}</h1>
41
+ <div class="meta">
42
+ Generated ${escapeHtml(generatedAt)} ·
43
+ ${reports.length} suite${plural(reports.length)} ·
44
+ ${totals.cases} case${plural(totals.cases)} ·
45
+ <strong class="${passRate === 100 ? 'ok' : passRate >= 80 ? 'warn' : 'bad'}">${passRate}% pass</strong> ·
46
+ ${formatCost(totals.cost)} ·
47
+ ${totals.tokens.toLocaleString()} tokens ·
48
+ ${formatMs(totals.duration)}
49
+ </div>
50
+ </header>
51
+ ${reports.map(renderSuite).join('\n')}
52
+ <script>${SCRIPT}</script>
53
+ </body>
54
+ </html>
55
+ `;
56
+ }
57
+ function renderSuite(r) {
58
+ const passRate = r.cases.length > 0 ? Math.round((r.passed / r.cases.length) * 100) : 0;
59
+ return `<section class="suite">
60
+ <header class="suite-header">
61
+ <h2>${escapeHtml(r.suite)}</h2>
62
+ <div class="suite-stats">
63
+ <span class="${passRate === 100 ? 'ok' : passRate >= 80 ? 'warn' : 'bad'}">${r.passed}/${r.cases.length} passed</span>
64
+ ${r.skipped > 0 ? `· <span class="muted">${r.skipped} skipped</span>` : ''}
65
+ · ${formatCost(r.cost)}
66
+ · ${r.tokens.toLocaleString()} tokens
67
+ · ${formatMs(r.duration)}
68
+ </div>
69
+ ${renderMetadata(r.metadata)}
70
+ </header>
71
+ <table class="cases">
72
+ <thead>
73
+ <tr>
74
+ <th>Case</th>
75
+ <th>Status</th>
76
+ <th class="num">Tokens</th>
77
+ <th class="num">Cost</th>
78
+ <th class="num">Duration</th>
79
+ </tr>
80
+ </thead>
81
+ <tbody>
82
+ ${r.cases.map(renderCase).join('\n')}
83
+ </tbody>
84
+ </table>
85
+ </section>`;
86
+ }
87
+ function renderCase(c) {
88
+ const glyph = c.status === 'passed' ? '✓' : c.status === 'failed' ? '✗' : '○';
89
+ const responseBlock = c.responseText !== undefined
90
+ ? `<h4>Response</h4><pre>${escapeHtml(c.responseText)}</pre>`
91
+ : '<h4>Response</h4><pre class="muted">&lt;no response — agent threw or skipped&gt;</pre>';
92
+ const reasonBlock = (c.metric?.reason ?? c.reason)
93
+ ? `<h4>Reason</h4><pre>${escapeHtml(c.metric?.reason ?? c.reason)}</pre>`
94
+ : '';
95
+ const scoreBlock = c.metric?.score !== undefined
96
+ ? `<h4>Score</h4><pre>${c.metric.score.toFixed(3)}</pre>`
97
+ : '';
98
+ return ` <tr class="case ${c.status}" tabindex="0" aria-expanded="false">
99
+ <td><span class="glyph">${glyph}</span> ${escapeHtml(c.name)}</td>
100
+ <td><span class="badge ${c.status}">${c.status}</span></td>
101
+ <td class="num">${c.tokens.toLocaleString()}</td>
102
+ <td class="num">${formatCost(c.cost)}</td>
103
+ <td class="num">${formatMs(c.duration)}</td>
104
+ </tr>
105
+ <tr class="case-detail" hidden>
106
+ <td colspan="5">
107
+ <h4>Input</h4>
108
+ <pre>${escapeHtml(c.input)}</pre>
109
+ ${responseBlock}
110
+ ${scoreBlock}
111
+ ${reasonBlock}
112
+ </td>
113
+ </tr>`;
114
+ }
115
+ function renderMetadata(meta) {
116
+ if (!meta)
117
+ return '';
118
+ const rows = Object.entries(meta).filter(([, v]) => v !== undefined && v !== '');
119
+ if (rows.length === 0)
120
+ return '';
121
+ return `<dl class="metadata">${rows.map(([k, v]) => `<dt>${escapeHtml(formatLabel(k))}</dt><dd>${escapeHtml(v)}</dd>`).join('')}</dl>`;
122
+ }
123
+ function formatLabel(key) {
124
+ // camelCase → Title Case for the well-known keys; pass others through.
125
+ if (key === 'lastReviewed')
126
+ return 'Last reviewed';
127
+ return key.charAt(0).toUpperCase() + key.slice(1);
128
+ }
129
+ // ─── HTML escape (no external dep) ───────────────────────
130
+ const ESCAPE_MAP = {
131
+ '&': '&amp;',
132
+ '<': '&lt;',
133
+ '>': '&gt;',
134
+ '"': '&quot;',
135
+ "'": '&#39;',
136
+ };
137
+ function escapeHtml(s) {
138
+ return s.replace(/[&<>"']/g, ch => ESCAPE_MAP[ch]);
139
+ }
140
+ function plural(n) {
141
+ return n === 1 ? '' : 's';
142
+ }
143
+ function formatMs(ms) {
144
+ if (ms < 1000)
145
+ return `${Math.round(ms)}ms`;
146
+ return `${(ms / 1000).toFixed(1)}s`;
147
+ }
148
+ function formatCost(usd) {
149
+ if (usd === 0)
150
+ return '$0.000';
151
+ if (usd < 0.001)
152
+ return '<$0.001';
153
+ return `$${usd.toFixed(3)}`;
154
+ }
155
+ // ─── Inline assets ────────────────────────────────────────
156
+ const STYLE = `
157
+ :root { color-scheme: light dark; --fg: #1a1a1a; --bg: #fff; --muted: #6a6a6a; --border: #e2e2e2; --row-hover: #f7f7f7; --ok: #1a7f37; --warn: #b08800; --bad: #b91c1c; --pre-bg: #f6f8fa; }
158
+ @media (prefers-color-scheme: dark) {
159
+ :root { --fg: #e6e6e6; --bg: #0d1117; --muted: #8a8a8a; --border: #30363d; --row-hover: #161b22; --ok: #3fb950; --warn: #d29922; --bad: #f85149; --pre-bg: #161b22; }
160
+ }
161
+ * { box-sizing: border-box }
162
+ body { font: 14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; color: var(--fg); background: var(--bg); margin: 0; padding: 24px; max-width: 1100px; margin-inline: auto }
163
+ h1 { margin: 0 0 4px; font-size: 24px }
164
+ h2 { margin: 0 0 4px; font-size: 18px }
165
+ h4 { margin: 12px 0 4px; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted) }
166
+ pre { background: var(--pre-bg); border: 1px solid var(--border); border-radius: 6px; padding: 8px 12px; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; font: 12px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace; margin: 0 }
167
+ .page-header { border-bottom: 1px solid var(--border); padding-bottom: 12px; margin-bottom: 20px }
168
+ .page-header .meta { color: var(--muted); font-size: 13px }
169
+ .suite { margin-bottom: 28px }
170
+ .suite-header h2 { display: inline }
171
+ .suite-stats { color: var(--muted); font-size: 13px; margin-top: 4px }
172
+ .metadata { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; margin: 8px 0 0; font-size: 13px }
173
+ .metadata dt { color: var(--muted); font-weight: normal }
174
+ .metadata dd { margin: 0 }
175
+ .cases { width: 100%; border-collapse: collapse; margin-top: 12px; border: 1px solid var(--border); border-radius: 6px; overflow: hidden }
176
+ .cases th, .cases td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border) }
177
+ .cases th { background: var(--pre-bg); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted) }
178
+ .cases tr:last-child td { border-bottom: none }
179
+ .cases tr.case { cursor: pointer; user-select: none }
180
+ .cases tr.case:hover { background: var(--row-hover) }
181
+ .cases tr.case:focus { outline: 2px solid var(--warn); outline-offset: -2px }
182
+ .cases tr.case-detail td { background: var(--pre-bg) }
183
+ .cases td.num { text-align: right; font-variant-numeric: tabular-nums }
184
+ .glyph { display: inline-block; width: 14px; font-weight: bold }
185
+ .cases tr.case.passed .glyph { color: var(--ok) }
186
+ .cases tr.case.failed .glyph { color: var(--bad) }
187
+ .cases tr.case.skipped .glyph { color: var(--muted) }
188
+ .badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em }
189
+ .badge.passed { background: rgba(63,185,80,.15); color: var(--ok) }
190
+ .badge.failed { background: rgba(248,81,73,.15); color: var(--bad) }
191
+ .badge.skipped { background: rgba(138,138,138,.15); color: var(--muted) }
192
+ .ok { color: var(--ok) } .warn { color: var(--warn) } .bad { color: var(--bad) } .muted { color: var(--muted) }
193
+ `.trim();
194
+ const SCRIPT = `
195
+ document.querySelectorAll('tr.case').forEach(function(row) {
196
+ function toggle() {
197
+ var detail = row.nextElementSibling;
198
+ if (!detail || !detail.classList.contains('case-detail')) return;
199
+ var open = !detail.hidden;
200
+ detail.hidden = open;
201
+ row.setAttribute('aria-expanded', String(!open));
202
+ }
203
+ row.addEventListener('click', toggle);
204
+ row.addEventListener('keydown', function(e) {
205
+ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
206
+ });
207
+ });
208
+ `.trim();
209
+ //# sourceMappingURL=html-reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-reporter.js","sourceRoot":"","sources":["../../src/eval/html-reporter.ts"],"names":[],"mappings":"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"}