evals-lab 0.13.0 → 0.14.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +2 -2
  3. package/bin/run.js +4 -2
  4. package/lab/VERSION +1 -1
  5. package/lab/demo/CREDITS.md +14 -0
  6. package/lab/demo/datasets/demo-1.json +2 -2
  7. package/lab/demo/datasets/demo-2.json +2 -2
  8. package/lab/demo/datasets/documents-type.json +79 -0
  9. package/lab/demo/datasets/documents-valid.json +117 -0
  10. package/lab/demo/datasets/sentiment.json +2 -2
  11. package/lab/demo/datasets/weather-alerts.json +2 -2
  12. package/lab/demo/datasets/wordings.json +1 -1
  13. package/lab/demo/manifest.json +3 -3
  14. package/lab/demo/pipelines/demo-1.json +4 -4
  15. package/lab/demo/pipelines/demo-2.json +4 -4
  16. package/lab/demo/pipelines/documents.json +102 -0
  17. package/lab/demo/pipelines/sentiment.json +4 -4
  18. package/lab/demo/pipelines/weather-alerts.json +9 -5
  19. package/lab/demo/pipelines/wordings.json +3 -3
  20. package/lab/demo/sources/Demo 1/source.json +1 -1
  21. package/lab/demo/sources/Demo 2/source.json +1 -1
  22. package/lab/demo/sources/documents/invoice.pdf +65 -0
  23. package/lab/demo/sources/documents/letter.pdf +63 -0
  24. package/lab/demo/sources/documents/not-a-pdf.pdf +2 -0
  25. package/lab/demo/sources/documents/receipt.pdf +62 -0
  26. package/lab/demo/sources/documents/report.pdf +59 -0
  27. package/lab/demo/sources/documents/source.json +3 -0
  28. package/lab/demo/sources/documents/truncated.pdf +19 -0
  29. package/lab/demo/sources/sentiment/source.json +1 -1
  30. package/lab/demo/sources/weather-alerts/source.json +1 -1
  31. package/lab/evals-core.mjs +217 -48
  32. package/lab/flows/record.mjs +5 -4
  33. package/lab/kinds/list.mjs +72 -21
  34. package/lab/run-evals.js +3 -1
  35. package/lab/server.py +536 -85
  36. package/lab/web/dist/assets/gallery-qrf0ZGXK.js +5 -0
  37. package/lab/web/dist/assets/main-D6xARg2A.js +16 -0
  38. package/lab/web/dist/assets/main-xVU6J7Gi.css +1 -0
  39. package/lab/web/dist/assets/tokens-C8dqXDHN.js +62 -0
  40. package/lab/web/dist/assets/tokens-tQ7zTPkd.css +1 -0
  41. package/lab/web/dist/gallery.html +3 -3
  42. package/lab/web/dist/index.html +4 -4
  43. package/package.json +1 -1
  44. package/lab/web/dist/assets/gallery-DpaqOg9Z.js +0 -5
  45. package/lab/web/dist/assets/main-BSw-jyYD.css +0 -1
  46. package/lab/web/dist/assets/main-CrB8wPZn.js +0 -17
  47. package/lab/web/dist/assets/tokens-CrjDMCbz.js +0 -60
  48. package/lab/web/dist/assets/tokens-DDOONQon.css +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,45 @@ Newest first. Read a release's **Upgrade notes** before installing it: an
5
5
  upgrade can rewrite what the lab keeps in your data directory, and an older
6
6
  version cannot always read it back.
7
7
 
