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

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 (69) hide show
  1. package/CHANGELOG.md +1733 -0
  2. package/dist/ai-sdk.cjs +9 -9
  3. package/dist/ai-sdk.d.cts +5 -5
  4. package/dist/ai-sdk.d.mts +5 -5
  5. package/dist/ai-sdk.mjs +4 -4
  6. package/dist/{decision-Bl_rKQnU.mjs → decision-DqO018Tp.mjs} +23 -10
  7. package/dist/{decision-oevZnkBe.cjs → decision-Iys2hzg3.cjs} +31 -18
  8. package/dist/{event-log-Dtb16p1p.cjs → event-log-Bdww2l1D.cjs} +104 -25
  9. package/dist/{event-log-GPZO9p7_.mjs → event-log-DE430ZCa.mjs} +87 -26
  10. package/dist/{event-log-store-bCdskPNS.cjs → event-log-store-BWMLi6oh.cjs} +1 -1
  11. package/dist/{event-log-store-yalq8C77.mjs → event-log-store-CCWdTPEP.mjs} +1 -1
  12. package/dist/{event-log-store-CN9ygggF.d.cts → event-log-store-DTf_OzB-.d.cts} +1 -1
  13. package/dist/{event-log-store-DS836wch.d.mts → event-log-store-RziIobdW.d.mts} +1 -1
  14. package/dist/index.cjs +136 -23
  15. package/dist/index.d.cts +58 -11
  16. package/dist/index.d.mts +58 -11
  17. package/dist/index.mjs +133 -21
  18. package/dist/log.cjs +2 -2
  19. package/dist/log.d.cts +1 -1
  20. package/dist/log.d.mts +1 -1
  21. package/dist/log.mjs +2 -2
  22. package/dist/machines.cjs +1 -1
  23. package/dist/machines.mjs +1 -1
  24. package/dist/{model-source-C7FFP2Sj.mjs → model-source-CXsSZPq0.mjs} +1 -2
  25. package/dist/{model-source-DjJPjGSP.cjs → model-source-DQ7KgJaT.cjs} +4 -5
  26. package/dist/openai.cjs +3 -3
  27. package/dist/openai.d.cts +2 -2
  28. package/dist/openai.d.mts +2 -2
  29. package/dist/openai.mjs +3 -3
  30. package/dist/otel.d.cts +1 -1
  31. package/dist/otel.d.mts +1 -1
  32. package/dist/{run-agent-C9ubX8Tx.d.cts → run-agent-B5opVUxx.d.cts} +25 -6
  33. package/dist/{run-agent-CxSyZmIE.d.mts → run-agent-D4MwS5GY.d.mts} +25 -6
  34. package/dist/{run-agent-CuQT1xSS.mjs → run-agent-DWZ1uyBJ.mjs} +100 -37
  35. package/dist/{run-agent-cToZ3K42.cjs → run-agent-tmk58M0x.cjs} +100 -37
  36. package/dist/{setup-agent-DniLvDu7.mjs → setup-agent-BaffhCcM.mjs} +38 -3
  37. package/dist/{setup-agent-tsc3vm5I.d.mts → setup-agent-CPyg2ic7.d.mts} +11 -3
  38. package/dist/{setup-agent-DTF3NQg3.cjs → setup-agent-D0L8Anl_.cjs} +38 -3
  39. package/dist/{setup-agent-DlbgwsIJ.d.cts → setup-agent-yFFVXf5s.d.cts} +11 -3
  40. package/dist/tanstack-ai.cjs +3 -3
  41. package/dist/tanstack-ai.d.cts +2 -2
  42. package/dist/tanstack-ai.d.mts +2 -2
  43. package/dist/tanstack-ai.mjs +3 -3
  44. package/dist/testing.cjs +176 -26
  45. package/dist/testing.d.cts +128 -10
  46. package/dist/testing.d.mts +128 -10
  47. package/dist/testing.mjs +168 -20
  48. package/dist/{text-logic-BDbGjYMh.d.mts → text-logic-BwdrDpO9.d.mts} +6 -2
  49. package/dist/{text-logic-9fv1i9aK.d.cts → text-logic-j9hShB7d.d.cts} +6 -2
  50. package/dist/{usage-D8UphgEA.d.mts → usage-BYqv7VBw.d.cts} +1 -1
  51. package/dist/{usage-R1NTmLxY.d.cts → usage-Bl4nK8D-.d.mts} +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-B5qGC5WN.mjs → verify-BH5e0XLK.mjs} +55 -5
  57. package/dist/{verify-DYH_2VzU.d.cts → verify-CPKDPMwY.d.cts} +14 -6
  58. package/dist/{verify-Cqghu4gz.cjs → verify-CS_xxvVU.cjs} +57 -7
  59. package/dist/{verify-CBuYIpsa.d.mts → verify-tkymWz6X.d.mts} +14 -6
  60. package/package.json +34 -4
  61. package/readme.md +72 -42
  62. package/skills/add-evals/SKILL.md +144 -0
  63. package/skills/add-traces/SKILL.md +147 -0
  64. package/skills/generate-machine/SKILL.md +6 -6
  65. package/skills/graph-engineering/SKILL.md +33 -0
  66. package/skills/improve-machine/SKILL.md +73 -21
  67. package/skills/improve-machine/reference.md +12 -7
  68. package/skills/loop-to-machine/SKILL.md +210 -0
  69. package/skills/loop-to-machine/policy.md +154 -0
