@vibe-agent-toolkit/agent-skills 0.2.0-rc.7 → 0.2.0-rc.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/README.md +5 -5
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +7 -17
- package/dist/builder.js.map +1 -1
- package/dist/files-config.d.ts +2 -2
- package/dist/files-config.d.ts.map +1 -1
- package/dist/files-config.js +4 -10
- package/dist/files-config.js.map +1 -1
- package/dist/import.d.ts.map +1 -1
- package/dist/import.js +0 -4
- package/dist/import.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/inventory/types.d.ts +8 -0
- package/dist/inventory/types.d.ts.map +1 -1
- package/dist/inventory/types.js.map +1 -1
- package/dist/link-graph-members.d.ts +18 -0
- package/dist/link-graph-members.d.ts.map +1 -0
- package/dist/link-graph-members.js +18 -0
- package/dist/link-graph-members.js.map +1 -0
- package/dist/plugin-distribution-layout.d.ts +70 -6
- package/dist/plugin-distribution-layout.d.ts.map +1 -1
- package/dist/plugin-distribution-layout.js +68 -10
- package/dist/plugin-distribution-layout.js.map +1 -1
- package/dist/post-build-checks.d.ts.map +1 -1
- package/dist/post-build-checks.js +12 -11
- package/dist/post-build-checks.js.map +1 -1
- package/dist/projection/skill-extent.d.ts +1 -1
- package/dist/projection/skill-extent.d.ts.map +1 -1
- package/dist/projection/skill-extent.js +3 -1
- package/dist/projection/skill-extent.js.map +1 -1
- package/dist/schemas/installed-plugins-registry.d.ts.map +1 -1
- package/dist/schemas/installed-plugins-registry.js +7 -1
- package/dist/schemas/installed-plugins-registry.js.map +1 -1
- package/dist/skill-identity.d.ts +8 -3
- package/dist/skill-identity.d.ts.map +1 -1
- package/dist/skill-identity.js +13 -6
- package/dist/skill-identity.js.map +1 -1
- package/dist/skill-packager.d.ts +2 -1
- package/dist/skill-packager.d.ts.map +1 -1
- package/dist/skill-packager.js +53 -44
- package/dist/skill-packager.js.map +1 -1
- package/dist/skill-source/content-hash.d.ts.map +1 -1
- package/dist/skill-source/content-hash.js +21 -10
- package/dist/skill-source/content-hash.js.map +1 -1
- package/dist/skill-source/fetch-cache.d.ts.map +1 -1
- package/dist/skill-source/fetch-cache.js +0 -5
- package/dist/skill-source/fetch-cache.js.map +1 -1
- package/dist/skill-source/git-clone.d.ts.map +1 -1
- package/dist/skill-source/git-clone.js +0 -2
- package/dist/skill-source/git-clone.js.map +1 -1
- package/dist/skill-source/sources/url-source.d.ts.map +1 -1
- package/dist/skill-source/sources/url-source.js +0 -1
- package/dist/skill-source/sources/url-source.js.map +1 -1
- package/dist/skill-source/stage.d.ts.map +1 -1
- package/dist/skill-source/stage.js +0 -6
- package/dist/skill-source/stage.js.map +1 -1
- package/dist/skill-test/baseline-integrity.d.ts.map +1 -1
- package/dist/skill-test/baseline-integrity.js +10 -3
- package/dist/skill-test/baseline-integrity.js.map +1 -1
- package/dist/skill-test/build-hook.d.ts +3 -2
- package/dist/skill-test/build-hook.d.ts.map +1 -1
- package/dist/skill-test/build-hook.js +4 -4
- package/dist/skill-test/build-hook.js.map +1 -1
- package/dist/skill-test/declared-env.d.ts +5 -4
- package/dist/skill-test/declared-env.d.ts.map +1 -1
- package/dist/skill-test/declared-env.js +7 -9
- package/dist/skill-test/declared-env.js.map +1 -1
- package/dist/skill-test/eval-executor.d.ts +1 -1
- package/dist/skill-test/eval-executor.js +2 -2
- package/dist/skill-test/eval-executor.js.map +1 -1
- package/dist/skill-test/eval-fragment.d.ts +7 -5
- package/dist/skill-test/eval-fragment.d.ts.map +1 -1
- package/dist/skill-test/eval-fragment.js +13 -7
- package/dist/skill-test/eval-fragment.js.map +1 -1
- package/dist/skill-test/eval-grader.d.ts +56 -4
- package/dist/skill-test/eval-grader.d.ts.map +1 -1
- package/dist/skill-test/eval-grader.js +138 -73
- package/dist/skill-test/eval-grader.js.map +1 -1
- package/dist/skill-test/eval-inputs.d.ts +8 -7
- package/dist/skill-test/eval-inputs.d.ts.map +1 -1
- package/dist/skill-test/eval-inputs.js +9 -11
- package/dist/skill-test/eval-inputs.js.map +1 -1
- package/dist/skill-test/eval-lint.d.ts +4 -4
- package/dist/skill-test/eval-lint.js +5 -5
- package/dist/skill-test/eval-lint.js.map +1 -1
- package/dist/skill-test/eval-suite-isolation.d.ts.map +1 -1
- package/dist/skill-test/eval-suite-isolation.js +8 -5
- package/dist/skill-test/eval-suite-isolation.js.map +1 -1
- package/dist/skill-test/evals-template.d.ts +1 -1
- package/dist/skill-test/evals-template.d.ts.map +1 -1
- package/dist/skill-test/evals-template.js +1 -3
- package/dist/skill-test/evals-template.js.map +1 -1
- package/dist/skill-test/executor-prompt.d.ts +2 -2
- package/dist/skill-test/executor-prompt.js +2 -2
- package/dist/skill-test/failure-reason.d.ts +113 -0
- package/dist/skill-test/failure-reason.d.ts.map +1 -0
- package/dist/skill-test/failure-reason.js +124 -0
- package/dist/skill-test/failure-reason.js.map +1 -0
- package/dist/skill-test/fragment-merge.d.ts +2 -2
- package/dist/skill-test/fragment-merge.js +4 -4
- package/dist/skill-test/grader-prompt.d.ts +2 -2
- package/dist/skill-test/grader-prompt.d.ts.map +1 -1
- package/dist/skill-test/grader-prompt.js +12 -8
- package/dist/skill-test/grader-prompt.js.map +1 -1
- package/dist/skill-test/grading-adapter.d.ts +7 -3
- package/dist/skill-test/grading-adapter.d.ts.map +1 -1
- package/dist/skill-test/grading-adapter.js +10 -9
- package/dist/skill-test/grading-adapter.js.map +1 -1
- package/dist/skill-test/harness-location.d.ts +3 -2
- package/dist/skill-test/harness-location.d.ts.map +1 -1
- package/dist/skill-test/harness-location.js +5 -16
- package/dist/skill-test/harness-location.js.map +1 -1
- package/dist/skill-test/index.d.ts +1 -1
- package/dist/skill-test/index.d.ts.map +1 -1
- package/dist/skill-test/index.js +1 -1
- package/dist/skill-test/index.js.map +1 -1
- package/dist/skill-test/lock.d.ts +11 -10
- package/dist/skill-test/lock.d.ts.map +1 -1
- package/dist/skill-test/lock.js +13 -14
- package/dist/skill-test/lock.js.map +1 -1
- package/dist/skill-test/pipeline.d.ts +3 -1
- package/dist/skill-test/pipeline.d.ts.map +1 -1
- package/dist/skill-test/pipeline.js +5 -1
- package/dist/skill-test/pipeline.js.map +1 -1
- package/dist/skill-test/preflight.d.ts.map +1 -1
- package/dist/skill-test/preflight.js +0 -1
- package/dist/skill-test/preflight.js.map +1 -1
- package/dist/skill-test/prompt-invariants.d.ts +4 -2
- package/dist/skill-test/prompt-invariants.d.ts.map +1 -1
- package/dist/skill-test/prompt-invariants.js +5 -4
- package/dist/skill-test/prompt-invariants.js.map +1 -1
- package/dist/skill-test/run-harness.d.ts +160 -123
- package/dist/skill-test/run-harness.d.ts.map +1 -1
- package/dist/skill-test/run-harness.js +310 -174
- package/dist/skill-test/run-harness.js.map +1 -1
- package/dist/skill-test/staging.d.ts +12 -6
- package/dist/skill-test/staging.d.ts.map +1 -1
- package/dist/skill-test/staging.js +17 -14
- package/dist/skill-test/staging.js.map +1 -1
- package/dist/skill-test/tier-plan.d.ts +1 -1
- package/dist/skill-test/tier-plan.js +1 -1
- package/dist/skill-test/tool-eval-schema.js +2 -2
- package/dist/skill-test/vendor-manifest.d.ts +2 -1
- package/dist/skill-test/vendor-manifest.d.ts.map +1 -1
- package/dist/skill-test/vendor-manifest.js +10 -10
- package/dist/skill-test/vendor-manifest.js.map +1 -1
- package/dist/test-input.d.ts +2 -2
- package/dist/test-input.d.ts.map +1 -1
- package/dist/test-input.js +6 -7
- package/dist/test-input.js.map +1 -1
- package/dist/validators/agent-instruction-presence.d.ts.map +1 -1
- package/dist/validators/agent-instruction-presence.js +0 -1
- package/dist/validators/agent-instruction-presence.js.map +1 -1
- package/dist/validators/bundled-resource-link-detection.d.ts +5 -3
- package/dist/validators/bundled-resource-link-detection.d.ts.map +1 -1
- package/dist/validators/bundled-resource-link-detection.js +38 -38
- package/dist/validators/bundled-resource-link-detection.js.map +1 -1
- package/dist/validators/format-detection.d.ts +3 -0
- package/dist/validators/format-detection.d.ts.map +1 -1
- package/dist/validators/format-detection.js +41 -26
- package/dist/validators/format-detection.js.map +1 -1
- package/dist/validators/frontmatter-validation.js +1 -1
- package/dist/validators/frontmatter-validation.js.map +1 -1
- package/dist/validators/marketplace-validator.d.ts.map +1 -1
- package/dist/validators/marketplace-validator.js +0 -1
- package/dist/validators/marketplace-validator.js.map +1 -1
- package/dist/validators/mcp-tool-qualification.d.ts +1 -1
- package/dist/validators/mcp-tool-qualification.js +1 -1
- package/dist/validators/packaged-size-limit.d.ts.map +1 -1
- package/dist/validators/packaged-size-limit.js +0 -2
- package/dist/validators/packaged-size-limit.js.map +1 -1
- package/dist/validators/packaging-validator.d.ts +2 -2
- package/dist/validators/packaging-validator.d.ts.map +1 -1
- package/dist/validators/packaging-validator.js +10 -13
- package/dist/validators/packaging-validator.js.map +1 -1
- package/dist/validators/plugin-hosted-shape.d.ts +3 -1
- package/dist/validators/plugin-hosted-shape.d.ts.map +1 -1
- package/dist/validators/plugin-hosted-shape.js +5 -6
- package/dist/validators/plugin-hosted-shape.js.map +1 -1
- package/dist/validators/referenced-path-missing.d.ts.map +1 -1
- package/dist/validators/referenced-path-missing.js +3 -4
- package/dist/validators/referenced-path-missing.js.map +1 -1
- package/dist/validators/registry-validator.d.ts.map +1 -1
- package/dist/validators/registry-validator.js +0 -1
- package/dist/validators/registry-validator.js.map +1 -1
- package/dist/validators/rule-engine/index.d.ts +1 -1
- package/dist/validators/rule-engine/rule-context.d.ts +3 -3
- package/dist/validators/rule-engine/rule-context.js +1 -1
- package/dist/validators/rule-engine/rule-engine.d.ts +1 -1
- package/dist/validators/rule-engine/rule-engine.js +5 -5
- package/dist/validators/rule-engine/rule-engine.js.map +1 -1
- package/dist/validators/skill-validator.d.ts.map +1 -1
- package/dist/validators/skill-validator.js +41 -51
- package/dist/validators/skill-validator.js.map +1 -1
- package/dist/validators/source-only-codes.js +1 -1
- package/dist/validators/source-only-codes.js.map +1 -1
- package/dist/validators/types.d.ts +7 -1
- package/dist/validators/types.d.ts.map +1 -1
- package/dist/validators/unified-validator.d.ts.map +1 -1
- package/dist/validators/unified-validator.js +3 -4
- package/dist/validators/unified-validator.js.map +1 -1
- package/dist/validators/validation-rules.d.ts +3 -3
- package/dist/validators/validation-rules.d.ts.map +1 -1
- package/dist/validators/validation-rules.js +9 -38
- package/dist/validators/validation-rules.js.map +1 -1
- package/dist/validators/walker-to-issues.d.ts +2 -0
- package/dist/validators/walker-to-issues.d.ts.map +1 -1
- package/dist/validators/walker-to-issues.js +17 -12
- package/dist/validators/walker-to-issues.js.map +1 -1
- package/dist/walk-link-graph.d.ts +2 -0
- package/dist/walk-link-graph.d.ts.map +1 -1
- package/dist/walk-link-graph.js +20 -8
- package/dist/walk-link-graph.js.map +1 -1
- package/package.json +12 -20
- package/dist/skill-test/exit-codes.d.ts +0 -134
- package/dist/skill-test/exit-codes.d.ts.map +0 -1
- package/dist/skill-test/exit-codes.js +0 -224
- package/dist/skill-test/exit-codes.js.map +0 -1
|
@@ -11,23 +11,22 @@
|
|
|
11
11
|
* agent-skills-specific concerns: token computation, interpolation, and gluing
|
|
12
12
|
* the result onto the plugin-root env.
|
|
13
13
|
*/
|
|
14
|
-
import { safePath } from '@vibe-agent-toolkit/utils';
|
|
14
|
+
import { safePath, VatError } from '@vibe-agent-toolkit/utils';
|
|
15
15
|
import { applyDeclaredEnv, formatForwardedEnvLine } from '@vibe-agent-toolkit/utils/skill-test';
|
|
16
16
|
import { withPluginRootEnv } from './plugin-env.js';
|
|
17
17
|
/**
|
|
18
18
|
* A declared `env` value referenced an unknown `${token}`. Exit 2 (preflight):
|
|
19
19
|
* fail loud naming the offending token rather than forwarding a literal `${x}`.
|
|
20
20
|
*/
|
|
21
|
-
export class UnknownEnvTokenError extends
|
|
21
|
+
export class UnknownEnvTokenError extends VatError {
|
|
22
22
|
token;
|
|
23
23
|
key;
|
|
24
|
-
|
|
24
|
+
reason = 'preflight';
|
|
25
25
|
constructor(token, key) {
|
|
26
|
-
super(`Unknown interpolation token \${${token}} in env value for "${key}". ` +
|
|
26
|
+
super('UNKNOWN_ENV_TOKEN', `Unknown interpolation token \${${token}} in env value for "${key}". ` +
|
|
27
27
|
`Known tokens: fixturesDir, stagedSkillDir, harnessRoot, resultsDir.`);
|
|
28
28
|
this.token = token;
|
|
29
29
|
this.key = key;
|
|
30
|
-
this.name = 'UnknownEnvTokenError';
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
32
|
/**
|
|
@@ -40,18 +39,17 @@ export class UnknownEnvTokenError extends Error {
|
|
|
40
39
|
* deleted directory produced a dead path the skill only discovered at runtime,
|
|
41
40
|
* where it read as a skill bug rather than a harness one.
|
|
42
41
|
*/
|
|
43
|
-
export class UnresolvableEnvTokenError extends
|
|
42
|
+
export class UnresolvableEnvTokenError extends VatError {
|
|
44
43
|
token;
|
|
45
44
|
key;
|
|
46
|
-
|
|
45
|
+
reason = 'preflight';
|
|
47
46
|
constructor(token, key) {
|
|
48
|
-
super(`Cannot resolve \${${token}} in env value for "${key}": this eval declares no input ` +
|
|
47
|
+
super('UNRESOLVABLE_ENV_TOKEN', `Cannot resolve \${${token}} in env value for "${key}": this eval declares no input ` +
|
|
49
48
|
`\`files\`, so it has no staged fixtures directory. Declare the fixture under the ` +
|
|
50
49
|
`eval's \`files\` list (it is staged into the eval's own workspace, which is also the ` +
|
|
51
50
|
`executor's working directory), or drop \${${token}} from that env value.`);
|
|
52
51
|
this.token = token;
|
|
53
52
|
this.key = key;
|
|
54
|
-
this.name = 'UnresolvableEnvTokenError';
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
55
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declared-env.js","sourceRoot":"","sources":["../../src/skill-test/declared-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"declared-env.js","sourceRoot":"","sources":["../../src/skill-test/declared-env.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,7 +43,7 @@ export interface ExecutorOutcome {
|
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* Run ONE eval's executor: a blind `claude -p` spawn that performs `task`
|
|
46
|
-
* against the staged subject
|
|
46
|
+
* against the staged subject. The executor's entire stream-json
|
|
47
47
|
* stdout is accumulated in memory (never written to a skill-writable disk
|
|
48
48
|
* path — the "stop discarding stdout" fix) and echoed to `onProgress` chunk
|
|
49
49
|
* by chunk for visibility.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { parseStreamJsonTranscript, spawnHeadlessClaude, } from '@vibe-agent-toolkit/utils/skill-test';
|
|
2
2
|
import { assertExecutorPromptInvariants, buildExecutorPrompt } from './executor-prompt.js';
|
|
3
|
-
import { InternalHarnessError } from './
|
|
3
|
+
import { InternalHarnessError } from './failure-reason.js';
|
|
4
4
|
import { RateLimitSignal } from './pipeline.js';
|
|
5
5
|
/**
|
|
6
6
|
* Run ONE eval's executor: a blind `claude -p` spawn that performs `task`
|
|
7
|
-
* against the staged subject
|
|
7
|
+
* against the staged subject. The executor's entire stream-json
|
|
8
8
|
* stdout is accumulated in memory (never written to a skill-writable disk
|
|
9
9
|
* path — the "stop discarding stdout" fix) and echoed to `onProgress` chunk
|
|
10
10
|
* by chunk for visibility.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-executor.js","sourceRoot":"","sources":["../../src/skill-test/eval-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,8BAA8B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"eval-executor.js","sourceRoot":"","sources":["../../src/skill-test/eval-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,8BAA8B,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA8ChD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAuB;IAC9D,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC;IACnC,MAAM,MAAM,GAAG,mBAAmB,CAAC;QACjC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,CAAC,KAAK,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACxF,YAAY,EAAE,KAAK,CAAC,YAAY;KACjC,CAAC,CAAC;IACH,yEAAyE;IACzE,0EAA0E;IAC1E,yEAAyE;IACzE,0EAA0E;IAC1E,8BAA8B,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,mBAAmB,CAAC;IAEjD,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAQ,EAAE;QACvC,UAAU,IAAI,KAAK,CAAC;QACpB,KAAK,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEF,IAAI,WAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,KAAK,CAAC;YACxB,MAAM;YACN,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,OAAO;YACnB,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ;YACR,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5D,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,oBAAoB,CAC5B,mCAAmC,KAAK,CAAC,MAAM,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACxG,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,yEAAyE;IACzE,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,oBAAoB,CAC5B,8BAA8B,KAAK,CAAC,MAAM,oBAAoB,KAAK,CAAC,OAAO,IAAI,CAAC,MAAM,CACvF,CAAC;IACJ,CAAC;IACD,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAC5B,gCAAgC,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,SAAS,MAAM,CAC9E,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAErD,2EAA2E;IAC3E,4EAA4E;IAC5E,6DAA6D;IAC7D,IAAI,MAAM,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,eAAe,CAAC,mCAAmC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,UAAU;QACV,MAAM;QACN,WAAW;QACX,YAAY,EAAE,WAAW,CAAC,MAAM,KAAK,CAAC;KACvC,CAAC;AACJ,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VatError } from '@vibe-agent-toolkit/utils';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
/** One graded expectation inside a per-eval grader fragment. */
|
|
3
4
|
export declare const EvalFragmentExpectationSchema: z.ZodObject<{
|
|
@@ -15,7 +16,7 @@ export declare const EvalFragmentExpectationSchema: z.ZodObject<{
|
|
|
15
16
|
}>;
|
|
16
17
|
export type EvalFragmentExpectation = z.infer<typeof EvalFragmentExpectationSchema>;
|
|
17
18
|
/**
|
|
18
|
-
* Strict shape of a single grader subagent's output
|
|
19
|
+
* Strict shape of a single grader subagent's output. One
|
|
19
20
|
* GRADER spawn grades ONE eval's expectations from that eval's captured
|
|
20
21
|
* transcript and writes exactly one fragment matching this schema; vat reads
|
|
21
22
|
* every eval's fragment back and merges them into the run's aggregate grading
|
|
@@ -28,7 +29,7 @@ export type EvalFragmentExpectation = z.infer<typeof EvalFragmentExpectationSche
|
|
|
28
29
|
* `arm` distinguishes a WITH/WITHOUT baseline run's fragment; absent means the
|
|
29
30
|
* default 'with' (skill present) arm.
|
|
30
31
|
*
|
|
31
|
-
* `tool`
|
|
32
|
+
* `tool` carries this eval's tool-expectation verdict —
|
|
32
33
|
* a SEPARATE channel from `expectations[]` and from `friction` (see
|
|
33
34
|
* tool-eval-schema.ts). It is {@link ToolVerdictBodySchema}, i.e. a
|
|
34
35
|
* {@link import('./tool-eval-schema.js').ToolVerdict} WITHOUT `evalId`: the
|
|
@@ -38,7 +39,7 @@ export type EvalFragmentExpectation = z.infer<typeof EvalFragmentExpectationSche
|
|
|
38
39
|
*/
|
|
39
40
|
export declare const EvalFragmentSchema: z.ZodObject<{
|
|
40
41
|
runNonce: z.ZodString;
|
|
41
|
-
evalId: z.ZodString
|
|
42
|
+
evalId: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, string, string | number>;
|
|
42
43
|
arm: z.ZodOptional<z.ZodEnum<["with", "without"]>>;
|
|
43
44
|
expectations: z.ZodArray<z.ZodObject<{
|
|
44
45
|
text: z.ZodString;
|
|
@@ -273,7 +274,7 @@ export declare const EvalFragmentSchema: z.ZodObject<{
|
|
|
273
274
|
passed: boolean;
|
|
274
275
|
evidence?: string | undefined;
|
|
275
276
|
}[];
|
|
276
|
-
evalId: string;
|
|
277
|
+
evalId: string | number;
|
|
277
278
|
runNonce: string;
|
|
278
279
|
tool?: {
|
|
279
280
|
passed: boolean;
|
|
@@ -328,7 +329,8 @@ export type EvalFragment = z.infer<typeof EvalFragmentSchema>;
|
|
|
328
329
|
* should point at the offending eval, not at "Re-sync the vendored
|
|
329
330
|
* skill-creator".
|
|
330
331
|
*/
|
|
331
|
-
export declare class EvalFragmentError extends
|
|
332
|
+
export declare class EvalFragmentError extends VatError {
|
|
333
|
+
readonly reason: "internal";
|
|
332
334
|
constructor(message: string);
|
|
333
335
|
}
|
|
334
336
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-fragment.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,gEAAgE;AAChE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;EAI/B,CAAC;AAEZ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"eval-fragment.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,gEAAgE;AAChE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;EAI/B,CAAC;AAEZ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAU7B;;;;;OAKG;;;;;;;;;;;;;;IAEH;;;;;;;;;;;;;;OAcG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEM,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C,QAAQ,CAAC,MAAM,EAAG,UAAU,CAAU;gBAC1B,OAAO,EAAE,MAAM;CAG5B;AAgED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,YAAY,CAyB/F"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VatError } from '@vibe-agent-toolkit/utils';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { BaselineContaminationHitSchema, BaselineScanDegradationSchema } from './baseline-integrity.js';
|
|
3
4
|
import { FrictionItemSchema } from './friction-schema.js';
|
|
@@ -10,7 +11,7 @@ export const EvalFragmentExpectationSchema = z.object({
|
|
|
10
11
|
evidence: z.string().optional(),
|
|
11
12
|
}).strict();
|
|
12
13
|
/**
|
|
13
|
-
* Strict shape of a single grader subagent's output
|
|
14
|
+
* Strict shape of a single grader subagent's output. One
|
|
14
15
|
* GRADER spawn grades ONE eval's expectations from that eval's captured
|
|
15
16
|
* transcript and writes exactly one fragment matching this schema; vat reads
|
|
16
17
|
* every eval's fragment back and merges them into the run's aggregate grading
|
|
@@ -23,7 +24,7 @@ export const EvalFragmentExpectationSchema = z.object({
|
|
|
23
24
|
* `arm` distinguishes a WITH/WITHOUT baseline run's fragment; absent means the
|
|
24
25
|
* default 'with' (skill present) arm.
|
|
25
26
|
*
|
|
26
|
-
* `tool`
|
|
27
|
+
* `tool` carries this eval's tool-expectation verdict —
|
|
27
28
|
* a SEPARATE channel from `expectations[]` and from `friction` (see
|
|
28
29
|
* tool-eval-schema.ts). It is {@link ToolVerdictBodySchema}, i.e. a
|
|
29
30
|
* {@link import('./tool-eval-schema.js').ToolVerdict} WITHOUT `evalId`: the
|
|
@@ -33,7 +34,10 @@ export const EvalFragmentExpectationSchema = z.object({
|
|
|
33
34
|
*/
|
|
34
35
|
export const EvalFragmentSchema = z.object({
|
|
35
36
|
runNonce: z.string().min(1),
|
|
36
|
-
|
|
37
|
+
// evals.json allows an integer id and every other layer carries it as a
|
|
38
|
+
// string; a grader that echoes the number names the same eval, so it is
|
|
39
|
+
// normalised here rather than refused as a forged fragment.
|
|
40
|
+
evalId: z.union([z.string().min(1), z.number().int()]).transform(String),
|
|
37
41
|
arm: z.enum(['with', 'without']).optional(),
|
|
38
42
|
expectations: z.array(EvalFragmentExpectationSchema).min(1),
|
|
39
43
|
friction: z.array(FrictionItemSchema).optional(),
|
|
@@ -72,10 +76,10 @@ export const EvalFragmentSchema = z.object({
|
|
|
72
76
|
* should point at the offending eval, not at "Re-sync the vendored
|
|
73
77
|
* skill-creator".
|
|
74
78
|
*/
|
|
75
|
-
export class EvalFragmentError extends
|
|
79
|
+
export class EvalFragmentError extends VatError {
|
|
80
|
+
reason = 'internal';
|
|
76
81
|
constructor(message) {
|
|
77
|
-
super(message);
|
|
78
|
-
this.name = 'EvalFragmentError';
|
|
82
|
+
super('EVAL_FRAGMENT', message);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
/**
|
|
@@ -88,6 +92,8 @@ export class EvalFragmentError extends Error {
|
|
|
88
92
|
function extractRawEvalId(raw) {
|
|
89
93
|
if (typeof raw === 'object' && raw !== null && 'evalId' in raw) {
|
|
90
94
|
const value = raw['evalId'];
|
|
95
|
+
if (typeof value === 'number')
|
|
96
|
+
return `"${String(value)}"`;
|
|
91
97
|
if (typeof value === 'string' && value.length > 0)
|
|
92
98
|
return `"${sanitizeGraderText(value)}"`;
|
|
93
99
|
}
|
|
@@ -106,7 +112,7 @@ const UNSANITIZED_FRAGMENT_KEYS = new Set(['runNonce']);
|
|
|
106
112
|
* Sanitize ONLY the (non-verdict-bearing) `friction` field before the strict
|
|
107
113
|
* fragment parse. Friction is auxiliary advisory data, not a verdict channel —
|
|
108
114
|
* so a grader that wobbles on the friction shape (e.g. emits bare strings, the
|
|
109
|
-
* common failure mode
|
|
115
|
+
* common failure mode) must NOT be allowed to discard the
|
|
110
116
|
* verdict-bearing grading for the whole run. We drop friction items that don't
|
|
111
117
|
* match {@link FrictionItemSchema} (and a `friction` that isn't an array at
|
|
112
118
|
* all), then hand the rest to the STRICT fragment parse — so the verdict
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-fragment.js","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,8BAA8B,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACxG,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,gEAAgE;AAChE,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC;IACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC,MAAM,EAAE,CAAC;AAIZ;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"eval-fragment.js","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VatError } from '@vibe-agent-toolkit/utils';
|
|
1
2
|
import { spawnHeadlessClaude } from '@vibe-agent-toolkit/utils/skill-test';
|
|
2
3
|
import { type EvalFragment } from './eval-fragment.js';
|
|
3
4
|
import type { ToolExpectations } from './eval-inputs.js';
|
|
@@ -10,7 +11,7 @@ export interface RunGraderInput {
|
|
|
10
11
|
/** Path to the vendored skill-creator grader rubric (references/grader.md). */
|
|
11
12
|
rubricPath: string;
|
|
12
13
|
/**
|
|
13
|
-
* The eval's declared tool expectations
|
|
14
|
+
* The eval's declared tool expectations. Optional — when
|
|
14
15
|
* absent, `buildGraderPrompt` emits no tool-verdict instruction and the
|
|
15
16
|
* returned fragment omits `tool`. See `grader-prompt.ts`'s
|
|
16
17
|
* `BuildGraderPromptOptions.toolExpectations`.
|
|
@@ -49,12 +50,63 @@ export interface RunGraderInput {
|
|
|
49
50
|
*/
|
|
50
51
|
onProgress: (chunk: string) => void;
|
|
51
52
|
/**
|
|
52
|
-
* Reports
|
|
53
|
+
* Reports each grader session's `total_cost_usd` (parsed from its stream-json
|
|
53
54
|
* transcript's terminal result; `undefined` when the transcript carried none,
|
|
54
|
-
* e.g. a mock spawn). Called once
|
|
55
|
-
*
|
|
55
|
+
* e.g. a mock spawn). Called once per successful grader spawn — twice when the
|
|
56
|
+
* unparseable-fragment re-grade fires — so the run can aggregate total spend
|
|
57
|
+
* across all executor+grader sessions (adopter follow-up).
|
|
56
58
|
*/
|
|
57
59
|
costSink?: (totalCostUsd: number | undefined) => void;
|
|
58
60
|
}
|
|
61
|
+
/** The reason named in {@link GraderFragmentUnparseableError}'s message and in every `evidence` of the failing fragment vat synthesizes from it. */
|
|
62
|
+
export declare const GRADER_FRAGMENT_UNPARSEABLE = "grader-fragment-unparseable";
|
|
63
|
+
/**
|
|
64
|
+
* Thrown when the grader's fragment was not valid JSON on BOTH attempts (see
|
|
65
|
+
* {@link runGraderForEval}). A per-eval GRADING failure, deliberately neither
|
|
66
|
+
* {@link InternalHarnessError} nor `EvalFragmentError`: the harness did its
|
|
67
|
+
* job twice and the model could not write strict JSON, which is a verdict about
|
|
68
|
+
* this eval's grading, not about the suite — so it ends on the verdict path
|
|
69
|
+
* (`FINDINGS`), never on `ERROR` with `Reason: internal`. `runEvalWorker` (run-harness.ts)
|
|
70
|
+
* turns it into that eval's failing fragment (reason
|
|
71
|
+
* {@link GRADER_FRAGMENT_UNPARSEABLE}) on the treatment arm, and into a recorded
|
|
72
|
+
* control-arm failure on the other — where a fabricated `fail` would read as
|
|
73
|
+
* skill lift. `detail` is already sanitized. Carries no `reason` on purpose:
|
|
74
|
+
* `skillTestFailureReason` would read it only if this escaped, and escaping IS
|
|
75
|
+
* the bug — the worker catches it on both arms.
|
|
76
|
+
*/
|
|
77
|
+
export declare class GraderFragmentUnparseableError extends VatError {
|
|
78
|
+
readonly evalId: string;
|
|
79
|
+
readonly detail: string;
|
|
80
|
+
constructor(evalId: string, detail: string);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Run ONE eval's grader: a blind `claude -p` spawn (grader model, NO
|
|
84
|
+
* skill/plugin loaded) that reads the executor's captured transcript via its
|
|
85
|
+
* prompt and writes a nonce'd fragment JSON to `graderOutDir`.
|
|
86
|
+
* `graderOutDir` is vat-only and separate from the skill sandbox the
|
|
87
|
+
* executor ran in — the grader's `sandboxDir` --add-dir is
|
|
88
|
+
* `graderOutDir` itself, and `pluginDirs: []` means no skill code ever runs
|
|
89
|
+
* inside the grader's process, so skill code cannot forge or tamper with the
|
|
90
|
+
* fragment this run trusts.
|
|
91
|
+
*
|
|
92
|
+
* The grader is vat infrastructure, not the thing under test: unlike the
|
|
93
|
+
* executor (see eval-executor.ts), there is NO clean-failure path here. A
|
|
94
|
+
* spawn rejection, watchdog kill (`timedOut`/`stalled`), non-zero exit, or a
|
|
95
|
+
* missing fragment file all mean the grader failed to do its ONE job and are
|
|
96
|
+
* thrown as {@link InternalHarnessError} (`ERROR`, `Reason: internal`) — never laundered into a
|
|
97
|
+
* passing (or even a valid failing) verdict.
|
|
98
|
+
*
|
|
99
|
+
* A fragment that exists but is not valid JSON is the one exception, because
|
|
100
|
+
* the grader MODEL writes it: one bad escape in a free-text `evidence` took a
|
|
101
|
+
* six-eval suite down as harness-broke after five evals had graded fine. That
|
|
102
|
+
* attempt is re-run ONCE — same transcript, a FRESH nonce (so the stale file, or
|
|
103
|
+
* anything left behind, cannot satisfy the retry), the bad file consumed first,
|
|
104
|
+
* and the prompt told what went wrong. Only a second unparseable fragment
|
|
105
|
+
* surfaces, as {@link GraderFragmentUnparseableError}. Once a fragment parses,
|
|
106
|
+
* shape problems throw `EvalFragmentError` (via {@link parseEvalFragment})
|
|
107
|
+
* and a nonce that doesn't match the nonce THAT attempt was prompted with throws
|
|
108
|
+
* {@link GradingNonceError} — both fail-closed with no retry, because the grader
|
|
109
|
+
* DID produce JSON, just not JSON we can trust.
|
|
110
|
+
*/
|
|
59
111
|
export declare function runGraderForEval(input: RunGraderInput): Promise<EvalFragment>;
|
|
60
112
|
//# sourceMappingURL=eval-grader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval-grader.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-grader.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,mBAAmB,EACpB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,
|
|
1
|
+
{"version":3,"file":"eval-grader.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-grader.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2B,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAEL,mBAAmB,EACpB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOzD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uGAAuG;IACvG,mBAAmB,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACnC;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACvD;AAED,oJAAoJ;AACpJ,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AAEzE;;;;;;;;;;;;;GAaG;AACH,qBAAa,8BAA+B,SAAQ,QAAQ;aAExC,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,MAAM;gBADd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;CAQjC;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAwDnF"}
|
|
@@ -1,18 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import { mkdirSyncReal, safePath, VatError } from '@vibe-agent-toolkit/utils';
|
|
3
4
|
import { parseStreamJsonTranscript, spawnHeadlessClaude, } from '@vibe-agent-toolkit/utils/skill-test';
|
|
4
|
-
import {
|
|
5
|
-
import { InternalHarnessError } from './
|
|
5
|
+
import { parseEvalFragment } from './eval-fragment.js';
|
|
6
|
+
import { InternalHarnessError } from './failure-reason.js';
|
|
6
7
|
import { assertGraderPromptInvariants, buildGraderPrompt } from './grader-prompt.js';
|
|
7
8
|
import { sanitizeGraderText } from './grader-text.js';
|
|
8
9
|
import { GradingNonceError } from './grading-adapter.js';
|
|
9
10
|
import { computeToolPassed } from './tool-eval-schema.js';
|
|
11
|
+
/** The reason named in {@link GraderFragmentUnparseableError}'s message and in every `evidence` of the failing fragment vat synthesizes from it. */
|
|
12
|
+
export const GRADER_FRAGMENT_UNPARSEABLE = 'grader-fragment-unparseable';
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when the grader's fragment was not valid JSON on BOTH attempts (see
|
|
15
|
+
* {@link runGraderForEval}). A per-eval GRADING failure, deliberately neither
|
|
16
|
+
* {@link InternalHarnessError} nor `EvalFragmentError`: the harness did its
|
|
17
|
+
* job twice and the model could not write strict JSON, which is a verdict about
|
|
18
|
+
* this eval's grading, not about the suite — so it ends on the verdict path
|
|
19
|
+
* (`FINDINGS`), never on `ERROR` with `Reason: internal`. `runEvalWorker` (run-harness.ts)
|
|
20
|
+
* turns it into that eval's failing fragment (reason
|
|
21
|
+
* {@link GRADER_FRAGMENT_UNPARSEABLE}) on the treatment arm, and into a recorded
|
|
22
|
+
* control-arm failure on the other — where a fabricated `fail` would read as
|
|
23
|
+
* skill lift. `detail` is already sanitized. Carries no `reason` on purpose:
|
|
24
|
+
* `skillTestFailureReason` would read it only if this escaped, and escaping IS
|
|
25
|
+
* the bug — the worker catches it on both arms.
|
|
26
|
+
*/
|
|
27
|
+
export class GraderFragmentUnparseableError extends VatError {
|
|
28
|
+
evalId;
|
|
29
|
+
detail;
|
|
30
|
+
constructor(evalId, detail) {
|
|
31
|
+
super('SKILL_TEST_GRADER_FRAGMENT_UNPARSEABLE', `${GRADER_FRAGMENT_UNPARSEABLE}: the grader for eval "${evalId}" wrote a fragment that was not valid JSON ` +
|
|
32
|
+
`on either attempt (${detail}).`);
|
|
33
|
+
this.evalId = evalId;
|
|
34
|
+
this.detail = detail;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Adapt the grader's stdout `onProgress` sink into the `onWarn` callback
|
|
39
|
+
* {@link parseEvalFragment} requires (called only when it drops malformed
|
|
40
|
+
* friction items).
|
|
41
|
+
*/
|
|
42
|
+
function fragmentWarnRouter(onProgress) {
|
|
43
|
+
return (message) => onProgress(`[skill-test] ${message}\n`);
|
|
44
|
+
}
|
|
10
45
|
/**
|
|
11
46
|
* Run ONE eval's grader: a blind `claude -p` spawn (grader model, NO
|
|
12
47
|
* skill/plugin loaded) that reads the executor's captured transcript via its
|
|
13
|
-
* prompt and writes a nonce'd fragment JSON to `graderOutDir
|
|
14
|
-
*
|
|
15
|
-
* executor ran in
|
|
48
|
+
* prompt and writes a nonce'd fragment JSON to `graderOutDir`.
|
|
49
|
+
* `graderOutDir` is vat-only and separate from the skill sandbox the
|
|
50
|
+
* executor ran in — the grader's `sandboxDir` --add-dir is
|
|
16
51
|
* `graderOutDir` itself, and `pluginDirs: []` means no skill code ever runs
|
|
17
52
|
* inside the grader's process, so skill code cannot forge or tamper with the
|
|
18
53
|
* fragment this run trusts.
|
|
@@ -21,23 +56,21 @@ import { computeToolPassed } from './tool-eval-schema.js';
|
|
|
21
56
|
* executor (see eval-executor.ts), there is NO clean-failure path here. A
|
|
22
57
|
* spawn rejection, watchdog kill (`timedOut`/`stalled`), non-zero exit, or a
|
|
23
58
|
* missing fragment file all mean the grader failed to do its ONE job and are
|
|
24
|
-
* thrown as {@link InternalHarnessError} (
|
|
59
|
+
* thrown as {@link InternalHarnessError} (`ERROR`, `Reason: internal`) — never laundered into a
|
|
25
60
|
* passing (or even a valid failing) verdict.
|
|
26
61
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
62
|
+
* A fragment that exists but is not valid JSON is the one exception, because
|
|
63
|
+
* the grader MODEL writes it: one bad escape in a free-text `evidence` took a
|
|
64
|
+
* six-eval suite down as harness-broke after five evals had graded fine. That
|
|
65
|
+
* attempt is re-run ONCE — same transcript, a FRESH nonce (so the stale file, or
|
|
66
|
+
* anything left behind, cannot satisfy the retry), the bad file consumed first,
|
|
67
|
+
* and the prompt told what went wrong. Only a second unparseable fragment
|
|
68
|
+
* surfaces, as {@link GraderFragmentUnparseableError}. Once a fragment parses,
|
|
69
|
+
* shape problems throw `EvalFragmentError` (via {@link parseEvalFragment})
|
|
70
|
+
* and a nonce that doesn't match the nonce THAT attempt was prompted with throws
|
|
71
|
+
* {@link GradingNonceError} — both fail-closed with no retry, because the grader
|
|
72
|
+
* DID produce JSON, just not JSON we can trust.
|
|
32
73
|
*/
|
|
33
|
-
/**
|
|
34
|
-
* Adapt the grader's stdout `onProgress` sink into the `onWarn` callback
|
|
35
|
-
* {@link parseEvalFragment} requires (called only when it drops malformed
|
|
36
|
-
* friction items).
|
|
37
|
-
*/
|
|
38
|
-
function fragmentWarnRouter(onProgress) {
|
|
39
|
-
return (message) => onProgress(`[skill-test] ${message}\n`);
|
|
40
|
-
}
|
|
41
74
|
export async function runGraderForEval(input) {
|
|
42
75
|
// 0700, like every other vat-only directory this codebase creates (the grader
|
|
43
76
|
// root in `resolveGraderOutDir`, the workspaces root and every eval workspace in
|
|
@@ -53,17 +86,60 @@ export async function runGraderForEval(input) {
|
|
|
53
86
|
// join is safe, but `joinUnderRoot` is used defensively — it costs nothing
|
|
54
87
|
// and closes off any future path where an unvalidated id reaches here.
|
|
55
88
|
const fragmentOut = safePath.joinUnderRoot(input.graderOutDir, `${input.evalId}.json`);
|
|
56
|
-
|
|
89
|
+
let attempt = await runGraderAttempt(input, fragmentOut, input.nonce, undefined);
|
|
90
|
+
if (attempt.unparseable !== undefined) {
|
|
91
|
+
input.onProgress(`[skill-test] grader fragment for eval "${input.evalId}" was not valid JSON (${attempt.unparseable}); re-grading once.\n`);
|
|
92
|
+
// Minted here, not derived from the run nonce: the retry must accept nothing
|
|
93
|
+
// written under the first prompt.
|
|
94
|
+
attempt = await runGraderAttempt(input, fragmentOut, randomBytes(16).toString('hex'), attempt.unparseable);
|
|
95
|
+
if (attempt.unparseable !== undefined) {
|
|
96
|
+
throw new GraderFragmentUnparseableError(input.evalId, attempt.unparseable);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const fragment = parseEvalFragment(attempt.parsed, fragmentWarnRouter(input.onProgress));
|
|
100
|
+
// Integrity gate: a missing/wrong nonce means this fragment was not produced
|
|
101
|
+
// by the grader we prompted for THIS attempt — most likely forged or left
|
|
102
|
+
// behind by untrusted skill code — so the verdict cannot be trusted, hard error.
|
|
103
|
+
if (fragment.runNonce !== attempt.nonce) {
|
|
104
|
+
throw new GradingNonceError(`eval "${input.evalId}" fragment \`runNonce\` does not match this run`);
|
|
105
|
+
}
|
|
106
|
+
assertExpectationCountDeclared(input.evalId, input.expectations, fragment.expectations);
|
|
107
|
+
assertToolVerdictConsistent(input.evalId, input.toolExpectations, fragment.tool);
|
|
108
|
+
// The grader's only input is the executor transcript, which untrusted skill code
|
|
109
|
+
// controls, and `evalId` is schema-typed as any non-empty string. It is echoed
|
|
110
|
+
// verbatim into the run summary and into `baseline.json` — including the
|
|
111
|
+
// CONTAMINATED banner — so a grader talked into emitting an id containing
|
|
112
|
+
// newlines and ANSI escapes can paint a reassuring "known false positive, the
|
|
113
|
+
// delta is valid" line directly beneath vat's own warning. VAT knows which eval
|
|
114
|
+
// it asked about; take the id from the request, never from the answer.
|
|
115
|
+
//
|
|
116
|
+
// `runNonce` is re-stamped for the same reason: the merge re-verifies every
|
|
117
|
+
// fragment against the ONE nonce the run minted, and a re-graded fragment has
|
|
118
|
+
// already passed the gate above against the nonce its own prompt carried.
|
|
119
|
+
return { ...fragment, evalId: input.evalId, runNonce: input.nonce };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* ONE grader spawn under `nonce`: build and assert the prompt, spawn, apply the
|
|
123
|
+
* harness-breakage gates, report cost, consume the fragment file. `previousFailure`
|
|
124
|
+
* is the re-grade's only difference — a trailing line telling the grader what its
|
|
125
|
+
* first fragment got wrong (sanitized where it was caught, at the bottom of this
|
|
126
|
+
* function). Required, not defaulted, so both call sites say which attempt they are.
|
|
127
|
+
*/
|
|
128
|
+
async function runGraderAttempt(input, fragmentOut, nonce, previousFailure) {
|
|
129
|
+
const built = buildGraderPrompt({
|
|
57
130
|
evalId: input.evalId,
|
|
58
131
|
transcript: input.transcript,
|
|
59
132
|
expectations: input.expectations,
|
|
60
133
|
...(input.expectedOutput === undefined ? {} : { expectedOutput: input.expectedOutput }),
|
|
61
134
|
rubricPath: input.rubricPath,
|
|
62
135
|
fragmentOut,
|
|
63
|
-
nonce
|
|
136
|
+
nonce,
|
|
64
137
|
...(input.toolExpectations === undefined ? {} : { toolExpectations: input.toolExpectations }),
|
|
65
138
|
...(input.declaredExecutables === undefined ? {} : { declaredExecutables: input.declaredExecutables }),
|
|
66
139
|
});
|
|
140
|
+
const prompt = previousFailure === undefined
|
|
141
|
+
? built
|
|
142
|
+
: `${built}\n\nYour previous fragment was not valid JSON: ${previousFailure}. Write strict JSON.`;
|
|
67
143
|
// Defense-in-depth (parity with eval-executor.ts's build→assert→use pattern):
|
|
68
144
|
// re-verify the built grader prompt still carries its required invariants
|
|
69
145
|
// (STOP, fragment path, browser/iteration forbids, nonce directive, and the
|
|
@@ -73,7 +149,7 @@ export async function runGraderForEval(input) {
|
|
|
73
149
|
// manifest, and the suite's own expectations/expected_output — and none of
|
|
74
150
|
// that attacker-controlled text can satisfy an invariant on the builder's
|
|
75
151
|
// behalf.
|
|
76
|
-
assertGraderPromptInvariants(prompt,
|
|
152
|
+
assertGraderPromptInvariants(prompt, nonce);
|
|
77
153
|
const spawn = input.spawn ?? spawnHeadlessClaude;
|
|
78
154
|
// Accumulate the grader's stream-json stdout so we can read its terminal
|
|
79
155
|
// `total_cost_usd` for run-wide spend aggregation (adopter follow-up). Held in
|
|
@@ -121,70 +197,59 @@ export async function runGraderForEval(input) {
|
|
|
121
197
|
// the in-memory transcript (not the fragment) so it reflects real API spend even
|
|
122
198
|
// under subscription auth; `undefined` when the transcript carried no result.
|
|
123
199
|
input.costSink?.(parseStreamJsonTranscript(graderTranscript).result?.totalCostUsd);
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
200
|
+
const warn = fragmentWarnRouter(input.onProgress);
|
|
201
|
+
const text = readAndConsumeFragmentFile(fragmentOut, input.evalId, spawnResult.status, warn);
|
|
202
|
+
try {
|
|
203
|
+
return { nonce, parsed: JSON.parse(text) };
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
if (!(err instanceof SyntaxError))
|
|
207
|
+
throw err;
|
|
208
|
+
// V8 embeds a VERBATIM slice of the offending bytes in its SyntaxError
|
|
209
|
+
// message, unescaped — and this is one of the few grader-controlled strings
|
|
210
|
+
// that reaches an operator WITHOUT passing `parseEvalFragment`, the
|
|
211
|
+
// documented text boundary, because the parse it would have gone through is
|
|
212
|
+
// the one that just failed. It lands in a thrown message (which the CLI writes
|
|
213
|
+
// as `Error: ${err.message}`, so an unsanitized `ESC[2K CR ESC[32m…` wipes the
|
|
214
|
+
// line vat just printed and continues in vat's own colour) AND in the re-grade
|
|
215
|
+
// prompt.
|
|
216
|
+
return { nonce, unparseable: sanitizeGraderText(err.message) };
|
|
131
217
|
}
|
|
132
|
-
assertExpectationCountDeclared(input.evalId, input.expectations, fragment.expectations);
|
|
133
|
-
assertToolVerdictConsistent(input.evalId, input.toolExpectations, fragment.tool);
|
|
134
|
-
// The grader's only input is the executor transcript, which untrusted skill code
|
|
135
|
-
// controls, and `evalId` is schema-typed as any non-empty string. It is echoed
|
|
136
|
-
// verbatim into the run summary and into `baseline.json` — including the
|
|
137
|
-
// CONTAMINATED banner — so a grader talked into emitting an id containing
|
|
138
|
-
// newlines and ANSI escapes can paint a reassuring "known false positive, the
|
|
139
|
-
// delta is valid" line directly beneath vat's own warning. VAT knows which eval
|
|
140
|
-
// it asked about; take the id from the request, never from the answer.
|
|
141
|
-
return { ...fragment, evalId: input.evalId };
|
|
142
218
|
}
|
|
143
219
|
/**
|
|
144
|
-
* Read the grader's fragment
|
|
145
|
-
* consume-on-read
|
|
146
|
-
*
|
|
147
|
-
* wrote no fragment, {@link EvalFragmentError} if it is not valid JSON.
|
|
220
|
+
* Read the grader's fragment file into memory and remove it immediately —
|
|
221
|
+
* consume-on-read, whether or not it will parse. Throws {@link InternalHarnessError}
|
|
222
|
+
* if the grader wrote no fragment.
|
|
148
223
|
*
|
|
149
|
-
* The
|
|
224
|
+
* The removal is the security-relevant half: the grader dir is same-uid (see
|
|
150
225
|
* `resolveGraderOutDir`), so a fragment left on disk lets skill code that
|
|
151
226
|
* survived the process-group kill read the echoed nonce at leisure and forge
|
|
152
227
|
* LATER fragments. Consuming it on read leaves no persisted copy — exposure
|
|
153
|
-
* shrinks to each fragment's own read window (no cross-eval harvest).
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
228
|
+
* shrinks to each fragment's own read window (no cross-eval harvest). It is also
|
|
229
|
+
* what makes the re-grade honest: a retry that writes nothing finds no file, not
|
|
230
|
+
* the unparseable one. The read here is the ONLY read of the file; all downstream
|
|
231
|
+
* logic runs off the returned text. A failed removal is not a run failure
|
|
232
|
+
* (end-of-run cleanup removes the whole dir) but it IS the one degradation this
|
|
233
|
+
* design exists to prevent, so it is reported through `onWarn` rather than
|
|
234
|
+
* swallowed: the operator learns the fragment lingered, with the errno. True
|
|
235
|
+
* isolation from same-uid code is a separate, unbuilt mechanism (a different uid
|
|
236
|
+
* or a sandbox), not this removal.
|
|
157
237
|
*/
|
|
158
|
-
function readAndConsumeFragmentFile(fragmentOut, evalId, status) {
|
|
159
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- fragmentOut is our own derived path (joinUnderRoot-guarded)
|
|
238
|
+
function readAndConsumeFragmentFile(fragmentOut, evalId, status, onWarn) {
|
|
160
239
|
if (!existsSync(fragmentOut)) {
|
|
161
240
|
throw new InternalHarnessError(`Grader exited (status ${status}) without writing a fragment at ${fragmentOut} for eval "${evalId}".`);
|
|
162
241
|
}
|
|
163
|
-
|
|
242
|
+
const text = readFileSync(fragmentOut, 'utf-8');
|
|
164
243
|
try {
|
|
165
|
-
//
|
|
166
|
-
|
|
244
|
+
// `force` covers the one benign case — the file is already gone — so what the
|
|
245
|
+
// catch sees is a refusal (EACCES/EPERM/EBUSY), never an absence.
|
|
246
|
+
rmSync(fragmentOut, { force: true });
|
|
167
247
|
}
|
|
168
248
|
catch (err) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
// that reaches an operator WITHOUT passing `parseEvalFragment`, the
|
|
172
|
-
// documented text boundary, because the parse it would have gone through is
|
|
173
|
-
// the one that just failed. The CLI writes it as `Error: ${err.message}`, so
|
|
174
|
-
// an unsanitized fragment of `ESC[2K CR ESC[32m…` wipes the line vat just
|
|
175
|
-
// printed and continues in vat's own colour (and a <=16-byte file gets its
|
|
176
|
-
// whole `ESC[2J ESC[H` echoed, clearing the screen).
|
|
177
|
-
throw new EvalFragmentError(`grader fragment for eval "${evalId}" at ${fragmentOut} is not valid JSON: ` +
|
|
178
|
-
sanitizeGraderText(err instanceof Error ? err.message : String(err)));
|
|
179
|
-
}
|
|
180
|
-
try {
|
|
181
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename -- fragmentOut is our own derived path (joinUnderRoot-guarded)
|
|
182
|
-
unlinkSync(fragmentOut);
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
// Swallow: cleanup removes the grader dir regardless.
|
|
249
|
+
onWarn(`grader fragment for eval "${evalId}" at ${fragmentOut} could not be removed after it was read ` +
|
|
250
|
+
`(${err instanceof Error ? err.message : String(err)}); it stays on disk until end-of-run cleanup.`);
|
|
186
251
|
}
|
|
187
|
-
return
|
|
252
|
+
return text;
|
|
188
253
|
}
|
|
189
254
|
/**
|
|
190
255
|
* The OUTPUT channel's declared-vs-reported check — the exact thing
|