8
+ ## 0.14.0
9
+
10
+ ### Upgrade notes
11
+
12
+ - **Copy your data directory before upgrading** (see "User data" in the
13
+ README). A pipeline 0.14.0 saves is pipeline version 18, which 0.13.x
14
+ cannot read. To go back, reinstall 0.13.0 and restore the copy.
15
+ - A job that graded a dynamic Source's saved content now grades one saved
16
+ response: on upgrade it is pinned to the Source's newest successful one.
17
+ Live data is unchanged. To grade several responses, clone the job.
18
+
19
+ ### Added
20
+
21
+ - An endpoint or call keeps its responses: Fetch now, an import or an edit
22
+ adds one, and Restore brings an earlier one back.
23
+ - A Source page lists Responses and History, and Saved response pins the
24
+ one response a job grades.
25
+ - Results show one block per eval group, export as JSON or PDF, say when a
26
+ reply was cut off, and show where content goes in the prompt.
27
+ - Post-format filters for a text reply, and more Rewrite text operations.
28
+ - A sixth demo: sort documents, with valid and invalid PDFs.
29
+ - The (Default) Connection Profile can be edited and applies to (Any)
30
+ connection.
31
+ - History filters by pipeline and content.
32
+
33
+ ### Changed
34
+
35
+ - A dialog says Close until something in it changes.
36
+ - Demo datasets are named for their kind, such as "Demo: sentiment evals".
37
+ - Response Format offers one text option, Plain text.
38
+ - A link to something that is gone says so.
39
+ - History fits a tablet, and Home and Results show long names on two lines.
40
+ - More colours reach WCAG AA contrast in both themes.
41
+
42
+ ### Fixed
43
+
44
+ - A job hands on its reply as its filters left it.
45
+ - A Read Reply step's `preamble: false` is dropped on upgrade and on read.
46
+
8
47
  ## 0.13.0
9
48
 
10
49
  ### Upgrade notes
package/README.md CHANGED
@@ -45,7 +45,7 @@ npm install -g evals-lab
45
45
  evals-lab
46
46
  ```
47
47
 
48
- Open <http://localhost:8080>. A new lab starts with five demos, each a dataset
48
+ Open <http://localhost:8080>. A new lab starts with six demos, each a dataset
49
49
  and its pipeline, which run once you add an AI Connection in Setup. Note the first start takes longer while it installs them. Without
50
50
  installing: `npx evals-lab`.
51
51
 
@@ -164,7 +164,7 @@ CI can run a lab's own pipeline there instead, so the run shows in that lab's
164
164
  History and its keys never leave it:
165
165
 
166
166
  ```bash
167
- LAB_PASSWORD=... evals-lab run --lab https://lab.example --pipeline "Demo: describe images" --wait
167
+ LAB_PASSWORD=... evals-lab run --lab https://lab.example --pipeline "Demo: images pipeline" --wait
168
168
  ```
169
169
 
170
170
  ```text
