@eigenpal/cli 0.4.9 → 0.4.11

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.
@@ -26,7 +26,7 @@ init
26
26
  | Command | Description |
27
27
  | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28
28
  | `eigenpal init workflow [options] <name>` | Alias of `eigenpal init <name>`. Kept so the `init {workflow,agent}` namespace stays visible — once the agent surface lights up, both kinds will live as siblings here. |
29
- | `eigenpal init agent [options] <name>` | Scaffold a new agent (agentic process) project — coming soon. The namespace is reserved so the workflow / agent split is visible from day one. |
29
+ | `eigenpal init agent [options] <name>` | Scaffold a new agent project — coming soon. Use `eigenpal agent push` with an existing agent project for now. |
30
30
 
31
31
  ## Details
32
32
 
@@ -50,7 +50,7 @@ Alias of `eigenpal init <name>`. Kept so the `init {workflow,agent}` namespace s
50
50
 
51
51
  ### `eigenpal init agent [options] <name>`
52
52
 
53
- Scaffold a new agent (agentic process) project — coming soon. The namespace is reserved so the workflow / agent split is visible from day one.
53
+ Scaffold a new agent project — coming soon. Use `eigenpal agent push` with an existing agent project for now.
54
54
 
55
55
  ### Arguments
56
56
 
@@ -11,16 +11,41 @@ this is the agent-facing summary.
11
11
  ```yaml
12
12
  evaluators: # array of evaluator definitions, ≥1 entry
13
13
  - name: ... # required, unique within this file, [a-z0-9][a-z0-9-_]*
14
+ description: ... # optional, ≤500 chars; one-sentence business explanation (see below)
14
15
  type: ... # required, one of: exact-diff | llm-judge | custom-script
15
16
  config: # required, shape depends on `type`
16
17
  passThreshold: 0.95 # 0..1, optional (default 1.0)
17
18
  ...
18
19
 
19
- # OPTIONAL global config
20
- concurrency: 4 # max examples in parallel during `experiment run` (default 1)
21
- judge: # optional shared model defaults for llm-judge evaluators
22
- model: gpt-4o
23
- temperature: 0
20
+ # OPTIONAL workflow-level pass threshold. A run passes when its weighted-mean
21
+ # score across evaluators clears this number. Defaults to 0.7.
22
+ passThreshold: 0.7
23
+ ```
24
+
25
+ ## Writing descriptions for stakeholders
26
+
27
+ Every evaluator entry takes an optional `description`. Always set it. The
28
+ dashboard surfaces this string to non-technical reviewers (legal, ops,
29
+ finance) who never see the YAML or the judge prompt. Write it for them:
30
+
31
+ - One short sentence, plain language.
32
+ - Name what the evaluator measures and why a business reader should care.
33
+ - Skip implementation detail (model names, thresholds, dot-paths). Those
34
+ belong in `config`.
35
+ - Keep it under ~120 characters when you can; the schema caps it at 500.
36
+
37
+ ```yaml
38
+ # Good. A non-technical reviewer immediately grasps the intent.
39
+ - name: covenants-recall
40
+ description: Checks every covenant from the contract appears in the extraction.
41
+ type: llm-judge
42
+ config: ...
43
+
44
+ # Bad. Restates the config; teaches a stakeholder nothing.
45
+ - name: covenants-recall
46
+ description: llm-judge with passThreshold 0.85 over the covenants array.
47
+ type: llm-judge
48
+ config: ...
24
49
  ```
25
50
 
26
51
  ## Evaluator types
@@ -47,23 +72,34 @@ judge: # optional shared model defaults for llm-judge evaluators
47
72
  - name: covenants-recall
48
73
  type: llm-judge
49
74
  config:
50
- model: gpt-4o # string — the OpenAI model id
51
- temperature: 0 # number — for reproducibility
75
+ model: gpt-4o # OPTIONAL — falls back to the workspace default LLM provider
76
+ mode: continuous # continuous | discrete (default: continuous)
52
77
  passThreshold: 0.85
53
- prompt: |
78
+ docLabel: extraction # what the judge calls the workflow output (default: "output")
79
+ promptExtension: |
54
80
  Score how well the actual output captures every covenant in the