package/dist/testing.cjs CHANGED
@@ -1,8 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_log = require("./event-log-Dtb16p1p.cjs");
3
- const require_decision = require("./decision-oevZnkBe.cjs");
4
- const require_run_agent = require("./run-agent-cToZ3K42.cjs");
5
- const require_verify = require("./verify-Cqghu4gz.cjs");
2
+ const require_event_log = require("./event-log-Bdww2l1D.cjs");
3
+ const require_run_agent = require("./run-agent-tmk58M0x.cjs");
4
+ const require_verify = require("./verify-CS_xxvVU.cjs");
6
5
  //#region src/trajectory.ts
7
6
  /**
8
7
  * Classifies one item. Event-shaped things (log entries, events) become events;
@@ -10,9 +9,9 @@ const require_verify = require("./verify-Cqghu4gz.cjs");
10
9
  * @internal
11
10
  */
12
11
  function normalize(item) {
13
- if (require_decision.isRecord(item)) {
12
+ if (require_event_log.isRecord(item)) {
14
13
  const nested = item["event"];
15
- if (require_decision.isRecord(nested) && typeof nested["type"] === "string") return {
14
+ if (require_event_log.isRecord(nested) && typeof nested["type"] === "string") return {
16
15
  kind: "event",
17
16
  event: nested
18
17
  };
@@ -33,7 +32,7 @@ function normalize(item) {
33
32
  /** Every leaf of a state value as a dot path (`{ review: 'editing' }` → `review.editing`). @internal */
34
33
  function statePaths$1(value) {
35
34
  if (typeof value === "string") return [value];
36
- if (!require_decision.isRecord(value)) return [];
35
+ if (!require_event_log.isRecord(value)) return [];
37
36
  return Object.entries(value).flatMap(([key, child]) => statePaths$1(child).map((path) => `${key}.${path}`));
38
37
  }
39
38
  /**
@@ -46,7 +45,7 @@ function stateMatchesPath(path, value) {
46
45
  function deepEqual(a, b) {
47
46
  if (Object.is(a, b)) return true;
48
47
  if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => deepEqual(item, b[index]));
49
- if (!require_decision.isRecord(a) || !require_decision.isRecord(b)) return false;
48
+ if (!require_event_log.isRecord(a) || !require_event_log.isRecord(b)) return false;
50
49
  const keys = Object.keys(a);
51
50
  return keys.length === Object.keys(b).length && keys.every((key) => deepEqual(a[key], b[key]));
52
51
  }
@@ -178,7 +177,7 @@ function isTextResult(value) {
178
177
  */
179
178
  async function resolveSeamScriptEntry(entry, request, info) {
180
179
  const value = typeof entry === "function" ? await entry(request, info) : entry;
181
- return require_decision.isRecord(value) && isTextResult(value) ? value : { result: value };
180
+ return require_event_log.isRecord(value) && isTextResult(value) ? value : { result: value };
182
181
  }
183
182
  /** Names a pending text request in an error message. @internal */
184
183
  function describeText(request) {
@@ -188,7 +187,7 @@ function describeText(request) {
188
187
  * Stream semantics with no model: the whole text lands as one chunk. @internal
189
188
  */
190
189
  function emitScriptedChunk(result, info) {
191
- const text = require_decision.isRecord(result) ? result["result"] : void 0;
190
+ const text = require_event_log.isRecord(result) ? result["result"] : void 0;
192
191
  if (typeof text === "string") info?.onChunk?.(text);
193
192
  }
194
193
  /**
@@ -196,7 +195,7 @@ function emitScriptedChunk(result, info) {
196
195
  * @internal
197
196
  */
198
197
  async function seamOutputOf(result, request) {
199
- if (!require_decision.isRecord(result)) return;
198
+ if (!require_event_log.isRecord(result)) return;
200
199
  return await require_event_log.normalizeGeneratorResult(result, `seam '${request.name ?? request.model}'`);
201
200
  }
202
201
  /**
@@ -321,7 +320,7 @@ async function runSeam(machine, options) {
321
320
  ...event ? { event } : {}
322
321
  });
323
322
  if (result.status !== "idle" || turn === maxTurns) break;
324
- const next = options.respond?.({
323
+ const next = await options.respond?.({
325
324
  snapshot: result.snapshot,
326
325
  state: result.snapshot.value,
327
326
  meta: require_event_log.getStateMeta(result.snapshot),
@@ -361,13 +360,36 @@ async function runSeam(machine, options) {
361
360
  };
362
361
  }
363
362
  //#endregion
363
+ //#region src/internal/trace-states.ts
364
+ /** The `value` of a trace event's `from` or `snapshot`. @internal */
365
+ function valueOf(holder) {
366
+ return require_event_log.isRecord(holder) ? holder.value : void 0;
367
+ }
368
+ /** A decision request on its first attempt (no failed attempts yet). @internal */
369
+ function isFirstDecision(request) {
370
+ return require_event_log.isRecord(request) && request.kind === "decision" && (!Array.isArray(request.attempts) || request.attempts.length === 0);
371
+ }
372
+ /**
373
+ * Every active leaf of a state value as a dot path:
374
+ * `'a'` → `['a']`; `{ a: 'b' }` → `['a.b']`; `{ p: { x: 'one', y: {} } }` → `['p.x.one', 'p.y']`.
375
+ * @internal
376
+ */
377
+ function statePaths(value, prefix = "") {
378
+ if (typeof value === "string") return [prefix + value];
379
+ if (!require_event_log.isRecord(value)) return [];
380
+ const entries = Object.entries(value);
381
+ if (entries.length === 0) return prefix ? [prefix.slice(0, -1)] : [];
382
+ return entries.flatMap(([key, child]) => statePaths(child, `${prefix}${key}.`));
383
+ }
384
+ //#endregion
364
385
  //#region src/fold-traces.ts
365
386
  /**
366
387
  * Folds many runs' traces into per-state stats: how many runs visited each
367
- * state, how many of those failed, and how many options the guards withheld
368
- * at decisions made there. Pure; reads only:
388
+ * state, how many of those failed, how many options the guards withheld
389
+ * at decisions made there, and how many events it ignored. Pure; reads only:
369
390
  *
370
- * - `machine.transition`: the run visited `from.value` and `snapshot.value`.
391
+ * - `machine.transition`: the run visited `from.value` and `snapshot.value`;
392
+ * with `ignored`, each of those states ignored one event.
371
393
  * - `request.start` of a decision, first attempt only: its `request.withheld`
372
394
  * counts toward the state the run was in, the `from.value` of the
373
395
  * transition its choice causes.
@@ -393,7 +415,8 @@ function foldTraces(traces, options) {
393
415
  state,
394
416
  visits: 0,
395
417
  failures: 0,
396
- withheld: 0
418
+ withheld: 0,
419
+ ignored: 0
397
420
  };
398
421
  stats.set(state, entry);
399
422
  }
@@ -410,6 +433,7 @@ function foldTraces(traces, options) {
410
433
  for (const state of statePaths(valueOf(event.from))) visit(state);
411
434
  current = statePaths(valueOf(event.snapshot));
412
435
  for (const state of current) visit(state);
436
+ if (event.ignored === true) for (const state of current) statsFor(state).ignored++;
413
437
  } else if (event.type === "request.start" && isFirstDecision(event.request)) {
414
438
  const withheld = event.request.withheld;
415
439
  if (!Array.isArray(withheld)) continue;
@@ -424,26 +448,152 @@ function foldTraces(traces, options) {
424
448
  }
425
449
  return [...stats.values()];
426
450
  }
427
- function valueOf(holder) {
428
- return require_decision.isRecord(holder) ? holder.value : void 0;
451
+ //#endregion
452
+ //#region src/decision-requests.ts
453
+ /**
454
+ * The decisions a run asked for, read from its trace: each decision's first
455
+ * `request.start`, with the states the run was in. A trace is one run's events,
456
+ * live or serialized with `serializeTraceEvent`. Retries of the same decision
457
+ * are left out, so each decision appears once.
458
+ *
459
+ * Use the requests as eval rows (run a decider on each and compare its event
460
+ * with a label) or as probe inputs for a policy. A serialized request keeps its
461
+ * `options`, `metadata`, `system`, and `prompt`; event schemas do not survive
462
+ * serialization, so replay closed choices (`options`) rather than open ones.
463
+ *
464
+ * @example
465
+ * ```ts no-check
466
+ * const rows = traces.flatMap((trace) => getDecisionRequests(trace, { name: "chooseResolution" }));
467
+ * for (const { request } of rows) console.log((await decide(request)).event);
468
+ * ```
469
+ */
470
+ function getDecisionRequests(trace, options = {}) {
471
+ const requests = [];
472
+ let current = [];
473
+ for (const event of trace) if (event.type === "machine.transition") current = statePaths(valueOf(event.snapshot));
474
+ else if (event.type === "request.start" && isFirstDecision(event.request)) {
475
+ if (options.name !== void 0 && event.request.name !== options.name) continue;
476
+ requests.push({
477
+ states: [...current],
478
+ request: event.request
479
+ });
480
+ }
481
+ return requests;
429
482
  }
430
- function isFirstDecision(request) {
431
- return require_decision.isRecord(request) && request.kind === "decision" && (!Array.isArray(request.attempts) || request.attempts.length === 0);
483
+ //#endregion
484
+ //#region src/compare-runs.ts
485
+ /**
486
+ * Runs every scenario through a baseline and a candidate implementation and
487
+ * labels each difference, so a port can show where it behaves like the code it
488
+ * replaces and where it differs on purpose.
489
+ *
490
+ * Parity is outcome-level: the terminal outcome and the effects in the world,
491
+ * not the sequence of tool calls, since a machine usually reorders steps. A
492
+ * candidate that broke no rule where the baseline broke one is intended, even
493
+ * when the outcome matches. A difference also counts as intended when only the
494
+ * candidate reached the scenario's `expected` outcome. Every other difference,
495
+ * and every candidate rule break, is a regression for a person to review.
496
+ *
497
+ * Runs are sequential, baseline first. A run that throws is recorded with
498
+ * outcome `'threw'` and the error message as its `detail`. Parity holds for
499
+ * these scenarios and these runs only; with a live model, run it more than once.
500
+ *
501
+ * @example
502
+ * ```ts no-check
503
+ * const report = await compareRuns({
504
+ * scenarios,
505
+ * baseline: async (s) => toParityRun(await runRawLoop(s)),
506
+ * candidate: async (s) => toParityRun(await runDesk(s)),
507
+ * });
508
+ * expect(report.ok).toBe(true);
509
+ * ```
510
+ */
511
+ async function compareRuns(options) {
512
+ const scenarios = [];
513
+ const counts = {
514
+ same: 0,
515
+ intended: 0,
516
+ regression: 0
517
+ };
518
+ for (const scenario of options.scenarios) {
519
+ const baseline = await settle(() => options.baseline(scenario));
520
+ const candidate = await settle(() => options.candidate(scenario));
521
+ const { label, reason } = labelRun(scenario.expected, baseline, candidate);
522
+ counts[label]++;
523
+ scenarios.push({
524
+ id: scenario.id,
525
+ scenario,
526
+ label,
527
+ reason,
528
+ baseline,
529
+ candidate
530
+ });
531
+ }
532
+ return {
533
+ scenarios,
534
+ counts,
535
+ ok: counts.regression === 0
536
+ };
432
537
  }
433
- function statePaths(value, prefix = "") {
434
- if (typeof value === "string") return [prefix + value];
435
- if (!require_decision.isRecord(value)) return [];
436
- const entries = Object.entries(value);
437
- if (entries.length === 0) return prefix ? [prefix.slice(0, -1)] : [];
438
- return entries.flatMap(([key, child]) => statePaths(child, `${prefix}${key}.`));
538
+ async function settle(run) {
539
+ try {
540
+ return await run();
541
+ } catch (error) {
542
+ return {
543
+ outcome: "threw",
544
+ detail: error instanceof Error ? error.message : String(error)
545
+ };
546
+ }
547
+ }
548
+ function labelRun(expected, baseline, candidate) {
549
+ if (candidate.violations?.length) return {
550
+ label: "regression",
551
+ reason: `candidate broke a rule: ${list(candidate.violations)}`
552
+ };
553
+ if (candidate.outcome === "threw") return {
554
+ label: "regression",
555
+ reason: `candidate threw: ${String(candidate.detail)}`
556
+ };
557
+ if (baseline.violations?.length) return {
558
+ label: "intended",
559
+ reason: `baseline broke a rule: ${list(baseline.violations)}`
560
+ };
561
+ const sameOutcome = baseline.outcome === candidate.outcome;
562
+ if (sameOutcome && structurallyEqual(baseline.effects, candidate.effects)) return {
563
+ label: "same",
564
+ reason: ""
565
+ };
566
+ if (expected !== void 0 && candidate.outcome === expected && baseline.outcome !== expected) return {
567
+ label: "intended",
568
+ reason: `only the candidate reached the expected '${expected}'`
569
+ };
570
+ return {
571
+ label: "regression",
572
+ reason: sameOutcome ? "effects differ" : `outcome differs: ${baseline.outcome} → ${candidate.outcome}`
573
+ };
574
+ }
575
+ function list(items) {
576
+ return items.map((item) => typeof item === "string" ? item : JSON.stringify(item)).join(", ");
577
+ }
578
+ function structurallyEqual(a, b) {
579
+ if (Object.is(a, b)) return true;
580
+ if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
581
+ if (a instanceof Map || b instanceof Map) return a instanceof Map && b instanceof Map && structurallyEqual([...a], [...b]);
582
+ if (a instanceof Set || b instanceof Set) return a instanceof Set && b instanceof Set && structurallyEqual([...a], [...b]);
583
+ if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, index) => structurallyEqual(item, b[index]));
584
+ if (!require_event_log.isRecord(a) || !require_event_log.isRecord(b)) return false;
585
+ const keys = Object.keys(a);
586
+ return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && structurallyEqual(a[key], b[key]));
439
587
  }
440
588
  //#endregion
441
589
  exports.AgentLintError = require_verify.AgentLintError;
442
590
  exports.AgentUnknownStateError = require_verify.AgentUnknownStateError;
443
591
  exports.assertAgentMachine = require_verify.assertAgentMachine;
444
592
  exports.canReach = require_verify.canReach;
593
+ exports.compareRuns = compareRuns;
445
594
  exports.explorePaths = require_verify.explorePaths;
446
595
  exports.foldTraces = foldTraces;
596
+ exports.getDecisionRequests = getDecisionRequests;
447
597
  exports.lintAgentMachine = require_verify.lintAgentMachine;
448
598
  exports.matchesTrajectory = matchesTrajectory;
449
599
  exports.runSeam = runSeam;
@@ -1,7 +1,7 @@
1
- import { c as AgentRequestExecutorInfo, f as AgentTextRequest, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-9fv1i9aK.cjs";
2
- import { f as AgentRuntimeOptions, l as AgentRunResult, o as AgentRunInit } from "./run-agent-C9ubX8Tx.cjs";
1
+ import { P as AgentExecutorDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-j9hShB7d.cjs";
2
+ import { f as AgentRuntimeOptions, l as AgentRunResult, o as AgentRunInit } from "./run-agent-B5opVUxx.cjs";
3
3
  import { t as MetaOfSnapshot } from "./utils-ebVpCYoF.cjs";
4
- import { _ as explorePaths, a as AgentPathTerminal, c as CanReachResult, d as SimulateAgentOptions, f as SimulateAgentResult, g as canReach, h as assertAgentMachine, i as AgentPathReport, l as ExplorePathsOptions, m as SimulationTrailEntry, n as AgentLintError, o as AgentUnknownStateError, p as SimulationScript, r as AgentLintSeverity, s as AssertAgentMachineOptions, t as AgentLintDiagnostic, u as LintAgentMachineOptions, v as lintAgentMachine, y as simulateAgent } from "./verify-DYH_2VzU.cjs";
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-CPKDPMwY.cjs";
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`. */
@@ -204,10 +204,10 @@ interface RunSeamOptions<TMachine extends AnyStateMachine> {
204
204
  candidate?: AgentRequestExecutor;
205
205
  /**
206
206
  * The simulated user. Called at every idle pause; return the event to send,
207
- * or `null`/`undefined` to stop the run there. Omitted, the run stops at the
208
- * first idle pause.
207
+ * or `null`/`undefined` to stop the run there, directly or as a promise (a
208
+ * real async client). Omitted, the run stops at the first idle pause.
209
209
  */
210
- respond?: (turn: SeamTurn<TMachine>) => EventFromLogic<TMachine> | null | undefined;
210
+ respond?: (turn: SeamTurn<TMachine>) => EventFromLogic<TMachine> | null | undefined | PromiseLike<EventFromLogic<TMachine> | null | undefined>;
211
211
  /** Maximum idle pauses to answer before stopping. Default `12`. */
212
212
  maxTurns?: number;
213
213
  /**
@@ -288,6 +288,8 @@ interface StateStats {
288
288
  failures: number;
289
289
  /** Options withheld by the guards at decisions made in this state, summed over runs. */
290
290
  withheld: number;
291
+ /** Events this state ignored (`machine.transition` with `ignored`), summed over runs. */
292
+ ignored: number;
291
293
  }
292
294
  /** Options for {@link foldTraces}. */
293
295
  interface FoldTracesOptions<TTrace> {
@@ -296,10 +298,11 @@ interface FoldTracesOptions<TTrace> {
296
298
  }
297
299
  /**
298
300
  * Folds many runs' traces into per-state stats: how many runs visited each
299
- * state, how many of those failed, and how many options the guards withheld
300
- * at decisions made there. Pure; reads only:
301
+ * 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:
301
303
  *
302
- * - `machine.transition`: the run visited `from.value` and `snapshot.value`.
304
+ * - `machine.transition`: the run visited `from.value` and `snapshot.value`;
305
+ * with `ignored`, each of those states ignored one event.
303
306
  * - `request.start` of a decision, first attempt only: its `request.withheld`
304
307
  * counts toward the state the run was in, the `from.value` of the
305
308
  * transition its choice causes.
@@ -320,4 +323,119 @@ export declare function foldTraces<TTrace extends readonly {
320
323
  readonly type: string;
321
324
  }[]>(traces: Iterable<TTrace>, options: FoldTracesOptions<TTrace>): StateStats[];
322
325
  //#endregion
323
- export { type AgentLintDiagnostic, AgentLintError, type AgentLintSeverity, type AgentPathReport, type AgentPathTerminal, AgentUnknownStateError, type AssertAgentMachineOptions, type CanReachResult, type ExplorePathsOptions, type FoldTracesOptions, type LintAgentMachineOptions, type MatchTrajectoryOptions, 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 TrajectoryEvent, type TrajectoryItem, type TrajectoryMatch, type TrajectoryMiss, assertAgentMachine, canReach, explorePaths, lintAgentMachine, simulateAgent };
326
+ //#region src/decision-requests.d.ts
327
+ /** One decision a run asked for. See {@link getDecisionRequests}. */
328
+ interface TracedDecisionRequest {
329
+ /** The active states when the decision was asked, as dot paths (one per parallel region). */
330
+ states: string[];
331
+ /** The request as the executor received it, on its first attempt. */
332
+ request: AgentExecutorDecisionRequest;
333
+ }
334
+ /** Options for {@link getDecisionRequests}. */
335
+ interface GetDecisionRequestsOptions {
336
+ /** Keep only requests with this `name` (the `agent.decide` input's `name`). */
337
+ name?: string;
338
+ }
339
+ /**
340
+ * The decisions a run asked for, read from its trace: each decision's first
341
+ * `request.start`, with the states the run was in. A trace is one run's events,
342
+ * live or serialized with `serializeTraceEvent`. Retries of the same decision
343
+ * are left out, so each decision appears once.
344
+ *
345
+ * Use the requests as eval rows (run a decider on each and compare its event
346
+ * with a label) or as probe inputs for a policy. A serialized request keeps its
347
+ * `options`, `metadata`, `system`, and `prompt`; event schemas do not survive
348
+ * serialization, so replay closed choices (`options`) rather than open ones.
349
+ *
350
+ * @example
351
+ * ```ts no-check
352
+ * const rows = traces.flatMap((trace) => getDecisionRequests(trace, { name: "chooseResolution" }));
353
+ * for (const { request } of rows) console.log((await decide(request)).event);
354
+ * ```
355
+ */
356
+ export declare function getDecisionRequests(trace: Iterable<{
357
+ readonly type: string;
358
+ }>, options?: GetDecisionRequestsOptions): TracedDecisionRequest[];
359
+ //#endregion
360
+ //#region src/compare-runs.d.ts
361
+ /** One run of one scenario, reduced to what parity compares. See {@link compareRuns}. */
362
+ interface ParityRun {
363
+ /** How the run ended: a final state name, or the label of the loop's return. `'threw'` marks a run that threw. */
364
+ outcome: string;
365
+ /** What the run changed in the world, compared structurally. Sort lists whose order does not matter. */
366
+ effects?: unknown;
367
+ /** The rules the run broke, from ground truth. Any entry marks the run as rule-breaking. */
368
+ violations?: readonly unknown[];
369
+ /** Anything else to keep in the report. Not compared. */
370
+ detail?: unknown;
371
+ }
372
+ /**
373
+ * How one scenario's candidate run relates to its baseline run.
374
+ *
375
+ * - `same`: same outcome, same effects, and neither run broke a rule.
376
+ * - `intended`: the candidate broke no rule, and the baseline broke one (even
377
+ * with the same outcome and effects), or the baseline missed the scenario's
378
+ * `expected` outcome that the candidate reached.
379
+ * - `regression`: the candidate broke a rule, or they differ for any other reason.
380
+ */
381
+ type ParityLabel = "same" | "intended" | "regression";
382
+ /** One scenario's row in a {@link ParityReport}. */
383
+ interface ParityResult<TScenario> {
384
+ id: string;
385
+ scenario: TScenario;
386
+ label: ParityLabel;
387
+ /** Why the label was given, in a few words. Empty for `same`. */
388
+ reason: string;
389
+ baseline: ParityRun;
390
+ candidate: ParityRun;
391
+ }
392
+ /** The result of {@link compareRuns}. */
393
+ interface ParityReport<TScenario> {
394
+ scenarios: ParityResult<TScenario>[];
395
+ counts: Record<ParityLabel, number>;
396
+ /** True when no scenario is a `regression`. */
397
+ ok: boolean;
398
+ }
399
+ /** Options for {@link compareRuns}. */
400
+ interface CompareRunsOptions<TScenario extends {
401
+ id: string;
402
+ expected?: string;
403
+ }> {
404
+ scenarios: readonly TScenario[];
405
+ /** Runs the existing implementation (the loop) on one scenario. */
406
+ baseline: (scenario: TScenario) => Promise<ParityRun>;
407
+ /** Runs the replacement (the machine) on one scenario. */
408
+ candidate: (scenario: TScenario) => Promise<ParityRun>;
409
+ }
410
+ /**
411
+ * Runs every scenario through a baseline and a candidate implementation and
412
+ * labels each difference, so a port can show where it behaves like the code it
413
+ * replaces and where it differs on purpose.
414
+ *
415
+ * Parity is outcome-level: the terminal outcome and the effects in the world,
416
+ * not the sequence of tool calls, since a machine usually reorders steps. A
417
+ * candidate that broke no rule where the baseline broke one is intended, even
418
+ * when the outcome matches. A difference also counts as intended when only the
419
+ * candidate reached the scenario's `expected` outcome. Every other difference,
420
+ * and every candidate rule break, is a regression for a person to review.
421
+ *
422
+ * Runs are sequential, baseline first. A run that throws is recorded with
423
+ * outcome `'threw'` and the error message as its `detail`. Parity holds for
424
+ * these scenarios and these runs only; with a live model, run it more than once.
425
+ *
426
+ * @example
427
+ * ```ts no-check
428
+ * const report = await compareRuns({
429
+ * scenarios,
430
+ * baseline: async (s) => toParityRun(await runRawLoop(s)),
431
+ * candidate: async (s) => toParityRun(await runDesk(s)),
432
+ * });
433
+ * expect(report.ok).toBe(true);
434
+ * ```
435
+ */
436
+ export declare function compareRuns<TScenario extends {
437
+ id: string;
438
+ expected?: string;
439
+ }>(options: CompareRunsOptions<TScenario>): Promise<ParityReport<TScenario>>;
440
+ //#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 };
@@ -1,7 +1,7 @@
1
- import { c as AgentRequestExecutorInfo, f as AgentTextRequest, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-BDbGjYMh.mjs";
2
- import { f as AgentRuntimeOptions, l as AgentRunResult, o as AgentRunInit } from "./run-agent-CxSyZmIE.mjs";
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";
3
3
  import { t as MetaOfSnapshot } from "./utils-BnXdWih3.mjs";
4
- import { _ as explorePaths, a as AgentPathTerminal, c as CanReachResult, d as SimulateAgentOptions, f as SimulateAgentResult, g as canReach, h as assertAgentMachine, i as AgentPathReport, l as ExplorePathsOptions, m as SimulationTrailEntry, n as AgentLintError, o as AgentUnknownStateError, p as SimulationScript, r as AgentLintSeverity, s as AssertAgentMachineOptions, t as AgentLintDiagnostic, u as LintAgentMachineOptions, v as lintAgentMachine, y as simulateAgent } from "./verify-CBuYIpsa.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";
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`. */
@@ -204,10 +204,10 @@ interface RunSeamOptions<TMachine extends AnyStateMachine> {
204
204
  candidate?: AgentRequestExecutor;
205
205
  /**
206
206
  * The simulated user. Called at every idle pause; return the event to send,
207
- * or `null`/`undefined` to stop the run there. Omitted, the run stops at the
208
- * first idle pause.
207
+ * or `null`/`undefined` to stop the run there, directly or as a promise (a
208
+ * real async client). Omitted, the run stops at the first idle pause.
209
209
  */
210
- respond?: (turn: SeamTurn<TMachine>) => EventFromLogic<TMachine> | null | undefined;
210
+ respond?: (turn: SeamTurn<TMachine>) => EventFromLogic<TMachine> | null | undefined | PromiseLike<EventFromLogic<TMachine> | null | undefined>;
211
211
  /** Maximum idle pauses to answer before stopping. Default `12`. */
212
212
  maxTurns?: number;
213
213
  /**
@@ -288,6 +288,8 @@ interface StateStats {
288
288
  failures: number;
289
289
  /** Options withheld by the guards at decisions made in this state, summed over runs. */
290
290
  withheld: number;
291
+ /** Events this state ignored (`machine.transition` with `ignored`), summed over runs. */
292
+ ignored: number;
291
293
  }
292
294
  /** Options for {@link foldTraces}. */
293
295
  interface FoldTracesOptions<TTrace> {
@@ -296,10 +298,11 @@ interface FoldTracesOptions<TTrace> {
296
298
  }
297
299
  /**
298
300
  * Folds many runs' traces into per-state stats: how many runs visited each
299
- * state, how many of those failed, and how many options the guards withheld
300
- * at decisions made there. Pure; reads only:
301
+ * 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:
301
303
  *
302
- * - `machine.transition`: the run visited `from.value` and `snapshot.value`.
304
+ * - `machine.transition`: the run visited `from.value` and `snapshot.value`;
305
+ * with `ignored`, each of those states ignored one event.
303
306
  * - `request.start` of a decision, first attempt only: its `request.withheld`
304
307
  * counts toward the state the run was in, the `from.value` of the
305
308
  * transition its choice causes.
@@ -320,4 +323,119 @@ export declare function foldTraces<TTrace extends readonly {
320
323
  readonly type: string;
321
324
  }[]>(traces: Iterable<TTrace>, options: FoldTracesOptions<TTrace>): StateStats[];
322
325
  //#endregion
323
- export { type AgentLintDiagnostic, AgentLintError, type AgentLintSeverity, type AgentPathReport, type AgentPathTerminal, AgentUnknownStateError, type AssertAgentMachineOptions, type CanReachResult, type ExplorePathsOptions, type FoldTracesOptions, type LintAgentMachineOptions, type MatchTrajectoryOptions, 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 TrajectoryEvent, type TrajectoryItem, type TrajectoryMatch, type TrajectoryMiss, assertAgentMachine, canReach, explorePaths, lintAgentMachine, simulateAgent };
326
+ //#region src/decision-requests.d.ts
327
+ /** One decision a run asked for. See {@link getDecisionRequests}. */
328
+ interface TracedDecisionRequest {
329
+ /** The active states when the decision was asked, as dot paths (one per parallel region). */
330
+ states: string[];
331
+ /** The request as the executor received it, on its first attempt. */
332
+ request: AgentExecutorDecisionRequest;
333
+ }
334
+ /** Options for {@link getDecisionRequests}. */
335
+ interface GetDecisionRequestsOptions {
336
+ /** Keep only requests with this `name` (the `agent.decide` input's `name`). */
337
+ name?: string;
338
+ }
339
+ /**
340
+ * The decisions a run asked for, read from its trace: each decision's first
341
+ * `request.start`, with the states the run was in. A trace is one run's events,
342
+ * live or serialized with `serializeTraceEvent`. Retries of the same decision
343
+ * are left out, so each decision appears once.
344
+ *
345
+ * Use the requests as eval rows (run a decider on each and compare its event
346
+ * with a label) or as probe inputs for a policy. A serialized request keeps its
347
+ * `options`, `metadata`, `system`, and `prompt`; event schemas do not survive
348
+ * serialization, so replay closed choices (`options`) rather than open ones.
349
+ *
350
+ * @example
351
+ * ```ts no-check
352
+ * const rows = traces.flatMap((trace) => getDecisionRequests(trace, { name: "chooseResolution" }));
353
+ * for (const { request } of rows) console.log((await decide(request)).event);
354
+ * ```
355
+ */
356
+ export declare function getDecisionRequests(trace: Iterable<{
357
+ readonly type: string;
358
+ }>, options?: GetDecisionRequestsOptions): TracedDecisionRequest[];
359
+ //#endregion
360
+ //#region src/compare-runs.d.ts
361
+ /** One run of one scenario, reduced to what parity compares. See {@link compareRuns}. */
362
+ interface ParityRun {
363
+ /** How the run ended: a final state name, or the label of the loop's return. `'threw'` marks a run that threw. */
364
+ outcome: string;
365
+ /** What the run changed in the world, compared structurally. Sort lists whose order does not matter. */
366
+ effects?: unknown;
367
+ /** The rules the run broke, from ground truth. Any entry marks the run as rule-breaking. */
368
+ violations?: readonly unknown[];
369
+ /** Anything else to keep in the report. Not compared. */
370
+ detail?: unknown;
371
+ }
372
+ /**
373
+ * How one scenario's candidate run relates to its baseline run.
374
+ *
375
+ * - `same`: same outcome, same effects, and neither run broke a rule.
376
+ * - `intended`: the candidate broke no rule, and the baseline broke one (even
377
+ * with the same outcome and effects), or the baseline missed the scenario's
378
+ * `expected` outcome that the candidate reached.
379
+ * - `regression`: the candidate broke a rule, or they differ for any other reason.
380
+ */
381
+ type ParityLabel = "same" | "intended" | "regression";
382
+ /** One scenario's row in a {@link ParityReport}. */
383
+ interface ParityResult<TScenario> {
384
+ id: string;
385
+ scenario: TScenario;
386
+ label: ParityLabel;
387
+ /** Why the label was given, in a few words. Empty for `same`. */
388
+ reason: string;
389
+ baseline: ParityRun;
390
+ candidate: ParityRun;
391
+ }
392
+ /** The result of {@link compareRuns}. */
393
+ interface ParityReport<TScenario> {
394
+ scenarios: ParityResult<TScenario>[];
395
+ counts: Record<ParityLabel, number>;
396
+ /** True when no scenario is a `regression`. */
397
+ ok: boolean;
398
+ }
399
+ /** Options for {@link compareRuns}. */
400
+ interface CompareRunsOptions<TScenario extends {
401
+ id: string;
402
+ expected?: string;
403
+ }> {
404
+ scenarios: readonly TScenario[];
405
+ /** Runs the existing implementation (the loop) on one scenario. */
406
+ baseline: (scenario: TScenario) => Promise<ParityRun>;
407
+ /** Runs the replacement (the machine) on one scenario. */
408
+ candidate: (scenario: TScenario) => Promise<ParityRun>;
409
+ }
410
+ /**
411
+ * Runs every scenario through a baseline and a candidate implementation and
412
+ * labels each difference, so a port can show where it behaves like the code it
413
+ * replaces and where it differs on purpose.
414
+ *
415
+ * Parity is outcome-level: the terminal outcome and the effects in the world,
416
+ * not the sequence of tool calls, since a machine usually reorders steps. A
417
+ * candidate that broke no rule where the baseline broke one is intended, even
418
+ * when the outcome matches. A difference also counts as intended when only the
419
+ * candidate reached the scenario's `expected` outcome. Every other difference,
420
+ * and every candidate rule break, is a regression for a person to review.
421
+ *
422
+ * Runs are sequential, baseline first. A run that throws is recorded with
423
+ * outcome `'threw'` and the error message as its `detail`. Parity holds for
424
+ * these scenarios and these runs only; with a live model, run it more than once.
425
+ *
426
+ * @example
427
+ * ```ts no-check
428
+ * const report = await compareRuns({
429
+ * scenarios,
430
+ * baseline: async (s) => toParityRun(await runRawLoop(s)),
431
+ * candidate: async (s) => toParityRun(await runDesk(s)),
432
+ * });
433
+ * expect(report.ok).toBe(true);
434
+ * ```
435
+ */
436
+ export declare function compareRuns<TScenario extends {
437
+ id: string;
438
+ expected?: string;
439
+ }>(options: CompareRunsOptions<TScenario>): Promise<ParityReport<TScenario>>;
440
+ //#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 };