@novedu/cli 0.19.0 → 0.20.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 (3) hide show
  1. package/README.md +99 -8
  2. package/dist/main.js +1684 -591
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # @novedu/cli
2
2
 
3
3
  Command-line companion for the Novedu chat app (installed command: `novedu-cli`;
4
- requires Node >= 20). It covers two jobs:
4
+ requires Node >= 22 `eval`'s glob expansion uses the built-in `fs.globSync`,
5
+ and Node 20 is end-of-life). It covers two jobs:
5
6
 
6
7
  - **Validate activity YAML** — tutors, fragment libraries, quizzes, writing
7
- activities, and coding activities — with the app's exact validation pipeline,
8
- offline and without signing in. `prompts` dumps the exact system prompts an
9
- activity produces, the same way.
8
+ activities, coding activities, and golden-answer evals — with the app's exact
9
+ validation pipeline, offline and without signing in. `prompts` dumps the exact
10
+ system prompts an activity produces, the same way.
10
11
  - **Manage the app as a teacher** — sign in with Microsoft Entra ID, then mint
11
- activity codes, upload app-hosted YAML files and images, and triage student
12
- reports, straight from the terminal (or from a coding agent, see below).
12
+ activity codes, upload app-hosted YAML files and images, triage student
13
+ reports, and **measure a quiz's grading rubric** (`eval`), straight from the
14
+ terminal (or from a coding agent, see below).
13
15
 
14
16
  No install needed:
15
17
 
@@ -30,12 +32,15 @@ npx @novedu/cli validate https://raw.githubusercontent.com/Teaching-HTL-Leonding
30
32
  npx @novedu/cli validate ./activities/examples/shared/general-fragments.yaml --kind fragment
31
33
  npx @novedu/cli validate ./activities/examples/sorting-algorithms/sorting-quiz.yaml --kind quiz
32
34
 
35
+ # A golden-answer eval (also strict-checks the quiz it targets)
36
+ npx @novedu/cli validate ./sorting-quiz.eval.yaml --kind eval
37
+
33
38
  # Machine-readable output (the raw validation result)
34
39
  npx @novedu/cli validate ./my-quiz.yaml --kind quiz --json