55
- expected output, on a scale of 0..1. Penalise missing covenants;
56
- do not penalise over-extraction. Return JSON { score, rationale }.
57
- ```
81
+ expected output. Penalise missing covenants; do not penalise
82
+ over-extraction. Be strict on covenants that change loan economics.
58
83
 
59
- The harness wraps your `prompt` and feeds:
60
-
61
- - `actual` — the workflow's output
62
- - `expected` — the example's `expected/output.json`
63
- - `meta` — example metadata
84
+ # discrete mode — the judge picks a label and the score table maps to a number
85
+ - name: tone-check
86
+ type: llm-judge
87
+ config:
88
+ mode: discrete
89
+ passThreshold: 0.7
90
+ labels:
91
+ excellent: 1.0
92
+ acceptable: 0.7
93
+ off-tone: 0.0
94
+ promptExtension: |
95
+ Pick the label that best matches the tone of the response.
96
+ ```
64
97
 
65
- It expects the model to return JSON with at least `score` (0..1) and
66
- `rationale` (string). The fixed harness handles parse failures + retries.
98
+ `promptExtension` is the only required field — it's appended to the harness
99
+ prompt and tells the judge what "good" looks like for this workflow. The
100
+ harness handles JSON parsing, retries, and feeds the judge `actual`,
101
+ `expected`, and example metadata. In `discrete` mode the judge MUST return
102
+ one of the keys in `labels`; the harness then looks up the score.
67
103
 
68
104
  ### `custom-script` — JavaScript in the sandbox
69
105
 
@@ -72,16 +108,38 @@ It expects the model to return JSON with at least `score` (0..1) and
72
108
  type: custom-script
73
109
  config:
74
110
  passThreshold: 1.0
75
- code: |
76
- const a = actual.totalAmount ?? 0;
77
- const e = expected.totalAmount ?? 0;
78
- const score = Math.abs(a - e) <= 0.01 ? 1 : 0;
79
- return { score, rationale: `actual=${a}, expected=${e}` };
111
+ function: |
112
+ /**
113
+ * @param {Expected} expected the example's expected output
114
+ * @param {Actual} actual the workflow's actual output
115
+ * @returns {number} a score in [0, 1]; throws are caught and scored as 0
116
+ */
117
+ function scoreScript(expected, actual) {
118
+ const a = actual.totalAmount ?? 0;
119
+ const e = expected.totalAmount ?? 0;
120
+ return Math.abs(a - e) <= 0.01 ? 1 : 0;
121
+ }
80
122
  ```
81
123
 
82
124
  Same WASM sandbox as `transform.script` (5s wall clock, 10 MB heap, no
83
- network). Receives `actual`, `expected`, `meta` in scope. Returns
84
- `{ score: number, label?: string, rationale?: string }`.
125
+ network). The YAML stores the **whole** `function scoreScript(expected,
126
+ actual) { ... }` declaration verbatim — same text the dashboard editor
127
+ shows. The JSDoc preamble is optional but recommended: it pulls the
128
+ workflow's output schema into IntelliSense for `expected.…` /
129
+ `actual.…` in the dashboard.
130
+
131
+ The signature shape is **locked**:
132
+
133
+ - Function name MUST be `scoreScript`.
134
+ - Parameters MUST be `(expected, actual)` in that order. Swapping them
135
+ would silently invert every score.
136
+ - Body MUST `return` a number in `[0, 1]`, or `throw` (which is caught
137
+ and scored as 0).
138
+
139
+ `workflow validate` and `workflow evaluators validate` flag YAML where
140
+ the function fails to parse, the signature doesn't match, or the body
141
+ contains neither `return` nor `throw` — so a hand-edited config errors
142
+ before it reaches the worker.
85
143
 
86
144
  ## Pass / fail vs score
87
145
 
@@ -160,9 +218,11 @@ process — `--out` writes the file directly from the server's storage.
160
218
  LLM-judge scores have variance. To reduce flake:
161
219
 
162
220
  - Pin a specific model id (`gpt-4o-2024-08-06` rather than `gpt-4o`).
163
- - Set `temperature: 0`.
164
- - Keep the prompt narrow — score one dimension per evaluator. Use
221
+ - Keep `promptExtension` narrow — score one dimension per evaluator. Use
165
222
  multiple judges instead of one omnibus prompt.
223
+ - Prefer `mode: discrete` with a small label set when the judgement is
224
+ categorical (good / acceptable / bad) — it eliminates the model's
225
+ free-form numeric drift.
166
226
  - For high-stakes thresholds, run the experiment ≥3 times and average.
167
227
 
168
228
  <!-- GENERATED:EVALUATOR_CATALOG START -->
@@ -177,6 +237,14 @@ _Generated from `EvalConfigYamlSchema` in `@eigenpal/types/src/eval/evaluator-co
177
237
  | `evaluators` | array<object> | no | `[]` | |
