@statelyai/agent 2.0.0-alpha.31 → 2.0.0-alpha.33

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 (62) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/ai-sdk.cjs +3 -3
  3. package/dist/ai-sdk.d.cts +1 -1
  4. package/dist/ai-sdk.d.mts +1 -1
  5. package/dist/ai-sdk.mjs +3 -3
  6. package/dist/{decision-Iys2hzg3.cjs → decision-BPdEaxPf.cjs} +1 -1
  7. package/dist/{decision-DqO018Tp.mjs → decision-CV7WiV5C.mjs} +1 -1
  8. package/dist/{event-log-Bdww2l1D.cjs → event-log-CKWeC7H-.cjs} +22 -3
  9. package/dist/{event-log-DE430ZCa.mjs → event-log-DAqsalT1.mjs} +22 -3
  10. package/dist/{event-log-store-CCWdTPEP.mjs → event-log-store-BGehvVTb.mjs} +2 -2
  11. package/dist/{event-log-store-DTf_OzB-.d.cts → event-log-store-C2NjVlWU.d.mts} +13 -5
  12. package/dist/{event-log-store-BWMLi6oh.cjs → event-log-store-DKyE7JKr.cjs} +2 -2
  13. package/dist/{event-log-store-RziIobdW.d.mts → event-log-store-s73r1Hxf.d.cts} +13 -5
  14. package/dist/index.cjs +5 -5
  15. package/dist/index.d.cts +9 -8
  16. package/dist/index.d.mts +9 -8
  17. package/dist/index.mjs +5 -5
  18. package/dist/log.cjs +40 -5
  19. package/dist/log.d.cts +1 -1
  20. package/dist/log.d.mts +1 -1
  21. package/dist/log.mjs +40 -5
  22. package/dist/machines.cjs +1 -1
  23. package/dist/machines.mjs +1 -1
  24. package/dist/{model-source-DQ7KgJaT.cjs → model-source-BQ97_l1-.cjs} +1 -1
  25. package/dist/{model-source-CXsSZPq0.mjs → model-source-BilDEyqk.mjs} +1 -1
  26. package/dist/openai.cjs +2 -2
  27. package/dist/openai.d.cts +1 -1
  28. package/dist/openai.d.mts +1 -1
  29. package/dist/openai.mjs +2 -2
  30. package/dist/otel.d.cts +1 -1
  31. package/dist/otel.d.mts +1 -1
  32. package/dist/{run-agent-DWZ1uyBJ.mjs → run-agent-2UnSUhDb.mjs} +7 -5
  33. package/dist/{run-agent-D4MwS5GY.d.mts → run-agent-Atu-wEk7.d.mts} +3 -3
  34. package/dist/{run-agent-B5opVUxx.d.cts → run-agent-B5QhabdY.d.cts} +3 -3
  35. package/dist/{run-agent-tmk58M0x.cjs → run-agent-Cg0xd3K-.cjs} +7 -5
  36. package/dist/{setup-agent-yFFVXf5s.d.cts → setup-agent-BiF1N3td.d.cts} +2 -2
  37. package/dist/{setup-agent-BaffhCcM.mjs → setup-agent-CmhB-U5P.mjs} +2 -2
  38. package/dist/{setup-agent-D0L8Anl_.cjs → setup-agent-CwUJyqKB.cjs} +2 -2
  39. package/dist/{setup-agent-CPyg2ic7.d.mts → setup-agent-J9f_Wu5T.d.mts} +2 -2
  40. package/dist/tanstack-ai.cjs +3 -3
  41. package/dist/tanstack-ai.d.cts +1 -1
  42. package/dist/tanstack-ai.d.mts +1 -1
  43. package/dist/tanstack-ai.mjs +3 -3
  44. package/dist/testing.cjs +495 -5
  45. package/dist/testing.d.cts +389 -5
  46. package/dist/testing.d.mts +389 -5
  47. package/dist/testing.mjs +491 -6
  48. package/dist/{text-logic-j9hShB7d.d.cts → text-logic-CYP502VT.d.cts} +5 -3
  49. package/dist/{text-logic-BwdrDpO9.d.mts → text-logic-DuK9HIFM.d.mts} +5 -3
  50. package/dist/{usage-BYqv7VBw.d.cts → usage-D7JKAxLc.d.mts} +1 -1
  51. package/dist/{usage-Bl4nK8D-.d.mts → usage-DVw-646x.d.cts} +1 -1
  52. package/dist/validate.cjs +3 -3
  53. package/dist/validate.d.cts +2 -2
  54. package/dist/validate.d.mts +2 -2
  55. package/dist/validate.mjs +3 -3
  56. package/dist/{verify-tkymWz6X.d.mts → verify-BVz4cURF.d.mts} +1 -1
  57. package/dist/{verify-CS_xxvVU.cjs → verify-CS_WLRXn.cjs} +19 -3
  58. package/dist/{verify-BH5e0XLK.mjs → verify-DgB8P-Wx.mjs} +14 -4
  59. package/dist/{verify-CPKDPMwY.d.cts → verify-Dk3Vwnha.d.cts} +1 -1
  60. package/package.json +1 -1
  61. package/skills/add-evals/SKILL.md +8 -2
  62. package/skills/improve-machine/SKILL.md +1 -1