35
40
  ```
36
41
 
37
- - `--kind` accepts `tutor` (default), `fragment`, `quiz`, `writing`, or
38
- `coding`; it is caller-declared, not auto-detected.
42
+ - `--kind` accepts `tutor` (default), `fragment`, `quiz`, `writing`, `coding`, or
43
+ `eval`; it is caller-declared, not auto-detected.
39
44
  - The CLI reuses the app's exact validation pipeline (`lib/prompt-fragments`,
40
45
  `lib/tutors`, `lib/quiz-validate`, `lib/writing-validate`,
41
46
  `lib/coding-validate`), so an activity that passes here is the same one the
@@ -91,6 +96,92 @@ npx @novedu/cli prompts ./sorting-quiz.yaml --kind quiz --json \
91
96
  JSON errors on stderr. Use `validate` for the strict authoring check — the two
92
97
  are complementary.
93
98
 
99
+ ## Measuring a quiz's grading rubric: `eval`
100
+
101
+ A quiz's `evaluation` prompt is a rubric, and a rubric is only as good as its
102
+ behavior on real answers. Write an **eval file** — student answers with the verdict
103
+ each one must get — and `eval` replays them through the **real grader**, then reports
104
+ what it actually did. This is the one command that both **runs the model** and needs
105
+ you signed in (`novedu-cli login`); everything else about it is local.
106
+
107
+ ```yaml
108
+ # sorting-quiz.eval.yaml
109
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/Teaching-HTL-Leonding/novedu-chat-mvp/refs/heads/main/activities/evals/eval-yaml.schema.json
110
+ id: sorting-quiz-eval
111
+ target: ./sorting-quiz.yaml # relative to THIS file, or an http(s) URL
112
+ questions:
113
+ - question: bubble-sort-complexity # the quiz's question id
114
+ answers:
115
+ - expect: correct
116
+ answer: |
117
+ O(n²) in the average and worst case.
118
+ - expect: [partial, incorrect] # more than one grading is defensible
119
+ answer: |
120
+ It's quadratic-ish.
121
+ ```
122
+
123
+ ```bash
124
+ # Run it (grading prompts are assembled locally, so an unpushed file works)
125
+ npx @novedu/cli eval ./sorting-quiz.eval.yaml
126
+
127
+ # A whole course part — quote the pattern so the CLI expands it (** included)
128
+ npx @novedu/cli eval "./part-1/**/*.eval.yaml"
129
+
130
+ # Is the grader stable? 3 runs per answer, majority verdict
131
+ npx @novedu/cli eval ./sorting-quiz.eval.yaml --repeats 3
132
+
133
+ # How would this rubric do on another model? (both flags, always together)
134
+ npx @novedu/cli eval ./sorting-quiz.eval.yaml \
135
+ --llm-provider "Azure Foundry" --llm-model gpt-5-mini
136
+
137
+ # Machine-readable, for CI
138
+ npx @novedu/cli eval ./sorting-quiz.eval.yaml --json --out eval-report.json
139
+
140
+ # A readable Markdown report to share or commit
141
+ npx @novedu/cli eval ./sorting-quiz.eval.yaml --report eval-report.md
142
+ ```
143
+
144
+ - Check the file first, for free: `npx @novedu/cli validate ./x.eval.yaml --kind eval`
145
+ (offline; it also strict-checks the quiz the eval targets).
146
+ - **`expect`** is one of `correct` / `partial` / `incorrect`, or a list of the
147
+ acceptable ones. **`question`** must be a question id of the resolved quiz — for a
148
+ question imported via `quiz_files` that is the namespaced `"<alias>/<id>"` id.
149
+ - **Report semantics.** A **case** is one golden answer; `--repeats` are repeated
150
+ observations of that case, and the case's verdict is the **majority** (a tie passes
151
+ only if every tied verdict is expected). Totals, mismatches, the confusion matrix
152
+ and the exit code are all over case verdicts, so `--repeats 3` is never harsher
153
+ than `--repeats 1`. Cases whose repeats disagreed are reported as **`unstable`** —
154
+ the interesting `--repeats` signal — but never fail the run.
155
+ - The **false-correct rate** counts answers you marked as not acceptable that the
156
+ grader called `correct` — the dangerous direction. The confusion matrix is keyed by
157
+ the sorted expected set (`correct|partial`), so list order never matters.
158
+ - **Exit code** `0` only when every file is valid, `failed = 0`, `errored = 0` and
159
+ `skipped = 0` — a CI gate like `validate`. Progress and the run's scope go to
160
+ stderr; stdout stays clean for `--json`.
161
+ - **Multi-file runs** grade files one after another (`--concurrency`, default 4,
162
+ bounds cases *within* a file), print a per-file summary + grand totals, and isolate
163
+ a broken file instead of aborting the batch. `--json` / `--out` always carry the
164
+ same batch shape `{ files: [...], passed, totals }`, single file or not — `passed`
165
+ is the exit-code verdict, per batch and per file.
166
+ - **`--report <file.md>`** additionally writes a readable **Markdown** report — an
167
+ overview table over the files, then the question, the golden answer and the grader's
168
+ feedback for every mismatched, errored or unstable case (passing cases stay in the
169
+ JSON). It composes with `--json` / `--out` and leaves stdout untouched.
170
+ - **Token totals.** The reports show what a run cost —
171
+ `tokens: 15,420 in (12,300 cached) / 2,810 out` — summed over the grading calls that
172
+ **succeeded**, so it is a lower bound (a retried or failed call reports nothing), and
173
+ nothing at all is printed when the server reports no usage.
174
+ - **Failure handling**: a 5xx or network hiccup is retried (4 attempts, linear
175
+ backoff); any 4xx is terminal; an auth failure aborts the run with one message; and
176
+ three consecutive errored cases trip a circuit breaker so a down server fails fast.
177
+ After an abort, untried cases are reported as **`skipped`**, not errored. If EVERY
178
+ case errors at once, suspect the server, not the rubric: the target must actually
179
+ offer `/api/eval/grade` (point `--server` at one that does), and a 1-case smoke
180
+ run localises the problem for the cost of a single grading call.
181
+ - **Caveat**: a green run certifies **the file you ran it on**, not the app-hosted
182
+ copy a live code serves — upload it (`files upload`) afterwards. An override run
183
+ certifies the override pair, not the quiz's configured `llm`.
184
+
94
185
  ## Authentication
95
186
 
96
187
  Commands that talk to the running app authenticate with Microsoft Entra ID: