@tuned-tensor/local 0.1.4 → 0.1.6

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/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to Tuned Tensor Local will be documented in this file.
4
4
 
5
+ ## 0.1.6 - 2026-07-02
6
+
7
+ ### Added
8
+
9
+ - Added `tt-local runs compare <run-id-a> <run-id-b>`: aligns two runs on their shared eval prompts and reports per-subset baseline/candidate averages, shared-subset deltas, new-example effects, and judge score noise measured on identical baseline outputs. Headline `avg_score_delta` values are not comparable across different eval subsets; the shared subset is.
10
+ - Added a baseline evaluation cache (default on, `evaluation.baselineCache: false` to disable): re-running a spec with an unchanged base model, eval examples, generation settings, and scoring config reuses the previous baseline report from `<storeRoot>/cache/baseline-evals/` instead of re-running inference and judge calls. Reports served from cache carry `cached: true` and a `cache_key`. Reports containing fallback-scored examples are never cached.
11
+ - Eval reports now record how each example was scored (`results[].scored_by`) and aggregate it as `judge_scored_count`, `fallback_scored_count`, and `judge_only_avg_score`, so transient judge failures that fall back to exact match can no longer silently skew `avg_score` without a trace. The comparison report includes `judge_only_avg_score_delta`.
12
+ - Comparison reports now classify each regressed example's judge reasoning into a coarse category (`factual`, `omission`, `style`, `fallback`, `other`) and aggregate counts as `regression_taxonomy`, answering "what kind of worse?" at a glance.
13
+
14
+ ## 0.1.5 - 2026-07-02
15
+
16
+ ### Added
17
+
18
+ - Added `avg_token_f1` to eval reports and `token_f1_delta` to the comparison report: a cheap deterministic token-overlap reference-similarity metric for free-text tasks where exact match is always 0 and an LLM judge can be noisy.
19
+ - The OpenRouter judge now receives the spec's compiled system message (system prompt, guidelines, constraints) as `task_instructions` and scores conformance to the task instead of treating the expected output as a fact checklist. Previously a model fine-tuned toward a concise style was penalized for omitting reference details even when the spec asked for brevity.
20
+ - `tt-local` now loads `.env` from the working directory (without overriding already-set variables), so `OPENROUTER_API_KEY` works without manual sourcing.
21
+ - `validate` and `run` now warn about unknown hyperparameter keys (for example `per_device_train_batch_size` instead of `batch_size`), which were previously stripped silently and trained with defaults.
22
+
23
+ ### Fixed
24
+
25
+ - Judge scoring with `scoring.fallback: "exact_match"` no longer fails the whole run when a judge request fails transiently; the affected example falls back to normalized exact match and records the judge failure in its reasoning.
26
+ - Fixed a crash-level race in atomic store writes: concurrent run-state updates in the same millisecond (typical when tqdm flushes several progress lines at training completion) collided on the same temp filename and killed the run with `ENOENT: rename` after training had succeeded. Temp filenames now include a UUID.
27
+ - The local evaluator no longer passes `temperature`/`top_p` to `model.generate` when decoding greedily, silencing the spurious transformers "generation flags are not valid" warning at `temperature: 0`.
28
+ - `--verbose` no longer prints consecutive duplicate subprocess log lines (tqdm redraws the same progress line several times per step).
29
+
5
30
  ## 0.1.4 - 2026-07-01
6
31
 
7
32
  ### Added
package/README.md CHANGED
@@ -186,7 +186,63 @@ exact matching:
186
186
  The evaluation report still includes `exact_match_rate`, but `avg_score`,
187
187
  `pass_rate`, and `json_field_metrics` are based on the selected JSON fields.
188
188
  If `fields` is omitted, the evaluator scores every key in the expected JSON