package/bin/run.js CHANGED
@@ -399,8 +399,10 @@ async function runOnLab(core, o, { env, stdout, say }) {
399
399
  const docs = (await call("GET", "/api/state")).docs ?? {};
400
400
  const setup = docs["promptlab.connections"]?.body ?? {};
401
401
  const connections = core.withSlugs(Array.isArray(setup.list) ? setup.list : []);
402
- const held = docs["promptlab.connectionProfiles"]?.body?.list;
403
- const answers = core.answersOf(connections, Array.isArray(held) ? held : []);
402
+ const held = docs["promptlab.connectionProfiles"]?.body;
403
+ // (Default)'s settings, under each target that names no profile (#603).
404
+ const answers = core.answersOf(connections, Array.isArray(held?.list) ? held.list : [],
405
+ held?.default && typeof held.default === "object" ? held.default : null);
404
406
  const saved = docs["promptlab.workflows"]?.body?.list;
405
407
  const found = pipelineNamed(Array.isArray(saved) ? saved : [], o.pipeline, base);
406
408
  const doc = core.upgradePipeline(found.work, { profileType: id => answers.connection(id)?.type,
package/lab/VERSION CHANGED
@@ -1 +1 @@
1
- 0.13.0 (2026.10.13-794)
1
+ 0.14.0 (2026.10.14-830)
@@ -124,3 +124,17 @@ on 2026-10-11. A work of the US federal government is in the public domain.
124
124
  | `volunteer-day.txt` | Written for this pack | Evals Lab | Public domain |
125
125
  | `weather-report.txt` | Written for this pack | Evals Lab | Public domain |
126
126
  | `https-api.weather.gov-alerts-types.txt` | https://api.weather.gov/alerts/types | National Weather Service | Public domain |
127
+
128
+ ## Documents
129
+
130
+ The PDFs of `documents/`, made for this pack: four short documents, a PDF cut
131
+ short, and a text file with a `.pdf` name.
132
+
133
+ | File | Source | Author | Licence |
134
+ |---|---|---|---|
135
+ | `invoice.pdf` | Written for this pack | Evals Lab | Public domain |
136
+ | `letter.pdf` | Written for this pack | Evals Lab | Public domain |
137
+ | `not-a-pdf.pdf` | Written for this pack | Evals Lab | Public domain |
138
+ | `receipt.pdf` | Written for this pack | Evals Lab | Public domain |
139
+ | `report.pdf` | Written for this pack | Evals Lab | Public domain |
140
+ | `truncated.pdf` | Written for this pack | Evals Lab | Public domain |
@@ -2,12 +2,12 @@
2
2
  "format": "evals-lab/dataset",
3
3
  "version": 6,
4
4
  "dataset": {
5
- "name": "Demo: describe images",
5
+ "name": "Demo: images evals",
6
6
  "body": {
7
7
  "version": 6,
8
8
  "source": {
9
9
  "id": "Demo 1",
10
- "name": "Demo: describe images"
10
+ "name": "Demo: images source"
11
11
  },
12
12
  "cases": [
13
13
  {
@@ -2,12 +2,12 @@
2
2
  "format": "evals-lab/dataset",
3
3
  "version": 6,
4
4
  "dataset": {
5
- "name": "Demo: describe images 2",
5
+ "name": "Demo: images 2 evals",
6
6
  "body": {
7
7
  "version": 6,
8
8
  "source": {
9
9
  "id": "Demo 2",
10
- "name": "Demo: describe images 2"
10
+ "name": "Demo: images 2 source"
11
11
  },
12
12
  "cases": [
13
13
  {
@@ -0,0 +1,79 @@
1
+ {
2
+ "format": "evals-lab/eval-group",
3
+ "version": 9,
4
+ "group": {
5
+ "name": "Document type",
6
+ "preview": {
7
+ "id": "documents",
8
+ "name": "Demo: documents source"
9
+ },
10
+ "body": {
11
+ "version": 9,
12
+ "scoring": {
13
+ "mode": "all",
14
+ "threshold": null
15
+ },
16
+ "grader": null,
17
+ "every": [],
18
+ "run": [],
19
+ "cases": [
20
+ {
21
+ "id": "invoice",
22
+ "item": "invoice.pdf",
23
+ "todo": false,
24
+ "note": "",
25
+ "metrics": [
26
+ {
27
+ "type": "json-field",
28
+ "path": "type",
29
+ "op": "equals",
30
+ "value": "invoice"
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "letter",
36
+ "item": "letter.pdf",
37
+ "todo": false,
38
+ "note": "",
39
+ "metrics": [
40
+ {
41
+ "type": "json-field",
42
+ "path": "type",
43
+ "op": "equals",
44
+ "value": "letter"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "id": "receipt",
50
+ "item": "receipt.pdf",
51
+ "todo": false,
52
+ "note": "",
53
+ "metrics": [
54
+ {
55
+ "type": "json-field",
56
+ "path": "type",
57
+ "op": "equals",
58
+ "value": "receipt"
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "id": "report",
64
+ "item": "report.pdf",
65
+ "todo": false,
66
+ "note": "",
67
+ "metrics": [
68
+ {
69
+ "type": "json-field",
70
+ "path": "type",
71
+ "op": "equals",
72
+ "value": "report"
73
+ }
74
+ ]
75
+ }
76
+ ]
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,117 @@
1
+ {
2
+ "format": "evals-lab/eval-group",
3
+ "version": 9,
4
+ "group": {
5
+ "name": "PDF is valid",
6
+ "preview": {
7
+ "id": "documents",
8
+ "name": "Demo: documents source"
9
+ },
10
+ "body": {
11
+ "version": 9,
12
+ "scoring": {
13
+ "mode": "weighted",
14
+ "threshold": 1
15
+ },
16
+ "grader": null,
17
+ "every": [],
18
+ "run": [],
19
+ "cases": [
20
+ {
21
+ "id": "invoice",
22
+ "item": "invoice.pdf",
23
+ "todo": false,
24
+ "note": "",
25
+ "metrics": [
26
+ {
27
+ "type": "json-field",
28
+ "path": "valid",
29
+ "op": "equals",
30
+ "value": "true"
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "letter",
36
+ "item": "letter.pdf",
37
+ "todo": false,
38
+ "note": "",
39
+ "metrics": [
40
+ {
41
+ "type": "json-field",
42
+ "path": "valid",
43
+ "op": "equals",
44
+ "value": "true"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "id": "receipt",
50
+ "item": "receipt.pdf",
51
+ "todo": false,
52
+ "note": "",
53
+ "metrics": [
54
+ {
55
+ "type": "json-field",
56
+ "path": "valid",
57
+ "op": "equals",
58
+ "value": "true"
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "id": "report",
64
+ "item": "report.pdf",
65
+ "todo": false,
66
+ "note": "",
67
+ "metrics": [
68
+ {
69
+ "type": "json-field",
70
+ "path": "valid",
71
+ "op": "equals",
72
+ "value": "true"
73
+ }
74
+ ]
75
+ },
76
+ {
77
+ "id": "truncated",
78
+ "item": "truncated.pdf",
79
+ "todo": false,
80
+ "note": "A real PDF cut short. Either the API refuses it or the model says it can't read it.",
81
+ "metrics": [
82
+ {
83
+ "type": "refused",
84
+ "weight": 1
85
+ },
86
+ {
87
+ "type": "json-field",
88
+ "path": "valid",
89
+ "op": "equals",
90
+ "value": "false",
91
+ "weight": 1
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "id": "not-a-pdf",
97
+ "item": "not-a-pdf.pdf",
98
+ "todo": false,
99
+ "note": "Plain text with a .pdf name. Either the API refuses it or the model says it can't read it.",
100
+ "metrics": [
101
+ {
102
+ "type": "refused",
103
+ "weight": 1
104
+ },
105
+ {
106
+ "type": "json-field",
107
+ "path": "valid",
108
+ "op": "equals",
109
+ "value": "false",
110
+ "weight": 1
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ }
116
+ }
117
+ }
@@ -2,7 +2,7 @@
2
2
  "format": "evals-lab/eval-group",
3
3
  "version": 9,
4
4
  "group": {
5
- "name": "Demo: classify sentiment",
5
+ "name": "Demo: sentiment evals",
6
6
  "body": {
7
7
  "version": 9,
8
8
  "scoring": {
@@ -377,7 +377,7 @@
377
377
  },
378
378
  "preview": {
379
379
  "id": "sentiment",
380
- "name": "Demo: classify sentiment"
380
+ "name": "Demo: sentiment source"
381
381
  }
382
382
  }
383
383
  }
@@ -2,7 +2,7 @@
2
2
  "format": "evals-lab/eval-group",
3
3
  "version": 9,
4
4
  "group": {
5
- "name": "Demo: sort weather alerts",
5
+ "name": "Demo: weather evals",
6
6
  "body": {
7
7
  "version": 9,
8
8
  "scoring": {
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "preview": {
57
57
  "id": "weather-alerts",
58
- "name": "Demo: sort weather alerts"
58
+ "name": "Demo: weather source"
59
59
  }
60
60
  }
61
61
  }
@@ -2,7 +2,7 @@
2
2
  "format": "evals-lab/eval-group",
3
3
  "version": 9,
4
4
  "group": {
5
- "name": "Demo: compare wordings",
5
+ "name": "Demo: wordings evals",
6
6
  "body": {
7
7
  "version": 9,
8
8
  "scoring": {
@@ -3,10 +3,10 @@
3
3
  "version": 1,
4
4
  "id": "demo",
5
5
  "name": "Demo",
6
- "packVersion": "2026.10.11",
6
+ "packVersion": "2026.10.14.2",
7
7
  "requires": {
8
- "lab": ">=17",
8
+ "lab": ">=18",
9
9
  "plugins": []
10
10
  },
11
- "description": "Five demos, each a dataset with a starter pipeline: two sets of public-domain images, short texts to classify, one question in four wordings, and a dynamic Source's snapshot."
11
+ "description": "Six demos, each a dataset with a starter pipeline: two sets of public-domain images, short texts to classify, one question in four wordings, a dynamic Source's snapshot, and PDFs to check and sort."
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": 17,
2
+ "version": 18,
3
3
  "id": "demo-1",
4
- "name": "Demo: describe images",
4
+ "name": "Demo: images pipeline",
5
5
  "jobs": [
6
6
  {
7
7
  "type": "job",
@@ -14,7 +14,7 @@
14
14
  "type": "source",
15
15
  "ref": {
16
16
  "id": "Demo 1",
17
- "name": "Demo: describe images"
17
+ "name": "Demo: images source"
18
18
  },
19
19
  "first": null,
20
20
  "loops": 1
@@ -141,7 +141,7 @@
141
141
  "continueOnFailure": true,
142
142
  "group": {
143
143
  "id": "demo-1",
144
- "name": "Demo: describe images"
144
+ "name": "Demo: images evals"
145
145
  },
146
146
  "pin": null
147
147
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": 17,
2
+ "version": 18,
3
3
  "id": "demo-2",
4
- "name": "Demo: describe images 2",
4
+ "name": "Demo: images 2 pipeline",
5
5
  "jobs": [
6
6
  {
7
7
  "type": "job",
@@ -14,7 +14,7 @@
14
14
  "type": "source",
15
15
  "ref": {
16
16
  "id": "Demo 2",
17
- "name": "Demo: describe images 2"
17
+ "name": "Demo: images 2 source"
18
18
  },
19
19
  "first": null,
20
20
  "loops": 1
@@ -141,7 +141,7 @@
141
141
  "continueOnFailure": true,
142
142
  "group": {
143
143
  "id": "demo-2",
144
- "name": "Demo: describe images 2"
144
+ "name": "Demo: images 2 evals"
145
145
  },
146
146
  "pin": null
147
147
  }
@@ -0,0 +1,102 @@
1
+ {
2
+ "version": 18,
3
+ "id": "documents",
4
+ "name": "Demo: documents pipeline",
5
+ "jobs": [
6
+ {
7
+ "type": "job",
8
+ "id": "j1",
9
+ "name": "",
10
+ "steps": [
11
+ {
12
+ "type": "attachContent",
13
+ "content": {
14
+ "type": "source",
15
+ "ref": {
16
+ "id": "documents",
17
+ "name": "Demo: documents source"
18
+ },
19
+ "first": null,
20
+ "loops": 1
21
+ }
22
+ },
23
+ {
24
+ "type": "attachImage"
25
+ },
26
+ {
27
+ "type": "filters",
28
+ "stage": "items",
29
+ "filterSets": [
30
+ {
31
+ "id": "filters-j1",
32
+ "set": null,
33
+ "pin": null,
34
+ "own": {
35
+ "version": 3,
36
+ "filters": [
37
+ {
38
+ "id": "unfence",
39
+ "type": "rewrite-text",
40
+ "match": {},
41
+ "options": {
42
+ "ignoreFailures": false,
43
+ "repeat": 1
44
+ },
45
+ "tests": [],
46
+ "op": {
47
+ "kind": "fences"
48
+ }
49
+ }
50
+ ]
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ ]
56
+ }
57
+ ],
58
+ "targets": [
59
+ {
60
+ "id": "s1",
61
+ "name": "",
62
+ "connection": {
63
+ "id": "model",
64
+ "name": "Model"
65
+ },
66
+ "profile": null,
67
+ "steps": [
68
+ {
69
+ "type": "prompt",
70
+ "prompt": "Read the attached document. Reply with JSON only: {\"valid\": true or false (false if you can't read it as a document), \"type\": \"invoice\" | \"letter\" | \"receipt\" | \"report\" | \"other\"}"
71
+ }
72
+ ]
73
+ }
74
+ ],
75
+ "evals": [
76
+ {
77
+ "id": "t1",
78
+ "name": "",
79
+ "type": "group",
80
+ "continueOnFailure": true,
81
+ "group": {
82
+ "id": "documents-valid",
83
+ "name": "PDF is valid"
84
+ },
85
+ "pin": null
86
+ },
87
+ {
88
+ "id": "t2",
89
+ "name": "",
90
+ "type": "group",
91
+ "continueOnFailure": true,
92
+ "group": {
93
+ "id": "documents-type",
94
+ "name": "Document type"
95
+ },
96
+ "pin": null
97
+ }
98
+ ],
99
+ "pass": {
100
+ "mode": "all"
101
+ }
102
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": 17,
2
+ "version": 18,
3
3
  "id": "sentiment",
4
- "name": "Demo: classify sentiment",
4
+ "name": "Demo: sentiment pipeline",
5
5
  "jobs": [
6
6
  {
7
7
  "type": "job",
@@ -14,7 +14,7 @@
14
14
  "type": "source",
15
15
  "ref": {
16
16
  "id": "sentiment",
17
- "name": "Demo: classify sentiment"
17
+ "name": "Demo: sentiment source"
18
18
  },
19
19
  "first": null,
20
20
  "loops": 1
@@ -54,7 +54,7 @@
54
54
  "continueOnFailure": true,
55
55
  "group": {
56
56
  "id": "sentiment",
57
- "name": "Demo: classify sentiment"
57
+ "name": "Demo: sentiment evals"
58
58
  },
59
59
  "pin": null
60
60
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": 17,
2
+ "version": 18,
3
3
  "id": "weather-alerts",
4
- "name": "Demo: sort weather alerts",
4
+ "name": "Demo: weather pipeline",
5
5
  "jobs": [
6
6
  {
7
7
  "type": "job",
@@ -14,11 +14,15 @@
14
14
  "type": "source",
15
15
  "ref": {
16
16
  "id": "weather-alerts",
17
- "name": "Demo: sort weather alerts"
17
+ "name": "Demo: weather source"
18
18
  },
19
19
  "first": null,
20
20
  "loops": 1,
21
- "live": false
21
+ "live": false,
22
+ "pin": {
23
+ "name": "https-api.weather.gov-alerts-types.txt",
24
+ "n": 0
25
+ }
22
26
  }
23
27
  },
24
28
  {
@@ -55,7 +59,7 @@
55
59
  "continueOnFailure": true,
56
60
  "group": {
57
61
  "id": "weather-alerts",
58
- "name": "Demo: sort weather alerts"
62
+ "name": "Demo: weather evals"
59
63
  },
60
64
  "pin": null
61
65
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": 17,
2
+ "version": 18,
3
3
  "id": "wordings",
4
- "name": "Demo: compare wordings",
4
+ "name": "Demo: wordings pipeline",
5
5
  "jobs": [
6
6
  {
7
7
  "type": "job",
@@ -93,7 +93,7 @@
93
93
  "continueOnFailure": true,
94
94
  "group": {
95
95
  "id": "wordings",
96
- "name": "Demo: compare wordings"
96
+ "name": "Demo: wordings evals"
97
97
  },
98
98
  "pin": null
99
99
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "name": "Demo: describe images"
2
+ "name": "Demo: images source"
3
3
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "name": "Demo: describe images 2"
2
+ "name": "Demo: images 2 source"
3
3
  }