@aipack-ai/eval 1.1.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.
Files changed (37) hide show
  1. package/dist/index.d.ts +24 -0
  2. package/dist/index.js +26 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/src/cli.d.ts +12 -0
  5. package/dist/src/cli.js +149 -0
  6. package/dist/src/cli.js.map +1 -0
  7. package/dist/src/core/loader.d.ts +21 -0
  8. package/dist/src/core/loader.js +91 -0
  9. package/dist/src/core/loader.js.map +1 -0
  10. package/dist/src/core/mock-stream.d.ts +16 -0
  11. package/dist/src/core/mock-stream.js +71 -0
  12. package/dist/src/core/mock-stream.js.map +1 -0
  13. package/dist/src/core/mock-tools.d.ts +24 -0
  14. package/dist/src/core/mock-tools.js +161 -0
  15. package/dist/src/core/mock-tools.js.map +1 -0
  16. package/dist/src/core/report.d.ts +26 -0
  17. package/dist/src/core/report.js +149 -0
  18. package/dist/src/core/report.js.map +1 -0
  19. package/dist/src/core/runner.d.ts +18 -0
  20. package/dist/src/core/runner.js +213 -0
  21. package/dist/src/core/runner.js.map +1 -0
  22. package/dist/src/core/scorer/index.d.ts +19 -0
  23. package/dist/src/core/scorer/index.js +56 -0
  24. package/dist/src/core/scorer/index.js.map +1 -0
  25. package/dist/src/core/scorer/rule.d.ts +17 -0
  26. package/dist/src/core/scorer/rule.js +231 -0
  27. package/dist/src/core/scorer/rule.js.map +1 -0
  28. package/dist/src/core/trajectory.d.ts +13 -0
  29. package/dist/src/core/trajectory.js +41 -0
  30. package/dist/src/core/trajectory.js.map +1 -0
  31. package/dist/src/core/types.d.ts +251 -0
  32. package/dist/src/core/types.js +16 -0
  33. package/dist/src/core/types.js.map +1 -0
  34. package/dist/src/core/validate.d.ts +7 -0
  35. package/dist/src/core/validate.js +71 -0
  36. package/dist/src/core/validate.js.map +1 -0
  37. package/package.json +53 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * packages/eval/src/core/report.ts - 报告渲染与 baseline 门禁