@@ -1,7 +1,7 @@
1
- import { P as AgentExecutorDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-BwdrDpO9.mjs";
2
- import { f as AgentRuntimeOptions, l as AgentRunResult, o as AgentRunInit } from "./run-agent-D4MwS5GY.mjs";
1
+ import { P as AgentExecutorDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-DuK9HIFM.mjs";
2
+ import { f as AgentRuntimeOptions, l as AgentRunResult, o as AgentRunInit } from "./run-agent-Atu-wEk7.mjs";
3
3
  import { t as MetaOfSnapshot } from "./utils-BnXdWih3.mjs";
4
- import { _ as assertAgentMachine, a as AgentPathTerminal, b as lintAgentMachine, c as CanReachResult, d as ExploreSnapshot, f as LintAgentMachineOptions, g as SimulationTrailEntry, h as SimulationScript, i as AgentPathReport, l as CanReachTarget, m as SimulateAgentResult, n as AgentLintError, o as AgentUnknownStateError, p as SimulateAgentOptions, r as AgentLintSeverity, s as AssertAgentMachineOptions, t as AgentLintDiagnostic, u as ExplorePathsOptions, v as canReach, x as simulateAgent, y as explorePaths } from "./verify-tkymWz6X.mjs";
4
+ import { _ as assertAgentMachine, a as AgentPathTerminal, b as lintAgentMachine, c as CanReachResult, d as ExploreSnapshot, f as LintAgentMachineOptions, g as SimulationTrailEntry, h as SimulationScript, i as AgentPathReport, l as CanReachTarget, m as SimulateAgentResult, n as AgentLintError, o as AgentUnknownStateError, p as SimulateAgentOptions, r as AgentLintSeverity, s as AssertAgentMachineOptions, t as AgentLintDiagnostic, u as ExplorePathsOptions, v as canReach, x as simulateAgent, y as explorePaths } from "./verify-BVz4cURF.mjs";
5
5
  import { AnyStateMachine, EventFromLogic, InputFrom, SnapshotFrom, StateValue } from "xstate";
6
6
  //#region src/trajectory.d.ts
7
7
  /** An event-shaped trajectory item: anything with a string `type`. */
@@ -290,16 +290,25 @@ interface StateStats {
290
290
  withheld: number;
291
291
  /** Events this state ignored (`machine.transition` with `ignored`), summed over runs. */
292
292
  ignored: number;
293
+ /** Failed runs `blame` attributed to this state. 0 without `blame`. */
294
+ blamed: number;
293
295
  }
294
296
  /** Options for {@link foldTraces}. */
295
297
  interface FoldTracesOptions<TTrace> {
296
298
  /** Whether a run failed, judged from its whole trace. */
297
299
  failed: (trace: TTrace) => boolean;
300
+ /**
301
+ * The state a failed run's failure started in, usually
302
+ * `firstDivergence(trace, reference)?.state`. Called for failed runs only;
303
+ * `undefined` blames no state.
304
+ */
305
+ blame?: (trace: TTrace) => string | undefined;
298
306
  }
299
307
  /**
300
308
  * Folds many runs' traces into per-state stats: how many runs visited each
301
309
  * state, how many of those failed, how many options the guards withheld
302
- * at decisions made there, and how many events it ignored. Pure; reads only:
310
+ * at decisions made there, how many events it ignored, and how many failures
311
+ * `blame` traced back to it. Pure; reads only:
303
312
  *
304
313
  * - `machine.transition`: the run visited `from.value` and `snapshot.value`;
305
314
  * with `ignored`, each of those states ignored one event.
@@ -312,6 +321,10 @@ interface FoldTracesOptions<TTrace> {
312
321
  * `{ type: 'request.start', request: result.request }` onto the trace before
313
322
  * sending its event. Parallel states count once per active leaf.
314
323
  *
324
+ * `failures` counts a failed run against every state it visited, so states
325
+ * after a bad decision rank as high as the decision. Sort by `blamed` to see
326
+ * where failures start.
327
+ *
315
328
  * @example
316
329
  * ```ts no-check
317
330
  * const stats = foldTraces(traces, {
@@ -323,6 +336,178 @@ export declare function foldTraces<TTrace extends readonly {
323
336
  readonly type: string;
324
337
  }[]>(traces: Iterable<TTrace>, options: FoldTracesOptions<TTrace>): StateStats[];
325
338
  //#endregion
339
+ //#region src/trace-coverage.d.ts
340
+ /** One state's row in a {@link CoverageReport}. */
341
+ interface StateCoverage {
342
+ /** The state's dot-joined path from the root, e.g. `'deciding'` or `'work.review'`. */
343
+ state: string;
344
+ /** Runs that were in this state at least once. */
345
+ runs: number;
346
+ }
347
+ /** A handler: the state node that declares it and its event descriptor. */
348
+ interface HandlerRef {
349
+ /** The declaring state's dot path; `''` for the machine root. */
350
+ state: string;
351
+ /** The descriptor as XState keys it: `'APPROVE'`, `'task.*'`, `'*'`, `'xstate.done.actor'`, `'xstate.error.actor'`, `'xstate.after'`. */
352
+ event: string;
353
+ }
354
+ /** One handler's row in a {@link CoverageReport}. */
355
+ interface HandlerCoverage extends HandlerRef {
356
+ /** Runs in which this handler was credited at least once. */
357
+ runs: number;
358
+ targets: {
359
+ /** Target state paths of the object transitions under this descriptor; `'dynamic'` when any is a function transition. */
360
+ declared: string[] | "dynamic";
361
+ /** Active leaves observed right after a step credited to this handler. */
362
+ seen: string[];
363
+ /** Declared targets that no seen leaf is in. Empty when `declared` is `'dynamic'`. */
364
+ unreached: string[];
365
+ };
366
+ }
367
+ /** The result of {@link traceCoverage}. */
368
+ interface CoverageReport {
369
+ /** Every atomic and final state, in document order, including `runs: 0`. */
370
+ states: StateCoverage[];
371
+ /** Every observable handler, in document order, including `runs: 0`. */
372
+ handlers: HandlerCoverage[];
373
+ /** States no run visited, excluding `unreachable` ones. */
374
+ unvisitedStates: string[];
375
+ /** Handlers no run was credited with. */
376
+ unvisitedHandlers: HandlerRef[];
377
+ /** `always` handlers: they fire inside a macrostep, which a trace does not record. */
378
+ unobservable: HandlerRef[];
379
+ /**
380
+ * With a complete `reachable` report: states no explored path reached and
381
+ * no trace visited. They leave the state denominator.
382
+ */
383
+ unreachable?: string[];
384
+ /**
385
+ * With `reachable`: whether the report explored every path. When `false`,
386
+ * a state it missed may still be reachable, so `unreachable` is absent and
387
+ * every state stays in the denominator.
388
+ */
389
+ reachableComplete?: boolean;
390
+ /** Visited over total, for states and for handlers (unobservable excluded). 1 when the total is 0. */
391
+ ratio: {
392
+ states: number;
393
+ handlers: number;
394
+ };
395
+ }
396
+ /** Options for {@link traceCoverage}. */
397
+ interface TraceCoverageOptions {
398
+ /**
399
+ * An `explorePaths` report. When it explored every path (no cap hit, every
400
+ * payload expanded, no branch stopped early), states it never reached drop
401
+ * out of the state denominator.
402
+ */
403
+ reachable?: AgentPathReport;
404
+ }
405
+ /**
406
+ * Measures how much of a machine a set of runs exercised: which atomic and
407
+ * final states they visited, and which handlers they took. A handler is a
408
+ * `(declaring state, event descriptor)` pair from `on`, invoke
409
+ * `onDone`/`onError`, and `after`, with the targets it declares and the
410
+ * leaves the runs landed in after it. Pure; reads only `machine.transition`
411
+ * events, live (`AgentTraceEvent`) or serialized (`serializeTraceEvent`).
412
+ *
413
+ * A step credits one handler per active leaf: the nearest node, from the leaf
414
+ * up, whose exact, partial (`a.*`), or wildcard (`*`) descriptor matches the
415
+ * event, preferred in XState's order. Guards are not replayed, so a step
416
+ * whose nearest handler was rejected and fell through to an ancestor is
417
+ * credited to the nearest one. XState keys invoke and `after` handlers by
418
+ * bare type (`xstate.done.actor`), one per state however many invokes; a
419
+ * definition's `matches` (an invoke's `actorId`) must accept the traced event
420
+ * for its state to be credited. Ignored steps credit no handler. `always`
421
+ * handlers are listed as `unobservable`, never as unvisited.
422
+ *
423
+ * @example
424
+ * ```ts no-check
425
+ * const report = traceCoverage(machine, traces, { reachable: await explorePaths(machine) });
426
+ * expect(report.unvisitedHandlers).toEqual([]);
427
+ * ```
428
+ */
429
+ export declare function traceCoverage<TTrace extends readonly {
430
+ readonly type: string;
431
+ }[]>(machine: AnyStateMachine, traces: Iterable<TTrace>, options?: TraceCoverageOptions): CoverageReport;
432
+ //#endregion
433
+ //#region src/internal/trace-states.d.ts
434
+ /** One macrostep read from a trace: a `machine.transition` event. */
435
+ interface TraceStep {
436
+ /** Active leaves before the step. */
437
+ from: string[];
438
+ /** The state value before the step, as traced. */
439
+ fromValue: unknown;
440
+ /** The event's `type`. */
441
+ event: string;
442
+ /** The event object, as traced. */
443
+ payload: unknown;
444
+ /** Active leaves after the step. */
445
+ to: string[];
446
+ /** The state value after the step, as traced. */
447
+ toValue: unknown;
448
+ /** The state had no transition for a host event, so nothing changed. */
449
+ ignored: boolean;
450
+ /** The `name` of the first-attempt decision request that started since the previous step. */
451
+ decision?: string;
452
+ }
453
+ //#endregion
454
+ //#region src/first-divergence.d.ts
455
+ /** Options for {@link firstDivergence}. */
456
+ interface FirstDivergenceOptions {
457
+ /**
458
+ * Projects a step to the key two traces are compared by. Default
459
+ * `from|event|to`. Override to leave out what may differ between equivalent
460
+ * runs, such as a parallel region that only logs. Steps are still compared
461
+ * in order. Trace references only.
462
+ */
463
+ key?: (step: TraceStep) => string;
464
+ }
465
+ /** Where a run first departs from its reference. See {@link firstDivergence}. */
466
+ interface Divergence {
467
+ /** The step's index in the run's steps, or the step count when the run ended early. */
468
+ index: number;
469
+ /** The state the run was in when it departed: the first active leaf before that step. */
470
+ state: string;
471
+ /** The decision request that chose that step's event, when one did. */
472
+ decision?: string;
473
+ /** The run's step. Absent when the run ended early. */
474
+ actual?: TraceStep;
475
+ /** The reference's step, or the expected trajectory item the run never reached. Absent when the run went on past a reference trace. */
476
+ expected?: TraceStep | TrajectoryItem;
477
+ }
478
+ /**
479
+ * Finds the first step where a run departs from a reference, so a failure is
480
+ * blamed on the state it started in rather than on every state the run went
481
+ * through afterwards.
482
+ *
483
+ * - Against a reference **trace**, such as a passing run of the same
484
+ * scenario, steps are compared in order by `key`. The first step that
485
+ * differs, or the point where either trace ends early, is the divergence.
486
+ * - Against an expected **trajectory** (`TrajectoryItem[]`, as for
487
+ * {@link matchesTrajectory}), the run is laid out as its initial state, then
488
+ * each step's event and new state. The first expected item it never reaches
489
+ * is the divergence, blamed on the step after the last item it did reach. A
490
+ * run that goes on past the trajectory has not diverged.
491
+ *
492
+ * An empty reference is a trace with no steps, so any step diverges from it.
493
+ * A trace is one run's events, live or serialized. Steps the machine ignored
494
+ * changed nothing and are left out on both sides. Returns `undefined` when the
495
+ * run does not diverge.
496
+ *
497
+ * @example
498
+ * ```ts no-check
499
+ * const stats = foldTraces(traces, {
500
+ * failed,
501
+ * blame: (trace) => firstDivergence(trace, passingRunFor(trace))?.state,
502
+ * });
503
+ * ```
504
+ */
505
+ export declare function firstDivergence(actual: readonly {
506
+ readonly type: string;
507
+ }[], reference: readonly {
508
+ readonly type: string;
509
+ }[] | readonly TrajectoryItem[], options?: FirstDivergenceOptions): Divergence | undefined;
510
+ //#endregion
326
511
  //#region src/decision-requests.d.ts
327
512
  /** One decision a run asked for. See {@link getDecisionRequests}. */
328
513
  interface TracedDecisionRequest {
@@ -357,6 +542,205 @@ export declare function getDecisionRequests(trace: Iterable<{
357
542
  readonly type: string;
358
543
  }>, options?: GetDecisionRequestsOptions): TracedDecisionRequest[];
359
544
  //#endregion
545
+ //#region src/repeat-runs.d.ts
546
+ type AnyTrace = readonly {
547
+ readonly type: string;
548
+ }[];
549
+ /** One run of a repeated scenario. See {@link summarizeRepeats}. */
550
+ interface RepeatRun<TTrace extends AnyTrace = AnyTrace> {
551
+ passed: boolean;
552
+ /** The run's trace. Absent for a run that threw. */
553
+ trace?: TTrace;
554
+ /** How the run ended, for the report. Not compared. */
555
+ outcome?: string;
556
+ /** The message of a run that threw. */
557
+ error?: string;
558
+ }
559
+ /** One scenario's runs. See {@link summarizeRepeats}. */
560
+ interface RepeatGroup<TScenario, TTrace extends AnyTrace = AnyTrace> {
561
+ id: string;
562
+ scenario: TScenario;
563
+ runs: readonly RepeatRun<TTrace>[];
564
+ }
565
+ /** One scenario's row in a {@link RepeatReport}. */
566
+ interface RepeatResult<TScenario, TTrace extends AnyTrace = AnyTrace> extends RepeatGroup<TScenario, TTrace> {
567
+ /** Runs that passed. */
568
+ passes: number;
569
+ /** At least one run passed: pass@k for this scenario. */
570
+ passAny: boolean;
571
+ /** Every run passed: pass^k for this scenario. */
572
+ passAll: boolean;
573
+ /** Distinct state paths the traced runs took. 1 when every run went the same way. */
574
+ distinctPaths: number;
575
+ /** The state where the runs first went different ways, judged against the first run whose trace has a transition. */
576
+ divergedAt?: string;
577
+ }
578
+ /** The result of {@link summarizeRepeats} and {@link repeatRuns}. */
579
+ interface RepeatReport<TScenario, TTrace extends AnyTrace = AnyTrace> {
580
+ scenarios: RepeatResult<TScenario, TTrace>[];
581
+ /**
582
+ * The suite's pass^j: the chance that `j` runs of a scenario, drawn from the
583
+ * ones recorded, all pass, averaged over scenarios. The unbiased estimate is
584
+ * C(passes, j) / C(runs, j) per scenario. Scenarios with fewer than `j` runs
585
+ * are left out. Throws when `j` is not a whole number from 1 to the most
586
+ * runs any scenario has.
587
+ */
588
+ passHat: (j: number) => number;
589
+ /** Every recorded trace, ready for `foldTraces` or `traceCoverage`. */
590
+ traces: TTrace[];
591
+ }
592
+ /** Options for {@link repeatRuns}. */
593
+ interface RepeatRunsOptions<TScenario extends {
594
+ id: string;
595
+ }, TTrace extends AnyTrace> {
596
+ scenarios: readonly TScenario[];
597
+ /** Runs per scenario. */
598
+ k: number;
599
+ /** Runs one scenario once and returns its trace. `attempt` counts from 0. */
600
+ run: (scenario: TScenario, attempt: number) => Promise<{
601
+ trace: TTrace;
602
+ outcome?: string;
603
+ }>;
604
+ /** Whether a run passed, judged from its ground truth. */
605
+ passed: (scenario: TScenario, result: {
606
+ trace: TTrace;
607
+ outcome?: string;
608
+ }) => boolean;
609
+ }
610
+ /**
611
+ * Summarizes repeated runs of each scenario: how often each passed, whether
612
+ * all its runs passed (pass^k), how many distinct state paths they took, and
613
+ * where they first went different ways. Pure. Use it for runs collected
614
+ * elsewhere, such as CI shards or replays; {@link repeatRuns} collects them and
615
+ * calls it.
616
+ *
617
+ * A scenario that passes 3 of 5 runs and `divergedAt: 'deciding'` points at one
618
+ * decision, not at a flaky agent.
619
+ *
620
+ * @example
621
+ * ```ts no-check
622
+ * const report = summarizeRepeats(shards.map((s) => ({ id: s.id, scenario: s, runs: s.runs })));
623
+ * report.passHat(3); // the chance 3 runs of a scenario all pass
624
+ * ```
625
+ */
626
+ export declare function summarizeRepeats<TScenario, TTrace extends AnyTrace = AnyTrace>(groups: readonly RepeatGroup<TScenario, TTrace>[]): RepeatReport<TScenario, TTrace>;
627
+ /**
628
+ * Runs every scenario `k` times and summarizes the runs with
629
+ * {@link summarizeRepeats}. Runs are sequential, scenario by scenario. A run
630
+ * that throws fails, with its message as `error` and no trace.
631
+ *
632
+ * With a live model, one run per scenario says little: τ-bench found pass^k
633
+ * falls well below the single-run rate. Report pass^k next to it.
634
+ *
635
+ * @example
636
+ * ```ts no-check
637
+ * const report = await repeatRuns({
638
+ * scenarios,
639
+ * k: 5,
640
+ * run: async (scenario) => {
641
+ * const trace: AgentTraceEvent[] = [];
642
+ * const result = await runToQuiescence(
643
+ * createAgentRuntime(machine, { executors, onTrace: (event) => trace.push(event) }),
644
+ * { input: scenario.input },
645
+ * );
646
+ * return { trace, outcome: String(result.snapshot.value) };
647
+ * },
648
+ * passed: (scenario, { outcome }) => outcome === scenario.expected,
649
+ * });
650
+ * report.passHat(5);
651
+ * ```
652
+ */
653
+ export declare function repeatRuns<TScenario extends {
654
+ id: string;
655
+ }, TTrace extends AnyTrace>(options: RepeatRunsOptions<TScenario, TTrace>): Promise<RepeatReport<TScenario, TTrace>>;
656
+ //#endregion
657
+ //#region src/judge-agreement.d.ts
658
+ /** One labeled case: what a person said and what the judge said. See {@link judgeAgreement}. */
659
+ interface AgreementRow {
660
+ /** Identifies the case in `disagreements`. */
661
+ id: string;
662
+ /** The confirmed human label. */
663
+ human: string;
664
+ /** The judge's label for the same case. */
665
+ judge: string;
666
+ /** The group the row is aligned in, e.g. a decision state or request name. `groupBy` overrides it. */
667
+ group?: string;
668
+ }
669
+ /** Agreement numbers for one set of rows. See {@link AgreementReport}. */
670
+ interface AgreementSummary {
671
+ /** Rows counted. */
672
+ total: number;
673
+ /** Share of rows where `judge` equals `human`. */
674
+ accuracy: number;
675
+ /** Per human label: rows with that label, and how many the judge matched. `agreed / human` is that label's recall. */
676
+ perLabel: Record<string, {
677
+ human: number;
678
+ agreed: number;
679
+ }>;
680
+ /** Counts by human label, then judge label. */
681
+ confusion: Record<string, Record<string, number>>;
682
+ /** Rows where the judge differs from the person, in input order. */
683
+ disagreements: {
684
+ id: string;
685
+ human: string;
686
+ judge: string;
687
+ }[];
688
+ /**
689
+ * With `positive` set: the true positive rate (judge says positive when the
690
+ * person did) and true negative rate (judge says any other label when the
691
+ * person did). A rate is `undefined` when no row has that human side.
692
+ */
693
+ binary?: {
694
+ tpr: number | undefined;
695
+ tnr: number | undefined;
696
+ };
697
+ /**
698
+ * With `positive` set: estimates the true share of positives among
699
+ * unlabeled rows from the share `p` the judge labeled positive,
700
+ * θ = (p + TNR − 1) / (TPR + TNR − 1), clamped to [0, 1]. Omitted when
701
+ * either rate is `undefined`, or when TPR + TNR ≤ 1: the judge is no better
702
+ * than chance, so its labels carry no signal to correct.
703
+ */
704
+ correct?: (observedPositiveRate: number) => number;
705
+ }
706
+ /** The result of {@link judgeAgreement}. */
707
+ interface AgreementReport extends AgreementSummary {
708
+ /** The same numbers per group. Present when any row has `group` or `groupBy` is given. */
709
+ groups?: Record<string, AgreementSummary>;
710
+ }
711
+ /** Options for {@link judgeAgreement}. */
712
+ interface JudgeAgreementOptions<TRow extends AgreementRow> {
713
+ /** The positive label. Every other label is negative. Turns on `binary` and `correct`. */
714
+ positive?: string;
715
+ /** The row's group, overriding `row.group`. Return `undefined` to leave the row out of every group. */
716
+ groupBy?: (row: TRow) => string | undefined;
717
+ }
718
+ /**
719
+ * Measures how well a judge agrees with people on the same cases: accuracy,
720
+ * per-label recall, the confusion matrix, and the rows that disagree. With
721
+ * `positive`, also the TPR and TNR, the recommended view for binary judges
722
+ * (Husain/Shankar), and a correction for the judge's bias on unlabeled rows.
723
+ * Pure.
724
+ *
725
+ * Build rows from confirmed labels only; draft labels gate nothing. Group by
726
+ * decision state or request name so each narrow judge is aligned on its own.
727
+ * A row with no group key counts in the totals and in no group. Run it on a
728
+ * dev split and report the held-out split separately.
729
+ *
730
+ * Throws `AgentError` with code `'empty-agreement-rows'` when `rows` is empty.
731
+ *
732
+ * @example
733
+ * ```ts no-check
734
+ * const report = judgeAgreement(
735
+ * labeled.map((s) => ({ id: s.id, human: s.label, judge: verdicts[s.id], group: s.request })),
736
+ * { positive: 'fail' },
737
+ * );
738
+ * report.binary; // { tpr: 0.9, tnr: 0.8 }
739
+ * report.correct?.(0.3); // estimated true failure rate in production
740
+ * ```
741
+ */
742
+ export declare function judgeAgreement<TRow extends AgreementRow>(rows: readonly TRow[], options?: JudgeAgreementOptions<TRow>): AgreementReport;
743
+ //#endregion
360
744
  //#region src/compare-runs.d.ts
361
745
  /** One run of one scenario, reduced to what parity compares. See {@link compareRuns}. */
362
746
  interface ParityRun {
@@ -438,4 +822,4 @@ export declare function compareRuns<TScenario extends {
438
822
  expected?: string;
439
823
  }>(options: CompareRunsOptions<TScenario>): Promise<ParityReport<TScenario>>;
440
824
  //#endregion
441
- export { type AgentLintDiagnostic, AgentLintError, type AgentLintSeverity, type AgentPathReport, type AgentPathTerminal, AgentUnknownStateError, type AssertAgentMachineOptions, type CanReachResult, type CanReachTarget, type CompareRunsOptions, type ExplorePathsOptions, type ExploreSnapshot, type FoldTracesOptions, type GetDecisionRequestsOptions, type LintAgentMachineOptions, type MatchTrajectoryOptions, type ParityLabel, type ParityReport, type ParityResult, type ParityRun, type RunSeamOptions, type RunSeamResult, type SeamCall, type SeamRef, type SeamScriptEntry, type SeamSlice, type SeamTurn, type SimulateAgentOptions, type SimulateAgentResult, type SimulationScript, type SimulationTrailEntry, type StateStats, type TracedDecisionRequest, type TrajectoryEvent, type TrajectoryItem, type TrajectoryMatch, type TrajectoryMiss, assertAgentMachine, canReach, explorePaths, lintAgentMachine, simulateAgent };
825
+ export { type AgentLintDiagnostic, AgentLintError, type AgentLintSeverity, type AgentPathReport, type AgentPathTerminal, AgentUnknownStateError, type AgreementReport, type AgreementRow, type AgreementSummary, type AssertAgentMachineOptions, type CanReachResult, type CanReachTarget, type CompareRunsOptions, type CoverageReport, type Divergence, type ExplorePathsOptions, type ExploreSnapshot, type FirstDivergenceOptions, type FoldTracesOptions, type GetDecisionRequestsOptions, type HandlerCoverage, type HandlerRef, type JudgeAgreementOptions, type LintAgentMachineOptions, type MatchTrajectoryOptions, type ParityLabel, type ParityReport, type ParityResult, type ParityRun, type RepeatGroup, type RepeatReport, type RepeatResult, type RepeatRun, type RepeatRunsOptions, type RunSeamOptions, type RunSeamResult, type SeamCall, type SeamRef, type SeamScriptEntry, type SeamSlice, type SeamTurn, type SimulateAgentOptions, type SimulateAgentResult, type SimulationScript, type SimulationTrailEntry, type StateCoverage, type StateStats, type TraceCoverageOptions, type TraceStep, type TracedDecisionRequest, type TrajectoryEvent, type TrajectoryItem, type TrajectoryMatch, type TrajectoryMiss, assertAgentMachine, canReach, explorePaths, lintAgentMachine, simulateAgent };