178
238
  | `passThreshold` | number | no | `0.7` | |
179
239
 
240
+ ### Common entry fields (every evaluator type)
241
+
242
+ | Field | Type | Required | Default | Description |
243
+ | --- | --- | --- | --- | --- |
244
+ | `name` | string | yes | | Identifier used in eval results and the weighted-mean formula. Use a short kebab-case slug like header-exact or covenants-recall. |
245
+ | `description` | string | no | | One-sentence explanation, in business language, of what this evaluator measures and why a stakeholder should care. Shown in the dashboard to non-technical reviewers (legal, ops, finance) who never see the YAML or judge prompt. Skip implementation detail (model names, thresholds, dot-paths); those live in `config`. |
246
+ | `weight` | number | no | `1` | Relative importance in the weighted mean. The overall score is Σ(weightᵢ × scoreᵢ) / Σweight. Set to 0 to score-only without affecting overall. |
247
+
180
248
  ### `exact-diff` — JSON deep-diff against expected output
181
249
 
182
250
  | Field | Type | Required | Default | Description |
@@ -203,7 +271,7 @@ _Generated from `EvalConfigYamlSchema` in `@eigenpal/types/src/eval/evaluator-co
203
271
 
204
272
  | Field | Type | Required | Default | Description |
205
273
  | --- | --- | --- | --- | --- |
206
- | `code` | string | yes | | Sandboxed JavaScript. Receives `actual`, `expected`, `input` as variables and must return { score, label? } where score is in [0, 1]. |
274
+ | `function` | string | yes | | Full JavaScript declaration of `function scoreScript(expected, actual) { ... }`. Receives `expected` (the example's expected output) and `actual` (the workflow's actual output), returns a number in [0, 1]. Throws are caught and scored as 0. |
207
275
  | `timeoutMs` | integer | no | `5000` | Maximum wall-clock time the script can run before it's killed and the run is marked failed. |
208
276
  | `memoryLimitMb` | integer | no | `10` | Maximum memory the sandbox may allocate. Increase if the script processes large arrays or strings. |
209
277
  | `passThreshold` | number | no | `1` | Minimum script score this evaluator must reach for a run to pass. |
@@ -70,21 +70,10 @@ the catalog tells you what fields it takes.
70
70
  - Real JS — `Array.prototype.reduce`, `JSON.parse`, etc.
71
71
  - Sandbox limits prevent infinite loops from blowing up an execution
72
72
 
73
- > **Common gotcha — TDZ on shadowed input names.** Each entry in `inputs`
74
- > becomes a top-level `const` binding inside your script. Re-declaring the
75
- > same name in the body shadows the binding and triggers a `ReferenceError:
76
- > Cannot access 'X' before initialization` (Temporal Dead Zone). For example:
77
- >
78
- > ```js
79
- > // ✗ TDZ — `located` is the input AND the inner const
80
- > const located = located || [];
81
- >
82
- > // ✓ Rename the inner variable
83
- > const safeLocated = located ?? [];
84
- > ```
85
- >
86
- > If you need a default, use `??` / `||` against the binding directly without
87
- > redeclaring, or rename the local. The same applies to `let` redeclarations.
73
+ > Each entry in `inputs:` becomes a parameter of `function script(...)`
74
+ > in declaration order. `inputs: { items, taxRate }` ⇒
75
+ > `function script(items, taxRate) { … }`. The function must `return`
76
+ > (or `throw`) a value.
88
77
 
89
78
  ## Reference / output paths
90
79
 
@@ -329,14 +318,14 @@ Convert XLSX spreadsheet to JSON array of row objects for use in scripts or down
329
318
 
330
319
  #### `transform.script` — Script
331
320
 
332
- Execute JavaScript code in a secure sandbox. Input keys become TOP-LEVEL variables (use "items" not "inputs.items"). Must return a value.
321
+ Execute a JavaScript function in a QuickJS sandbox. Input keys become the function's parameter list, in declaration order: `inputs: { items, taxRate }` ⇒ `function script(items, taxRate) { … }`. Must `return` (or `throw`) a value.
333
322
 
334
323
  **Config** (in `step.with`):
335
324
 
336
325
  | Field | Type | Required | Default | Description |
337
326
  | --- | --- | --- | --- | --- |
338
- | `inputs` | record<string, string> | no | | Named inputs mapped from template expressions. IMPORTANT: Keys become TOP-LEVEL variables in code (e.g., if key is "items", use "items" not "inputs.items"). |
339
- | `code` | string | yes | | JavaScript code. Input keys are available as top-level variables (NOT as inputs.key). Must return a value. |
327
+ | `inputs` | record<string, string> | no | | Named inputs mapped from template expressions. Keys become the function parameter list in declaration order: `inputs: { items, taxRate }` ⇒ `function script(items, taxRate) { … }`. |
328
+ | `function` | string | no | | JavaScript function declaration. Must be `function script(arg1, arg2, …) { … }` where the parameter list equals `Object.keys(inputs)` in declaration order. Must `return` (or `throw`) a value. |
340
329
  | `outputSchema` | record<string, unknown> | no | | JSON Schema describing the expected return value. Used for validation and type hints. |
341
330
  | `timeout` | number | no | `5000` | Max execution time in milliseconds (default: 5000) |
342
331
  | `memoryLimit` | number | no | `10485760` | Max memory in bytes (default: 10MB) |
@@ -158,10 +158,12 @@ arithmetic, regex) goes in `transform.script`:
158
158
  inputs: # explicit data deps — visible to the validator
159
159
  lineItems: '{{ steps.extract.output.lineItems }}'
160
160
  taxRate: '{{ input.taxRate }}'
161
- code: |
162
- const subtotal = lineItems.reduce((s, i) => s + i.price * i.qty, 0);
163
- const tax = subtotal * taxRate;
164
- return { subtotal, tax, total: subtotal + tax };
161
+ function: |
162
+ function script(lineItems, taxRate) {
163
+ const subtotal = lineItems.reduce((s, i) => s + i.price * i.qty, 0);
164
+ const tax = subtotal * taxRate;
165
+ return { subtotal, tax, total: subtotal + tax };
166
+ }
165
167
  outputSchema: # optional but recommended — runtime-validated
166
168
  type: object
167
169
  properties:
@@ -25,8 +25,10 @@ steps:
25
25
  with:
26
26
  inputs:
27
27
  text: '{{ input.text }}'
28
- code: |
29
- return { length: text.length, original: text };
28
+ function: |
29
+ function script(text) {
30
+ return { length: text.length, original: text };
31
+ }
30
32
  outputSchema:
31
33
  type: object
32
34
  properties:
@@ -1,5 +1,6 @@
1
1
  evaluators:
2
2
  - name: exact-match
3
+ description: Checks the extracted fields match the expected output exactly.
3
4
  type: exact-diff
4
5
  config:
5
6
  passThreshold: 1.0
@@ -1,5 +1,6 @@
1
1
  evaluators:
2
2
  - name: label-match
3
+ description: Checks the predicted label matches the expected label.
3
4
  type: exact-diff
4
5
  config:
5
6
  passThreshold: 1.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eigenpal/cli",
3
- "version": "0.4.9",
3
+ "version": "0.4.11",
4
4
  "description": "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
5
5
  "keywords": [
6
6
  "eigenpal",