@catheadowl/dsh-eval 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.mjs CHANGED
@@ -1,49 +1,34 @@
1
- /**
2
- * @catheadowl/dsh-eval public surface — what plugin eval cases import:
3
- * matchers for the `expect` list and mock-script step builders. The runner
4
- * and trace parser are bin/runner internals, also exported for ad-hoc use.
5
- */
6
-
7
- export {
8
- toolCalled,
9
- toolNotCalled,
10
- firstTool,
11
- toolSequence,
12
- toolCallArgs,
13
- toolResultFor,
14
- toolResultIsError,
15
- toolResultSucceeded,
16
- toolResultTextIncludes,
17
- finalTextIncludes,
18
- finalTextMatches,
19
- assistantTextIncludes,
20
- systemPromptIncludes,
21
- toolMounted,
22
- userMessageTextIncludes,
23
- userMessageTextExcludes,
24
- } from './assertions.mjs'
25
-
26
- export { toolCallStep, textStep } from './mock/script.mjs'
27
-
28
- export { runEvalCase, buildOverlayYaml, looksLikeDshRepo, stageProfileStore, FRAMEWORK_ROOT } from './runner.mjs'
29
-
30
- export { parseSessionLog, buildTrace, loadTraceDir } from './trace.mjs'
31
-
32
- export {
33
- defineReviewExperiment,
34
- executeReviewExperiment,
35
- materializeReviewExperiment,
36
- renderObservationSections,
37
- OBSERVATIONS_PLACEHOLDER,
38
- } from './experiment/review.mjs'
39
-
40
- export {
41
- createDshHeadlessReviewExecutor,
42
- resolveDshCli,
43
- runDshReviewExperiment,
44
- } from './adapters/dsh/review.mjs'
45
-
46
- export {
47
- validateToolBoundary,
48
- renderToolBoundaryEvidence,
49
- } from './tool-validation.mjs'
1
+ /**
2
+ * @catheadowl/dsh-eval stable SDK surface — what eval/review case authors
3
+ * import: assertion matchers, mock-script step builders, the review
4
+ * experiment DSL, and the programmatic case runner.
5
+ *
6
+ * Mechanism primitives (sandbox/overlay/trace, review executors, CLI chain)
7
+ * live behind the `./experimental` subpath with no compatibility promise;
8
+ * everything else is bin-internal.
9
+ */
10
+
11
+ export {
12
+ toolCalled,
13
+ toolNotCalled,
14
+ firstTool,
15
+ toolSequence,
16
+ toolCallArgs,
17
+ toolResultFor,
18
+ toolResultIsError,
19
+ toolResultSucceeded,
20
+ toolResultTextIncludes,
21
+ finalTextIncludes,
22
+ finalTextMatches,
23
+ assistantTextIncludes,
24
+ systemPromptIncludes,
25
+ toolMounted,
26
+ userMessageTextIncludes,
27
+ userMessageTextExcludes,
28
+ } from './assertions.mjs'
29
+
30
+ export { toolCallStep, textStep } from './mock/script.mjs'
31
+
32
+ export { runEvalCase } from './runner.mjs'
33
+
34
+ export { defineReviewExperiment } from './experiment/review.mjs'
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Overlay (cordis patch) serialization — the ONLY hand-rolled YAML emitter
3
+ * in the package. Both the behavior runner (buildOverlayYaml) and the dsh
4
+ * review adapter (overlayDisableRows for its tool-less overlay) generate
5
+ * per-run overlay files; sharing one emitter keeps quoting rules and
6
+ * row-patch syntax (`- id: <row>` / `disabled: true`) identical everywhere.
7
+ *
8
+ * YAML strategy: JSON double-quoted strings are valid YAML scalars, so the
9
+ * emitters lean on JSON.stringify — zero dependencies, identical quoting
10
+ * across scalar and array leaves.
11
+ */
12
+
13
+ import { join } from 'node:path'
14
+ import { fileURLToPath, pathToFileURL } from 'node:url'
15
+
16
+ /** This framework's root directory (the eval package dir). */
17
+ const FRAMEWORK_ROOT = fileURLToPath(new URL('..', import.meta.url))
18
+
19
+ /** The scripted mock adapter plugin, referenced from generated overlays. */
20
+ const MOCK_ADAPTER_PATH = join(FRAMEWORK_ROOT, 'src', 'mock', 'mock-adapter.mjs')
21
+
22
+ /** JSON double-quoted strings are valid YAML scalars — enough for this emitter. */
23
+ function yamlScalar(value) {
24
+ if (typeof value === 'boolean' || typeof value === 'number') return String(value)
25
+ return JSON.stringify(String(value))
26
+ }
27
+
28
+ /**
29
+ * One rowConfig leaf: a scalar, or an array of scalars emitted as a YAML flow
30
+ * sequence (a JSON array is valid YAML flow syntax, and keeps quoting rules
31
+ * identical to `yamlScalar`).
32
+ */
33
+ function yamlConfigValue(value) {
34
+ if (Array.isArray(value)) return JSON.stringify(value.map(item => typeof item === 'string' ? item : String(item)))
35
+ return yamlScalar(value)
36
+ }
37
+
38
+ /**
39
+ * Serialize `- id: <row> / disabled: true` patches for every row id — the
40
+ * cross-layer row-disable mechanism shared by case `disableRows` and the
41
+ * review adapter's host-tool lockdown.
42
+ * @param {string[]} rowIds - loader row ids to disable.
43
+ * @returns {string} overlay entries (each line-terminated).
44
+ */
45
+ export function overlayDisableRows(rowIds) {
46
+ return rowIds.map(rowId => `- id: ${yamlScalar(rowId)}\n disabled: true\n`).join('')
47
+ }
48
+
49
+ /**
50
+ * Serialize the per-run overlay patch list for one eval case.
51
+ * @param {object} parts - overlay ingredients (see runEvalCase):
52
+ * `sessionsRoot` (required), optional `persona`, `disableRows`,
53
+ * `rowConfig`, and `mock` (mount the scripted adapter + re-point the
54
+ * default model).
55
+ * @returns {string} the overlay file text.
56
+ */
57
+ export function buildOverlayYaml(parts) {
58
+ const lines = []
59
+ lines.push('- id: session-persistence-jsonl')
60
+ lines.push(' config:')
61
+ lines.push(` root: ${yamlScalar(parts.sessionsRoot)}`)
62
+ lines.push(' packChunks: false')
63
+ lines.push(' compression: none')
64
+ if (parts.persona !== undefined) {
65
+ lines.push('- id: system-prompt')
66
+ lines.push(' config:')
67
+ lines.push(` persona: ${yamlScalar(parts.persona)}`)
68
+ }
69
+ if (parts.disableRows !== undefined && parts.disableRows.length > 0) {
70
+ lines.push(overlayDisableRows(parts.disableRows).trimEnd())
71
+ }
72
+ for (const [rowId, config] of Object.entries(parts.rowConfig ?? {})) {
73
+ // Whole-replace semantics: these config keys REPLACE the row's config
74
+ // (cordis patch layer), so the emitter adds to a fresh `- id:` entry —
75
+ // restating keys is the declaring case's responsibility.
76
+ lines.push(`- id: ${yamlScalar(rowId)}`)
77
+ lines.push(' config:')
78
+ for (const [key, value] of Object.entries(config)) {
79
+ lines.push(` ${key}: ${yamlConfigValue(value)}`)
80
+ }
81
+ }
82
+ if (parts.mock) {
83
+ lines.push('- id: agent-default-model')
84
+ lines.push(' config:')
85
+ lines.push(' provider: eval-mock')
86
+ lines.push(' model: eval-mock')
87
+ // The title generator also calls the default provider and would consume
88
+ // script steps; deterministic runs own every model call themselves.
89
+ lines.push('- id: session-title-llm')
90
+ lines.push(' disabled: true')
91
+ lines.push('- insert:')
92
+ lines.push(' - id: eval-mock-llm')
93
+ lines.push(` name: ${yamlScalar(pathToFileURL(MOCK_ADAPTER_PATH).href)}`)
94
+ }
95
+ return `${lines.join('\n')}\n`
96
+ }
package/src/report.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Machine-readable run reports for the behavior CLI (EVAL-007).
2
+ * Machine-readable run reports for the behavior CLI.
3
3
  *
4
4
  * One report covers ONE `dsh-eval run` invocation: the selection summary,
5
5
  * per-case outcomes, and the invocation's environment anchors (profile /