dsh-eval-pack 0.1.0-alpha.7 → 0.1.0-alpha.9
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/CHANGELOG.md +15 -0
- package/README-zh.md +0 -1
- package/README.md +0 -1
- package/docs/assets/dsh-eval-pack-capability.png +0 -0
- package/docs/assets/dsh-eval-pack-capability2.png +0 -0
- package/lib/core/harness.d.ts +37 -0
- package/lib/core/harness.js +58 -1
- package/lib/plugin/tools.js +16 -2
- package/package.json +1 -1
- package/screenshots.json +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-alpha.9] — 2026-11-01
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `eval.pass_at_k`: unbiased pass@k estimator `1 - C(n-c,k)/C(n,k)` with exact binomials, plus the per-task and mean values. Verified by `node --test test/*.test.mjs` (12/12).
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `eval.summary`: aggregate pass count, pass rate and failing task ids for a graded run, using the same grader as `eval.grade`.
|
|
14
|
+
- Canonical-JSON grading: object key order no longer changes the verdict; array order still matters.
|
|
15
|
+
|
|
16
|
+
Verified by `node --test test/*.test.mjs` (7/7).
|
|
17
|
+
|
|
3
18
|
## [0.1.0-alpha.7] — 2026-11-01
|
|
4
19
|
|
|
5
20
|
### Changed
|
package/README-zh.md
CHANGED
package/README.md
CHANGED
|
@@ -132,7 +132,6 @@ pnpm build && pnpm lint && pnpm typecheck && pnpm test
|
|
|
132
132
|
- Runs locally; no network, no model call, no upload.
|
|
133
133
|
- Public/synthetic fixtures only; no customer data, no customer evidence.
|
|
134
134
|
- Alpha/partial; not counted, no GA or production-readiness claim.
|
|
135
|
-
- Frozen packages stay installable; no new features, only genuine breakage fixes.
|
|
136
135
|
|
|
137
136
|
## Related work
|
|
138
137
|
|
|
Binary file
|
|
Binary file
|
package/lib/core/harness.d.ts
CHANGED
|
@@ -8,4 +8,41 @@ export interface EvalPack {
|
|
|
8
8
|
tasks: EvalTask[];
|
|
9
9
|
}
|
|
10
10
|
export declare function lintPack(input: unknown): string[];
|
|
11
|
+
/** Stable serialisation: object keys sorted at every level, arrays kept in order. */
|
|
12
|
+
export declare function canonical(value: unknown): string;
|
|
11
13
|
export declare function grade(actual: unknown, expected: unknown): boolean;
|
|
14
|
+
export interface EvalResult {
|
|
15
|
+
id: string;
|
|
16
|
+
actual: unknown;
|
|
17
|
+
expected: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface EvalSummary {
|
|
20
|
+
total: number;
|
|
21
|
+
passed: number;
|
|
22
|
+
failed: number;
|
|
23
|
+
pass_rate: number;
|
|
24
|
+
failures: string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function summarize(results: EvalResult[]): EvalSummary;
|
|
27
|
+
export interface PassAtKInput {
|
|
28
|
+
task_id: string;
|
|
29
|
+
samples: number;
|
|
30
|
+
correct: number;
|
|
31
|
+
}
|
|
32
|
+
export interface PassAtKResult {
|
|
33
|
+
task_id: string;
|
|
34
|
+
k: number;
|
|
35
|
+
n: number;
|
|
36
|
+
c: number;
|
|
37
|
+
pass_at_k: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Unbiased pass@k estimator: 1 - C(n-c, k) / C(n, k).
|
|
41
|
+
* Clean-room from the published estimator definition; exact binomials via BigInt.
|
|
42
|
+
*/
|
|
43
|
+
export declare function passAtK(task: PassAtKInput, k: number): PassAtKResult;
|
|
44
|
+
export declare function passAtKMean(tasks: PassAtKInput[], k: number): {
|
|
45
|
+
k: number;
|
|
46
|
+
tasks: PassAtKResult[];
|
|
47
|
+
mean: number;
|
|
48
|
+
};
|
package/lib/core/harness.js
CHANGED
|
@@ -23,6 +23,63 @@ export function lintPack(input) {
|
|
|
23
23
|
}
|
|
24
24
|
return errors;
|
|
25
25
|
}
|
|
26
|
+
/** Stable serialisation: object keys sorted at every level, arrays kept in order. */
|
|
27
|
+
export function canonical(value) {
|
|
28
|
+
const walk = (input) => {
|
|
29
|
+
if (Array.isArray(input))
|
|
30
|
+
return input.map(walk);
|
|
31
|
+
if (input && typeof input === 'object') {
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const key of Object.keys(input).sort())
|
|
34
|
+
out[key] = walk(input[key]);
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
return input;
|
|
38
|
+
};
|
|
39
|
+
return JSON.stringify(walk(value));
|
|
40
|
+
}
|
|
26
41
|
export function grade(actual, expected) {
|
|
27
|
-
return
|
|
42
|
+
return canonical(actual) === canonical(expected);
|
|
43
|
+
}
|
|
44
|
+
export function summarize(results) {
|
|
45
|
+
const failures = [];
|
|
46
|
+
let passed = 0;
|
|
47
|
+
for (const r of results) {
|
|
48
|
+
if (grade(r.actual, r.expected))
|
|
49
|
+
passed += 1;
|
|
50
|
+
else
|
|
51
|
+
failures.push(r.id);
|
|
52
|
+
}
|
|
53
|
+
const total = results.length;
|
|
54
|
+
return { total, passed, failed: total - passed, pass_rate: total ? Math.round((passed / total) * 1e6) / 1e6 : 0, failures };
|
|
55
|
+
}
|
|
56
|
+
function comb(n, k) {
|
|
57
|
+
if (k < 0 || k > n)
|
|
58
|
+
return 0n;
|
|
59
|
+
let result = 1n;
|
|
60
|
+
for (let i = 1n; i <= BigInt(k); i += 1n)
|
|
61
|
+
result = (result * (BigInt(n) - BigInt(k) + i)) / i;
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Unbiased pass@k estimator: 1 - C(n-c, k) / C(n, k).
|
|
66
|
+
* Clean-room from the published estimator definition; exact binomials via BigInt.
|
|
67
|
+
*/
|
|
68
|
+
export function passAtK(task, k) {
|
|
69
|
+
const { samples, correct } = task;
|
|
70
|
+
if (!Number.isInteger(samples) || samples < 1)
|
|
71
|
+
throw new Error('E_EVAL_SAMPLES: samples must be a positive integer');
|
|
72
|
+
if (!Number.isInteger(correct) || correct < 0 || correct > samples)
|
|
73
|
+
throw new Error('E_EVAL_CORRECT: correct must be between 0 and samples');
|
|
74
|
+
if (!Number.isInteger(k) || k < 1 || k > samples)
|
|
75
|
+
throw new Error('E_EVAL_K: k must be between 1 and samples');
|
|
76
|
+
const denominator = comb(samples, k);
|
|
77
|
+
const numerator = comb(samples - correct, k);
|
|
78
|
+
const value = 1 - Number(numerator) / Number(denominator);
|
|
79
|
+
return { task_id: task.task_id, k, n: samples, c: correct, pass_at_k: Math.round(value * 1e6) / 1e6 };
|
|
80
|
+
}
|
|
81
|
+
export function passAtKMean(tasks, k) {
|
|
82
|
+
const results = tasks.map((t) => passAtK(t, k));
|
|
83
|
+
const mean = results.length ? Math.round((results.reduce((sum, r) => sum + r.pass_at_k, 0) / results.length) * 1e6) / 1e6 : 0;
|
|
84
|
+
return { k, tasks: results, mean };
|
|
28
85
|
}
|
package/lib/plugin/tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
2
|
-
import { grade, lintPack } from '../core/harness.js';
|
|
2
|
+
import { grade, lintPack, passAtKMean, summarize } from '../core/harness.js';
|
|
3
3
|
const text = (t) => [{ type: 'text', text: t }];
|
|
4
4
|
export function createTools() {
|
|
5
5
|
const lint = defineTool({
|
|
@@ -16,5 +16,19 @@ export function createTools() {
|
|
|
16
16
|
output: { schema: { type: 'object', additionalProperties: false, properties: { pass: { type: 'boolean', required: true } } }, render: (_a, v) => text(`grade ${v.pass ? 'pass' : 'fail'}`) },
|
|
17
17
|
async execute(args) { return { pass: grade(args.actual, args.expected) }; },
|
|
18
18
|
});
|
|
19
|
-
|
|
19
|
+
const summary = defineTool({
|
|
20
|
+
name: 'eval.summary',
|
|
21
|
+
description: 'Aggregate graded results for a public/synthetic run: pass count, pass rate and the failing task ids, using the same canonical-JSON grader. Read-only; no runner.',
|
|
22
|
+
parameters: { results: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { id: { type: 'string', required: true }, actual: { type: 'json', required: true }, expected: { type: 'json', required: true } } } } },
|
|
23
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { total: { type: 'number', required: true }, passed: { type: 'number', required: true }, failed: { type: 'number', required: true }, pass_rate: { type: 'number', required: true }, failures: { type: 'array', items: { type: 'string' }, required: true } } }, render: (_a, v) => text(`summary ${v.passed}/${v.total}`) },
|
|
24
|
+
async execute(args) { return summarize(args.results); },
|
|
25
|
+
});
|
|
26
|
+
const passAtKTool = defineTool({
|
|
27
|
+
name: 'eval.pass_at_k',
|
|
28
|
+
description: 'Unbiased pass@k for sampled tasks: 1 - C(n-c, k)/C(n, k), exact binomials. Read-only; no runner.',
|
|
29
|
+
parameters: { k: { type: 'number', required: true }, tasks: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { task_id: { type: 'string', required: true }, samples: { type: 'number', required: true }, correct: { type: 'number', required: true } } } } },
|
|
30
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { k: { type: 'number', required: true }, mean: { type: 'number', required: true }, tasks: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { task_id: { type: 'string', required: true }, pass_at_k: { type: 'number', required: true } } } } } }, render: (_a, v) => text(`pass@${v.k} mean ${v.mean}`) },
|
|
31
|
+
async execute(args) { const r = passAtKMean(args.tasks, args.k); return { k: r.k, mean: r.mean, tasks: r.tasks.map((t) => ({ task_id: t.task_id, pass_at_k: t.pass_at_k })) }; },
|
|
32
|
+
});
|
|
33
|
+
return [lint, gradeTool, summary, passAtKTool];
|
|
20
34
|
}
|
package/package.json
CHANGED
package/screenshots.json
CHANGED
|
@@ -10,5 +10,17 @@
|
|
|
10
10
|
"kind": "demo",
|
|
11
11
|
"alt": "Animated dsh-eval-pack terminal session",
|
|
12
12
|
"caption": "The same run, assembled line by line."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "docs/assets/dsh-eval-pack-capability.png",
|
|
16
|
+
"kind": "capability",
|
|
17
|
+
"alt": "dsh-eval-pack real test run",
|
|
18
|
+
"caption": "Real command: node --test test/summary.test.mjs — 4 tests passed, 0 failed (canonical grading and run summary). Run 2026-11-01; the image is rendered from the captured terminal output."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "docs/assets/dsh-eval-pack-capability2.png",
|
|
22
|
+
"kind": "capability",
|
|
23
|
+
"alt": "dsh-eval-pack second capability run",
|
|
24
|
+
"caption": "Real command: node --test test/pass-at-k.test.mjs — 5 tests passed, 0 failed (Unbiased pass@k estimator with exact binomials.) Run 2026-11-01; rendered from the captured terminal output."
|
|
13
25
|
}
|
|
14
26
|
]
|