@chatcops/cli 0.0.0-stage → 0.1.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 (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -2
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +4 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/config.d.ts +53 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +55 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +7 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/main.d.ts +53 -0
  16. package/dist/main.d.ts.map +1 -0
  17. package/dist/main.js +247 -0
  18. package/dist/main.js.map +1 -0
  19. package/dist/test/assertions/index.d.ts +18 -0
  20. package/dist/test/assertions/index.d.ts.map +1 -0
  21. package/dist/test/assertions/index.js +50 -0
  22. package/dist/test/assertions/index.js.map +1 -0
  23. package/dist/test/assertions/javascript.d.ts +10 -0
  24. package/dist/test/assertions/javascript.d.ts.map +1 -0
  25. package/dist/test/assertions/javascript.js +51 -0
  26. package/dist/test/assertions/javascript.js.map +1 -0
  27. package/dist/test/assertions/judge.d.ts +8 -0
  28. package/dist/test/assertions/judge.d.ts.map +1 -0
  29. package/dist/test/assertions/judge.js +33 -0
  30. package/dist/test/assertions/judge.js.map +1 -0
  31. package/dist/test/assertions/parts.d.ts +12 -0
  32. package/dist/test/assertions/parts.d.ts.map +1 -0
  33. package/dist/test/assertions/parts.js +39 -0
  34. package/dist/test/assertions/parts.js.map +1 -0
  35. package/dist/test/assertions/text.d.ts +4 -0
  36. package/dist/test/assertions/text.d.ts.map +1 -0
  37. package/dist/test/assertions/text.js +10 -0
  38. package/dist/test/assertions/text.js.map +1 -0
  39. package/dist/test/assertions/tools.d.ts +13 -0
  40. package/dist/test/assertions/tools.d.ts.map +1 -0
  41. package/dist/test/assertions/tools.js +82 -0
  42. package/dist/test/assertions/tools.js.map +1 -0
  43. package/dist/test/assertions/usage.d.ts +8 -0
  44. package/dist/test/assertions/usage.d.ts.map +1 -0
  45. package/dist/test/assertions/usage.js +52 -0
  46. package/dist/test/assertions/usage.js.map +1 -0
  47. package/dist/test/assertions/values.d.ts +8 -0
  48. package/dist/test/assertions/values.d.ts.map +1 -0
  49. package/dist/test/assertions/values.js +19 -0
  50. package/dist/test/assertions/values.js.map +1 -0
  51. package/dist/test/cassette.d.ts +77 -0
  52. package/dist/test/cassette.d.ts.map +1 -0
  53. package/dist/test/cassette.js +236 -0
  54. package/dist/test/cassette.js.map +1 -0
  55. package/dist/test/command.d.ts +9 -0
  56. package/dist/test/command.d.ts.map +1 -0
  57. package/dist/test/command.js +139 -0
  58. package/dist/test/command.js.map +1 -0
  59. package/dist/test/cost.d.ts +26 -0
  60. package/dist/test/cost.d.ts.map +1 -0
  61. package/dist/test/cost.js +33 -0
  62. package/dist/test/cost.js.map +1 -0
  63. package/dist/test/judge.d.ts +32 -0
  64. package/dist/test/judge.d.ts.map +1 -0
  65. package/dist/test/judge.js +109 -0
  66. package/dist/test/judge.js.map +1 -0
  67. package/dist/test/load.d.ts +9 -0
  68. package/dist/test/load.d.ts.map +1 -0
  69. package/dist/test/load.js +98 -0
  70. package/dist/test/load.js.map +1 -0
  71. package/dist/test/reporters/index.d.ts +35 -0
  72. package/dist/test/reporters/index.d.ts.map +1 -0
  73. package/dist/test/reporters/index.js +11 -0
  74. package/dist/test/reporters/index.js.map +1 -0
  75. package/dist/test/reporters/json.d.ts +4 -0
  76. package/dist/test/reporters/json.d.ts.map +1 -0
  77. package/dist/test/reporters/json.js +8 -0
  78. package/dist/test/reporters/json.js.map +1 -0
  79. package/dist/test/reporters/pretty.d.ts +3 -0
  80. package/dist/test/reporters/pretty.d.ts.map +1 -0
  81. package/dist/test/reporters/pretty.js +119 -0
  82. package/dist/test/reporters/pretty.js.map +1 -0
  83. package/dist/test/run.d.ts +46 -0
  84. package/dist/test/run.d.ts.map +1 -0
  85. package/dist/test/run.js +157 -0
  86. package/dist/test/run.js.map +1 -0
  87. package/dist/test/types.d.ts +116 -0
  88. package/dist/test/types.d.ts.map +1 -0
  89. package/dist/test/types.js +2 -0
  90. package/dist/test/types.js.map +1 -0
  91. package/package.json +60 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"judge.js","sourceRoot":"","sources":["../../src/test/judge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Fixture, TestCase } from './types.js';
2
+ export declare const DEFAULT_PATTERN = "evals/**/*.chat.yaml";
3
+ /** A fixture file, checked, with defaults applied to each test. */
4
+ export declare function loadFixture(file: string): Promise<Fixture>;
5
+ /** Files under `cwd` matching any of the globs (relative to `cwd`). */
6
+ export declare function findFixtures(cwd: string, patterns: string[]): Promise<string[]>;
7
+ /** `--filter`: a substring of the test name, or `tag:<name>`. */
8
+ export declare function matchesFilter(test: TestCase, filter: string | undefined): boolean;
9
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/test/load.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAO,MAAM,eAAe,yBAAyB,CAAC;AAiCtD,mEAAmE;AACnE,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBhE;AAWD,uEAAuE;AACvE,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAerF;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIjF"}
@@ -0,0 +1,98 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { join, relative, resolve, sep } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { globToRegExp } from '@chatcops/ingest';
5
+ import { parse as parseYaml } from 'yaml';
6
+ import { z } from 'zod';
7
+ import { ConfigError } from '../config.js';
8
+ export const DEFAULT_PATTERN = 'evals/**/*.chat.yaml';
9
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '__cassettes__']);
10
+ const assertion = z.record(z.unknown()).refine((value) => Object.keys(value).length === 1, {
11
+ message: 'an assertion has exactly one key, such as `contains: "$19"`',
12
+ });
13
+ const pageContext = z.object({
14
+ url: z.string().url(),
15
+ title: z.string(),
16
+ description: z.string().optional(),
17
+ contentSnippet: z.string().optional(),
18
+ });
19
+ const toolResult = z.object({ success: z.boolean(), data: z.unknown().optional(), message: z.string().optional() });
20
+ const common = {
21
+ tags: z.array(z.string()).optional(),
22
+ locale: z.string().optional(),
23
+ pageContext: pageContext.optional(),
24
+ userData: z.record(z.string()).optional(),
25
+ mocks: z.object({ tools: z.record(toolResult).optional() }).strict().optional(),
26
+ repeat: z.number().int().min(1).max(100).optional(),
27
+ passRate: z.number().min(0).max(1).optional(),
28
+ };
29
+ const turn = z.object({ user: z.string().min(1), expect: z.array(assertion).optional() }).strict();
30
+ const testCase = z.object({ name: z.string().min(1), turns: z.array(turn).min(1), ...common }).strict();
31
+ const fixtureSchema = z
32
+ .object({
33
+ version: z.literal(1),
34
+ name: z.string().min(1),
35
+ defaults: z.object(common).strict().optional(),
36
+ tests: z.array(testCase).min(1),
37
+ })
38
+ .strict();
39
+ /** A fixture file, checked, with defaults applied to each test. */
40
+ export async function loadFixture(file) {
41
+ let raw;
42
+ try {
43
+ if (/\.ya?ml$/i.test(file)) {
44
+ raw = parseYaml(await readFile(file, 'utf8'));
45
+ }
46
+ else {
47
+ raw = (await import(pathToFileURL(file).href)).default;
48
+ }
49
+ }
50
+ catch (error) {
51
+ throw new ConfigError(`${file}: ${error instanceof Error ? error.message : String(error)}`);
52
+ }
53
+ const parsed = fixtureSchema.safeParse(raw);
54
+ if (!parsed.success) {
55
+ const issues = parsed.error.issues.map((issue) => ` ${issue.path.join('.') || '(root)'}: ${issue.message}`);
56
+ throw new ConfigError(`${file} isn't a valid eval file:\n${issues.join('\n')}`);
57
+ }
58
+ const fixture = parsed.data;
59
+ return { ...fixture, tests: fixture.tests.map((test) => withDefaults(test, fixture.defaults)) };
60
+ }
61
+ function withDefaults(test, defaults) {
62
+ if (!defaults)
63
+ return test;
64
+ return {
65
+ ...defaults,
66
+ ...test,
67
+ mocks: { tools: { ...defaults.mocks?.tools, ...test.mocks?.tools } },
68
+ };
69
+ }
70
+ /** Files under `cwd` matching any of the globs (relative to `cwd`). */
71
+ export async function findFixtures(cwd, patterns) {
72
+ const regexes = patterns.map((pattern) => globToRegExp(pattern.replace(/^\.\//, '')));
73
+ const found = [];
74
+ async function walk(dir) {
75
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
76
+ if (entry.isDirectory()) {
77
+ if (!SKIP_DIRS.has(entry.name))
78
+ await walk(join(dir, entry.name));
79
+ }
80
+ else if (entry.isFile()) {
81
+ const path = relative(cwd, join(dir, entry.name)).split(sep).join('/');
82
+ if (regexes.some((regex) => regex.test(path)))
83
+ found.push(resolve(cwd, path));
84
+ }
85
+ }
86
+ }
87
+ await walk(cwd);
88
+ return found.sort();
89
+ }
90
+ /** `--filter`: a substring of the test name, or `tag:<name>`. */
91
+ export function matchesFilter(test, filter) {
92
+ if (!filter)
93
+ return true;
94
+ if (filter.startsWith('tag:'))
95
+ return test.tags?.includes(filter.slice(4)) ?? false;
96
+ return test.name.toLowerCase().includes(filter.toLowerCase());
97
+ }
98
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/test/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { CassetteMode } from '../cassette.js';
2
+ import type { TestResult } from '../types.js';
3
+ /** Where a reporter writes: stdout, unless the reporter is given a file. */
4
+ export interface ReporterOutput {
5
+ write(text: string): unknown;
6
+ }
7
+ /** About the whole run, for the end of a report. */
8
+ export interface RunSummary {
9
+ mode: CassetteMode;
10
+ /** The bot's model id, when available. */
11
+ model?: string;
12
+ /** Total time spent running the evals, in milliseconds. */
13
+ elapsedMs: number;
14
+ /** Whether some calls could not be priced. */
15
+ costIncomplete: boolean;
16
+ /** The judge's `provider:model`, when the run used one. */
17
+ judge?: string;
18
+ /** Turns and judge calls with a price, in US dollars. Unset when nothing had a price. */
19
+ costUsd?: number;
20
+ }
21
+ /** Gets results as tests finish, and all of them at the end. */
22
+ export interface Reporter {
23
+ onResult?(result: TestResult): void;
24
+ onEnd?(results: TestResult[], summary: RunSummary): void | Promise<void>;
25
+ }
26
+ export type ReporterFactory = (output: ReporterOutput, options: {
27
+ verbose?: boolean;
28
+ env?: Record<string, string | undefined>;
29
+ }) => Reporter;
30
+ /**
31
+ * The reporters `--reporter` can name. To add one, write it in its own file
32
+ * in this folder and add it here.
33
+ */
34
+ export declare const REPORTERS: Map<string, ReporterFactory>;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/test/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,oDAAoD;AACpD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,cAAc,EAAE,OAAO,CAAC;IACxB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,gEAAgE;AAChE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,KAAK,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,KAAK,QAAQ,CAAC;AAE7I;;;GAGG;AACH,eAAO,MAAM,SAAS,8BAGpB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { jsonReporter } from './json.js';
2
+ import { prettyReporter } from './pretty.js';
3
+ /**
4
+ * The reporters `--reporter` can name. To add one, write it in its own file
5
+ * in this folder and add it here.
6
+ */
7
+ export const REPORTERS = new Map([
8
+ ['pretty', prettyReporter],
9
+ ['json', jsonReporter],
10
+ ]);
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/test/reporters/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8B7C;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAA0B;IACxD,CAAC,QAAQ,EAAE,cAAc,CAAC;IAC1B,CAAC,MAAM,EAAE,YAAY,CAAC;CACvB,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ReporterFactory } from './index.js';
2
+ /** One JSON object at the end: counts, and every run with every turn. */
3
+ export declare const jsonReporter: ReporterFactory;
4
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/test/reporters/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,yEAAyE;AACzE,eAAO,MAAM,YAAY,EAAE,eAKzB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** One JSON object at the end: counts, and every run with every turn. */
2
+ export const jsonReporter = (output) => ({
3
+ onEnd(results, summary) {
4
+ const failed = results.filter((result) => !result.pass).length;
5
+ output.write(`${JSON.stringify({ passed: results.length - failed, failed, summary, results })}\n`);
6
+ },
7
+ });
8
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/test/reporters/json.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,CAAC,MAAM,YAAY,GAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,OAAO,EAAE,OAAO;QACpB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IACrG,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ReporterFactory } from './index.js';
2
+ export declare const prettyReporter: ReporterFactory;
3
+ //# sourceMappingURL=pretty.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pretty.d.ts","sourceRoot":"","sources":["../../../src/test/reporters/pretty.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,YAAY,CAAC;AAE9D,eAAO,MAAM,cAAc,EAAE,eAU5B,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { styleText } from 'node:util';
2
+ import { dollars } from '../cost.js';
3
+ export const prettyReporter = (output, options = {}) => {
4
+ const env = options.env ?? process.env;
5
+ const colors = 'isTTY' in output && output.isTTY === true && env.NO_COLOR === undefined;
6
+ const paint = (color, text) => (colors ? styleText(color, text, { validateStream: false }) : text);
7
+ return {
8
+ onEnd(results, summary) {
9
+ output.write(prettyReport(results, summary, options.verbose === true, paint));
10
+ },
11
+ };
12
+ };
13
+ function prettyReport(results, summary, verbose, paint) {
14
+ const lines = [
15
+ '',
16
+ paint('cyan', 'ChatCops evaluations'),
17
+ paint('gray', '────────────────────────────────────────'),
18
+ paint('gray', `Model: ${summary.model ?? 'unavailable'}`),
19
+ ...(summary.judge ? [paint('gray', `Judge: ${summary.judge}`)] : []),
20
+ paint('gray', `Mode: ${summary.mode === 'record' ? 'recorded' : summary.mode}`),
21
+ '',
22
+ ];
23
+ const groups = new Map();
24
+ for (const result of results) {
25
+ const group = groups.get(result.fixture) ?? [];
26
+ group.push(result);
27
+ groups.set(result.fixture, group);
28
+ }
29
+ for (const [fixture, tests] of groups) {
30
+ lines.push(paint('cyan', fixture));
31
+ for (const result of tests) {
32
+ const status = result.pass ? paint('green', '✓') : paint('red', '✗');
33
+ const rate = result.runs.length > 1 ? ` (${result.runs.filter((run) => run.pass).length}/${result.runs.length} runs)` : '';
34
+ const elapsed = result.durationMs;
35
+ const duration = elapsed === undefined ? '' : ` ${formatDuration(elapsed)}`;
36
+ lines.push(` ${status} ${result.test}${rate}${duration}`);
37
+ if (!result.pass || verbose) {
38
+ appendDetails(lines, result, result.runs.length > 1, paint);
39
+ lines.push('');
40
+ }
41
+ }
42
+ if (lines.at(-1) !== '')
43
+ lines.push('');
44
+ }
45
+ const failed = results.filter((result) => !result.pass).length;
46
+ const assertions = results.flatMap((result) => result.runs.flatMap((run) => run.turns.flatMap(({ results: checks }) => checks)));
47
+ const passedAssertions = assertions.filter((check) => check.pass).length;
48
+ const cost = summary.mode === 'replay'
49
+ ? ' Replayed, nothing spent.'
50
+ : summary.costUsd === undefined
51
+ ? ''
52
+ : summary.costIncomplete
53
+ ? ` Spent about ${dollars(summary.costUsd)} (partial; some calls could not be priced).`
54
+ : ` Spent about ${dollars(summary.costUsd)}.`;
55
+ const judge = summary.judge ? ` Judged by ${summary.judge}.` : '';
56
+ lines.push(paint('cyan', 'Summary'), paint('gray', '────────────────────────────────────────'), `${paint('green', `${results.length - failed} passed`)}, ${paint(failed ? 'red' : 'gray', `${failed} failed`)}.${cost}${judge}`, `Assertions: ${passedAssertions} passed, ${assertions.length - passedAssertions} failed`, formatUsage(results), paint('gray', `Elapsed: ${formatDuration(summary.elapsedMs)}`));
57
+ return `${lines.join('\n')}\n`;
58
+ }
59
+ function appendDetails(lines, result, showRun, paint) {
60
+ for (const run of result.runs) {
61
+ for (const [index, { turn, results: checks }] of run.turns.entries()) {
62
+ if (showRun && index === 0)
63
+ lines.push(paint('gray', ` Run ${run.run}`));
64
+ if (!checks.length)
65
+ lines.push(paint('gray', ' No assertions for this turn.'));
66
+ for (const check of checks) {
67
+ const status = check.pass ? paint('green', '✓') : paint('red', '✗');
68
+ const wrapped = wrapText(`turn ${index + 1}: ${reason(check)}`, 76);
69
+ lines.push(` ${status} ${wrapped[0]}`);
70
+ for (const continuation of wrapped.slice(1))
71
+ lines.push(` ${continuation}`);
72
+ }
73
+ if (checks.some((check) => !check.pass)) {
74
+ lines.push(paint('gray', ` reply: ${clip(turn.text)}`));
75
+ }
76
+ }
77
+ if (run.error)
78
+ lines.push(` Run ${run.run}: ${run.error}`);
79
+ }
80
+ }
81
+ /** Wrap long explanations without losing words or relying on ANSI string widths. */
82
+ function wrapText(text, width) {
83
+ const lines = [];
84
+ let line = '';
85
+ for (const word of text.split(/\s+/)) {
86
+ if (line && line.length + word.length + 1 > width) {
87
+ lines.push(line);
88
+ line = word;
89
+ }
90
+ else {
91
+ line = line ? `${line} ${word}` : word;
92
+ }
93
+ }
94
+ lines.push(line);
95
+ return lines;
96
+ }
97
+ function reason(check) {
98
+ return check.reason ?? Object.keys(check.assertion)[0];
99
+ }
100
+ function formatUsage(results) {
101
+ const turns = results.flatMap((result) => result.runs.flatMap((run) => run.turns.map(({ turn }) => turn)));
102
+ const reported = turns.flatMap((turn) => (turn.usage ? [turn.usage] : []));
103
+ if (!reported.length)
104
+ return 'Bot tokens: unavailable (not reported)';
105
+ const input = reported.reduce((total, usage) => total + usage.inputTokens, 0);
106
+ const output = reported.reduce((total, usage) => total + usage.outputTokens, 0);
107
+ const partial = reported.length < turns.length ? ` (partial; reported for ${reported.length} of ${turns.length} turns)` : '';
108
+ return `Bot tokens${partial}: ${input} input + ${output} output = ${input + output} total`;
109
+ }
110
+ function formatDuration(milliseconds) {
111
+ if (milliseconds === undefined)
112
+ return 'unavailable';
113
+ return milliseconds < 1000 ? `${Math.round(milliseconds)} ms` : `${(milliseconds / 1000).toFixed(2)} s`;
114
+ }
115
+ function clip(text) {
116
+ const flat = text.replace(/\s+/g, ' ').trim();
117
+ return flat ? (flat.length > 200 ? `${flat.slice(0, 199)}…` : flat) : '(empty)';
118
+ }
119
+ //# sourceMappingURL=pretty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pretty.js","sourceRoot":"","sources":["../../../src/test/reporters/pretty.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { type ChatTool, type ToolResult } from '@chatcops/core';
2
+ import { createChatHandler, type ChatCopsServerConfig } from '@chatcops/server';
3
+ import type { Cassettes } from './cassette.js';
4
+ import { type Prices, type Spend } from './cost.js';
5
+ import type { Fixture, Judge, TestCase, TestResult, TurnResult } from './types.js';
6
+ export interface RunOptions {
7
+ /** Tests run at once. Default 4. */
8
+ concurrency?: number;
9
+ /** Overrides each test's `repeat`. */
10
+ repeat?: number;
11
+ /** Called as each test finishes. */
12
+ onResult?: (result: TestResult) => void;
13
+ /** Records or replays each test's HTTP calls. */
14
+ cassettes?: Cassettes;
15
+ /** For `judge` assertions. */
16
+ judge?: Judge;
17
+ /** The bot's model id, to price its turns. */
18
+ model?: string;
19
+ prices?: Prices;
20
+ /** Stops starting turns once `--max-cost` is reached. */
21
+ spend?: Spend;
22
+ }
23
+ /** An eval file to run: `file` as reported, `path` on disk (for its cassette). */
24
+ export interface FixtureJob {
25
+ file: string;
26
+ path?: string;
27
+ fixture: Fixture;
28
+ tests: TestCase[];
29
+ }
30
+ /**
31
+ * Runs every test of the fixtures against the server config, in process: the
32
+ * real request path (knowledge, page context, locale, tools), with fresh
33
+ * in-memory storage for every run and the fixture's tool mocks.
34
+ */
35
+ export declare function runFixtures(server: ChatCopsServerConfig, fixtures: FixtureJob[], options?: RunOptions): Promise<TestResult[]>;
36
+ /** Sends one message and collects the reply's parts as a turn result. */
37
+ export declare function sendTurn(handler: ReturnType<typeof createChatHandler>, body: Record<string, unknown>): Promise<TurnResult>;
38
+ /** The config's tools, with mocked ones answering their fixed result instead of running. */
39
+ export declare function withMocks(tools: ChatTool[], mocks: Record<string, ToolResult> | undefined): ChatTool[];
40
+ /**
41
+ * In replay nothing reaches the network, so CI needs no keys. The built-in
42
+ * providers refuse to start without one, so give them a stand-in. Headers
43
+ * aren't part of what a recording is matched on.
44
+ */
45
+ export declare function withoutKeys(server: ChatCopsServerConfig): ChatCopsServerConfig;
46
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/test/run.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAGhF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAmB,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AAElG,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,iDAAiD;IACjD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,UAAU,EAAE,CAAC,CA2BvB;AAgED,yEAAyE;AACzE,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CA8BhI;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,GAAG,QAAQ,EAAE,CAQtG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,oBAAoB,GAAG,oBAAoB,CAI9E"}
@@ -0,0 +1,157 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { isAIProvider, memoryStorage } from '@chatcops/core';
3
+ import { createChatHandler } from '@chatcops/server';
4
+ import { ConfigError } from '../config.js';
5
+ import { check } from './assertions/index.js';
6
+ import { costOf, dollars } from './cost.js';
7
+ /**
8
+ * Runs every test of the fixtures against the server config, in process: the
9
+ * real request path (knowledge, page context, locale, tools), with fresh
10
+ * in-memory storage for every run and the fixture's tool mocks.
11
+ */
12
+ export async function runFixtures(server, fixtures, options = {}) {
13
+ if (options.cassettes?.mode === 'replay')
14
+ server = withoutKeys(server);
15
+ const jobs = fixtures.flatMap(({ file, path, tests }) => tests.map((test) => ({ file, path: path ?? file, test })));
16
+ const results = new Array(jobs.length);
17
+ let next = 0;
18
+ const worker = async () => {
19
+ while (next < jobs.length) {
20
+ const index = next++;
21
+ const { file, path, test } = jobs[index];
22
+ const started = performance.now();
23
+ results[index] = await runTest(file, test, options.repeat, (run) => {
24
+ const once = () => runOnce(server, { file, path, test, run }, options);
25
+ if (!options.cassettes)
26
+ return once();
27
+ return options.cassettes.run(path, test.name, once).then(({ value, problems }) => {
28
+ if (problems.length) {
29
+ value.pass = false;
30
+ value.error = problems.length > 1 ? `${problems[0]} (and ${problems.length - 1} more)` : problems[0];
31
+ }
32
+ return value;
33
+ });
34
+ });
35
+ results[index].durationMs = performance.now() - started;
36
+ options.onResult?.(results[index]);
37
+ }
38
+ };
39
+ await Promise.all(Array.from({ length: Math.min(Math.max(1, options.concurrency ?? 4), jobs.length) }, worker));
40
+ return results;
41
+ }
42
+ async function runTest(fixture, test, repeatOverride, once) {
43
+ const repeat = repeatOverride ?? test.repeat ?? 1;
44
+ const runs = [];
45
+ for (let run = 1; run <= repeat; run++)
46
+ runs.push(await once(run));
47
+ const passed = runs.filter((result) => result.pass).length;
48
+ const passRate = passed / runs.length;
49
+ return { fixture, test: test.name, runs, passRate, pass: passRate >= (test.passRate ?? 1) };
50
+ }
51
+ async function runOnce(server, { file, path, test, run }, options) {
52
+ const result = { fixture: file, test: test.name, run, pass: true, turns: [] };
53
+ const { spend } = options;
54
+ const context = { fixture: path, ...(options.judge ? { judge: options.judge } : {}) };
55
+ // Usage on `finish` is what usage assertions read.
56
+ const handler = createChatHandler({ ...server, exposeUsage: true, storage: memoryStorage(), tools: withMocks(server.tools ?? [], test.mocks?.tools) });
57
+ const conversationId = `eval-${randomUUID()}`;
58
+ const conversation = [];
59
+ for (const turnSpec of test.turns) {
60
+ if (spend?.exceeded) {
61
+ result.pass = false;
62
+ result.error = `stopped before turn ${conversation.length + 1}: --max-cost ${dollars(spend.max ?? 0)} reached (${dollars(spend.spent)} spent)`;
63
+ break;
64
+ }
65
+ const turn = await sendTurn(handler, {
66
+ conversationId,
67
+ message: turnSpec.user,
68
+ ...(test.locale ? { locale: test.locale } : {}),
69
+ ...(test.pageContext ? { pageContext: test.pageContext } : {}),
70
+ ...(test.userData ? { userData: test.userData } : {}),
71
+ });
72
+ if (options.model)
73
+ turn.model = options.model;
74
+ const costUsd = costOf(options.model, turn.usage, options.prices);
75
+ if (costUsd !== undefined)
76
+ turn.costUsd = costUsd;
77
+ spend?.add(costUsd);
78
+ conversation.push(turn);
79
+ const checks = [];
80
+ for (const assertion of turnSpec.expect ?? []) {
81
+ const checked = await check(assertion, turn, conversation, context);
82
+ spend?.add(checked.costUsd);
83
+ checks.push(checked);
84
+ }
85
+ result.turns.push({ turn, results: checks });
86
+ if (checks.some((c) => !c.pass))
87
+ result.pass = false;
88
+ if (turn.error) {
89
+ result.pass = false;
90
+ result.error = `turn ${conversation.length} failed: ${turn.error}`;
91
+ break;
92
+ }
93
+ }
94
+ return result;
95
+ }
96
+ /** Sends one message and collects the reply's parts as a turn result. */
97
+ export async function sendTurn(handler, body) {
98
+ const started = performance.now();
99
+ const turn = { user: String(body.message), text: '', toolCalls: [], sources: [], leads: [], latencyMs: 0 };
100
+ const start = await handler.startChat(body, undefined, { format: 'v1' });
101
+ if (!start.ok) {
102
+ turn.error = start.error.message ? `${start.error.code}: ${start.error.message}` : start.error.code;
103
+ turn.latencyMs = performance.now() - started;
104
+ return turn;
105
+ }
106
+ try {
107
+ for await (const part of start.parts) {
108
+ if (part.type === 'text-delta')
109
+ turn.text += part.delta;
110
+ else if (part.type === 'tool-call')
111
+ turn.toolCalls.push({ name: part.toolName, input: part.input });
112
+ else if (part.type === 'source')
113
+ turn.sources.push({ url: part.url, ...(part.title ? { title: part.title } : {}) });
114
+ else if (part.type === 'lead-captured')
115
+ turn.leads.push(part.lead);
116
+ else if (part.type === 'error')
117
+ turn.error = part.code;
118
+ else if (part.type === 'finish') {
119
+ turn.finishReason = part.reason;
120
+ if (part.usage)
121
+ turn.usage = { inputTokens: part.usage.inputTokens, outputTokens: part.usage.outputTokens };
122
+ turn.latencyMs = performance.now() - started;
123
+ }
124
+ }
125
+ }
126
+ catch (error) {
127
+ // The server's HTTP layer turns this into an internal_error part; in
128
+ // process it arrives as a throw, such as a knowledge source that failed.
129
+ // It fails this test instead of stopping the whole run.
130
+ turn.error = `internal_error: ${error instanceof Error ? error.message : String(error)}`;
131
+ }
132
+ if (!turn.latencyMs)
133
+ turn.latencyMs = performance.now() - started;
134
+ return turn;
135
+ }
136
+ /** The config's tools, with mocked ones answering their fixed result instead of running. */
137
+ export function withMocks(tools, mocks) {
138
+ if (!mocks || !Object.keys(mocks).length)
139
+ return tools;
140
+ const names = new Set(tools.map((tool) => tool.name));
141
+ const unknown = Object.keys(mocks).filter((name) => !names.has(name));
142
+ if (unknown.length)
143
+ throw new ConfigError(`Mocks for tools the server config doesn't have: ${unknown.join(', ')}`);
144
+ return tools.map((tool) => mocks[tool.name] ? Object.assign(Object.create(tool), { execute: async () => structuredClone(mocks[tool.name]) }) : tool);
145
+ }
146
+ /**
147
+ * In replay nothing reaches the network, so CI needs no keys. The built-in
148
+ * providers refuse to start without one, so give them a stand-in. Headers
149
+ * aren't part of what a recording is matched on.
150
+ */
151
+ export function withoutKeys(server) {
152
+ const { provider } = server;
153
+ if (isAIProvider(provider) || provider.apiKey?.trim())
154
+ return server;
155
+ return { ...server, provider: { ...provider, apiKey: 'chatcops-replay' } };
156
+ }
157
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/test/run.ts"],"names":[],"mappings":"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"}