@statelyai/agent 2.0.0-alpha.24 → 2.0.0-alpha.25

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 (53) hide show
  1. package/dist/ai-sdk.cjs +30 -34
  2. package/dist/ai-sdk.d.cts +27 -31
  3. package/dist/ai-sdk.d.mts +27 -31
  4. package/dist/ai-sdk.mjs +27 -31
  5. package/dist/decision-CM9CYZ6t.cjs +519 -0
  6. package/dist/decision-DzSv1NpD.mjs +453 -0
  7. package/dist/event-log-store-Ba2fsc4E.mjs +576 -0
  8. package/dist/event-log-store-DQmImLYk.cjs +702 -0
  9. package/dist/event-log-store-DvOcs10J.d.cts +338 -0
  10. package/dist/event-log-store-DxyVgnas.d.mts +338 -0
  11. package/dist/index.cjs +429 -4272
  12. package/dist/index.d.cts +104 -1005
  13. package/dist/index.d.mts +104 -1005
  14. package/dist/index.mjs +389 -4202
  15. package/dist/log.cjs +392 -0
  16. package/dist/log.d.cts +32 -0
  17. package/dist/log.d.mts +32 -0
  18. package/dist/log.mjs +371 -0
  19. package/dist/machines.cjs +27 -16
  20. package/dist/machines.d.cts +1 -1
  21. package/dist/machines.d.mts +1 -1
  22. package/dist/machines.mjs +27 -16
  23. package/dist/openai.cjs +16 -15
  24. package/dist/openai.d.cts +9 -9
  25. package/dist/openai.d.mts +9 -9
  26. package/dist/openai.mjs +10 -9
  27. package/dist/otel.d.cts +1 -1
  28. package/dist/otel.d.mts +1 -1
  29. package/dist/{run-agent-Ck7Sa3Tb.d.mts → run-agent-BOfoJg5B.d.cts} +86 -387
  30. package/dist/{run-agent-DWqA8KiI.d.cts → run-agent-CG343kFs.d.mts} +86 -387
  31. package/dist/run-agent-Cb1-LS5P.cjs +1783 -0
  32. package/dist/run-agent-DvDQd4If.mjs +1669 -0
  33. package/dist/{setup-agent-CeO2fARv.mjs → setup-agent-CFW-jPI8.mjs} +9 -20
  34. package/dist/{setup-agent-Dl2VELLi.cjs → setup-agent-CPf7MxnG.cjs} +20 -37
  35. package/dist/testing.cjs +1222 -0
  36. package/dist/testing.d.cts +602 -0
  37. package/dist/testing.d.mts +602 -0
  38. package/dist/testing.mjs +1212 -0
  39. package/dist/{text-logic-DJBK3LbG.d.mts → text-logic-BFEOxyxv.d.cts} +71 -147
  40. package/dist/text-logic-Bl_ZRxDi.mjs +833 -0
  41. package/dist/text-logic-C8xyr6Ag.cjs +1091 -0
  42. package/dist/{text-logic-C7bSnH_B.d.cts → text-logic-hZSiRUo1.d.mts} +71 -147
  43. package/dist/{types-CjHk5OdH.d.cts → types-B1Qs2q3q.d.cts} +2 -1
  44. package/dist/{types-DWA6X9R-.d.mts → types-tA3SdczG.d.mts} +2 -1
  45. package/dist/usage-BdEjFuIi.mjs +5 -0
  46. package/dist/usage-efOQPdf_.cjs +10 -0
  47. package/dist/utils-C1p37X_c.d.mts +209 -0
  48. package/dist/utils-RalRn9sk.d.cts +209 -0
  49. package/package.json +24 -4
  50. package/readme.md +2 -2
  51. package/skills/generate-machine/SKILL.md +4 -6
  52. package/dist/decision-BBZ2jMO1.mjs +0 -1490
  53. package/dist/decision-Cv6SfNWl.cjs +0 -1856
