@kodax-ai/kodax 0.7.95 → 0.7.96-alpha.2
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 +178 -1
- package/LICENSE +158 -158
- package/README.md +149 -24
- package/README_CN.md +117 -24
- package/config-templates/config.example.jsonc +2 -1
- package/config-templates/integrations/a2a.example.jsonc +91 -91
- package/config-templates/integrations/extensions.example.jsonc +7 -7
- package/config-templates/integrations/mcp.example.jsonc +16 -16
- package/dist/builtin/code-review/SKILL.md +82 -82
- package/dist/builtin/git-workflow/SKILL.md +84 -84
- package/dist/builtin/skill-creator/SKILL.md +127 -127
- package/dist/builtin/skill-creator/agents/analyzer.md +12 -12
- package/dist/builtin/skill-creator/agents/comparator.md +13 -13
- package/dist/builtin/skill-creator/agents/grader.md +13 -13
- package/dist/builtin/skill-creator/references/schemas.md +227 -227
- package/dist/builtin/skill-creator/scripts/aggregate-benchmark.d.ts +46 -46
- package/dist/builtin/skill-creator/scripts/aggregate-benchmark.js +208 -208
- package/dist/builtin/skill-creator/scripts/analyze-benchmark.d.ts +46 -46
- package/dist/builtin/skill-creator/scripts/analyze-benchmark.js +286 -286
- package/dist/builtin/skill-creator/scripts/compare-runs.d.ts +62 -62
- package/dist/builtin/skill-creator/scripts/compare-runs.js +330 -330
- package/dist/builtin/skill-creator/scripts/generate-review.d.ts +33 -33
- package/dist/builtin/skill-creator/scripts/generate-review.js +414 -414
- package/dist/builtin/skill-creator/scripts/grade-evals.d.ts +73 -73
- package/dist/builtin/skill-creator/scripts/grade-evals.js +402 -402
- package/dist/builtin/skill-creator/scripts/improve-description.d.ts +23 -23
- package/dist/builtin/skill-creator/scripts/improve-description.js +160 -160
- package/dist/builtin/skill-creator/scripts/init-skill.d.ts +14 -14
- package/dist/builtin/skill-creator/scripts/init-skill.js +155 -155
- package/dist/builtin/skill-creator/scripts/install-skill.d.ts +29 -29
- package/dist/builtin/skill-creator/scripts/install-skill.js +173 -173
- package/dist/builtin/skill-creator/scripts/package-skill.d.ts +38 -38
- package/dist/builtin/skill-creator/scripts/package-skill.js +121 -121
- package/dist/builtin/skill-creator/scripts/quick-validate.d.ts +8 -8
- package/dist/builtin/skill-creator/scripts/quick-validate.js +163 -163
- package/dist/builtin/skill-creator/scripts/run-eval.d.ts +66 -66
- package/dist/builtin/skill-creator/scripts/run-eval.js +353 -353
- package/dist/builtin/skill-creator/scripts/run-loop.d.ts +49 -49
- package/dist/builtin/skill-creator/scripts/run-loop.js +242 -242
- package/dist/builtin/skill-creator/scripts/run-trigger-eval.d.ts +58 -58
- package/dist/builtin/skill-creator/scripts/run-trigger-eval.js +224 -224
- package/dist/builtin/tdd/SKILL.md +56 -56
- package/dist/chunks/agent-4FABF6WK.js +2 -0
- package/dist/chunks/argument-completer-72VHB2VL.js +2 -0
- package/dist/chunks/{chunk-7JXA3533.js → chunk-4OIQZWA5.js} +223 -226
- package/dist/chunks/{chunk-BNVSKIAB.js → chunk-6BVF3HZ7.js} +136 -136
- package/dist/chunks/chunk-7JZZIFZH.js +501 -0
- package/dist/chunks/chunk-AC7Z2OIY.js +2 -0
- package/dist/chunks/{chunk-JS452J2F.js → chunk-C4KYZAFU.js} +2 -2
- package/dist/chunks/chunk-CHUPIWIF.js +251 -0
- package/dist/chunks/{chunk-C4DTUKTR.js → chunk-GYUU7XLH.js} +5 -4
- package/dist/chunks/{chunk-OK4AXDC5.js → chunk-HAX55GOQ.js} +1 -1
- package/dist/chunks/chunk-JKTJCGO2.js +418 -0
- package/dist/chunks/{chunk-O743AJ5V.js → chunk-LQYETRFK.js} +171 -175
- package/dist/chunks/{chunk-2PEDBGKN.js → chunk-LTUZTQ6W.js} +1 -1
- package/dist/chunks/chunk-LYWDUSKO.js +2 -0
- package/dist/chunks/chunk-NGH6T4FD.js +92 -0
- package/dist/chunks/{chunk-SRIJX5ZP.js → chunk-NVRWCSA5.js} +1 -1
- package/dist/chunks/chunk-O4DS7RIQ.js +384 -0
- package/dist/chunks/chunk-ORXU6OWZ.js +2 -0
- package/dist/chunks/chunk-POTW3O65.js +124 -0
- package/dist/chunks/{chunk-2TM3W3GK.js → chunk-RIQSS56Y.js} +1 -1
- package/dist/chunks/chunk-U27XKEN5.js +407 -0
- package/dist/chunks/{chunk-6ABQJUK6.js → chunk-XUX6OUCA.js} +2 -2
- package/dist/chunks/{client-JDOS3YJR.js → client-4C456K4O.js} +1 -1
- package/dist/chunks/compaction-config-3VQRDFF4.js +2 -0
- package/dist/chunks/{construction-bootstrap-YCWHHUYO.js → construction-bootstrap-AHN7EDGG.js} +1 -1
- package/dist/chunks/dist-BCBQXAGI.js +2 -0
- package/dist/chunks/dist-QK2YDWU6.js +2 -0
- package/dist/chunks/host-VIHV7ADG.js +2 -0
- package/dist/chunks/run-manager-NBVMU3KV.js +2 -0
- package/dist/chunks/utils-MEJZ2IGI.js +2 -0
- package/dist/index.d.ts +22 -21
- package/dist/index.js +7 -7
- package/dist/kodax_bootstrap.js +26 -26
- package/dist/kodax_cli.js +1905 -1882
- package/dist/native/darwin-arm64/LICENSE-APACHE.txt +13 -0
- package/dist/native/darwin-arm64/kodax-text-transaction.node +0 -0
- package/dist/native/darwin-arm64/manifest.json +16 -0
- package/dist/native/darwin-x64/LICENSE-APACHE.txt +13 -0
- package/dist/native/darwin-x64/kodax-text-transaction.node +0 -0
- package/dist/native/darwin-x64/manifest.json +16 -0
- package/dist/native/linux-arm64/LICENSE-APACHE.txt +13 -0
- package/dist/native/linux-arm64/kodax-text-transaction.node +0 -0
- package/dist/native/linux-arm64/manifest.json +16 -0
- package/dist/native/linux-x64/LICENSE-APACHE.txt +13 -0
- package/dist/native/linux-x64/kodax-text-transaction.node +0 -0
- package/dist/native/linux-x64/manifest.json +16 -0
- package/dist/native/win32-x64/LICENSE-APACHE.txt +13 -0
- package/dist/native/win32-x64/NOTICE-windows-sandbox.txt +8 -0
- package/dist/native/win32-x64/kodax-windows-sandbox.exe +0 -0
- package/dist/native/win32-x64/kodax-windows-text-transaction.node +0 -0
- package/dist/native/win32-x64/manifest.json +30 -0
- package/dist/provider-capabilities.json +108 -2
- package/dist/runtime-worker.js +1745 -1727
- package/dist/sandbox-network-broker.js +1715 -0
- package/dist/sdk-a2a.d.ts +13 -12
- package/dist/sdk-a2a.js +1 -1
- package/dist/sdk-agent.d.ts +27 -18
- package/dist/sdk-agent.js +1 -1
- package/dist/sdk-coding.d.ts +107 -58
- package/dist/sdk-coding.js +1 -1
- package/dist/sdk-experimental-memory.d.ts +4 -4
- package/dist/sdk-experimental-memory.js +1 -1
- package/dist/sdk-llm.d.ts +9 -10
- package/dist/sdk-llm.js +1 -1
- package/dist/sdk-mcp.js +1 -1
- package/dist/sdk-media.d.ts +1 -1
- package/dist/sdk-media.js +1 -1
- package/dist/sdk-repl.d.ts +25 -17
- package/dist/sdk-repl.js +1 -1
- package/dist/sdk-runtime.d.ts +41 -17
- package/dist/sdk-runtime.js +1 -1
- package/dist/sdk-sandbox.d.ts +17 -3
- package/dist/sdk-sandbox.js +1 -1
- package/dist/sdk-session.d.ts +8 -7
- package/dist/sdk-session.js +1 -1
- package/dist/sdk-skills.js +1 -1
- package/dist/semantic-worker.js +61 -61
- package/dist/types-chunks/{base.d-vopO1rml.d.ts → base.d-COo8E2dk.d.ts} +18 -27
- package/dist/types-chunks/{bash-prefix-extractor.d-B2rxNI4L.d.ts → bash-prefix-extractor.d-DQOlA8cy.d.ts} +72 -52
- package/dist/types-chunks/{capability-learning.d-CE1tm29C.d.ts → capability-learning.d-lRPgA3Or.d.ts} +1 -1
- package/dist/types-chunks/{capsule.d-Y7QRS4J2.d.ts → capsule.d-0zxsgXg_.d.ts} +3 -3
- package/dist/types-chunks/{controller.d-BR-UVeUR.d.ts → controller.d-BTtyIIC1.d.ts} +1 -1
- package/dist/types-chunks/{controller.d-C5noq5-w.d.ts → controller.d-C7tXUcXo.d.ts} +2 -2
- package/dist/types-chunks/{guardrail.d-DqHD-61O.d.ts → guardrail.d-DKTyEHJa.d.ts} +5 -5
- package/dist/types-chunks/{history-retrieval.d-CKU8zmt_.d.ts → history-retrieval.d-CHnL99S7.d.ts} +2 -2
- package/dist/types-chunks/{public-api.d-D7fXaWW8.d.ts → public-api.d-Dx3L3W4Z.d.ts} +7 -4
- package/dist/types-chunks/{repl.d-BYDb14s6.d.ts → repl.d-mO01olIa.d.ts} +5 -5
- package/dist/types-chunks/{resolver.d-CwHUwbdE.d.ts → resolver.d-DlXPjeyx.d.ts} +38 -6
- package/dist/types-chunks/{review-inbox.d-BSgFewyj.d.ts → review-inbox.d-WDSe1nze.d.ts} +1 -1
- package/dist/types-chunks/{run-manager.d-BVJSntpS.d.ts → run-manager.d-DENbbzgR.d.ts} +1 -1
- package/dist/types-chunks/{sdk-session-CqEG84oP.d.ts → sdk-session-DYHGXXH4.d.ts} +3 -3
- package/dist/types-chunks/{shell-command-sets.d-DqaaBwhU.d.ts → shell-command-sets.d-CjFqS4dp.d.ts} +1 -1
- package/dist/types-chunks/{side-query.d-iH0P9ASy.d.ts → side-query.d-j8A3sFv_.d.ts} +2 -2
- package/dist/types-chunks/{types.d-rUOjXych.d.ts → types.d-BbZjR0Wr.d.ts} +1 -1
- package/dist/types-chunks/{types.d-CaTXAW_Q.d.ts → types.d-BkTIKdH6.d.ts} +2 -2
- package/dist/types-chunks/{types.d-C5xQEFcj.d.ts → types.d-DncLrpu_.d.ts} +4 -4
- package/dist/types-chunks/{types.d-CK9A9rpP.d.ts → types.d-Xy0f3x4i.d.ts} +9 -0
- package/dist/types-chunks/{utils.d-CWUyLiXo.d.ts → utils.d-CnxefMos.d.ts} +6 -6
- package/package.json +10 -3
- package/public_docs/README.md +130 -0
- package/public_docs/configuration/sandbox.md +289 -0
- package/public_docs/sdk/embedder-guide.md +6674 -0
- package/scripts/kodax-bin.cjs +28 -28
- package/scripts/production-env.cjs +25 -25
- package/dist/chunks/agent-XXZMXKKA.js +0 -2
- package/dist/chunks/argument-completer-KCYDGTQW.js +0 -2
- package/dist/chunks/chunk-77PNP27P.js +0 -92
- package/dist/chunks/chunk-7QBWHCIZ.js +0 -2
- package/dist/chunks/chunk-BHE66SP3.js +0 -123
- package/dist/chunks/chunk-BR2OSB2I.js +0 -722
- package/dist/chunks/chunk-DSMONSVB.js +0 -407
- package/dist/chunks/chunk-Q5VRWSKG.js +0 -418
- package/dist/chunks/chunk-XWRPOGJN.js +0 -4
- package/dist/chunks/chunk-Y5VIQBT6.js +0 -383
- package/dist/chunks/compaction-config-EGS4577X.js +0 -2
- package/dist/chunks/dist-ITTXQHRJ.js +0 -2
- package/dist/chunks/dist-KFYN3OKD.js +0 -2
- package/dist/chunks/host-VAYADIPW.js +0 -2
- package/dist/chunks/run-manager-52IJZMZJ.js +0 -2
- package/dist/chunks/utils-P7PBSL3R.js +0 -2
- package/dist/sandbox-workspace-session.js +0 -1705
|
@@ -1,406 +1,406 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import {
|
|
7
|
-
computePassSummary,
|
|
8
|
-
ensureDirectory,
|
|
9
|
-
extractJsonObject,
|
|
10
|
-
loadKodaXSDK,
|
|
11
|
-
loadRelativeText,
|
|
12
|
-
readJsonFile,
|
|
13
|
-
truncateText,
|
|
14
|
-
} from './utils.js';
|
|
15
|
-
|
|
16
|
-
function normalizeExpectationText(value) {
|
|
17
|
-
return String(value ?? '').trim();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function normalizeExpectedRubric(evalMetadata) {
|
|
21
|
-
const assertions = Array.isArray(evalMetadata?.assertions) ? evalMetadata.assertions : [];
|
|
22
|
-
const items = assertions
|
|
23
|
-
.map((assertion) => {
|
|
24
|
-
if (typeof assertion === 'string') {
|
|
25
|
-
return normalizeExpectationText(assertion);
|
|
26
|
-
}
|
|
27
|
-
if (assertion && typeof assertion === 'object' && typeof assertion.text === 'string') {
|
|
28
|
-
return normalizeExpectationText(assertion.text);
|
|
29
|
-
}
|
|
30
|
-
return '';
|
|
31
|
-
})
|
|
32
|
-
.filter(Boolean);
|
|
33
|
-
|
|
34
|
-
if (items.length > 0) {
|
|
35
|
-
return items;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const expectedOutput = normalizeExpectationText(evalMetadata?.expected_output);
|
|
39
|
-
return expectedOutput ? [expectedOutput] : [];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function normalizeStringArray(value) {
|
|
43
|
-
if (!Array.isArray(value)) {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
return value
|
|
47
|
-
.map((item) => String(item ?? '').trim())
|
|
48
|
-
.filter(Boolean);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function normalizeExpectationEntry(entry, fallbackText) {
|
|
52
|
-
const text = normalizeExpectationText(entry?.text ?? fallbackText);
|
|
53
|
-
return {
|
|
54
|
-
text,
|
|
55
|
-
passed: entry?.passed === true,
|
|
56
|
-
evidence: normalizeExpectationText(entry?.evidence),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function normalizeParsedGrading(rawText, rubric) {
|
|
61
|
-
const parsed = extractJsonObject(rawText) ?? {};
|
|
62
|
-
const returnedExpectations = Array.isArray(parsed.expectations) ? parsed.expectations : [];
|
|
63
|
-
const normalizedExpectations = [];
|
|
64
|
-
const consumed = new Set();
|
|
65
|
-
|
|
66
|
-
for (const rubricText of rubric) {
|
|
67
|
-
const matchIndex = returnedExpectations.findIndex((entry, index) => {
|
|
68
|
-
if (consumed.has(index)) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const candidate = normalizeExpectationText(entry?.text);
|
|
73
|
-
return candidate.toLowerCase() === rubricText.toLowerCase();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (matchIndex === -1) {
|
|
77
|
-
normalizedExpectations.push({
|
|
78
|
-
text: rubricText,
|
|
79
|
-
passed: false,
|
|
80
|
-
evidence: '',
|
|
81
|
-
});
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
consumed.add(matchIndex);
|
|
86
|
-
normalizedExpectations.push(normalizeExpectationEntry(returnedExpectations[matchIndex], rubricText));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (rubric.length === 0) {
|
|
90
|
-
for (const entry of returnedExpectations) {
|
|
91
|
-
const normalized = normalizeExpectationEntry(entry, '');
|
|
92
|
-
if (normalized.text) {
|
|
93
|
-
normalizedExpectations.push(normalized);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
overall_summary: normalizeExpectationText(parsed.overall_summary),
|
|
100
|
-
expectations: normalizedExpectations,
|
|
101
|
-
user_notes_summary: {
|
|
102
|
-
uncertainties: normalizeStringArray(parsed.user_notes_summary?.uncertainties),
|
|
103
|
-
needs_review: normalizeStringArray(parsed.user_notes_summary?.needs_review),
|
|
104
|
-
workarounds: normalizeStringArray(parsed.user_notes_summary?.workarounds),
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function listDirectories(dirPath) {
|
|
110
|
-
const entries = await readdir(dirPath, { withFileTypes: true }).catch(() => []);
|
|
111
|
-
return entries
|
|
112
|
-
.filter((entry) => entry.isDirectory())
|
|
113
|
-
.map((entry) => path.join(dirPath, entry.name))
|
|
114
|
-
.sort((left, right) => left.localeCompare(right));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function loadRunContext(runDir) {
|
|
118
|
-
const configDir = path.dirname(runDir);
|
|
119
|
-
const evalDir = path.dirname(configDir);
|
|
120
|
-
const configName = path.basename(configDir);
|
|
121
|
-
const runId = path.basename(runDir);
|
|
122
|
-
const outputsDir = path.join(runDir, 'outputs');
|
|
123
|
-
const evalMetadata = await readJsonFile(path.join(evalDir, 'eval_metadata.json'), {});
|
|
124
|
-
const resultText = await readFile(path.join(outputsDir, 'result.md'), 'utf8').catch(() => '');
|
|
125
|
-
const promptText = await readFile(path.join(outputsDir, 'prompt.txt'), 'utf8').catch(() => '');
|
|
126
|
-
const transcript = await readFile(path.join(runDir, 'transcript.md'), 'utf8').catch(() => '');
|
|
127
|
-
const metrics = await readJsonFile(path.join(outputsDir, 'metrics.json'), {});
|
|
128
|
-
const result = await readJsonFile(path.join(runDir, 'result.json'), {});
|
|
129
|
-
const timing = await readJsonFile(path.join(runDir, 'timing.json'), {});
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
evalDir,
|
|
133
|
-
runDir,
|
|
134
|
-
runId,
|
|
135
|
-
configName,
|
|
136
|
-
evalMetadata,
|
|
137
|
-
outputsDir,
|
|
138
|
-
resultText,
|
|
139
|
-
promptText,
|
|
140
|
-
transcript,
|
|
141
|
-
metrics,
|
|
142
|
-
result,
|
|
143
|
-
timing,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function buildGradingPrompt(input) {
|
|
148
|
-
const rubric = normalizeExpectedRubric(input.evalMetadata);
|
|
149
|
-
const rubricText = rubric.length > 0
|
|
150
|
-
? rubric.map((item, index) => `${index + 1}. ${item}`).join('\n')
|
|
151
|
-
: '(No explicit assertions; infer one expectation from expected_output if present.)';
|
|
152
|
-
|
|
153
|
-
return `${input.agentInstructions.trim()}
|
|
154
|
-
|
|
155
|
-
Return JSON with this shape:
|
|
156
|
-
{
|
|
157
|
-
"overall_summary": "short summary",
|
|
158
|
-
"expectations": [
|
|
159
|
-
{
|
|
160
|
-
"text": "expectation text",
|
|
161
|
-
"passed": true,
|
|
162
|
-
"evidence": "short evidence grounded in the output"
|
|
163
|
-
}
|
|
164
|
-
],
|
|
165
|
-
"user_notes_summary": {
|
|
166
|
-
"uncertainties": [],
|
|
167
|
-
"needs_review": [],
|
|
168
|
-
"workarounds": []
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
## Run Metadata
|
|
173
|
-
- eval_id: ${input.evalMetadata.eval_id ?? 'unknown'}
|
|
174
|
-
- eval_name: ${input.evalMetadata.eval_name ?? 'unknown'}
|
|
175
|
-
- config: ${input.configName}
|
|
176
|
-
- run_id: ${input.runId}
|
|
177
|
-
|
|
178
|
-
## Eval Prompt
|
|
179
|
-
${truncateText(input.evalMetadata.prompt ?? input.promptText, 4000)}
|
|
180
|
-
|
|
181
|
-
## Expected Outcome
|
|
182
|
-
${truncateText(input.evalMetadata.expected_output ?? '', 2000)}
|
|
183
|
-
|
|
184
|
-
## Assertions
|
|
185
|
-
${rubricText}
|
|
186
|
-
|
|
187
|
-
## Final Output
|
|
188
|
-
${truncateText(input.resultText, 12000)}
|
|
189
|
-
|
|
190
|
-
## Result Flags
|
|
191
|
-
${JSON.stringify({
|
|
192
|
-
success: input.result.success ?? null,
|
|
193
|
-
signal: input.result.signal ?? null,
|
|
194
|
-
interrupted: input.result.interrupted ?? false,
|
|
195
|
-
limit_reached: input.result.limit_reached ?? input.result.limitReached ?? false,
|
|
196
|
-
}, null, 2)}
|
|
197
|
-
|
|
198
|
-
## Execution Metrics
|
|
199
|
-
${JSON.stringify({
|
|
200
|
-
total_tool_calls: input.metrics.total_tool_calls ?? input.result.execution_metrics?.total_tool_calls ?? 0,
|
|
201
|
-
errors_encountered: input.metrics.errors_encountered ?? input.result.execution_metrics?.errors_encountered ?? 0,
|
|
202
|
-
output_chars: input.metrics.output_chars ?? input.result.execution_metrics?.output_chars ?? input.resultText.length,
|
|
203
|
-
total_tokens: input.timing.total_tokens ?? 0,
|
|
204
|
-
total_duration_seconds: input.timing.total_duration_seconds ?? 0,
|
|
205
|
-
}, null, 2)}
|
|
206
|
-
|
|
207
|
-
## Transcript Excerpt
|
|
208
|
-
${truncateText(input.transcript, 5000)}
|
|
209
|
-
`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async function defaultRunJudge(prompt, options) {
|
|
213
|
-
const { runKodaX } = await loadKodaXSDK();
|
|
214
|
-
const result = await runKodaX(
|
|
215
|
-
{
|
|
216
|
-
provider: options.provider ?? 'anthropic',
|
|
217
|
-
model: options.model,
|
|
218
|
-
maxIter: options.maxIter ?? 20,
|
|
219
|
-
reasoningMode: options.reasoningMode ?? 'balanced',
|
|
220
|
-
thinking: options.reasoningMode ? options.reasoningMode !== 'off' : true,
|
|
221
|
-
context: {
|
|
222
|
-
gitRoot: path.resolve(options.cwd ?? options.workspaceDir ?? process.cwd()),
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
prompt
|
|
226
|
-
);
|
|
227
|
-
return result.lastText;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
export async function gradeRun(runDir, options, runner = defaultRunJudge) {
|
|
231
|
-
const run = await loadRunContext(path.resolve(runDir));
|
|
232
|
-
const rubric = normalizeExpectedRubric(run.evalMetadata);
|
|
233
|
-
const agentInstructions = await loadRelativeText(import.meta.url, '../agents/grader.md');
|
|
234
|
-
const prompt = buildGradingPrompt({
|
|
235
|
-
...run,
|
|
236
|
-
agentInstructions,
|
|
237
|
-
});
|
|
238
|
-
const rawResponse = await runner(prompt, {
|
|
239
|
-
...options,
|
|
240
|
-
runDir: run.runDir,
|
|
241
|
-
configName: run.configName,
|
|
242
|
-
evalMetadata: run.evalMetadata,
|
|
243
|
-
runId: run.runId,
|
|
244
|
-
});
|
|
245
|
-
const parsed = normalizeParsedGrading(rawResponse, rubric);
|
|
246
|
-
const executionMetrics = {
|
|
247
|
-
total_tool_calls: run.metrics.total_tool_calls ?? run.result.execution_metrics?.total_tool_calls ?? 0,
|
|
248
|
-
errors_encountered: run.metrics.errors_encountered ?? run.result.execution_metrics?.errors_encountered ?? 0,
|
|
249
|
-
output_chars: run.metrics.output_chars ?? run.result.execution_metrics?.output_chars ?? run.resultText.length,
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const grading = {
|
|
253
|
-
summary: computePassSummary(parsed.expectations),
|
|
254
|
-
expectations: parsed.expectations,
|
|
255
|
-
execution_metrics: executionMetrics,
|
|
256
|
-
user_notes_summary: parsed.user_notes_summary,
|
|
257
|
-
overall_summary: parsed.overall_summary,
|
|
258
|
-
timing: {
|
|
259
|
-
total_tokens: run.timing.total_tokens ?? 0,
|
|
260
|
-
total_duration_seconds: run.timing.total_duration_seconds ?? 0,
|
|
261
|
-
},
|
|
262
|
-
meta: {
|
|
263
|
-
generated_at: new Date().toISOString(),
|
|
264
|
-
eval_id: run.evalMetadata.eval_id ?? null,
|
|
265
|
-
eval_name: run.evalMetadata.eval_name ?? null,
|
|
266
|
-
config: run.configName,
|
|
267
|
-
run_id: run.runId,
|
|
268
|
-
},
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
await writeFile(
|
|
272
|
-
path.join(run.runDir, 'grading.json'),
|
|
273
|
-
`${JSON.stringify(grading, null, 2)}\n`,
|
|
274
|
-
'utf8'
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
runDir: run.runDir,
|
|
279
|
-
grading,
|
|
280
|
-
prompt,
|
|
281
|
-
rawResponse,
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
export async function gradeWorkspace(options, runner = defaultRunJudge) {
|
|
286
|
-
const workspaceDir = path.resolve(options.workspaceDir);
|
|
287
|
-
await ensureDirectory(workspaceDir);
|
|
288
|
-
|
|
289
|
-
const configFilter = new Set(
|
|
290
|
-
(options.configs ?? [])
|
|
291
|
-
.map((item) => String(item).trim())
|
|
292
|
-
.filter(Boolean)
|
|
293
|
-
);
|
|
294
|
-
const processedRuns = [];
|
|
295
|
-
const skippedRuns = [];
|
|
296
|
-
|
|
297
|
-
for (const evalDir of await listDirectories(workspaceDir)) {
|
|
298
|
-
if (!path.basename(evalDir).startsWith('eval-')) {
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
for (const configDir of await listDirectories(evalDir)) {
|
|
303
|
-
const configName = path.basename(configDir);
|
|
304
|
-
if (configFilter.size > 0 && !configFilter.has(configName)) {
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
for (const runDir of await listDirectories(configDir)) {
|
|
309
|
-
if (!path.basename(runDir).startsWith('run-')) {
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const gradingPath = path.join(runDir, 'grading.json');
|
|
314
|
-
const existing = await readJsonFile(gradingPath, null);
|
|
315
|
-
if (existing && options.overwrite !== true) {
|
|
316
|
-
skippedRuns.push(path.relative(workspaceDir, runDir).replace(/\\/g, '/'));
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const graded = await gradeRun(runDir, options, runner);
|
|
321
|
-
processedRuns.push({
|
|
322
|
-
run: path.relative(workspaceDir, runDir).replace(/\\/g, '/'),
|
|
323
|
-
summary: graded.grading.summary,
|
|
324
|
-
config: graded.grading.meta.config,
|
|
325
|
-
eval_id: graded.grading.meta.eval_id,
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const summary = {
|
|
332
|
-
workspace: workspaceDir,
|
|
333
|
-
generated_at: new Date().toISOString(),
|
|
334
|
-
processed: processedRuns.length,
|
|
335
|
-
skipped: skippedRuns.length,
|
|
336
|
-
processed_runs: processedRuns,
|
|
337
|
-
skipped_runs: skippedRuns,
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
await writeFile(
|
|
341
|
-
path.join(workspaceDir, 'grading-summary.json'),
|
|
342
|
-
`${JSON.stringify(summary, null, 2)}\n`,
|
|
343
|
-
'utf8'
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
return summary;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function parseArgs(argv) {
|
|
350
|
-
const args = {
|
|
351
|
-
workspaceDir: argv[2] ?? '',
|
|
352
|
-
provider: 'anthropic',
|
|
353
|
-
model: undefined,
|
|
354
|
-
reasoningMode: 'balanced',
|
|
355
|
-
maxIter: 20,
|
|
356
|
-
cwd: process.cwd(),
|
|
357
|
-
overwrite: false,
|
|
358
|
-
configs: [],
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
for (let index = 3; index < argv.length; index += 1) {
|
|
362
|
-
const token = argv[index];
|
|
363
|
-
if (token === '--provider' && argv[index + 1]) {
|
|
364
|
-
args.provider = argv[++index];
|
|
365
|
-
} else if (token === '--model' && argv[index + 1]) {
|
|
366
|
-
args.model = argv[++index];
|
|
367
|
-
} else if (token === '--reasoning' && argv[index + 1]) {
|
|
368
|
-
args.reasoningMode = argv[++index];
|
|
369
|
-
} else if (token === '--max-iter' && argv[index + 1]) {
|
|
370
|
-
args.maxIter = Number(argv[++index]);
|
|
371
|
-
} else if (token === '--cwd' && argv[index + 1]) {
|
|
372
|
-
args.cwd = argv[++index];
|
|
373
|
-
} else if (token === '--overwrite') {
|
|
374
|
-
args.overwrite = true;
|
|
375
|
-
} else if (token === '--configs' && argv[index + 1]) {
|
|
376
|
-
args.configs = argv[++index]
|
|
377
|
-
.split(',')
|
|
378
|
-
.map((item) => item.trim())
|
|
379
|
-
.filter(Boolean);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return args;
|
|
384
|
-
}
|
|
385
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import {
|
|
7
|
+
computePassSummary,
|
|
8
|
+
ensureDirectory,
|
|
9
|
+
extractJsonObject,
|
|
10
|
+
loadKodaXSDK,
|
|
11
|
+
loadRelativeText,
|
|
12
|
+
readJsonFile,
|
|
13
|
+
truncateText,
|
|
14
|
+
} from './utils.js';
|
|
15
|
+
|
|
16
|
+
function normalizeExpectationText(value) {
|
|
17
|
+
return String(value ?? '').trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeExpectedRubric(evalMetadata) {
|
|
21
|
+
const assertions = Array.isArray(evalMetadata?.assertions) ? evalMetadata.assertions : [];
|
|
22
|
+
const items = assertions
|
|
23
|
+
.map((assertion) => {
|
|
24
|
+
if (typeof assertion === 'string') {
|
|
25
|
+
return normalizeExpectationText(assertion);
|
|
26
|
+
}
|
|
27
|
+
if (assertion && typeof assertion === 'object' && typeof assertion.text === 'string') {
|
|
28
|
+
return normalizeExpectationText(assertion.text);
|
|
29
|
+
}
|
|
30
|
+
return '';
|
|
31
|
+
})
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
|
|
34
|
+
if (items.length > 0) {
|
|
35
|
+
return items;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const expectedOutput = normalizeExpectationText(evalMetadata?.expected_output);
|
|
39
|
+
return expectedOutput ? [expectedOutput] : [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeStringArray(value) {
|
|
43
|
+
if (!Array.isArray(value)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return value
|
|
47
|
+
.map((item) => String(item ?? '').trim())
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function normalizeExpectationEntry(entry, fallbackText) {
|
|
52
|
+
const text = normalizeExpectationText(entry?.text ?? fallbackText);
|
|
53
|
+
return {
|
|
54
|
+
text,
|
|
55
|
+
passed: entry?.passed === true,
|
|
56
|
+
evidence: normalizeExpectationText(entry?.evidence),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeParsedGrading(rawText, rubric) {
|
|
61
|
+
const parsed = extractJsonObject(rawText) ?? {};
|
|
62
|
+
const returnedExpectations = Array.isArray(parsed.expectations) ? parsed.expectations : [];
|
|
63
|
+
const normalizedExpectations = [];
|
|
64
|
+
const consumed = new Set();
|
|
65
|
+
|
|
66
|
+
for (const rubricText of rubric) {
|
|
67
|
+
const matchIndex = returnedExpectations.findIndex((entry, index) => {
|
|
68
|
+
if (consumed.has(index)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const candidate = normalizeExpectationText(entry?.text);
|
|
73
|
+
return candidate.toLowerCase() === rubricText.toLowerCase();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (matchIndex === -1) {
|
|
77
|
+
normalizedExpectations.push({
|
|
78
|
+
text: rubricText,
|
|
79
|
+
passed: false,
|
|
80
|
+
evidence: '',
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
consumed.add(matchIndex);
|
|
86
|
+
normalizedExpectations.push(normalizeExpectationEntry(returnedExpectations[matchIndex], rubricText));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (rubric.length === 0) {
|
|
90
|
+
for (const entry of returnedExpectations) {
|
|
91
|
+
const normalized = normalizeExpectationEntry(entry, '');
|
|
92
|
+
if (normalized.text) {
|
|
93
|
+
normalizedExpectations.push(normalized);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
overall_summary: normalizeExpectationText(parsed.overall_summary),
|
|
100
|
+
expectations: normalizedExpectations,
|
|
101
|
+
user_notes_summary: {
|
|
102
|
+
uncertainties: normalizeStringArray(parsed.user_notes_summary?.uncertainties),
|
|
103
|
+
needs_review: normalizeStringArray(parsed.user_notes_summary?.needs_review),
|
|
104
|
+
workarounds: normalizeStringArray(parsed.user_notes_summary?.workarounds),
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function listDirectories(dirPath) {
|
|
110
|
+
const entries = await readdir(dirPath, { withFileTypes: true }).catch(() => []);
|
|
111
|
+
return entries
|
|
112
|
+
.filter((entry) => entry.isDirectory())
|
|
113
|
+
.map((entry) => path.join(dirPath, entry.name))
|
|
114
|
+
.sort((left, right) => left.localeCompare(right));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function loadRunContext(runDir) {
|
|
118
|
+
const configDir = path.dirname(runDir);
|
|
119
|
+
const evalDir = path.dirname(configDir);
|
|
120
|
+
const configName = path.basename(configDir);
|
|
121
|
+
const runId = path.basename(runDir);
|
|
122
|
+
const outputsDir = path.join(runDir, 'outputs');
|
|
123
|
+
const evalMetadata = await readJsonFile(path.join(evalDir, 'eval_metadata.json'), {});
|
|
124
|
+
const resultText = await readFile(path.join(outputsDir, 'result.md'), 'utf8').catch(() => '');
|
|
125
|
+
const promptText = await readFile(path.join(outputsDir, 'prompt.txt'), 'utf8').catch(() => '');
|
|
126
|
+
const transcript = await readFile(path.join(runDir, 'transcript.md'), 'utf8').catch(() => '');
|
|
127
|
+
const metrics = await readJsonFile(path.join(outputsDir, 'metrics.json'), {});
|
|
128
|
+
const result = await readJsonFile(path.join(runDir, 'result.json'), {});
|
|
129
|
+
const timing = await readJsonFile(path.join(runDir, 'timing.json'), {});
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
evalDir,
|
|
133
|
+
runDir,
|
|
134
|
+
runId,
|
|
135
|
+
configName,
|
|
136
|
+
evalMetadata,
|
|
137
|
+
outputsDir,
|
|
138
|
+
resultText,
|
|
139
|
+
promptText,
|
|
140
|
+
transcript,
|
|
141
|
+
metrics,
|
|
142
|
+
result,
|
|
143
|
+
timing,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function buildGradingPrompt(input) {
|
|
148
|
+
const rubric = normalizeExpectedRubric(input.evalMetadata);
|
|
149
|
+
const rubricText = rubric.length > 0
|
|
150
|
+
? rubric.map((item, index) => `${index + 1}. ${item}`).join('\n')
|
|
151
|
+
: '(No explicit assertions; infer one expectation from expected_output if present.)';
|
|
152
|
+
|
|
153
|
+
return `${input.agentInstructions.trim()}
|
|
154
|
+
|
|
155
|
+
Return JSON with this shape:
|
|
156
|
+
{
|
|
157
|
+
"overall_summary": "short summary",
|
|
158
|
+
"expectations": [
|
|
159
|
+
{
|
|
160
|
+
"text": "expectation text",
|
|
161
|
+
"passed": true,
|
|
162
|
+
"evidence": "short evidence grounded in the output"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"user_notes_summary": {
|
|
166
|
+
"uncertainties": [],
|
|
167
|
+
"needs_review": [],
|
|
168
|
+
"workarounds": []
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
## Run Metadata
|
|
173
|
+
- eval_id: ${input.evalMetadata.eval_id ?? 'unknown'}
|
|
174
|
+
- eval_name: ${input.evalMetadata.eval_name ?? 'unknown'}
|
|
175
|
+
- config: ${input.configName}
|
|
176
|
+
- run_id: ${input.runId}
|
|
177
|
+
|
|
178
|
+
## Eval Prompt
|
|
179
|
+
${truncateText(input.evalMetadata.prompt ?? input.promptText, 4000)}
|
|
180
|
+
|
|
181
|
+
## Expected Outcome
|
|
182
|
+
${truncateText(input.evalMetadata.expected_output ?? '', 2000)}
|
|
183
|
+
|
|
184
|
+
## Assertions
|
|
185
|
+
${rubricText}
|
|
186
|
+
|
|
187
|
+
## Final Output
|
|
188
|
+
${truncateText(input.resultText, 12000)}
|
|
189
|
+
|
|
190
|
+
## Result Flags
|
|
191
|
+
${JSON.stringify({
|
|
192
|
+
success: input.result.success ?? null,
|
|
193
|
+
signal: input.result.signal ?? null,
|
|
194
|
+
interrupted: input.result.interrupted ?? false,
|
|
195
|
+
limit_reached: input.result.limit_reached ?? input.result.limitReached ?? false,
|
|
196
|
+
}, null, 2)}
|
|
197
|
+
|
|
198
|
+
## Execution Metrics
|
|
199
|
+
${JSON.stringify({
|
|
200
|
+
total_tool_calls: input.metrics.total_tool_calls ?? input.result.execution_metrics?.total_tool_calls ?? 0,
|
|
201
|
+
errors_encountered: input.metrics.errors_encountered ?? input.result.execution_metrics?.errors_encountered ?? 0,
|
|
202
|
+
output_chars: input.metrics.output_chars ?? input.result.execution_metrics?.output_chars ?? input.resultText.length,
|
|
203
|
+
total_tokens: input.timing.total_tokens ?? 0,
|
|
204
|
+
total_duration_seconds: input.timing.total_duration_seconds ?? 0,
|
|
205
|
+
}, null, 2)}
|
|
206
|
+
|
|
207
|
+
## Transcript Excerpt
|
|
208
|
+
${truncateText(input.transcript, 5000)}
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function defaultRunJudge(prompt, options) {
|
|
213
|
+
const { runKodaX } = await loadKodaXSDK();
|
|
214
|
+
const result = await runKodaX(
|
|
215
|
+
{
|
|
216
|
+
provider: options.provider ?? 'anthropic',
|
|
217
|
+
model: options.model,
|
|
218
|
+
maxIter: options.maxIter ?? 20,
|
|
219
|
+
reasoningMode: options.reasoningMode ?? 'balanced',
|
|
220
|
+
thinking: options.reasoningMode ? options.reasoningMode !== 'off' : true,
|
|
221
|
+
context: {
|
|
222
|
+
gitRoot: path.resolve(options.cwd ?? options.workspaceDir ?? process.cwd()),
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
prompt
|
|
226
|
+
);
|
|
227
|
+
return result.lastText;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export async function gradeRun(runDir, options, runner = defaultRunJudge) {
|
|
231
|
+
const run = await loadRunContext(path.resolve(runDir));
|
|
232
|
+
const rubric = normalizeExpectedRubric(run.evalMetadata);
|
|
233
|
+
const agentInstructions = await loadRelativeText(import.meta.url, '../agents/grader.md');
|
|
234
|
+
const prompt = buildGradingPrompt({
|
|
235
|
+
...run,
|
|
236
|
+
agentInstructions,
|
|
237
|
+
});
|
|
238
|
+
const rawResponse = await runner(prompt, {
|
|
239
|
+
...options,
|
|
240
|
+
runDir: run.runDir,
|
|
241
|
+
configName: run.configName,
|
|
242
|
+
evalMetadata: run.evalMetadata,
|
|
243
|
+
runId: run.runId,
|
|
244
|
+
});
|
|
245
|
+
const parsed = normalizeParsedGrading(rawResponse, rubric);
|
|
246
|
+
const executionMetrics = {
|
|
247
|
+
total_tool_calls: run.metrics.total_tool_calls ?? run.result.execution_metrics?.total_tool_calls ?? 0,
|
|
248
|
+
errors_encountered: run.metrics.errors_encountered ?? run.result.execution_metrics?.errors_encountered ?? 0,
|
|
249
|
+
output_chars: run.metrics.output_chars ?? run.result.execution_metrics?.output_chars ?? run.resultText.length,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const grading = {
|
|
253
|
+
summary: computePassSummary(parsed.expectations),
|
|
254
|
+
expectations: parsed.expectations,
|
|
255
|
+
execution_metrics: executionMetrics,
|
|
256
|
+
user_notes_summary: parsed.user_notes_summary,
|
|
257
|
+
overall_summary: parsed.overall_summary,
|
|
258
|
+
timing: {
|
|
259
|
+
total_tokens: run.timing.total_tokens ?? 0,
|
|
260
|
+
total_duration_seconds: run.timing.total_duration_seconds ?? 0,
|
|
261
|
+
},
|
|
262
|
+
meta: {
|
|
263
|
+
generated_at: new Date().toISOString(),
|
|
264
|
+
eval_id: run.evalMetadata.eval_id ?? null,
|
|
265
|
+
eval_name: run.evalMetadata.eval_name ?? null,
|
|
266
|
+
config: run.configName,
|
|
267
|
+
run_id: run.runId,
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
await writeFile(
|
|
272
|
+
path.join(run.runDir, 'grading.json'),
|
|
273
|
+
`${JSON.stringify(grading, null, 2)}\n`,
|
|
274
|
+
'utf8'
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
runDir: run.runDir,
|
|
279
|
+
grading,
|
|
280
|
+
prompt,
|
|
281
|
+
rawResponse,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export async function gradeWorkspace(options, runner = defaultRunJudge) {
|
|
286
|
+
const workspaceDir = path.resolve(options.workspaceDir);
|
|
287
|
+
await ensureDirectory(workspaceDir);
|
|
288
|
+
|
|
289
|
+
const configFilter = new Set(
|
|
290
|
+
(options.configs ?? [])
|
|
291
|
+
.map((item) => String(item).trim())
|
|
292
|
+
.filter(Boolean)
|
|
293
|
+
);
|
|
294
|
+
const processedRuns = [];
|
|
295
|
+
const skippedRuns = [];
|
|
296
|
+
|
|
297
|
+
for (const evalDir of await listDirectories(workspaceDir)) {
|
|
298
|
+
if (!path.basename(evalDir).startsWith('eval-')) {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (const configDir of await listDirectories(evalDir)) {
|
|
303
|
+
const configName = path.basename(configDir);
|
|
304
|
+
if (configFilter.size > 0 && !configFilter.has(configName)) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const runDir of await listDirectories(configDir)) {
|
|
309
|
+
if (!path.basename(runDir).startsWith('run-')) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const gradingPath = path.join(runDir, 'grading.json');
|
|
314
|
+
const existing = await readJsonFile(gradingPath, null);
|
|
315
|
+
if (existing && options.overwrite !== true) {
|
|
316
|
+
skippedRuns.push(path.relative(workspaceDir, runDir).replace(/\\/g, '/'));
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const graded = await gradeRun(runDir, options, runner);
|
|
321
|
+
processedRuns.push({
|
|
322
|
+
run: path.relative(workspaceDir, runDir).replace(/\\/g, '/'),
|
|
323
|
+
summary: graded.grading.summary,
|
|
324
|
+
config: graded.grading.meta.config,
|
|
325
|
+
eval_id: graded.grading.meta.eval_id,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const summary = {
|
|
332
|
+
workspace: workspaceDir,
|
|
333
|
+
generated_at: new Date().toISOString(),
|
|
334
|
+
processed: processedRuns.length,
|
|
335
|
+
skipped: skippedRuns.length,
|
|
336
|
+
processed_runs: processedRuns,
|
|
337
|
+
skipped_runs: skippedRuns,
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
await writeFile(
|
|
341
|
+
path.join(workspaceDir, 'grading-summary.json'),
|
|
342
|
+
`${JSON.stringify(summary, null, 2)}\n`,
|
|
343
|
+
'utf8'
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
return summary;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function parseArgs(argv) {
|
|
350
|
+
const args = {
|
|
351
|
+
workspaceDir: argv[2] ?? '',
|
|
352
|
+
provider: 'anthropic',
|
|
353
|
+
model: undefined,
|
|
354
|
+
reasoningMode: 'balanced',
|
|
355
|
+
maxIter: 20,
|
|
356
|
+
cwd: process.cwd(),
|
|
357
|
+
overwrite: false,
|
|
358
|
+
configs: [],
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
for (let index = 3; index < argv.length; index += 1) {
|
|
362
|
+
const token = argv[index];
|
|
363
|
+
if (token === '--provider' && argv[index + 1]) {
|
|
364
|
+
args.provider = argv[++index];
|
|
365
|
+
} else if (token === '--model' && argv[index + 1]) {
|
|
366
|
+
args.model = argv[++index];
|
|
367
|
+
} else if (token === '--reasoning' && argv[index + 1]) {
|
|
368
|
+
args.reasoningMode = argv[++index];
|
|
369
|
+
} else if (token === '--max-iter' && argv[index + 1]) {
|
|
370
|
+
args.maxIter = Number(argv[++index]);
|
|
371
|
+
} else if (token === '--cwd' && argv[index + 1]) {
|
|
372
|
+
args.cwd = argv[++index];
|
|
373
|
+
} else if (token === '--overwrite') {
|
|
374
|
+
args.overwrite = true;
|
|
375
|
+
} else if (token === '--configs' && argv[index + 1]) {
|
|
376
|
+
args.configs = argv[++index]
|
|
377
|
+
.split(',')
|
|
378
|
+
.map((item) => item.trim())
|
|
379
|
+
.filter(Boolean);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return args;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
386
|
export async function main(argv = process.argv) {
|
|
387
387
|
const args = parseArgs(argv);
|
|
388
|
-
if (!args.workspaceDir) {
|
|
389
|
-
console.error('Usage: node scripts/grade-evals.js <workspace> [--provider anthropic] [--configs with_skill,without_skill] [--overwrite]');
|
|
390
|
-
process.exit(1);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const summary = await gradeWorkspace(args);
|
|
394
|
-
process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
395
|
-
}
|
|
396
|
-
|
|
388
|
+
if (!args.workspaceDir) {
|
|
389
|
+
console.error('Usage: node scripts/grade-evals.js <workspace> [--provider anthropic] [--configs with_skill,without_skill] [--overwrite]');
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const summary = await gradeWorkspace(args);
|
|
394
|
+
process.stdout.write(`${JSON.stringify(summary, null, 2)}\n`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
397
|
const isDirectRun = process.env.KODAX_MODULE_BUNDLE !== 'true'
|
|
398
398
|
&& process.argv[1]
|
|
399
|
-
&& fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
|
400
|
-
|
|
401
|
-
if (isDirectRun) {
|
|
402
|
-
main().catch((error) => {
|
|
403
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
404
|
-
process.exit(1);
|
|
405
|
-
});
|
|
406
|
-
}
|
|
399
|
+
&& fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
|
|
400
|
+
|
|
401
|
+
if (isDirectRun) {
|
|
402
|
+
main().catch((error) => {
|
|
403
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
404
|
+
process.exit(1);
|
|
405
|
+
});
|
|
406
|
+
}
|