3
+ *
4
+ * - JSON + Markdown 双格式输出到报告目录(缺省 ./eval-results)
5
+ * - baseline:对比整体与分套件通过率,回归超阈值判失败
6
+ */
7
+ import type { BaselineComparison, BaselineFile, EvalReport, RunConfig } from './types';
8
+ export declare function renderMarkdown(report: EvalReport): string;
9
+ export declare function writeReport(report: EvalReport, reportDir: string): Promise<{
10
+ jsonPath: string;
11
+ mdPath: string;
12
+ }>;
13
+ export declare function reportToBaseline(report: EvalReport): BaselineFile;
14
+ export declare function writeBaseline(report: EvalReport, baselinePath: string): Promise<string>;
15
+ /**
16
+ * 对比当前报告与 baseline。
17
+ * ok = 整体通过率不低于 baseline - threshold,且无套件回归超阈值。
18
+ */
19
+ export declare function compareBaseline(report: EvalReport, baseline: BaselineFile, threshold?: number): BaselineComparison;
20
+ export declare function readBaseline(baselinePath: string): Promise<BaselineFile | undefined>;
21
+ export declare function finalizeReport(report: EvalReport, config: RunConfig): Promise<{
22
+ jsonPath?: string;
23
+ mdPath?: string;
24
+ baseline?: BaselineFile;
25
+ comparison?: BaselineComparison;
26
+ }>;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * packages/eval/src/core/report.ts - 报告渲染与 baseline 门禁
3
+ *
4
+ * - JSON + Markdown 双格式输出到报告目录(缺省 ./eval-results)
5
+ * - baseline:对比整体与分套件通过率,回归超阈值判失败
6
+ */
7
+ import { mkdir, writeFile } from 'node:fs/promises';
8
+ import { dirname, join, resolve } from 'node:path';
9
+ // ─── Markdown 渲染 ────────────────────────────────────────────────
10
+ function pct(x) {
11
+ return `${(x * 100).toFixed(1)}%`;
12
+ }
13
+ function renderSummaryTable(byKey, keyHeader) {
14
+ const rows = Object.entries(byKey)
15
+ .sort(([a], [b]) => a.localeCompare(b))
16
+ .map(([k, s]) => `| ${k} | ${s.total} | ${s.passed} | ${pct(s.passRate)} | ${s.avgScore.toFixed(2)} |`);
17
+ return [
18
+ `| ${keyHeader} | 用例数 | 通过 | 通过率 | 平均分 |`,
19
+ `|---|---|---|---|---|`,
20
+ ...rows,
21
+ ].join('\n');
22
+ }
23
+ export function renderMarkdown(report) {
24
+ const lines = [];
25
+ lines.push(`# aipack Eval 报告`);
26
+ lines.push('');
27
+ lines.push(`- Run: \`${report.runId}\`(mode: ${report.mode})`);
28
+ lines.push(`- 总览: **${report.totals.passed}/${report.totals.cases} 通过(${pct(report.totals.passRate)})**,平均分 ${report.totals.avgScore.toFixed(2)},耗时 ${(report.durationMs / 1000).toFixed(2)}s`);
29
+ lines.push('');
30
+ lines.push(`## 按套件`);
31
+ lines.push('');
32
+ lines.push(renderSummaryTable(report.bySuite, '套件'));
33
+ lines.push('');
34
+ lines.push(`## 按来源(分布漂移诊断)`);
35
+ lines.push('');
36
+ lines.push(renderSummaryTable(report.byOrigin, 'origin'));
37
+ lines.push('');
38
+ const failures = report.results.filter((r) => !r.passed);
39
+ if (failures.length === 0) {
40
+ lines.push(`## 失败用例`);
41
+ lines.push('');
42
+ lines.push(`无 ✅`);
43
+ }
44
+ else {
45
+ lines.push(`## 失败用例(${failures.length})`);
46
+ lines.push('');
47
+ for (const f of failures) {
48
+ lines.push(`### ${f.caseId}`);
49
+ lines.push('');
50
+ if (f.error)
51
+ lines.push(`- 运行错误: ${f.error}`);
52
+ for (const s of f.scores) {
53
+ if (!s.passed)
54
+ lines.push(`- [${s.scorer}] ${s.reason}`);
55
+ }
56
+ lines.push('');
57
+ }
58
+ }
59
+ return lines.join('\n');
60
+ }
61
+ // ─── 报告写盘 ─────────────────────────────────────────────────────
62
+ export async function writeReport(report, reportDir) {
63
+ const dir = resolve(reportDir);
64
+ await mkdir(dir, { recursive: true });
65
+ const jsonPath = join(dir, `${report.runId}.json`);
66
+ const mdPath = join(dir, `${report.runId}.md`);
67
+ await writeFile(jsonPath, JSON.stringify(report, null, 2), 'utf-8');
68
+ await writeFile(mdPath, renderMarkdown(report), 'utf-8');
69
+ return { jsonPath, mdPath };
70
+ }
71
+ // ─── Baseline ─────────────────────────────────────────────────────
72
+ export function reportToBaseline(report) {
73
+ return {
74
+ runId: report.runId,
75
+ updatedAt: new Date().toISOString(),
76
+ totals: {
77
+ cases: report.totals.cases,
78
+ passed: report.totals.passed,
79
+ passRate: report.totals.passRate,
80
+ },
81
+ bySuite: Object.fromEntries(Object.entries(report.bySuite).map(([k, s]) => [
82
+ k,
83
+ { total: s.total, passed: s.passed, passRate: s.passRate },
84
+ ])),
85
+ };
86
+ }
87
+ export async function writeBaseline(report, baselinePath) {
88
+ const path = resolve(baselinePath);
89
+ await mkdir(dirname(path), { recursive: true });
90
+ await writeFile(path, JSON.stringify(reportToBaseline(report), null, 2), 'utf-8');
91
+ return path;
92
+ }
93
+ /**
94
+ * 对比当前报告与 baseline。
95
+ * ok = 整体通过率不低于 baseline - threshold,且无套件回归超阈值。
96
+ */
97
+ export function compareBaseline(report, baseline, threshold = 0.02) {
98
+ const overallDelta = report.totals.passRate - baseline.totals.passRate;
99
+ const regressions = [];
100
+ for (const [suite, b] of Object.entries(baseline.bySuite)) {
101
+ const cur = report.bySuite[suite];
102
+ if (!cur)
103
+ continue; // baseline 中存在但本次未跑的套件不判回归
104
+ const delta = cur.passRate - b.passRate;
105
+ if (delta < -threshold) {
106
+ regressions.push({
107
+ suite,
108
+ baseline: b.passRate,
109
+ current: cur.passRate,
110
+ delta,
111
+ });
112
+ }
113
+ }
114
+ return {
115
+ ok: overallDelta >= -threshold && regressions.length === 0,
116
+ overallDelta,
117
+ regressions,
118
+ };
119
+ }
120
+ export async function readBaseline(baselinePath) {
121
+ const { readFile } = await import('node:fs/promises');
122
+ try {
123
+ return JSON.parse(await readFile(resolve(baselinePath), 'utf-8'));
124
+ }
125
+ catch {
126
+ return undefined;
127
+ }
128
+ }
129
+ // ─── 便捷:跑完即出报告 ───────────────────────────────────────────
130
+ export async function finalizeReport(report, config) {
131
+ const out = {};
132
+ if (config.reportDir) {
133
+ const { jsonPath, mdPath } = await writeReport(report, config.reportDir);
134
+ out.jsonPath = jsonPath;
135
+ out.mdPath = mdPath;
136
+ }
137
+ if (config.updateBaseline && config.baselinePath) {
138
+ await writeBaseline(report, config.baselinePath);
139
+ }
140
+ else if (config.baselinePath) {
141
+ const baseline = await readBaseline(config.baselinePath);
142
+ if (baseline) {
143
+ out.baseline = baseline;
144
+ out.comparison = compareBaseline(report, baseline, config.regressionThreshold ?? 0.02);
145
+ }
146
+ }
147
+ return out;
148
+ }
149
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/core/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * packages/eval/src/core/runner.ts - Eval Runner
3
+ *
4
+ * mock 模式:每个用例构造独立 Runtime(createMockStreamFn 注入
5
+ * streamFn + createMockTools 提供工具),run() 后经 getMessages()
6
+ * 重建完整轨迹,再交给规则评分器。
7
+ *
8
+ * 工程保障:
9
+ * - 用例间完全隔离(独立 runtime / 独立 fs 副本 / 独立 sessionKey)
10
+ * - 墙钟超时(Promise.race)
11
+ * - 步数上限(映射 RuntimeOptions.maxTurns)
12
+ * - 预算熔断(usage.total 超 case.metadata.maxTokens 判失败)
13
+ * - repeats 消随机性(live 模式用;mock 模式缺省 1)
14
+ * - 并发受控(简单队列实现)
15
+ */
16
+ import type { EvalCase, EvalReport, RunConfig } from './types';
17
+ /** 执行一次评测 */
18
+ export declare function runEval(cases: EvalCase[], config: RunConfig): Promise<EvalReport>;
@@ -0,0 +1,213 @@
1
+ /**
2
+ * packages/eval/src/core/runner.ts - Eval Runner
3
+ *
4
+ * mock 模式:每个用例构造独立 Runtime(createMockStreamFn 注入
5
+ * streamFn + createMockTools 提供工具),run() 后经 getMessages()
6
+ * 重建完整轨迹,再交给规则评分器。
7
+ *
8
+ * 工程保障:
9
+ * - 用例间完全隔离(独立 runtime / 独立 fs 副本 / 独立 sessionKey)
10
+ * - 墙钟超时(Promise.race)
11
+ * - 步数上限(映射 RuntimeOptions.maxTurns)
12
+ * - 预算熔断(usage.total 超 case.metadata.maxTokens 判失败)
13
+ * - repeats 消随机性(live 模式用;mock 模式缺省 1)
14
+ * - 并发受控(简单队列实现)
15
+ */
16
+ import { createRuntime, createRequest, } from '@aipack-ai/agent';
17
+ import { createMockStreamFn } from './mock-stream.js';
18
+ import { createMockTools } from './mock-tools.js';
19
+ import { countTurns, extractTrajectory } from './trajectory.js';
20
+ import { resolveScorers, scoreTrace } from './scorer/index.js';
21
+ const DEFAULT_TIMEOUT_MS = 30_000;
22
+ const DEFAULT_MAX_STEPS = 50;
23
+ const DEFAULT_CONCURRENCY = 8;
24
+ /** sanitize sessionKey(用例 id 可能含 '/') */
25
+ function sessionKeyFor(caseId, repeat) {
26
+ return `eval:${caseId.replace(/[^a-zA-Z0-9_-]/g, '_')}#r${repeat}`;
27
+ }
28
+ /** 单用例单次运行:返回轨迹(失败时返回 error 字符串) */
29
+ async function runCaseOnce(c, config, repeat) {
30
+ if (!c.input.mock) {
31
+ return { error: 'mock 模式要求 input.mock 脚本(live 模式 M3 接入)' };
32
+ }
33
+ const timeoutMs = c.metadata?.timeoutMs ?? config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
34
+ const maxSteps = c.metadata?.maxSteps ?? config.maxSteps ?? DEFAULT_MAX_STEPS;
35
+ const tools = createMockTools(c.input.fs ?? {}, c.input.tools);
36
+ const runtime = createRuntime({
37
+ systemPrompt: c.input.systemPrompt ?? '',
38
+ streamFn: createMockStreamFn(c.input.mock),
39
+ tools,
40
+ maxTurns: maxSteps,
41
+ traceIdGenerator: () => sessionKeyFor(c.id, repeat),
42
+ });
43
+ const sessionKey = sessionKeyFor(c.id, repeat);
44
+ const startedAt = Date.now();
45
+ let run;
46
+ try {
47
+ run = runtime
48
+ .run(createRequest(c.input.message, { sessionKey }))
49
+ .then((result) => {
50
+ const messages = runtime.getMessages(sessionKey);
51
+ const trajectory = extractTrajectory(messages);
52
+ const turns = countTurns(messages);
53
+ const durationMs = Date.now() - startedAt;
54
+ const usageTotal = typeof result.usage?.total === 'number' ? result.usage.total : 0;
55
+ return {
56
+ ok: true,
57
+ result,
58
+ messages,
59
+ trajectory,
60
+ turns,
61
+ durationMs,
62
+ usageTotal,
63
+ };
64
+ })
65
+ .catch((e) => ({
66
+ ok: false,
67
+ error: `框架异常: ${e.message}`,
68
+ }));
69
+ // 墙钟超时:到期时把 pending 的 run 替换为失败结果
70
+ const timeoutOutcome = new Promise((resolve) => {
71
+ const t = setTimeout(() => resolve({ ok: false, error: `超时(${timeoutMs}ms)` }), timeoutMs);
72
+ t.unref?.();
73
+ });
74
+ const outcome = await Promise.race([run, timeoutOutcome]);
75
+ if (!outcome.ok)
76
+ return { error: outcome.error };
77
+ const trace = {
78
+ caseId: c.id,
79
+ suite: c.suite,
80
+ origin: c.origin,
81
+ result: outcome.result,
82
+ trajectory: outcome.trajectory,
83
+ messages: outcome.messages,
84
+ durationMs: outcome.durationMs,
85
+ usageTotal: outcome.usageTotal,
86
+ turns: outcome.turns,
87
+ };
88
+ // 预算熔断:token 超限直接判失败
89
+ const maxTokens = c.metadata?.maxTokens;
90
+ if (maxTokens !== undefined && trace.usageTotal > maxTokens) {
91
+ return { error: `预算熔断:usage.total=${trace.usageTotal} > maxTokens=${maxTokens}` };
92
+ }
93
+ return { trace };
94
+ }
95
+ finally {
96
+ await runtime.close().catch(() => undefined);
97
+ }
98
+ }
99
+ /** 单用例(含 repeats) */
100
+ async function runCase(c, config) {
101
+ const repeats = config.mode === 'mock' ? (config.repeats ?? 1) : (config.repeats ?? 1);
102
+ const scorers = resolveScorers(c.expected, c.scorers);
103
+ const startedAt = Date.now();
104
+ let passed = true;
105
+ let score = 0;
106
+ let scoreCount = 0;
107
+ const scoreResults = [];
108
+ let runError;
109
+ let steps = 0;
110
+ let usageTotal = 0;
111
+ let durationMs = 0;
112
+ for (let r = 0; r < repeats; r++) {
113
+ const { trace, error } = await runCaseOnce(c, config, r);
114
+ durationMs += Date.now() - startedAt;
115
+ if (error || !trace) {
116
+ passed = false;
117
+ runError = error;
118
+ scoreResults.push({
119
+ scorer: 'success',
120
+ score: 0,
121
+ passed: false,
122
+ reason: `运行失败: ${error ?? '未知错误'}`,
123
+ });
124
+ break;
125
+ }
126
+ steps = trace.trajectory.length;
127
+ usageTotal += trace.usageTotal;
128
+ const caseScore = scoreTrace(trace, scorers);
129
+ passed = passed && caseScore.passed;
130
+ score += caseScore.score;
131
+ scoreCount += 1;
132
+ if (!caseScore.passed) {
133
+ scoreResults.push(...caseScore.scores.filter((s) => !s.passed).map((s) => ({
134
+ ...s,
135
+ reason: s.reason,
136
+ })));
137
+ }
138
+ }
139
+ return {
140
+ caseId: c.id,
141
+ suite: c.suite,
142
+ origin: c.origin,
143
+ passed,
144
+ score: scoreCount === 0 ? 0 : score / scoreCount,
145
+ scores: scoreResults,
146
+ error: runError,
147
+ durationMs,
148
+ steps,
149
+ usageTotal,
150
+ };
151
+ }
152
+ /** 简单并发队列(避免引入依赖) */
153
+ async function runAllConcurrent(items, concurrency, fn) {
154
+ const results = new Array(items.length);
155
+ let next = 0;
156
+ const workers = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
157
+ while (next < items.length) {
158
+ const i = next++;
159
+ results[i] = await fn(items[i]);
160
+ }
161
+ });
162
+ await Promise.all(workers);
163
+ return results;
164
+ }
165
+ function summarize(results) {
166
+ const groups = new Map();
167
+ for (const r of results) {
168
+ const list = groups.get(r.suite) ?? [];
169
+ list.push(r);
170
+ groups.set(r.suite, list);
171
+ }
172
+ const out = {};
173
+ for (const [key, list] of groups) {
174
+ const total = list.length;
175
+ const passed = list.filter((r) => r.passed).length;
176
+ out[key] = {
177
+ total,
178
+ passed,
179
+ passRate: total === 0 ? 0 : passed / total,
180
+ avgScore: total === 0 ? 0 : list.reduce((a, r) => a + r.score, 0) / total,
181
+ };
182
+ }
183
+ return out;
184
+ }
185
+ /** 执行一次评测 */
186
+ export async function runEval(cases, config) {
187
+ const startedAt = Date.now();
188
+ const filtered = config.suites && config.suites.length > 0
189
+ ? cases.filter((c) => config.suites.includes(c.suite))
190
+ : cases;
191
+ const concurrency = config.concurrency ?? DEFAULT_CONCURRENCY;
192
+ const results = await runAllConcurrent(filtered, concurrency, (c) => runCase(c, config));
193
+ const casesPassed = results.filter((r) => r.passed).length;
194
+ return {
195
+ runId: `run_${new Date().toISOString().replace(/[:.]/g, '-')}`,
196
+ startedAt: new Date(startedAt).toISOString(),
197
+ durationMs: Date.now() - startedAt,
198
+ mode: config.mode,
199
+ totals: {
200
+ cases: results.length,
201
+ passed: casesPassed,
202
+ passRate: results.length === 0 ? 0 : casesPassed / results.length,
203
+ avgScore: results.length === 0
204
+ ? 0
205
+ : results.reduce((a, r) => a + r.score, 0) / results.length,
206
+ usageTotal: results.reduce((a, r) => a + r.usageTotal, 0),
207
+ },
208
+ bySuite: summarize(results),
209
+ byOrigin: summarize(results.map((r) => ({ ...r, suite: r.origin }))),
210
+ results,
211
+ };
212
+ }
213
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/core/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * packages/eval/src/core/scorer/index.ts - 评分入口与 expected 归一化
3
+ *
4
+ * - expected(声明式)→ ScorerConfig[](与显式 scorers 合并)
5
+ * - scoreCase:依次执行规则评分器,加权合成用例总分
6
+ */
7
+ import type { ExpectedResult, RunTrace, ScoreResult, ScorerConfig } from '../types';
8
+ export { RULE_SCORER_TYPES, runRuleScorer, partialMatch } from './rule';
9
+ /** 声明式 expected → 评分器配置 */
10
+ export declare function expectedToScorers(expected: ExpectedResult): ScorerConfig[];
11
+ /** 合并用例的 expected + scorers */
12
+ export declare function resolveScorers(expected?: ExpectedResult, explicit?: ScorerConfig[]): ScorerConfig[];
13
+ export interface CaseScore {
14
+ passed: boolean;
15
+ score: number;
16
+ scores: ScoreResult[];
17
+ }
18
+ /** 对一次运行轨迹执行全部评分器 */
19
+ export declare function scoreTrace(trace: RunTrace, scorers: ScorerConfig[]): CaseScore;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * packages/eval/src/core/scorer/index.ts - 评分入口与 expected 归一化
3
+ *
4
+ * - expected(声明式)→ ScorerConfig[](与显式 scorers 合并)
5
+ * - scoreCase:依次执行规则评分器,加权合成用例总分
6
+ */
7
+ import { runRuleScorer } from './rule.js';
8
+ export { RULE_SCORER_TYPES, runRuleScorer, partialMatch } from './rule.js';
9
+ /** 声明式 expected → 评分器配置 */
10
+ export function expectedToScorers(expected) {
11
+ switch (expected.type) {
12
+ case 'exact':
13
+ case 'contains':
14
+ return [{ type: expected.type, params: { value: expected.value } }];
15
+ case 'regex':
16
+ return [
17
+ { type: 'regex', params: { value: expected.value, flags: expected.flags ?? '' } },
18
+ ];
19
+ case 'tool-call':
20
+ return [
21
+ {
22
+ type: 'tool-call',
23
+ params: { calls: expected.calls, order: expected.order ?? 'subset' },
24
+ },
25
+ ];
26
+ case 'tools-used':
27
+ return [{ type: 'tools-used', params: { tools: expected.tools } }];
28
+ case 'json-field':
29
+ return 'value' in expected
30
+ ? [{ type: 'json-field', params: { path: expected.path, value: expected.value } }]
31
+ : [{ type: 'json-field', params: { path: expected.path } }];
32
+ case 'success':
33
+ return [{ type: 'success', params: { value: expected.value ?? true } }];
34
+ case 'stop-reason':
35
+ return [{ type: 'stop-reason', params: { value: expected.value } }];
36
+ }
37
+ }
38
+ /** 合并用例的 expected + scorers */
39
+ export function resolveScorers(expected, explicit) {
40
+ return [...(expected ? expectedToScorers(expected) : []), ...(explicit ?? [])];
41
+ }
42
+ /** 对一次运行轨迹执行全部评分器 */
43
+ export function scoreTrace(trace, scorers) {
44
+ const scores = scorers.map((s) => runRuleScorer(trace, s.type, s.params));
45
+ const totalWeight = scorers.reduce((acc, s) => acc + (s.weight ?? 1), 0);
46
+ const weighted = totalWeight === 0
47
+ ? 0
48
+ : scores.reduce((acc, r, i) => acc + r.score * (scorers[i].weight ?? 1), 0) /
49
+ totalWeight;
50
+ return {
51
+ passed: scores.length > 0 && scores.every((r) => r.passed),
52
+ score: scorers.length === 0 ? 0 : weighted,
53
+ scores,
54
+ };
55
+ }
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/scorer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAqB,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAExE,2BAA2B;AAC3B,MAAM,UAAU,iBAAiB,CAAC,QAAwB;IACxD,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,OAAO,CAAC;QACb,KAAK,UAAU;YACb,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACtE,KAAK,OAAO;YACV,OAAO;gBACL,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE;aAClF,CAAC;QACJ,KAAK,WAAW;YACd,OAAO;gBACL;oBACE,IAAI,EAAE,WAAW;oBACjB,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,QAAQ,EAAE;iBACrE;aACF,CAAC;QACJ,KAAK,YAAY;YACf,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrE,KAAK,YAAY;YACf,OAAO,OAAO,IAAI,QAAQ;gBACxB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;gBAClF,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAChE,KAAK,SAAS;YACZ,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1E,KAAK,aAAa;YAChB,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,cAAc,CAC5B,QAAyB,EACzB,QAAyB;IAEzB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;AACjF,CAAC;AAQD,qBAAqB;AACrB,MAAM,UAAU,UAAU,CAAC,KAAe,EAAE,OAAuB;IACjE,MAAM,MAAM,GAAkB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CACvC,CAAC;IACF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,QAAQ,GACZ,WAAW,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;YACzE,WAAW,CAAC;IAClB,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1D,KAAK,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;QAC1C,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * packages/eval/src/core/scorer/rule.ts - 规则评分器
3
+ *
4
+ * M1 范围:8 个确定性评分器(零 LLM 成本):
5
+ * exact / contains / regex —— 最终文本断言
6
+ * json-field —— 结构化输出断言(dot 路径取值)
7
+ * tool-call —— 工具调用轨迹断言(顺序 + 参数部分匹配)
8
+ * tools-used —— 去重工具集合断言(对齐 Result.toolsUsed)
9
+ * success / stop-reason —— 运行状态断言
10
+ */
11
+ import type { RunTrace, ScoreResult } from '../types';
12
+ export declare function partialMatch(expected: unknown, actual: unknown): boolean;
13
+ type RuleParams = Record<string, unknown>;
14
+ export declare const RULE_SCORER_TYPES: string[];
15
+ /** 执行单个规则评分器;未知类型 / 参数错误返回 scorer 自身失败而非抛出 */
16
+ export declare function runRuleScorer(trace: RunTrace, type: string, params: RuleParams): ScoreResult;
17
+ export {};