@@ -0,0 +1,602 @@
1
+ import { u as ChosenEvent } from "./types-B1Qs2q3q.cjs";
2
+ import { Z as AgentError, s as AgentRequestExecutor, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-BFEOxyxv.cjs";
3
+ import { d as RunAgentOptions, f as RunAgentResult } from "./run-agent-BOfoJg5B.cjs";
4
+ import { _ as ScriptedExecutorsScript, g as ScriptedExecutors, h as ScriptedDecisionValue, m as ScriptedDecisionEntry, p as ScriptedByName, t as MetaOfSnapshot, v as ScriptedTextEntry, y as createScriptedExecutors } from "./utils-RalRn9sk.cjs";
5
+ import { AnyMachineSnapshot, AnyStateMachine, EventFromLogic, InputFrom, SnapshotFrom, StateValue } from "xstate";
6
+
7
+ //#region src/verify.d.ts
8
+ /** Severity of an {@link AgentLintDiagnostic}. `error` findings fail CI/the CLI; `warning`s are advisory. */
9
+ type AgentLintSeverity = "error" | "warning";
10
+ /**
11
+ * One static-analysis finding from {@link lintAgentMachine}. `code` names the
12
+ * check (stable, machine-readable), `path` points at the offending state path
13
+ * or config location, and `message` explains the problem and its remedy.
14
+ */
15
+ interface AgentLintDiagnostic {
16
+ code: "decide-without-events" | "direct-object-src" | "invoke-without-on-error";
17
+ severity: AgentLintSeverity;
18
+ /** State path (`parent.child`) or config pointer (e.g. `(root)`, `context`) the finding is about. */
19
+ path: string;
20
+ message: string;
21
+ }
22
+ /** Options for {@link lintAgentMachine}. */
23
+ interface LintAgentMachineOptions {
24
+ /** Skip these check codes entirely. */
25
+ disable?: AgentLintDiagnostic["code"][];
26
+ /**
27
+ * Throw {@link AgentLintError} on failing diagnostics instead of returning
28
+ * them. Fails on error-severity findings; add `warnings: true` to fail on
29
+ * warnings too.
30
+ */
31
+ throw?: boolean;
32
+ /** With `throw: true`, also fail on warning-severity findings. Default: errors only. */
33
+ warnings?: boolean;
34
+ }
35
+ /**
36
+ * Runs static structural checks over a built agent machine and returns the
37
+ * findings ({@link AgentLintDiagnostic}[], empty when clean). Works for
38
+ * TS-authored (`setupAgent(...).createMachine(...)`) and
39
+ * `setupAgent.fromConfig(...)`-compiled machines alike, reading `machine.config`
40
+ * plus the schemas/actor sources the library already retains per machine.
41
+ *
42
+ * No model calls, no API keys — a coding agent that emits an agent machine can
43
+ * call this to catch agent-specific mistakes such as undeliverable decisions,
44
+ * un-rebindable request sources, and an unhandled transcript event. General
45
+ * state-machine lint belongs to XState tooling.
46
+ *
47
+ * Pass `{ throw: true }` for the one-liner form used in tests and generation
48
+ * loops: it returns silently when the machine is clean and throws
49
+ * {@link AgentLintError} (findings on `.diagnostics`) on error-severity
50
+ * findings, or on warnings too with `{ throw: true, warnings: true }`.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const errors = lintAgentMachine(machine).filter((d) => d.severity === 'error');
55
+ * if (errors.length) throw new Error(errors.map((e) => `${e.path}: ${e.message}`).join('\n'));
56
+ * ```
57
+ *
58
+ * @example Throwing form
59
+ * ```ts
60
+ * test('agent machine is structurally sound', () => {
61
+ * lintAgentMachine(machine, { throw: true });
62
+ * });
63
+ * ```
64
+ */
65
+ declare function lintAgentMachine(machine: AnyStateMachine, options?: LintAgentMachineOptions): AgentLintDiagnostic[];
66
+ /**
67
+ * Thrown by `lintAgentMachine(machine, { throw: true })` (and its
68
+ * {@link assertAgentMachine} alias) when lint finds failing diagnostics.
69
+ * `diagnostics` holds the findings; the message lists them one per finding,
70
+ * so a test runner's failure output reads like the CLI's lint report.
71
+ */
72
+ declare class AgentLintError extends AgentError {
73
+ readonly diagnostics: AgentLintDiagnostic[];
74
+ constructor(machineId: string, diagnostics: AgentLintDiagnostic[]);
75
+ }
76
+ /** Options for {@link assertAgentMachine}. */
77
+ interface AssertAgentMachineOptions extends LintAgentMachineOptions {
78
+ /** Also fail on warning-severity findings. Default: errors only. */
79
+ warnings?: boolean;
80
+ }
81
+ /**
82
+ * Asserts a machine passes {@link lintAgentMachine}: returns silently when
83
+ * clean, throws {@link AgentLintError} (with the findings on `.diagnostics`)
84
+ * otherwise — sugar for `lintAgentMachine(machine, { ...options, throw: true })`.
85
+ * Fails on error-severity findings; set `warnings: true` to fail on warnings
86
+ * too. The one-liner for tests and generation loops:
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * test('agent machine is structurally sound', () => {
91
+ * assertAgentMachine(machine);
92
+ * });
93
+ * ```
94
+ */
95
+ declare function assertAgentMachine(machine: AnyStateMachine, options?: AssertAgentMachineOptions): void;
96
+ /**
97
+ * Scripted responses for a {@link simulateAgent} playthrough. Each channel is a
98
+ * by-`src` map of FIFO queues, consumed in the order the machine reaches the
99
+ * requests:
100
+ * - `text` — output values for text requests, keyed by request src (the
101
+ * `setupAgent({ requests })` key, or `agent.generateText`/`agent.streamText`).
102
+ * - `decisions` — the {@link ChosenEvent} to apply for a decision request,
103
+ * keyed by decision src (usually `agent.decide`). An invoke whose src is an
104
+ * inline logic object has only an auto-generated src, so its queue may be
105
+ * keyed by the invoke's `id` instead.
106
+ * - `invokes` — output values for scripted invokes (any actor whose output must
107
+ * be canned), keyed by src.
108
+ * - `errors` — failure values to reject a request or invoke with instead of
109
+ * resolving it, keyed by the same srcs the other channels use. An entry here
110
+ * is consumed BEFORE that src's output queue, so a script can fail the first
111
+ * call and let the second succeed. The invoke is rejected with
112
+ * {@link rejectAgentStep}, so the machine takes its `onError`; for
113
+ * `agent.decide` the entry stands in for retry exhaustion. A value can be
114
+ * anything — an `Error`, a string, or an object such as `{ code: 'truncated' }`
115
+ * for a machine that branches on `event.error.code`.
116
+ * - `events` — a flat FIFO queue of external (human/host-sent) events. When the
117
+ * machine settles idle with no pending request or invoke — a human gate — the
118
+ * next queued event is applied, so a simulation can cross states that a live
119
+ * run crosses via `actor.send(...)`. An event the current state cannot take
120
+ * (no handler, or guard-rejected) throws rather than silently vanishing.
121
+ */
122
+ interface SimulationScript {
123
+ text?: Record<string, unknown[]>;
124
+ decisions?: Record<string, ChosenEvent[]>;
125
+ invokes?: Record<string, unknown[]>;
126
+ errors?: Record<string, unknown[]>;
127
+ events?: ChosenEvent[];
128
+ }
129
+ /**
130
+ * One entry in a {@link SimulateAgentResult.trail}: the state after this step,
131
+ * plus what drove the step. The first entry is always the machine's initial
132
+ * state, with no `appliedEvent`/`resolvedRequest` — so `trail.map((e) =>
133
+ * e.state)` is the complete state path, directly comparable with
134
+ * `matchesTrajectory` without prepending the initial state by hand.
135
+ */
136
+ interface SimulationTrailEntry {
137
+ /** The machine state value after applying this step. */
138
+ state: unknown;
139
+ /** The chosen event applied (for a decision request), or the external event applied (when `external`). */
140
+ appliedEvent?: ChosenEvent;
141
+ /** True when `appliedEvent` came from the script's `events` queue (an external/user event), not a decision. */
142
+ external?: boolean;
143
+ /**
144
+ * Scripted decisions that failed validation (unknown event, invalid payload,
145
+ * or guard-rejected — live-run retry parity, see {@link simulateAgent})
146
+ * before this step settled. Present with an `appliedEvent` when a later
147
+ * scripted attempt succeeded, or alone when every attempt failed and the
148
+ * exhaustion error was routed through the decision invoke's `onError`.
149
+ */
150
+ rejectedEvents?: ChosenEvent[];
151
+ /**
152
+ * The request this step settled (a text, decision, or scripted invoke): its
153
+ * kind, src, and how it settled. `outcome` is `'output'` when a scripted
154
+ * output resolved it and `'error'` when a `script.errors` entry rejected it,
155
+ * in which case `error` carries the scripted failure value.
156
+ */
157
+ resolvedRequest?: {
158
+ kind: "text" | "invoke" | "decision";
159
+ src: string;
160
+ id: string;
161
+ outcome: "output" | "error";
162
+ error?: unknown;
163
+ };
164
+ }
165
+ /** Options for {@link simulateAgent}. */
166
+ interface SimulateAgentOptions {
167
+ input?: unknown;
168
+ script: SimulationScript;
169
+ /** Max steps before returning `'exhausted'`. Default 100. */
170
+ maxSteps?: number;
171
+ }
172
+ /** The outcome of a {@link simulateAgent} playthrough. */
173
+ interface SimulateAgentResult {
174
+ /** `'done'` = reached a final state; `'idle'` = paused with no pending work; `'exhausted'` = hit `maxSteps`. */
175
+ status: "done" | "idle" | "exhausted";
176
+ snapshot: AnyMachineSnapshot;
177
+ trail: SimulationTrailEntry[];
178
+ }
179
+ /**
180
+ * Deterministically plays a machine through, resolving each request from a
181
+ * {@link SimulationScript} instead of a model — no API keys, no model calls.
182
+ * Runs on the pure step path ({@link initialAgentStep} etc.), so it exercises
183
+ * the real transition logic. Returns the terminal `status`, final `snapshot`,
184
+ * and a `trail` of every step taken.
185
+ *
186
+ * Decisions run through the live run's own validation/retry core,
187
+ * {@link resolveDecision}, with the script standing in for the model: each
188
+ * attempt consumes the next queued {@link ChosenEvent} for that src, so an
189
+ * unknown, payload-invalid, or guard-rejected event is NOT silently swallowed
190
+ * — the next queued decision is tried, exactly as a live run re-asks the
191
+ * model. The decision logic's `maxRetries` caps attempts as it would live;
192
+ * when retries continue past the end of the queue, the last queued decision
193
+ * repeats (a scripted model that insists). The repeat applies only within one
194
+ * decision request's retries — each new decision request must have its own
195
+ * queued entry, or the dry-script error throws as usual. Exhausting all
196
+ * attempts delivers
197
+ * the resulting {@link AgentDecisionExhaustedError} to the machine as the
198
+ * decision invoke's error (so an `onError` transition observes it, as it
199
+ * would live); with no `onError` to catch it, it is thrown.
200
+ *
201
+ * Throws a descriptive error when the script runs dry mid-request, naming the
202
+ * pending request's kind, src, and id so the missing scripted response is
203
+ * obvious.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * const { status, snapshot } = simulateAgent(machine, {
208
+ * input: { topic: 'state machines' },
209
+ * script: {
210
+ * decisions: { 'agent.decide': [{ type: 'ESCALATE' }] },
211
+ * events: [{ type: 'APPROVE' }], // crosses the human gate
212
+ * },
213
+ * });
214
+ * ```
215
+ */
216
+ declare function simulateAgent(machine: AnyStateMachine, options: SimulateAgentOptions): Promise<SimulateAgentResult>;
217
+ /** Options for {@link explorePaths}. */
218
+ interface ExplorePathsOptions {
219
+ input?: unknown;
220
+ /** Max branch points (decisions + external-event forks) along any path. Default 8. */
221
+ maxDepth?: number;
222
+ /** Total path cap before exploration stops (reported via `hitPathCap`). Default 200. */
223
+ maxPaths?: number;
224
+ /**
225
+ * Canned output for each text request, keyed by src (the
226
+ * `setupAgent({ requests })` key, or `agent.generateText`/`agent.streamText`).
227
+ * One value per src, reused every time that src is reached. A missing src
228
+ * halts that branch with a `needs-output` terminal.
229
+ */
230
+ text?: Record<string, unknown>;
231
+ /** Canned output for scripted invokes, keyed by src. Same one-value-per-src rule as `text`. */
232
+ invokes?: Record<string, unknown>;
233
+ /**
234
+ * A canned failure per src, keyed like `text`/`invokes`. A src listed here
235
+ * forks an extra branch at that invoke, where the invoke is rejected and the
236
+ * machine takes its `onError` — so states reachable only through a failure
237
+ * are explored. When the src also has an output, both branches are explored;
238
+ * when it has only an error, only the failing one is. Each fork counts
239
+ * against `maxDepth`, and the failing branch records
240
+ * `{ type: 'xstate.error.actor.<id>' }` in the path.
241
+ *
242
+ * A decision invoke can be keyed here too — by its src (usually
243
+ * `agent.decide`) or by its invoke id — standing in for retry exhaustion.
244
+ * Its success branch is the usual per-candidate-event fork, so the failing
245
+ * branch is explored in addition to, not instead of, the candidates.
246
+ *
247
+ * A rejection that reaches no `onError` errors the machine, and that path
248
+ * ends in an `error` terminal.
249
+ */
250
+ errors?: Record<string, unknown>;
251
+ }
252
+ /** A single explored path's terminal outcome. */
253
+ interface AgentPathTerminal {
254
+ /**
255
+ * `'error'` is a scripted failure the machine had no `onError` for: the
256
+ * snapshot is errored, exactly as a live run's unhandled invoke failure.
257
+ */
258
+ status: "done" | "idle" | "needs-output" | "max-depth" | "error";
259
+ /** The chosen/applied events, in order, that produced this terminal. */
260
+ path: ChosenEvent[];
261
+ /** The final state value on this path. */
262
+ state: unknown;
263
+ /** For `needs-output`: the src whose canned output was missing. */
264
+ missingSrc?: string;
265
+ /** For `error`: the failure value that errored the machine. */
266
+ error?: unknown;
267
+ }
268
+ /** The report returned by {@link explorePaths}. */
269
+ interface AgentPathReport {
270
+ /** Every distinct state value (JSON) encountered across all explored paths. */
271
+ reachedStates: unknown[];
272
+ /** One entry per explored path. */
273
+ terminals: AgentPathTerminal[];
274
+ /** How many candidate events were pruned because a guard rejected them. */
275
+ prunedByGuard: number;
276
+ /** Notes about coverage the exploration could not complete (missing outputs, depth/path caps). */
277
+ unexplored: string[];
278
+ /** Total paths explored. */
279
+ pathsExplored: number;
280
+ /** True when the total-paths cap was hit (report is partial). */
281
+ hitPathCap: boolean;
282
+ }
283
+ /**
284
+ * Enumerates a machine's decision and external-event branches to a bounded
285
+ * depth, model-free, and reports which states are reached and how each path
286
+ * terminates. At each decision request it forks one branch per candidate event
287
+ * (guard-rejected candidates are counted in `prunedByGuard`, not explored); at
288
+ * an idle wait it forks per externally-accepted event. Text requests resolve
289
+ * from `text`, other invokes from `invokes` — all by-src canned-output maps, and a missing src halts
290
+ * that branch with a `needs-output` terminal rather than throwing. A src in
291
+ * `errors` forks an extra branch where that invoke is rejected, so states
292
+ * behind an `onError` are explored too.
293
+ *
294
+ * Combinatorics are bounded by `maxDepth` (default 8) and `maxPaths` (default
295
+ * 200, reported via `hitPathCap`).
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * const report = await explorePaths(refundMachine, { input: { request: 'x', amount: 5000 } });
300
+ * // report.terminals → both 'refunded' and 'denied'; report.prunedByGuard → 1
301
+ * ```
302
+ */
303
+ declare function explorePaths(machine: AnyStateMachine, options?: ExplorePathsOptions): Promise<AgentPathReport>;
304
+ /** The result of a {@link canReach} query. */
305
+ interface CanReachResult {
306
+ /** True when the target state was reached within the exploration bounds. */
307
+ reachable: boolean;
308
+ /** Resolved XState state-node id for a string target. */
309
+ target?: string;
310
+ /** When reachable, the sequence of chosen/applied events that gets there. */
311
+ witness?: ChosenEvent[];
312
+ }
313
+ /** Thrown when a string reachability target is not a state in the machine. */
314
+ declare class AgentUnknownStateError extends AgentError {
315
+ readonly target: string;
316
+ constructor(machineId: string, target: string);
317
+ }
318
+ /**
319
+ * Answers "can the machine reach this?" by exploring its branches (a thin
320
+ * wrapper over {@link explorePaths}). The target is either a state path string
321
+ * (`snapshot.matches(...)` semantics) or a snapshot predicate — the predicate
322
+ * form checks any property (a context invariant, a tag, a state+context
323
+ * combination) without reifying a sentinel state for it. Returns
324
+ * `{ reachable: true, witness }` with the event sequence that reaches it, or
325
+ * `{ reachable: false }`.
326
+ *
327
+ * @example
328
+ * ```ts
329
+ * const { reachable, witness } = await canReach(refundMachine, 'denied', { input: { request: 'x', amount: 5000 } });
330
+ * // reachable → true; witness → [{ type: 'NEEDS_REVIEW' }, { type: 'DENY' }]
331
+ * ```
332
+ *
333
+ * @example Predicate target — a violation property, no sentinel state needed
334
+ * ```ts
335
+ * const violation = await canReach(
336
+ * refundMachine,
337
+ * (snapshot) => snapshot.matches('issued') && !snapshot.context.approved,
338
+ * { input: { amount: 5000 } },
339
+ * );
340
+ * // violation.reachable → false is the safety proof
341
+ * ```
342
+ */
343
+ declare function canReach(machine: AnyStateMachine, target: string | ((snapshot: AnyMachineSnapshot) => boolean), options?: ExplorePathsOptions): Promise<CanReachResult>;
344
+ //#endregion
345
+ //#region src/trajectory.d.ts
346
+ /** An event-shaped trajectory item: anything with a string `type`. */
347
+ interface TrajectoryEvent {
348
+ type: string;
349
+ [key: string]: unknown;
350
+ }
351
+ /** Any host-owned envelope around an event. */
352
+ interface TrajectoryEventEnvelope {
353
+ event: TrajectoryEvent;
354
+ }
355
+ /**
356
+ * One item in a trajectory, on either side of the comparison:
357
+ *
358
+ * - a state value — `'drafting'`, a dot path `'review.editing'`, or the nested
359
+ * object XState reports (`{ review: 'editing' }`),
360
+ * - an event object, or just the event type as a string,
361
+ * - a machine snapshot, whose `value` is used.
362
+ */
363
+ type TrajectoryItem = StateValue | TrajectoryEvent | TrajectoryEventEnvelope | {
364
+ value: StateValue;
365
+ };
366
+ /** Options for {@link matchesTrajectory}. */
367
+ interface MatchTrajectoryOptions {
368
+ /**
369
+ * Require the trajectories to be equal: same length, item for item. Default
370
+ * `false` — expected items must appear in `actual` in order, gaps allowed.
371
+ */
372
+ exact?: boolean;
373
+ }
374
+ /** The first expected item that could not be found. */
375
+ interface TrajectoryMiss {
376
+ /** Its position in `expected`. */
377
+ index: number;
378
+ /** The expected item itself. */
379
+ expected: TrajectoryItem;
380
+ /** Where the search for it started in `actual` (everything before was already consumed). */
381
+ searchedFrom: number;
382
+ }
383
+ /**
384
+ * The result of {@link matchesTrajectory}: a boolean for tests, plus enough
385
+ * detail for a scorer's partial credit and a failure message's diagnosis.
386
+ */
387
+ interface TrajectoryMatch {
388
+ /** Every expected item was found, in order (and, in `exact` mode, nothing else). */
389
+ matched: boolean;
390
+ /** How many expected items were matched before the first miss. */
391
+ matchedCount: number;
392
+ /** `expected.length`, so a scorer can compute its own ratio. */
393
+ expectedCount: number;
394
+ /**
395
+ * Partial credit, 0..1. `1` for an empty expectation. Denominator is
396
+ * `max(expectedCount, actual.length)` in `exact` mode, `expectedCount` otherwise.
397
+ */
398
+ score: number;
399
+ /** Absent when `matched`. */
400
+ firstMiss?: TrajectoryMiss;
401
+ }
402
+ /**
403
+ * Matches a run's trajectory against an expected one.
404
+ *
405
+ * Both trajectories may be state values or events collected from
406
+ * `onTransition`;
407
+ * items are compared by shape, so `['prompting', 'drafting']` scores a state
408
+ * path and `['PROMPT_SUBMITTED', 'SEND']` scores an event log with the same
409
+ * call.
410
+ *
411
+ * Semantics are an ordered subsequence: every expected item must appear in
412
+ * `actual`, in order, with gaps allowed. Pass `{ exact: true }` to require
413
+ * equality instead.
414
+ *
415
+ * @example Trajectory assertions in a test
416
+ * ```ts
417
+ * const statePath: unknown[] = [];
418
+ * const result = await runAgent(machine, {
419
+ * input,
420
+ * executors,
421
+ * onTransition: (snapshot) => statePath.push(snapshot.value),
422
+ * });
423
+ *
424
+ * const path = matchesTrajectory(statePath, ['prompting', 'drafting', 'sent']);
425
+ * expect(path.matched, JSON.stringify(path.firstMiss)).toBe(true);
426
+ * expect(matchesTrajectory(events, ['PROMPT_SUBMITTED', 'SEND']).matched).toBe(true);
427
+ * ```
428
+ *
429
+ * @example Partial credit in an eval scorer
430
+ * ```ts
431
+ * const match = matchesTrajectory(output.statePath, expected.statePath);
432
+ * return { name: 'state_path', score: match.score, metadata: { ...match.firstMiss } };
433
+ * ```
434
+ */
435
+ declare function matchesTrajectory(actual: readonly unknown[], expected: readonly TrajectoryItem[], options?: MatchTrajectoryOptions): TrajectoryMatch;
436
+ //#endregion
437
+ //#region src/seam.d.ts
438
+ /**
439
+ * Which model call is under test: the Nth call with this request `name` (the
440
+ * `setupAgent({ requests })` key, or `createTextLogic({ name })`). Name the
441
+ * requests you want to score — a seam is a developer-facing handle, not a
442
+ * model binding, so there is no addressing by model key.
443
+ */
444
+ interface SeamRef {
445
+ /** The request's registered `name`. */
446
+ request: string;
447
+ /** 0-based occurrence among the calls with this name. Default `0`. */
448
+ occurrence?: number;
449
+ }
450
+ /**
451
+ * One idle pause, handed to {@link RunSeamOptions.respond} so the simulated
452
+ * user answers off the machine's own state rather than a fixed transcript — a
453
+ * live seam may branch differently, and a reactive policy scores that run
454
+ * instead of crashing on it.
455
+ */
456
+ interface SeamTurn<TMachine extends AnyStateMachine> {
457
+ /** The idle snapshot to answer. */
458
+ snapshot: SnapshotFrom<TMachine>;
459
+ /** Its state value, for a `switch` on flat machines. */
460
+ state: StateValue;
461
+ /**
462
+ * The merged `meta` of the active state(s), e.g. a declared `interaction`.
463
+ * Typed from the machine's own meta schema (`setupAgent({ meta })`).
464
+ */
465
+ meta: Partial<MetaOfSnapshot<SnapshotFrom<TMachine>>>;
466
+ /** 0-based index of this pause within the run. */
467
+ turn: number;
468
+ /** The `idle` result that produced the pause. */
469
+ result: RunAgentResult<TMachine>;
470
+ }
471
+ /**
472
+ * One text call in a {@link runSeam} run's ledger, in call order — the receipt
473
+ * that says which answers came from the script and which one came from the
474
+ * candidate, so "everything else stayed scripted" is a plain assertion on
475
+ * {@link RunSeamResult.calls} rather than a recording function wrapped around
476
+ * every script entry. Text calls only: `decide` and other base executors are
477
+ * not routed by the seam and do not appear.
478
+ */
479
+ interface SeamCall {
480
+ /** The request's `name`, when it has one. */
481
+ name?: string;
482
+ /** The request's model key. */
483
+ model: string;
484
+ /** The `scripts` queue key that routed this call. */
485
+ key: string;
486
+ /** Where the answer came from: the script, or the seam's `candidate`. */
487
+ source: "script" | "candidate";
488
+ /** True for the seam call itself — scripted or candidate. */
489
+ seam: boolean;
490
+ }
491
+ /** One side of the seam: a trajectory pair ready for `matchesTrajectory`. */
492
+ interface SeamSlice {
493
+ /** State values entered on this side of the seam, in order. */
494
+ statePath: StateValue[];
495
+ /** Root-machine transition events on this side of the seam, in order. */
496
+ events: TrajectoryEvent[];
497
+ }
498
+ /** Options for {@link runSeam}. */
499
+ interface RunSeamOptions<TMachine extends AnyStateMachine> {
500
+ /** Machine input, passed straight through to `runAgent`. */
501
+ input?: InputFrom<TMachine>;
502
+ /**
503
+ * The call plan: scripted answers per key, consumed in order. A key is a
504
+ * request `name` when one is scripted under it, else a `model` key, so a
505
+ * machine whose requests are named routes by name and an unnamed one routes
506
+ * by model.
507
+ *
508
+ * Entries follow {@link ScriptedTextEntry} conventions (a value, an
509
+ * `{ result, usage? }` object, or a function of the request). A queue that
510
+ * runs dry throws; set {@link RunSeamOptions.repeatLast} to replay its last
511
+ * entry instead.
512
+ */
513
+ scripts?: Record<string, ScriptedTextEntry[]>;
514
+ /**
515
+ * Replay the LAST entry of a queue once it is exhausted, so a live seam that
516
+ * sends the run down a longer branch still finds an answer. Off by default:
517
+ * a dry queue throws, the same as every other scripted surface.
518
+ */
519
+ repeatLast?: boolean;
520
+ /** The call under test. */
521
+ seam: SeamRef;
522
+ /**
523
+ * The executor for the seam — the real model, a candidate prompt, anything
524
+ * request-shaped. Omit to run the seam scripted too: the whole seam run is
525
+ * then deterministic.
526
+ */
527
+ candidate?: AgentRequestExecutor;
528
+ /**
529
+ * The simulated user. Called at every idle pause; return the event to send,
530
+ * or `null`/`undefined` to stop the run there. Omitted, the run stops at the
531
+ * first idle pause.
532
+ */
533
+ respond?: (turn: SeamTurn<TMachine>) => EventFromLogic<TMachine> | null | undefined;
534
+ /** Maximum idle pauses to answer before stopping. Default `12`. */
535
+ maxTurns?: number;
536
+ /**
537
+ * Base executors merged UNDER the seam routing — supply `decide` (e.g. from
538
+ * `createScriptedExecutors({ decisions })`) for a machine that also decides.
539
+ * Text slots are always owned by the routing.
540
+ */
541
+ executors?: Partial<AgentRequestExecutors>;
542
+ /** Passed through to `runAgent`: actor implementations merged onto the machine. */
543
+ actors?: RunAgentOptions<TMachine>["actors"];
544
+ }
545
+ /** What {@link runSeam} returns: the seam's own answer, plus the run it caused. */
546
+ interface RunSeamResult<TMachine extends AnyStateMachine> {
547
+ /**
548
+ * The final `runAgent` result. `usage` accounts for the last leg.
549
+ */
550
+ result: RunAgentResult<TMachine>;
551
+ /** What the seam call returned, or `undefined` when the run never reached it. */
552
+ seamOutput: unknown;
553
+ /**
554
+ * The seam call's own reported token usage — the cost of the one live call
555
+ * when a `candidate` is a real model. `undefined` when the run never reached
556
+ * the seam or its answer reported no usage (scripted entries report usage
557
+ * only via the `{ result, usage }` form).
558
+ */
559
+ seamUsage?: AgentCallUsage;
560
+ /** Model calls made before the seam, or `-1` when the run never reached it. */
561
+ callsBeforeSeam: number;
562
+ /** The run's text calls in order: what was served, and by whom. */
563
+ calls: SeamCall[];
564
+ /** Everything up to the seam's own effect completion. */
565
+ before: SeamSlice;
566
+ /**
567
+ * Everything from the seam's own effect completion onward — the branch the
568
+ * seam caused, and the score. Empty when the run never reached the seam.
569
+ */
570
+ after: SeamSlice;
571
+ }
572
+ /**
573
+ * Runs a machine end to end with one model call under test, and slices the run
574
+ * at that call.
575
+ *
576
+ * The `before`/`after` slices are the point: `after.statePath` is the branch
577
+ * the seam chose and `after.events` is the same question against the durable
578
+ * log, both ready for `matchesTrajectory`. The state slice splits where the
579
+ * state path stood when the seam answered; the event slice splits at the
580
+ * seam's own effect completion (the first `xstate.done.*`/`xstate.error.*`
581
+ * entry appended after the call was made).
582
+ *
583
+ * @example No API key: the seam is scripted too, so the whole thing runs offline.
584
+ * ```ts
585
+ * const run = await runSeam(emailDrafter, {
586
+ * scripts: { promptEvaluator: [vague, complete], emailDrafter: [draft] },
587
+ * seam: { request: 'evaluatePrompt' },
588
+ * respond: ({ state }) => (state === 'prompting' ? { type: 'PROMPT_SUBMITTED', prompt } : null),
589
+ * });
590
+ *
591
+ * matchesTrajectory(run.after.statePath, ['needsMoreInfo', 'drafting']);
592
+ * ```
593
+ *
594
+ * @example A candidate prompt at the seam, scored against the same rows.
595
+ * ```ts
596
+ * const { generateText } = createAiSdkExecutors({ models });
597
+ * const run = await runSeam(emailDrafter, { ...row, candidate: generateText });
598
+ * ```
599
+ */
600
+ declare function runSeam<TMachine extends AnyStateMachine>(machine: TMachine, options: RunSeamOptions<TMachine>): Promise<RunSeamResult<TMachine>>;
601
+ //#endregion
602
+ export { type AgentLintDiagnostic, AgentLintError, type AgentLintSeverity, type AgentPathReport, type AgentPathTerminal, AgentUnknownStateError, type AssertAgentMachineOptions, type CanReachResult, type ExplorePathsOptions, type LintAgentMachineOptions, type MatchTrajectoryOptions, type RunSeamOptions, type RunSeamResult, type ScriptedByName, type ScriptedDecisionEntry, type ScriptedDecisionValue, type ScriptedExecutors, type ScriptedExecutorsScript, type ScriptedTextEntry, type SeamCall, type SeamRef, type SeamSlice, type SeamTurn, type SimulateAgentOptions, type SimulateAgentResult, type SimulationScript, type SimulationTrailEntry, type TrajectoryEvent, type TrajectoryItem, type TrajectoryMatch, type TrajectoryMiss, assertAgentMachine, canReach, createScriptedExecutors, explorePaths, lintAgentMachine, matchesTrajectory, runSeam, simulateAgent };