189
- object for each example.
189
+ object for each example. A configured field that is missing from the expected
190
+ JSON is always scored as incorrect (with a reasoning note), so misconfigured
191
+ field lists cannot inflate scores.
192
+
193
+ The judge receives the spec's compiled system message (system prompt,
194
+ guidelines, and constraints) as task instructions and scores how well each
195
+ output fulfills the task; the expected output is treated as a reference
196
+ answer, not a fact checklist. Every eval report also includes `avg_token_f1`
197
+ (and the comparison includes `token_f1_delta`), a deterministic token-overlap
198
+ similarity against the reference outputs that is useful for free-text tasks
199
+ such as summarization, where exact match is always 0 and judge scores can be
200
+ noisy.
201
+
202
+ Each eval example records how it was scored (`results[].scored_by`), and the
203
+ report aggregates `judge_scored_count`, `fallback_scored_count`, and
204
+ `judge_only_avg_score`. When a judge request fails transiently and the
205
+ example falls back to exact match, `avg_score` mixes two metrics; use
206
+ `judge_only_avg_score` (and the comparison's `judge_only_avg_score_delta`)
207
+ when comparing judge quality. The comparison also classifies each regressed
208
+ example's judge reasoning as `factual`, `omission`, `style`, `fallback`, or
209
+ `other` and reports the counts in `regression_taxonomy`.
210
+
211
+ Baseline evaluations are cached under `<storeRoot>/cache/baseline-evals/`:
212
+ re-running a spec with an unchanged base model, eval examples, generation
213
+ settings, and scoring config reuses the previous baseline report instead of
214
+ re-running inference and judge calls. Cached reports carry `cached: true`.
215
+ Set `evaluation.baselineCache: false` to disable. Reports containing
216
+ fallback-scored examples are never cached, so a transient judge failure is
217
+ not replayed into future runs.
218
+
219
+ To compare two runs whose eval sets may differ (for example after raising
220
+ `evaluation.maxExamples`), use:
221
+
222
+ ```bash
223
+ tt-local runs compare <run-id-a> <run-id-b> --config spark-runner.json
224
+ ```
225
+
226
+ It aligns the runs on their shared eval prompts, reports both runs' averages
227
+ on that shared subset plus the new-example subset separately, and measures
228
+ judge score noise on baseline outputs that are byte-identical across the two
229
+ runs.
230
+
231
+ With `"mode": "llm_judge"`, `scoring.fallback` controls what happens when the
232
+ judge is unavailable, a judge request fails, or the judge returns malformed
233
+ JSON. With `"fallback": "exact_match"` (the default), the affected example is
234
+ scored by normalized exact match and its reasoning records the judge failure;
235
+ the run does not fail. With `"fallback": "fail"`, judge errors fail the run.
236
+
237
+ `evaluation.maxExamples` caps how many evaluation examples are scored. If it
238
+ is unset, the request hyperparameter `max_eval_examples` is used instead;
239
+ an explicit `maxExamples` in the config always wins. When the cap truncates
240
+ the eval set, the runner draws a deterministic seeded random sample (not a
241
+ prefix), so sorted or grouped eval files do not bias the subset. The seed
242
+ defaults to a hash of the run id, can be pinned with `evaluation.sampleSeed`,
243
+ and is recorded in each eval report as `eval_sample_seed`. Baseline and
244
+ candidate evaluations always score the same sampled examples in the same
245
+ order.
190
246
 
191
247
  If you want OpenRouter judging, set your key:
192
248
 
@@ -194,6 +250,14 @@ If you want OpenRouter judging, set your key:
194
250
  export OPENROUTER_API_KEY="your_openrouter_key"
195
251
  ```
196
252
 
253
+ `tt-local` also loads a `.env` file from the working directory (existing
254
+ environment variables win), so the key can live in the project's `.env`
255
+ instead.
256
+
257
+ `validate` and `run` warn about hyperparameter keys the schema does not
258
+ recognize (for example `per_device_train_batch_size` instead of
259
+ `batch_size`); unknown keys are ignored rather than passed to training.
260
+
197
261
  Run the job:
198
262
 
199
263
  ```bash
@@ -209,10 +273,30 @@ recorded as run events, so `tt-local runs watch` and per-run `progress.jsonl`
209
273
  show epoch, loss, step, percentage, and ETA updates when the trainer emits
210
274
  them.
211
275
 
276
+ For spec-based runs (no `dataset_prebuilt`), the runner automatically holds
277
+ out about 20% of the spec examples (at least 1 holdout and at least 1 training
278
+ example) for evaluation, so baseline and candidate scores are not measured on
279
+ the training data. The split is deterministic: it uses the per-run sample seed
280
+ (a hash of the run id, or `evaluation.sampleSeed` when set), so re-running the
281
+ same run id reproduces the same split and baseline/candidate always score the
282
+ identical holdout. The training JSONL artifact contains only the training
283
+ split, `run_metadata.training_example_count` records the training split size,
284
+ and `eval_examples_total` records the holdout size. These runs report
285
+ `eval_split: "spec_holdout"`. With only 1 spec example there is nothing to
286
+ hold out, so evaluation runs on the training set and is reported as
287
+ `eval_split: "spec_examples"` (training-set evaluation due to insufficient
288
+ examples).
289
+
212
290
  For prebuilt datasets, `dataset_prebuilt.training` is always copied into the
213
291
  run artifact as the training set. Evaluation uses `dataset_prebuilt.test` when
214
- present, then `dataset_prebuilt.validation`, and otherwise falls back to the
215
- training file.
292
+ present, then `dataset_prebuilt.validation`. If neither is provided, a real
293
+ (non-dry) run fails with an error, because evaluating on the training split
294
+ overstates improvement; set `evaluation.allowPrebuiltTrainingEval: true` to
295
+ evaluate on the training file anyway. Dry runs are allowed to fall back to the
296
+ training file without the override. Each eval report and the run's
297
+ `run_metadata` record the split that was evaluated in `eval_split`
298
+ (`spec_holdout`, `spec_examples`, `prebuilt_test`, `prebuilt_validation`, or
299
+ `prebuilt_training`), so training-set evaluation is always visible.
216
300
 
217
301
  Multimodal runs use the same chat JSONL shape with structured user content.
218
302
  For `image_text_to_text` models such as `Qwen/Qwen3-VL-2B-Instruct`, image
@@ -281,6 +365,7 @@ tt-local runs list --config spark-runner.json
281
365
  tt-local runs get <run-id> --config spark-runner.json
282
366
  tt-local runs events <run-id> --config spark-runner.json
283
367
  tt-local runs report <run-id> --config spark-runner.json
368
+ tt-local runs compare <run-id-a> <run-id-b> --config spark-runner.json
284
369
  tt-local models list --config spark-runner.json
285
370
  tt-local serve --config spark-runner.json
286
371
  ```
@@ -0,0 +1,47 @@
1
+ import type { RunReport } from "./contracts.js";
2
+ interface SubsetSide {
3
+ baseline_avg_score: number | null;
4
+ candidate_avg_score: number | null;
5
+ candidate_avg_token_f1: number | null;
6
+ }
7
+ interface RunSummary {
8
+ run_id: string;
9
+ started_at: string;
10
+ base_model: string;
11
+ training_example_count: number | null;
12
+ eval_examples_used: number;
13
+ baseline_avg_score: number;
14
+ candidate_avg_score: number;
15
+ candidate_avg_token_f1: number | null;
16
+ avg_score_delta: number;
17
+ fallback_scored_count: number;
18
+ }
19
+ export interface RunComparison {
20
+ run_a: RunSummary;
21
+ run_b: RunSummary;
22
+ shared: {
23
+ examples: number;
24
+ run_a: SubsetSide;
25
+ run_b: SubsetSide;
26
+ candidate_avg_score_delta: number | null;
27
+ candidate_avg_token_f1_delta: number | null;
28
+ };
29
+ b_only: SubsetSide & {
30
+ examples: number;
31
+ };
32
+ judge_noise: {
33
+ identical_baseline_outputs: number;
34
+ mean_score_spread: number | null;
35
+ max_score_spread: number | null;
36
+ };
37
+ notes: string[];
38
+ }
39
+ /**
40
+ * Aligns two run reports on their shared eval prompts so recipe changes can
41
+ * be compared apples-to-apples even when the eval set grew or shifted between
42
+ * runs. Headline avg_score_delta values are not comparable across different
43
+ * eval subsets; the shared subset is. Identical baseline outputs that appear
44
+ * in both runs also give a free measurement of judge score noise.
45
+ */
46
+ export declare function compareRuns(a: RunReport, b: RunReport): RunComparison;
47
+ export {};
@@ -0,0 +1,95 @@
1
+ import { tokenF1 } from "./evaluation.js";
2
+ function byPrompt(report) {
3
+ return new Map(report.results.map((result) => [result.prompt, result]));
4
+ }
5
+ function avg(values) {
6
+ return values.length > 0 ? values.reduce((sum, value) => sum + value, 0) / values.length : null;
7
+ }
8
+ function summarizeRun(report) {
9
+ return {
10
+ run_id: report.run_id,
11
+ started_at: report.run_metadata.started_at,
12
+ base_model: report.base_model,
13
+ training_example_count: report.run_metadata.training_example_count,
14
+ eval_examples_used: report.run_metadata.eval_examples_used,
15
+ baseline_avg_score: report.baseline.avg_score,
16
+ candidate_avg_score: report.candidate.avg_score,
17
+ candidate_avg_token_f1: report.candidate.avg_token_f1 ?? null,
18
+ avg_score_delta: report.comparison.avg_score_delta,
19
+ fallback_scored_count: (report.baseline.fallback_scored_count ?? 0)
20
+ + (report.candidate.fallback_scored_count ?? 0),
21
+ };
22
+ }
23
+ function subsetSide(prompts, baseline, candidate) {
24
+ const candidateResults = prompts
25
+ .map((prompt) => candidate.get(prompt))
26
+ .filter((result) => Boolean(result));
27
+ return {
28
+ baseline_avg_score: avg(prompts
29
+ .map((prompt) => baseline.get(prompt)?.score)
30
+ .filter((score) => typeof score === "number")),
31
+ candidate_avg_score: avg(candidateResults.map((result) => result.score)),
32
+ candidate_avg_token_f1: avg(candidateResults.map((result) => tokenF1(result.expected, result.actual))),
33
+ };
34
+ }
35
+ /**
36
+ * Aligns two run reports on their shared eval prompts so recipe changes can
37
+ * be compared apples-to-apples even when the eval set grew or shifted between
38
+ * runs. Headline avg_score_delta values are not comparable across different
39
+ * eval subsets; the shared subset is. Identical baseline outputs that appear
40
+ * in both runs also give a free measurement of judge score noise.
41
+ */
42
+ export function compareRuns(a, b) {
43
+ const aCandidate = byPrompt(a.candidate);
44
+ const bCandidate = byPrompt(b.candidate);
45
+ const aBaseline = byPrompt(a.baseline);
46
+ const bBaseline = byPrompt(b.baseline);
47
+ const sharedPrompts = [...bCandidate.keys()].filter((prompt) => aCandidate.has(prompt));
48
+ const bOnlyPrompts = [...bCandidate.keys()].filter((prompt) => !aCandidate.has(prompt));
49
+ const spreads = [];
50
+ let identical = 0;
51
+ for (const prompt of sharedPrompts) {
52
+ const first = aBaseline.get(prompt);
53
+ const second = bBaseline.get(prompt);
54
+ if (!first || !second || first.actual !== second.actual)
55
+ continue;
56
+ identical += 1;
57
+ spreads.push(Math.abs(first.score - second.score));
58
+ }
59
+ const sharedA = subsetSide(sharedPrompts, aBaseline, aCandidate);
60
+ const sharedB = subsetSide(sharedPrompts, bBaseline, bCandidate);
61
+ const runA = summarizeRun(a);
62
+ const runB = summarizeRun(b);
63
+ const notes = [];
64
+ if (bOnlyPrompts.length > 0) {
65
+ notes.push(`run_b evaluated ${bOnlyPrompts.length} example(s) run_a never saw; headline avg_score_delta values `
66
+ + "are not directly comparable across the two runs. Use the shared subset for recipe comparisons.");
67
+ }
68
+ if (runA.fallback_scored_count + runB.fallback_scored_count > 0) {
69
+ notes.push(`${runA.fallback_scored_count + runB.fallback_scored_count} example(s) across both runs were `
70
+ + "fallback-scored after judge failures; prefer judge_only_avg_score when comparing judge quality.");
71
+ }
72
+ return {
73
+ run_a: runA,
74
+ run_b: runB,
75
+ shared: {
76
+ examples: sharedPrompts.length,
77
+ run_a: sharedA,
78
+ run_b: sharedB,
79
+ candidate_avg_score_delta: sharedA.candidate_avg_score !== null && sharedB.candidate_avg_score !== null
80
+ ? sharedB.candidate_avg_score - sharedA.candidate_avg_score
81
+ : null,
82
+ candidate_avg_token_f1_delta: sharedA.candidate_avg_token_f1 !== null && sharedB.candidate_avg_token_f1 !== null
83
+ ? sharedB.candidate_avg_token_f1 - sharedA.candidate_avg_token_f1
84
+ : null,
85
+ },
86
+ b_only: { examples: bOnlyPrompts.length, ...subsetSide(bOnlyPrompts, bBaseline, bCandidate) },
87
+ judge_noise: {
88
+ identical_baseline_outputs: identical,
89
+ mean_score_spread: avg(spreads),
90
+ max_score_spread: spreads.length > 0 ? Math.max(...spreads) : null,
91
+ },
92
+ notes,
93
+ };
94
+ }
95
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"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"}
@@ -183,6 +183,13 @@ export declare const evalExampleResultSchema: z.ZodObject<{
183
183
  score: z.ZodNumber;
184
184
  reasoning: z.ZodNullable<z.ZodString>;
185
185
  latency_ms: z.ZodNumber;
186
+ scored_by: z.ZodOptional<z.ZodEnum<{
187
+ llm_judge: "llm_judge";
188
+ exact_match: "exact_match";
189
+ json_fields: "json_fields";
190
+ heuristic: "heuristic";
191
+ exact_match_fallback: "exact_match_fallback";
192
+ }>>;
186
193
  }, z.core.$strip>;
187
194
  export declare const jsonFieldMetricsSchema: z.ZodObject<{
188
195
  fields: z.ZodArray<z.ZodString>;
@@ -198,6 +205,13 @@ export declare const jsonFieldMetricsSchema: z.ZodObject<{
198
205
  accuracy: z.ZodNumber;
199
206
  }, z.core.$strip>>;
200
207
  }, z.core.$strip>;
208
+ export declare const evalSplitSchema: z.ZodEnum<{
209
+ spec_examples: "spec_examples";
210
+ spec_holdout: "spec_holdout";
211
+ prebuilt_test: "prebuilt_test";
212
+ prebuilt_validation: "prebuilt_validation";
213
+ prebuilt_training: "prebuilt_training";
214
+ }>;
201
215
  export declare const evalReportSchema: z.ZodObject<{
202
216
  kind: z.ZodEnum<{
203
217
  candidate: "candidate";
@@ -208,10 +222,24 @@ export declare const evalReportSchema: z.ZodObject<{
208
222
  eval_examples_total: z.ZodNumber;
209
223
  eval_examples_used: z.ZodNumber;
210
224
  eval_truncated: z.ZodBoolean;
225
+ eval_split: z.ZodOptional<z.ZodEnum<{
226
+ spec_examples: "spec_examples";
227
+ spec_holdout: "spec_holdout";
228
+ prebuilt_test: "prebuilt_test";
229
+ prebuilt_validation: "prebuilt_validation";
230
+ prebuilt_training: "prebuilt_training";
231
+ }>>;
232
+ eval_sample_seed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
211
233
  avg_score: z.ZodNumber;
212
234
  pass_rate: z.ZodNumber;
213
235
  exact_match_rate: z.ZodNumber;
236
+ avg_token_f1: z.ZodOptional<z.ZodNumber>;
214
237
  avg_latency_ms: z.ZodNumber;
238
+ judge_scored_count: z.ZodOptional<z.ZodNumber>;
239
+ fallback_scored_count: z.ZodOptional<z.ZodNumber>;
240
+ judge_only_avg_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
241
+ cached: z.ZodOptional<z.ZodBoolean>;
242
+ cache_key: z.ZodOptional<z.ZodString>;
215
243
  results: z.ZodArray<z.ZodObject<{
216
244
  prompt: z.ZodString;
217
245
  expected: z.ZodString;
@@ -220,14 +248,21 @@ export declare const evalReportSchema: z.ZodObject<{
220
248
  score: z.ZodNumber;
221
249
  reasoning: z.ZodNullable<z.ZodString>;
222
250
  latency_ms: z.ZodNumber;
251
+ scored_by: z.ZodOptional<z.ZodEnum<{
252
+ llm_judge: "llm_judge";
253
+ exact_match: "exact_match";
254
+ json_fields: "json_fields";
255
+ heuristic: "heuristic";
256
+ exact_match_fallback: "exact_match_fallback";
257
+ }>>;
223
258
  }, z.core.$strip>>;
224
259
  artifact_uri: z.ZodString;
225
260
  scoring_method: z.ZodEnum<{
226
261
  command: "command";
227
- heuristic: "heuristic";
228
262
  llm_judge: "llm_judge";
229
263
  exact_match: "exact_match";
230
264
  json_fields: "json_fields";
265
+ heuristic: "heuristic";
231
266
  }>;
232
267
  judge_model_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
233
268
  inference_provider: z.ZodOptional<z.ZodEnum<{
@@ -257,16 +292,39 @@ export declare const evalReportSchema: z.ZodObject<{
257
292
  generation_config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
258
293
  log_uri: z.ZodOptional<z.ZodString>;
259
294
  }, z.core.$strip>;
295
+ export declare const regressionCategorySchema: z.ZodEnum<{
296
+ fallback: "fallback";
297
+ other: "other";
298
+ style: "style";
299
+ factual: "factual";
300
+ omission: "omission";
301
+ }>;
260
302
  export declare const comparisonReportSchema: z.ZodObject<{
261
303
  avg_score_delta: z.ZodNumber;
262
304
  pass_rate_delta: z.ZodNumber;
263
305
  exact_match_rate_delta: z.ZodNumber;
306
+ token_f1_delta: z.ZodOptional<z.ZodNumber>;
307
+ judge_only_avg_score_delta: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
264
308
  regressions: z.ZodNumber;
265
309
  improvements: z.ZodNumber;
310
+ regression_taxonomy: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
311
+ fallback: "fallback";
312
+ other: "other";
313
+ style: "style";
314
+ factual: "factual";
315
+ omission: "omission";
316
+ }>, z.ZodNumber>>;
266
317
  regressed_examples: z.ZodArray<z.ZodObject<{
267
318
  prompt: z.ZodString;
268
319
  old_score: z.ZodNumber;
269
320
  new_score: z.ZodNumber;
321
+ category: z.ZodOptional<z.ZodEnum<{
322
+ fallback: "fallback";
323
+ other: "other";
324
+ style: "style";
325
+ factual: "factual";
326
+ omission: "omission";
327
+ }>>;
270
328
  }, z.core.$strip>>;
271
329
  }, z.core.$strip>;
272
330
  export declare const trainingReportSchema: z.ZodObject<{
@@ -300,10 +358,24 @@ export declare const runReportSchema: z.ZodObject<{
300
358
  eval_examples_total: z.ZodNumber;
301
359
  eval_examples_used: z.ZodNumber;
302
360
  eval_truncated: z.ZodBoolean;
361
+ eval_split: z.ZodOptional<z.ZodEnum<{
362
+ spec_examples: "spec_examples";
363
+ spec_holdout: "spec_holdout";
364
+ prebuilt_test: "prebuilt_test";
365
+ prebuilt_validation: "prebuilt_validation";
366
+ prebuilt_training: "prebuilt_training";
367
+ }>>;
368
+ eval_sample_seed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
303
369
  avg_score: z.ZodNumber;
304
370
  pass_rate: z.ZodNumber;
305
371
  exact_match_rate: z.ZodNumber;
372
+ avg_token_f1: z.ZodOptional<z.ZodNumber>;
306
373
  avg_latency_ms: z.ZodNumber;
374
+ judge_scored_count: z.ZodOptional<z.ZodNumber>;
375
+ fallback_scored_count: z.ZodOptional<z.ZodNumber>;
376
+ judge_only_avg_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
377
+ cached: z.ZodOptional<z.ZodBoolean>;
378
+ cache_key: z.ZodOptional<z.ZodString>;
307
379
  results: z.ZodArray<z.ZodObject<{
308
380
  prompt: z.ZodString;
309
381
  expected: z.ZodString;
@@ -312,14 +384,21 @@ export declare const runReportSchema: z.ZodObject<{
312
384
  score: z.ZodNumber;
313
385
  reasoning: z.ZodNullable<z.ZodString>;
314
386
  latency_ms: z.ZodNumber;
387
+ scored_by: z.ZodOptional<z.ZodEnum<{
388
+ llm_judge: "llm_judge";
389
+ exact_match: "exact_match";
390
+ json_fields: "json_fields";
391
+ heuristic: "heuristic";
392
+ exact_match_fallback: "exact_match_fallback";
393
+ }>>;
315
394
  }, z.core.$strip>>;
316
395
  artifact_uri: z.ZodString;
317
396
  scoring_method: z.ZodEnum<{
318
397
  command: "command";
319
- heuristic: "heuristic";
320
398
  llm_judge: "llm_judge";
321
399
  exact_match: "exact_match";
322
400
  json_fields: "json_fields";
401
+ heuristic: "heuristic";
323
402
  }>;
324
403
  judge_model_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
325
404
  inference_provider: z.ZodOptional<z.ZodEnum<{
@@ -359,10 +438,24 @@ export declare const runReportSchema: z.ZodObject<{
359
438
  eval_examples_total: z.ZodNumber;
360
439
  eval_examples_used: z.ZodNumber;
361
440
  eval_truncated: z.ZodBoolean;
441
+ eval_split: z.ZodOptional<z.ZodEnum<{
442
+ spec_examples: "spec_examples";
443
+ spec_holdout: "spec_holdout";
444
+ prebuilt_test: "prebuilt_test";
445
+ prebuilt_validation: "prebuilt_validation";
446
+ prebuilt_training: "prebuilt_training";
447
+ }>>;
448
+ eval_sample_seed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
362
449
  avg_score: z.ZodNumber;
363
450
  pass_rate: z.ZodNumber;
364
451
  exact_match_rate: z.ZodNumber;
452
+ avg_token_f1: z.ZodOptional<z.ZodNumber>;
365
453
  avg_latency_ms: z.ZodNumber;
454
+ judge_scored_count: z.ZodOptional<z.ZodNumber>;
455
+ fallback_scored_count: z.ZodOptional<z.ZodNumber>;
456
+ judge_only_avg_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
457
+ cached: z.ZodOptional<z.ZodBoolean>;
458
+ cache_key: z.ZodOptional<z.ZodString>;
366
459
  results: z.ZodArray<z.ZodObject<{
367
460
  prompt: z.ZodString;
368
461
  expected: z.ZodString;
@@ -371,14 +464,21 @@ export declare const runReportSchema: z.ZodObject<{
371
464
  score: z.ZodNumber;
372
465
  reasoning: z.ZodNullable<z.ZodString>;
373
466
  latency_ms: z.ZodNumber;
467
+ scored_by: z.ZodOptional<z.ZodEnum<{
468
+ llm_judge: "llm_judge";
469
+ exact_match: "exact_match";
470
+ json_fields: "json_fields";
471
+ heuristic: "heuristic";
472
+ exact_match_fallback: "exact_match_fallback";
473
+ }>>;
374
474
  }, z.core.$strip>>;
375
475
  artifact_uri: z.ZodString;
376
476
  scoring_method: z.ZodEnum<{
377
477
  command: "command";
378
- heuristic: "heuristic";
379
478
  llm_judge: "llm_judge";
380
479
  exact_match: "exact_match";
381
480
  json_fields: "json_fields";
481
+ heuristic: "heuristic";
382
482
  }>;
383
483
  judge_model_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
384
484
  inference_provider: z.ZodOptional<z.ZodEnum<{
@@ -412,12 +512,28 @@ export declare const runReportSchema: z.ZodObject<{
412
512
  avg_score_delta: z.ZodNumber;
413
513
  pass_rate_delta: z.ZodNumber;
414
514
  exact_match_rate_delta: z.ZodNumber;
515
+ token_f1_delta: z.ZodOptional<z.ZodNumber>;
516
+ judge_only_avg_score_delta: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
415
517
  regressions: z.ZodNumber;
416
518
  improvements: z.ZodNumber;
519
+ regression_taxonomy: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
520
+ fallback: "fallback";
521
+ other: "other";
522
+ style: "style";
523
+ factual: "factual";
524
+ omission: "omission";
525
+ }>, z.ZodNumber>>;
417
526
  regressed_examples: z.ZodArray<z.ZodObject<{
418
527
  prompt: z.ZodString;
419
528
  old_score: z.ZodNumber;
420
529
  new_score: z.ZodNumber;
530
+ category: z.ZodOptional<z.ZodEnum<{
531
+ fallback: "fallback";
532
+ other: "other";
533
+ style: "style";
534
+ factual: "factual";
535
+ omission: "omission";
536
+ }>>;
421
537
  }, z.core.$strip>>;
422
538
  }, z.core.$strip>;
423
539
  training: z.ZodObject<{
@@ -445,6 +561,14 @@ export declare const runReportSchema: z.ZodObject<{
445
561
  training_example_count: z.ZodNullable<z.ZodNumber>;
446
562
  eval_examples_total: z.ZodNumber;
447
563
  eval_examples_used: z.ZodNumber;
564
+ eval_split: z.ZodOptional<z.ZodEnum<{
565
+ spec_examples: "spec_examples";
566
+ spec_holdout: "spec_holdout";
567
+ prebuilt_test: "prebuilt_test";
568
+ prebuilt_validation: "prebuilt_validation";
569
+ prebuilt_training: "prebuilt_training";
570
+ }>>;
571
+ eval_sample_seed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
448
572
  started_at: z.ZodString;
449
573
  completed_at: z.ZodString;
450
574
  elapsed_ms: z.ZodNumber;
@@ -474,8 +598,8 @@ export declare const localRunnerConfigSchema: z.ZodObject<{
474
598
  evaluation: z.ZodDefault<z.ZodObject<{
475
599
  mode: z.ZodDefault<z.ZodEnum<{
476
600
  command: "command";
477
- heuristic: "heuristic";
478
601
  llm_judge: "llm_judge";
602
+ heuristic: "heuristic";
479
603
  }>>;
480
604
  baselineCommand: z.ZodOptional<z.ZodArray<z.ZodString>>;
481
605
  candidateCommand: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -515,6 +639,9 @@ export declare const localRunnerConfigSchema: z.ZodObject<{
515
639
  }, z.core.$strip>>;
516
640
  timeoutMs: z.ZodDefault<z.ZodNumber>;
517
641
  maxExamples: z.ZodOptional<z.ZodNumber>;
642
+ sampleSeed: z.ZodOptional<z.ZodNumber>;
643
+ allowPrebuiltTrainingEval: z.ZodDefault<z.ZodBoolean>;
644
+ baselineCache: z.ZodDefault<z.ZodBoolean>;
518
645
  }, z.core.$strip>>;
519
646
  llm: z.ZodOptional<z.ZodObject<{
520
647
  provider: z.ZodDefault<z.ZodLiteral<"openrouter">>;
@@ -531,6 +658,7 @@ export type FineTuneHyperparameters = z.infer<typeof fineTuneHyperparametersSche
531
658
  export type FineTuneRunRequest = z.infer<typeof fineTuneRunRequestSchema>;
532
659
  export type LocalBehaviorSpecFile = z.infer<typeof localBehaviorSpecFileSchema>;
533
660
  export type EvalExampleResult = z.infer<typeof evalExampleResultSchema>;
661
+ export type EvalSplit = z.infer<typeof evalSplitSchema>;
534
662
  export type EvalReport = z.infer<typeof evalReportSchema>;
535
663
  export type ComparisonReport = z.infer<typeof comparisonReportSchema>;
536
664
  export type TrainingReport = z.infer<typeof trainingReportSchema>;