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

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 +1088 -0
  36. package/dist/testing.d.cts +617 -0
  37. package/dist/testing.d.mts +617 -0
  38. package/dist/testing.mjs +1079 -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-C2DPqomn.d.mts +109 -0
  48. package/dist/utils-ceStNCOh.d.cts +109 -0
  49. package/package.json +26 -5
  50. package/readme.md +5 -3
  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,1669 @@
1
+ import { C as isUnboundPlaceholder, H as AgentError, I as isStandardSchema, L as resolveMachineVersion, S as getRegisteredAgentExecutionOptions, V as validateSchemaSync, c as executeAgentTextRequest, d as getCallUsage, f as isTextLogic, k as findNonSerializableContextPaths, p as normalizeGeneratorResult, u as getCallFinishReason, v as responseMessagesOf, x as getMachineIdlePredicate, y as executorBoundLogics } from "./text-logic-Bl_ZRxDi.mjs";
2
+ import { a as isDecisionLogic, l as getAcceptedEvents, s as resolveDecision, t as AgentDecisionExhaustedError } from "./decision-DzSv1NpD.mjs";
3
+ import { t as AGENT_USAGE_EVENT_TYPE } from "./usage-BdEjFuIi.mjs";
4
+ import { _ as getUsageFromEvents, b as replay, f as canonicalEventJson, g as getSnapshotStateHash, h as getLogExecutionId, l as agentCallOccurrence, o as AgentMachineVersionMismatchError, p as createReplayEntry, t as AgentEventLogConflictError, v as initEntry, x as validateReplayEntries } from "./event-log-store-Ba2fsc4E.mjs";
5
+ import { createActor, createAsyncLogic, getNextTransitions, initialTransition, isMachineSnapshot, transition } from "xstate";
6
+ //#region src/steps.ts
7
+ /**
8
+ * The step API: the pure `(state, event) => (nextState, requests)` view of an
9
+ * agent machine. An {@link AgentStep} is a snapshot plus the model requests
10
+ * the machine is now waiting on; nothing here executes anything. A host
11
+ * resolves each request however it likes ({@link executeAgentRequest},
12
+ * `resolveDecision`, a queue, a durable workflow, a replayed log) and feeds
13
+ * the result back with {@link resolveAgentStep} or {@link rejectAgentStep}.
14
+ * `runAgent` is the in-process host built for the common case.
15
+ * @module
16
+ */
17
+ /** @internal Normalizes current and legacy XState invoke effect shapes. */
18
+ function getInvokeEffectMetadata(action) {
19
+ if (action.type === "@xstate.spawn") return action;
20
+ if (action.type === "xstate.spawnChild") {
21
+ const params = action.params;
22
+ return params ? {
23
+ ...params,
24
+ logic: action.logic
25
+ } : void 0;
26
+ }
27
+ if (action.type === "@xstate.start" && typeof action.src === "string") return action;
28
+ }
29
+ /**
30
+ * The invokes a snapshot is still waiting on, lowered to the same spawn-effect
31
+ * shape {@link getAgentRequests} reads. Derived from the snapshot's live
32
+ * children rather than the last transition's actions, so a state that invokes
33
+ * several actors at once (an `invoke: [...]` array, or parallel regions each
34
+ * invoking) keeps reporting the siblings after the first one settles —
35
+ * including when the settled invoke's `onDone` is targetless and starts
36
+ * nothing new.
37
+ *
38
+ * Entries are ordered by invoke id, so a walker that resolves one invoke per
39
+ * step is deterministic.
40
+ *
41
+ * @internal
42
+ */
43
+ function getPendingInvokes(snapshot) {
44
+ const children = snapshot.children ?? {};
45
+ return Object.keys(children).sort().flatMap((id) => {
46
+ const child = children[id];
47
+ const childSnapshot = child?.getSnapshot?.();
48
+ if (!child || childSnapshot?.status !== "active") return [];
49
+ return [{
50
+ type: "@xstate.spawn",
51
+ id,
52
+ src: child.src,
53
+ input: childSnapshot.input,
54
+ logic: child.logic
55
+ }];
56
+ });
57
+ }
58
+ /**
59
+ * Scans a set of executable actions (as returned by xstate's `transition`/
60
+ * `initialTransition`) for spawned `TextLogic`/`DecisionLogic` invokes and
61
+ * lowers each into an {@link AgentStepRequest}. Pass `options.machine` to
62
+ * pre-fill `schemas`/`actors` from the machine's registered `setupAgent`
63
+ * options instead of passing them by hand.
64
+ * `options.snapshot` is required to resolve a decision's candidate events
65
+ * (intersecting declared `allowedEvents` with what's currently legal) — omit
66
+ * it and decision requests report an empty `events` list.
67
+ *
68
+ * @internal
69
+ */
70
+ function getAgentRequests(actions, { machine, ...options } = {}) {
71
+ if (machine) options = {
72
+ ...getRegisteredAgentExecutionOptions(machine),
73
+ ...options
74
+ };
75
+ return actions.flatMap((action) => {
76
+ const params = getInvokeEffectMetadata(action);
77
+ if (!params || typeof params.src !== "string") return [];
78
+ if (typeof params.id !== "string" || params.id.length === 0) throw new Error(`Agent invoke '${params.src}' must define a durable string id.`);
79
+ const registeredLogic = isTextLogic(params.logic) || isDecisionLogic(params.logic) ? params.logic : options.actors?.[params.src];
80
+ if (isDecisionLogic(registeredLogic)) {
81
+ const decisionRequest = registeredLogic.request(params.input);
82
+ const allowedEventTypes = registeredLogic.allowedEventTypes?.(params.input);
83
+ const events = options.snapshot ? getAcceptedEvents(options.snapshot, {
84
+ events: options.events,
85
+ schemas: options.schemas,
86
+ eventTypes: allowedEventTypes
87
+ }) : [];
88
+ return [{
89
+ ...decisionRequest,
90
+ id: params.id,
91
+ events
92
+ }];
93
+ }
94
+ const textLogic = isTextLogic(registeredLogic) ? registeredLogic : void 0;
95
+ const input = textLogic ? textLogic.request(params.input) : void 0;
96
+ if (!input) return [];
97
+ return [{
98
+ kind: "text",
99
+ id: params.id,
100
+ src: params.src,
101
+ ...textLogic ? { mode: textLogic.mode } : {},
102
+ input,
103
+ tools: input.tools ?? {},
104
+ events: []
105
+ }];
106
+ });
107
+ }
108
+ /**
109
+ * Builds the canonical `xstate.done.actor` event xstate's `transition()`
110
+ * expects to resolve a spawned invoke — including the child session identity
111
+ * that rejects a stale completion from an earlier incarnation.
112
+ *
113
+ * @internal
114
+ */
115
+ function doneEvent(snapshot, request, output) {
116
+ const id = typeof request === "string" ? request : request.id;
117
+ const child = snapshot.children[id];
118
+ return {
119
+ type: "xstate.done.actor",
120
+ actorId: id,
121
+ ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {},
122
+ output
123
+ };
124
+ }
125
+ /**
126
+ * The `xstate.error.actor` counterpart of {@link doneEvent} — the event a
127
+ * failed invoke delivers, which `onError` transitions observe. Carries the
128
+ * same child session identity, so xstate does not discard it as stale.
129
+ *
130
+ * @internal
131
+ */
132
+ function errorEvent(snapshot, request, error) {
133
+ const id = typeof request === "string" ? request : request.id;
134
+ const child = snapshot.children[id];
135
+ return {
136
+ type: "xstate.error.actor",
137
+ actorId: id,
138
+ ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {},
139
+ error
140
+ };
141
+ }
142
+ /**
143
+ * Applies a request's `output` as a done event (or, with `outcome: 'error'`,
144
+ * its `output` as the invoke's error) via `transition(...)`, returning the raw
145
+ * `[snapshot, actions]` tuple. Lower-level than {@link resolveAgentStep} /
146
+ * {@link rejectAgentStep} — those helpers wrap this and also run
147
+ * {@link getAgentRequests} to produce the next {@link AgentStep}.
148
+ *
149
+ * @internal
150
+ */
151
+ function transitionResult(logic, snapshot, request, output, outcome = "output") {
152
+ const event = outcome === "error" ? errorEvent(snapshot, request, output) : doneEvent(snapshot, request, output);
153
+ const result = transition(logic, snapshot, event);
154
+ applyFinalStateOutput(logic, result[0], event);
155
+ return result;
156
+ }
157
+ /**
158
+ * Starts a machine and returns its first {@link AgentStep} — the step-path
159
+ * equivalent of `initialTransition` plus request discovery. Begins the
160
+ * durable/per-model-call-checkpoint loop: resolve each `step.requests` entry
161
+ * (via {@link executeAgentRequest} for `kind: 'text'`, or
162
+ * {@link resolveDecision} for `kind: 'decision'`), then advance with
163
+ * {@link resolveAgentStep} or {@link transitionAgentStep}.
164
+ */
165
+ function initialAgentStep(machine, input, options) {
166
+ const [snapshot, actions] = initialTransition(machine, input);
167
+ return createAgentStep(machine, snapshot, actions, getRegisteredAgentExecutionOptions(machine, options));
168
+ }
169
+ /**
170
+ * Applies an externally-sent event (e.g. a decision's chosen event, or a
171
+ * human's reply) and returns the next {@link AgentStep}. Accepts **either**
172
+ * a raw snapshot **or** a prior `AgentStep` as the second argument —
173
+ * `.snapshot` is unwrapped automatically, so callers can thread the whole
174
+ * step object through without manually plucking the snapshot out.
175
+ */
176
+ function transitionAgentStep(machine, snapshotOrStep, event, options) {
177
+ const [nextSnapshot, actions] = transition(machine, isAgentStep(snapshotOrStep) ? snapshotOrStep.snapshot : snapshotOrStep, event);
178
+ return createAgentStep(machine, nextSnapshot, actions, getRegisteredAgentExecutionOptions(machine, options));
179
+ }
180
+ /**
181
+ * Applies a resolved text request's output (a `kind: 'text'`
182
+ * {@link AgentRequest} — not a decision) as a done event and returns the
183
+ * next {@link AgentStep}. For decisions, resolve with `resolveDecision`
184
+ * (which returns a {@link ChosenEvent}) and apply it with
185
+ * {@link transitionAgentStep} instead — a decision has no output value of
186
+ * its own to feed here.
187
+ */
188
+ function resolveAgentStep(machine, step, request, output, options) {
189
+ const [snapshot, actions] = transitionResult(machine, step.snapshot, request, output);
190
+ return createAgentStep(machine, snapshot, actions, getRegisteredAgentExecutionOptions(machine, options));
191
+ }
192
+ /**
193
+ * Rejects a pending invoke — the failure counterpart of
194
+ * {@link resolveAgentStep}. Delivers `error` as the invoke's
195
+ * `xstate.error.actor` event, so the machine takes that invoke's `onError`
196
+ * transition and returns the next {@link AgentStep}. With no `onError` in
197
+ * scope the returned step's snapshot has `status: 'error'`, exactly as a live
198
+ * run's failed invoke does.
199
+ *
200
+ * A durable host replays a failed call with this: the log says the call
201
+ * failed, so the replay rejects the invoke instead of resolving it. Scripted
202
+ * playthroughs use it too — see `simulateAgent`'s `script.errors`.
203
+ *
204
+ * `error` can be any value. An `Error` instance is the usual one, but a plain
205
+ * object (`{ code: 'truncated' }`) reaches the `onError` transition as
206
+ * `event.error` untouched, so a machine that branches on a failure code is
207
+ * testable without constructing a provider's error class.
208
+ */
209
+ function rejectAgentStep(machine, step, request, error, options) {
210
+ const [snapshot, actions] = transitionResult(machine, step.snapshot, request, error, "error");
211
+ return createAgentStep(machine, snapshot, actions, getRegisteredAgentExecutionOptions(machine, options));
212
+ }
213
+ /**
214
+ * Resolves one **text** request ({@link AgentRequest}, from
215
+ * {@link AgentStep.requests}) against a host's {@link AgentRequestExecutors}
216
+ * — merges the request's tools, dispatches to `generateText`/`streamText`
217
+ * per `mode`, and validates the result against the request's
218
+ * `outputSchema` if present. **Text-only**: passing a `kind: 'decision'`
219
+ * request throws, directing the caller to `resolveDecision(request,
220
+ * executors, ...)` instead. Returns the invoke's output — `{ result,
221
+ * messages }`, ready for {@link resolveAgentStep} — plus the `raw` executor
222
+ * result (tool calls, usage, finish reason).
223
+ */
224
+ async function executeAgentRequest(request, executors) {
225
+ if (request.kind === "decision") throw new Error("executeAgentRequest(...) is text-only. Resolve a 'decision' request with resolveDecision(request, executors, ...) instead.");
226
+ assertTextExecutor(request, executors);
227
+ const { result, raw } = await executeAgentTextRequest(request.mode ?? "generate", request.id, request.input, executors, request.tools);
228
+ return {
229
+ result: request.input.outputSchema ? validateSchemaSync(request.input.outputSchema, result) : result,
230
+ messages: responseMessagesOf(raw),
231
+ raw
232
+ };
233
+ }
234
+ function assertTextExecutor(request, executors) {
235
+ const mode = request.mode ?? "generate";
236
+ const kind = mode === "stream" ? "streamText" : "generateText";
237
+ if (!(mode === "stream" ? executors.streamText : executors.generateText)) throw new Error(`this step's text request '${request.src}' needs a '${kind}' executor but none was provided.`);
238
+ }
239
+ function createAgentStep(machine, snapshot, actions, options) {
240
+ applyFinalStateOutput(machine, snapshot);
241
+ return {
242
+ snapshot,
243
+ actions,
244
+ requests: getAgentRequests(getPendingInvokes(snapshot), {
245
+ ...options,
246
+ snapshot
247
+ }),
248
+ done: snapshot.status === "done"
249
+ };
250
+ }
251
+ function resolveStateValueConfig(config, value) {
252
+ if (typeof value === "string") return config.states?.[value];
253
+ if (!value || typeof value !== "object") return;
254
+ for (const [key, childValue] of Object.entries(value)) {
255
+ const childConfig = config.states?.[key];
256
+ if (!childConfig) continue;
257
+ if (childConfig.type === "final") return childConfig;
258
+ const nested = resolveStateValueConfig(childConfig, childValue);
259
+ if (nested) return nested;
260
+ }
261
+ }
262
+ function applyFinalStateOutput(logic, snapshot, event) {
263
+ const machineSnapshot = snapshot;
264
+ if (machineSnapshot.status !== "done" || machineSnapshot.output !== void 0 || !("config" in logic)) return;
265
+ const config = logic.config;
266
+ if (!config) return;
267
+ const output = resolveStateValueConfig(config, machineSnapshot.value)?.output;
268
+ if (output === void 0) return;
269
+ machineSnapshot.output = typeof output === "function" ? output({
270
+ context: machineSnapshot.context,
271
+ event
272
+ }) : output;
273
+ }
274
+ function isAgentStep(value) {
275
+ return !!value && typeof value === "object" && "snapshot" in value && "actions" in value && "requests" in value;
276
+ }
277
+ //#endregion
278
+ //#region src/run-agent.ts
279
+ /**
280
+ * Thrown by {@link runAgent} when a resume is given BOTH an `events` log and a
281
+ * `snapshot` that claims a position in that log (`agentMeta.logIndex`), and the
282
+ * two disagree about the state at that position. The log is the source of
283
+ * truth, so this is a host bug (a snapshot cached from a different lineage, or
284
+ * a snapshot mutated out of band), not a recoverable resume: pass the log
285
+ * alone, or the matching snapshot.
286
+ */
287
+ var AgentSnapshotDivergedError = class extends AgentError {
288
+ constructor(expected, actual, logIndex) {
289
+ super("snapshot-diverged", `runAgent: the resume snapshot disagrees with the event log at index ${logIndex}: the log replays to state hash '${expected}', the snapshot hashes '${actual}'.`);
290
+ this.expected = expected;
291
+ this.actual = actual;
292
+ this.logIndex = logIndex;
293
+ this.name = "AgentSnapshotDivergedError";
294
+ }
295
+ };
296
+ function hashResumeSnapshot(snapshot) {
297
+ if (snapshot !== null && typeof snapshot === "object" && "agentMeta" in snapshot) {
298
+ const rest = {};
299
+ for (const [key, value] of Object.entries(snapshot)) if (key !== "agentMeta") rest[key] = value;
300
+ return getSnapshotStateHash(rest);
301
+ }
302
+ return getSnapshotStateHash(snapshot);
303
+ }
304
+ function readAgentMeta(snapshot) {
305
+ const meta = snapshot?.agentMeta;
306
+ return meta !== null && typeof meta === "object" ? meta : void 0;
307
+ }
308
+ /**
309
+ * The version of the {@link AgentTraceEvent} envelope every trace event carries
310
+ * as `schemaVersion`. Bumped only on a breaking change to the envelope or any
311
+ * payload shape, so a consumer can gate on it. Emitted identically by
312
+ * {@link runAgent}, {@link provideExecutors}' `onTrace`, and
313
+ * {@link traceTransitions}.
314
+ */
315
+ const AGENT_TRACE_SCHEMA_VERSION = 1;
316
+ const TRACE_ENVELOPE_KEYS = [
317
+ "schemaVersion",
318
+ "runId",
319
+ "seq",
320
+ "timestamp",
321
+ "machineId",
322
+ "machineVersion",
323
+ "type",
324
+ "status",
325
+ "cause",
326
+ "reasoning",
327
+ "finishReason",
328
+ "chunk"
329
+ ];
330
+ /**
331
+ * Best-effort JSON projection of an arbitrary value. Never throws: functions,
332
+ * symbols, `undefined`, and cyclic back-references are DROPPED (array holes
333
+ * become `null`), non-finite numbers become `null`, `bigint`s become strings,
334
+ * `Error`s become `{ name, message, stack?, code? }`, and anything with a
335
+ * `toJSON()` (e.g. `Date`) is projected through it — the same losses a
336
+ * `JSON.parse(JSON.stringify(...))` round-trip incurs, minus the throws.
337
+ */
338
+ function toJsonValue(value, ancestors) {
339
+ if (value === null) return null;
340
+ const type = typeof value;
341
+ if (type === "string" || type === "boolean") return value;
342
+ if (type === "number") return Number.isFinite(value) ? value : null;
343
+ if (type === "bigint") return value.toString();
344
+ if (type !== "object") return;
345
+ const object = value;
346
+ if (ancestors.includes(object)) return;
347
+ const nextAncestors = [...ancestors, object];
348
+ if (object instanceof Error) {
349
+ const serialized = {
350
+ name: object.name,
351
+ message: object.message
352
+ };
353
+ if (typeof object.stack === "string") serialized.stack = object.stack;
354
+ const code = object.code;
355
+ if (typeof code === "string") serialized.code = code;
356
+ const cause = toJsonValue(object.cause, nextAncestors);
357
+ if (cause !== void 0) serialized.cause = cause;
358
+ return serialized;
359
+ }
360
+ const toJSON = object.toJSON;
361
+ if (typeof toJSON === "function") return toJsonValue(toJSON.call(object), nextAncestors);
362
+ if (Array.isArray(object)) return object.map((item) => toJsonValue(item, nextAncestors) ?? null);
363
+ const out = {};
364
+ for (const [key, item] of Object.entries(object)) {
365
+ const serializedItem = toJsonValue(item, nextAncestors);
366
+ if (serializedItem !== void 0) out[key] = serializedItem;
367
+ }
368
+ return out;
369
+ }
370
+ /**
371
+ * Projects an {@link AgentTraceEvent} into a guaranteed JSON-safe envelope —
372
+ * the form the trace stream is actually sold for (one `JSON.stringify` per line
373
+ * in a JSONL file). Live values are sanitized rather than trusted:
374
+ *
375
+ * - Snapshots (`run.start`, `machine.transition`, `run.end`) go through the
376
+ * same JSON round-trip as `machine.getPersistedSnapshot(...)`, so what lands on disk is
377
+ * what a resume would see.
378
+ * - `request.end`'s `raw` (a provider SDK object, frequently cyclic) is DROPPED
379
+ * unless `includeRaw` is set, in which case it is sanitized like everything
380
+ * else.
381
+ * - Non-serializable values anywhere (functions, symbols, `undefined`, cyclic
382
+ * back-references) are dropped; `Error`s become `{ name, message, stack?,
383
+ * code? }` instead of `{}`. Nothing throws.
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * await appendFile('trace.jsonl', JSON.stringify(serializeTraceEvent(event)) + '\n');
388
+ * ```
389
+ */
390
+ function serializeTraceEvent(event, options = {}) {
391
+ const out = {};
392
+ for (const [key, value] of Object.entries(event)) {
393
+ if (key === "raw" && !options.includeRaw) continue;
394
+ if (TRACE_ENVELOPE_KEYS.includes(key)) {
395
+ if (value !== void 0) out[key] = value;
396
+ continue;
397
+ }
398
+ const serialized = toJsonValue(value, []);
399
+ if (serialized !== void 0) out[key] = serialized;
400
+ }
401
+ return out;
402
+ }
403
+ let nextRunAgentTraceId = 1;
404
+ /**
405
+ * Thrown into the invoke that would have made the call once
406
+ * {@link RunAgentOptions.maxModelCalls} is spent. It reaches the machine
407
+ * through the normal error channel, so an invoke's `onError` can branch on it
408
+ * (`error.code === 'max-model-calls'`, the same string the settled result's
409
+ * `cause` uses) and route to a degraded/finish state instead of failing the
410
+ * run. Unhandled, it settles `{ status: 'error', cause: 'max-model-calls' }`.
411
+ *
412
+ * ```ts
413
+ * onError: [
414
+ * { guard: ({ event }) => event.error?.code === 'max-model-calls', target: 'budgetSpent' },
415
+ * { target: 'failed' },
416
+ * ]
417
+ * ```
418
+ */
419
+ var AgentMaxModelCallsExceededError = class extends AgentError {
420
+ /** The budget that was exceeded (`options.maxModelCalls`). */
421
+ maxModelCalls;
422
+ constructor(maxModelCalls) {
423
+ super("max-model-calls", `runAgent exceeded maxModelCalls (${maxModelCalls}). Raise the budget, or handle it in the invoke's onError (error.code === 'max-model-calls').`);
424
+ this.name = "AgentMaxModelCallsExceededError";
425
+ this.maxModelCalls = maxModelCalls;
426
+ }
427
+ };
428
+ function wrapsDecisionExhausted(error) {
429
+ let current = error;
430
+ for (let depth = 0; depth < 10 && current != null; depth++) {
431
+ if (current instanceof AgentDecisionExhaustedError) return true;
432
+ current = current.cause;
433
+ }
434
+ return false;
435
+ }
436
+ /**
437
+ * Recursively collects every invoke's `src` from raw machine config (spike
438
+ * S6: `machine.config` preserves authored srcs; the built `machine.root`
439
+ * normalizes object srcs to synthetic string ids and loses the distinction
440
+ * this walk needs). Function-valued `src` resolvers are dynamic and are not
441
+ * statically analyzable, so they are skipped (pass-through, like any other
442
+ * non-agent actor).
443
+ */
444
+ function collectConfiguredInvokeSrcs(stateConfig, stateName, out) {
445
+ if (!stateConfig) return;
446
+ const invokes = stateConfig.invoke === void 0 ? [] : Array.isArray(stateConfig.invoke) ? stateConfig.invoke : [stateConfig.invoke];
447
+ for (const invokeConfig of invokes) {
448
+ const src = invokeConfig?.src;
449
+ if (typeof src === "string" || src && typeof src === "object") out.push({
450
+ stateName,
451
+ src
452
+ });
453
+ }
454
+ for (const [childName, childConfig] of Object.entries(stateConfig.states ?? {})) collectConfiguredInvokeSrcs(childConfig, `${stateName}.${childName}`, out);
455
+ }
456
+ /**
457
+ * Duck-types a state machine actor logic (an invoked child machine) vs. any
458
+ * other actor logic. xstate's `StateMachine` carries `.config`, `.root`, and
459
+ * a `.provide(...)` method plus a `sources.actors` map — this
460
+ * combination is unique to machines and survives the dual-package/version
461
+ * boundary an `instanceof` check would not. Used to descend the bind-time
462
+ * walk into invoked child machines (their internal agent requests are opaque
463
+ * to the parent-level source walk otherwise).
464
+ */
465
+ function isStateMachineLogic(logic) {
466
+ return !!logic && typeof logic === "object" && "config" in logic && "root" in logic && typeof logic.provide === "function" && typeof logic.sources === "object" && !!logic.sources?.actors;
467
+ }
468
+ /**
469
+ * Fails fast (throws) at bind time — before any actor runs — when the
470
+ * machine invokes an agent actor `runAgent` cannot execute. See §3.2 point 2.
471
+ *
472
+ * Recurses into invoked child state machines (arbitrarily deep). A child
473
+ * machine's agent requests reached through string-keyed invoke srcs DO inherit
474
+ * the parent runAgent's `generateText`/`streamText`/`decide` executors —
475
+ * runAgent rebinds them with the same host-backed wrappers (see
476
+ * {@link rebindChildMachine}) — so the only remaining bind-time errors are: a
477
+ * required executor kind missing entirely (naming the invoke chain and src),
478
+ * and an unbound request reached through a direct-object invoke src that can't
479
+ * be rebound ({@link unrebindableChildRequestError}). A request that carries
480
+ * its own executor (`.withExecutor(...)`, tracked in `executorBoundLogics`)
481
+ * always runs itself; explicit binding shadows inheritance.
482
+ */
483
+ function assertBindable(machine, effectiveSources, executors) {
484
+ assertMachineBindable(machine, effectiveSources, executors, {
485
+ isChild: false,
486
+ childPath: "",
487
+ rebindable: true,
488
+ visited: new Set([machine])
489
+ });
490
+ }
491
+ function assertMachineBindable(machine, effectiveSources, executors, ctx) {
492
+ const invokes = [];
493
+ collectConfiguredInvokeSrcs(machine.config, machine.config.id ?? "(root)", invokes);
494
+ const where = ctx.isChild ? `child machine '${ctx.childPath}' state` : "state";
495
+ for (const { stateName, src } of invokes) {
496
+ if (typeof src !== "string") {
497
+ if (isStateMachineLogic(src)) {
498
+ assertChildMachineBindable(src, src, stateName, executors, ctx);
499
+ continue;
500
+ }
501
+ if ((isTextLogic(src) || isDecisionLogic(src)) && !executorBoundLogics.has(src)) throw new Error(`runAgent: ${where} '${stateName}' invokes a direct-object actor logic (kind: '${src.kind}'). Direct-object invoke srcs cannot be rebound by runAgent — either call '.withExecutor(...)' on the logic before invoking it, or register it as a string-keyed actor source instead (machine.provide({ actors: { name: logic } })) and invoke it by name.`);
502
+ continue;
503
+ }
504
+ const logic = effectiveSources[src];
505
+ if (logic === void 0) throw new Error(`runAgent: ${where} '${stateName}' invokes unregistered actor source '${src}'. Provide it via machine.provide({ actors: { '${src}': ... } }) or runAgent(machine, { actors: { '${src}': ... } }).`);
506
+ if (isStateMachineLogic(logic)) {
507
+ assertChildMachineBindable(logic, src, stateName, executors, ctx);
508
+ continue;
509
+ }
510
+ if (isDecisionLogic(logic)) {
511
+ if (executorBoundLogics.has(logic)) continue;
512
+ if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, "decision");
513
+ if (!executors.decide) throw new Error(`runAgent: ${where} '${stateName}' invokes decision source '${src}' but no 'decide' executor was provided to runAgent(...).`);
514
+ continue;
515
+ }
516
+ if (isTextLogic(logic)) {
517
+ if (executorBoundLogics.has(logic)) continue;
518
+ if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, logic.mode === "stream" ? "streaming text" : "text");
519
+ if (logic.mode === "stream" && !executors.streamText) throw new Error(`runAgent: ${where} '${stateName}' invokes streaming text source '${src}' but no 'streamText' executor was provided to runAgent(...).`);
520
+ if (logic.mode !== "stream" && !executors.generateText) throw new Error(`runAgent: ${where} '${stateName}' invokes text source '${src}' but no 'generateText' executor was provided to runAgent(...).`);
521
+ continue;
522
+ }
523
+ if (isUnboundPlaceholder(logic)) throw new Error(`runAgent: ${where} '${stateName}' invokes actor source '${src}', which has no host execution. Provide it via machine.provide({ actors: { '${src}': ... } }) or runAgent(machine, { actors: { '${src}': ... } }).`);
524
+ }
525
+ }
526
+ /** Descends the bind-time walk into an invoked child state machine, guarding
527
+ * against a machine that (transitively) invokes itself. */
528
+ function assertChildMachineBindable(childMachine, childSrc, stateName, executors, ctx) {
529
+ if (ctx.visited.has(childMachine)) return;
530
+ const childName = typeof childSrc === "string" ? childSrc : childMachine.config.id ?? "(child machine)";
531
+ const childPath = ctx.childPath ? `${ctx.childPath} > ${childName}` : childName;
532
+ const childSources = childMachine.sources.actors;
533
+ assertMachineBindable(childMachine, childSources, executors, {
534
+ isChild: true,
535
+ childPath,
536
+ rebindable: ctx.rebindable && typeof childSrc === "string",
537
+ visited: new Set([...ctx.visited, childMachine])
538
+ });
539
+ }
540
+ /** The loud bind-time error for an unbound agent request reached under a
541
+ * direct-object invoke src, which runAgent cannot rebind (only string-keyed
542
+ * sources can be swapped via `.provide`). Names the invoke chain AND the
543
+ * request src, and spells out the `.withExecutor`/string-keyed remedy. Note:
544
+ * requests reachable through string-keyed srcs at any depth DO inherit
545
+ * runAgent's executors — this error is only for the unrebindable direct-object
546
+ * case. */
547
+ function unrebindableChildRequestError(childPath, stateName, requestSrc, kind) {
548
+ return /* @__PURE__ */ new Error(`runAgent: child machine '${childPath}' (state '${stateName}') invokes ${kind} source '${requestSrc}', which has no host execution and is reached through a direct-object invoke src that runAgent cannot rebind. Requests reached through string-keyed actor sources inherit runAgent's generateText/streamText/decide executors automatically; a direct-object child machine does not. Either bind the request with its own executor (requestLogic.withExecutor(...)), or register the child as a string-keyed actor source (machine.provide({ actors: { <child>: childMachine } })) and invoke it by name.`);
549
+ }
550
+ /**
551
+ * True when the snapshot's active states declare a transition that would
552
+ * receive the reserved `'@agent.usage'` type — an explicit `on: { '@agent.usage'
553
+ * }` OR a catch-all `on: { '*': … }`. Plain XState semantics apply unmodified:
554
+ * a wildcard matches every event delivered to the machine, reserved ones
555
+ * included. (The MODEL-facing side stays closed: `getAcceptedEvents` drops
556
+ * `@agent.*` before any `allowedEvents` matching, so a wildcard never offers
557
+ * the reserved event as a decision candidate.) @internal
558
+ */
559
+ function declaresUsageTransition(snapshot) {
560
+ return getNextTransitions(snapshot).some((transition) => transition.eventType === "@agent.usage" || transition.eventType === "*");
561
+ }
562
+ /**
563
+ * Builds the ONE place a trace payload is emitted: it hands the payload to the
564
+ * envelope-stamping trace sink and, from that same payload, invokes the sugar
565
+ * callbacks that are projections of it — {@link RunAgentOptions.onChunk},
566
+ * {@link RunAgentOptions.onResult}, {@link RunAgentOptions.onTransition}. Each
567
+ * keeps its historical position relative to the trace: `onResult` fires just
568
+ * BEFORE its `request.end`, `onChunk`/`onTransition` just AFTER their
569
+ * `stream.chunk`/`machine.transition`. Sugar dispatch never depends on whether
570
+ * a trace sink is present, and the trace sink is never called when it is
571
+ * absent — so an `onTrace`-less run still mints no envelope (and advances no
572
+ * `seq`). @internal
573
+ */
574
+ function createTraceDispatch(sinks) {
575
+ return (payload, self) => {
576
+ switch (payload.type) {
577
+ case "stream.chunk":
578
+ sinks.onTrace?.(payload, self);
579
+ sinks.onChunk?.(payload.chunk, { request: payload.request });
580
+ return;
581
+ case "request.end":
582
+ sinks.onResult?.(payload.request, {
583
+ result: payload.output,
584
+ raw: payload.raw
585
+ });
586
+ sinks.onTrace?.(payload, self);
587
+ return;
588
+ case "machine.transition":
589
+ sinks.onTrace?.(payload, self);
590
+ sinks.onTransition?.(payload.snapshot, payload.event);
591
+ return;
592
+ default: sinks.onTrace?.(payload, self);
593
+ }
594
+ };
595
+ }
596
+ /** Reads the durable invoke id/src off the async actor's own ref (`self`). */
597
+ function selfIdAndSrc(self) {
598
+ return {
599
+ id: typeof self?.id === "string" ? self.id : "",
600
+ src: typeof self?.src === "string" ? self.src : ""
601
+ };
602
+ }
603
+ /**
604
+ * The machine actor that INVOKED a decision request — the actor whose
605
+ * live snapshot supplies the candidate events and drives `canTake`/`send`.
606
+ * For a top-level request this is the root actor (identity-equal to
607
+ * `runCtx.actorHolder.actorRef`); for a request inside an invoked child
608
+ * machine it is that child's actor, so a child decision reads and drives
609
+ * the CHILD's snapshot — not the root's. Read off `self._parent`, with the
610
+ * root actor as a fallback.
611
+ */
612
+ function invokingActorOf(self, runCtx) {
613
+ return self?._parent ?? runCtx.actorHolder.actorRef;
614
+ }
615
+ /**
616
+ * The shared text/stream emission helper: binds a {@link TextLogic} to
617
+ * `runCtx`'s executor and constructs the `request.start` / `stream.chunk` /
618
+ * `request.end` (incl. the lifted `reasoning`) / `request.error` trace payloads.
619
+ * Used by both `runAgent` and `provideExecutors` so the two paths produce
620
+ * identical event shapes by construction. @internal
621
+ */
622
+ function bindTextLogic(logic, runCtx) {
623
+ return logic.withExecutor(async ({ request: rawRequest, self: selfArg, signal }) => {
624
+ const self = selfArg;
625
+ const { id, src } = selfIdAndSrc(self);
626
+ const request = {
627
+ ...rawRequest,
628
+ name: rawRequest.name ?? (src !== "" && src !== "agent.generateText" && src !== "agent.streamText" ? src : id || src)
629
+ };
630
+ const executor = logic.mode === "stream" ? runCtx.streamText : runCtx.generateText;
631
+ if (!executor) throw new Error(`No '${logic.mode === "stream" ? "streamText" : "generateText"}' executor provided.`);
632
+ const requestWithTools = {
633
+ ...request,
634
+ tools: request.tools ?? {}
635
+ };
636
+ const agentRequest = {
637
+ kind: "text",
638
+ id,
639
+ src,
640
+ mode: logic.mode,
641
+ input: request,
642
+ tools: requestWithTools.tools,
643
+ events: []
644
+ };
645
+ runCtx.consumeModelCall();
646
+ runCtx.emitTrace?.({
647
+ type: "request.start",
648
+ request: agentRequest
649
+ }, self);
650
+ try {
651
+ const callKey = id !== "" ? runCtx.callKey?.(id, self) : void 0;
652
+ await runCtx.awaitJournal?.();
653
+ const raw = await executor(requestWithTools, {
654
+ onChunk: (chunk) => {
655
+ runCtx.emitTrace?.({
656
+ type: "stream.chunk",
657
+ request: agentRequest,
658
+ chunk
659
+ }, self);
660
+ },
661
+ signal,
662
+ ...runCtx.runId !== void 0 ? { runId: runCtx.runId } : {},
663
+ ...id !== "" ? { requestId: id } : {},
664
+ ...callKey !== void 0 ? { callKey } : {}
665
+ });
666
+ const output = await normalizeGeneratorResult(raw, id);
667
+ const rawReasoning = raw?.reasoning;
668
+ const reasoning = typeof rawReasoning === "string" ? rawReasoning : void 0;
669
+ const usage = getCallUsage(raw);
670
+ const finishReason = getCallFinishReason(raw);
671
+ if (usage) runCtx.recordUsage?.(usage, {
672
+ kind: "text",
673
+ ...id !== "" ? { id } : {},
674
+ ...src !== "" ? { src } : {},
675
+ model: request.model,
676
+ ...request.name !== void 0 ? { name: request.name } : {}
677
+ }, self);
678
+ runCtx.emitTrace?.({
679
+ type: "request.end",
680
+ request: agentRequest,
681
+ output,
682
+ raw,
683
+ ...reasoning !== void 0 ? { reasoning } : {},
684
+ ...usage !== void 0 ? { usage } : {},
685
+ ...finishReason !== void 0 ? { finishReason } : {}
686
+ }, self);
687
+ return {
688
+ result: output,
689
+ messages: responseMessagesOf(raw)
690
+ };
691
+ } catch (error) {
692
+ runCtx.emitTrace?.({
693
+ type: "request.error",
694
+ request: agentRequest,
695
+ error
696
+ }, self);
697
+ throw error;
698
+ }
699
+ });
700
+ }
701
+ function createCountingDecide(runCtx, self) {
702
+ return async (attemptRequest, info) => {
703
+ runCtx.consumeModelCall();
704
+ runCtx.emitTrace?.({
705
+ type: "request.start",
706
+ request: attemptRequest
707
+ }, self);
708
+ try {
709
+ const { id } = selfIdAndSrc(self);
710
+ const invokeCallKey = id !== "" ? runCtx.callKey?.(id, self) : void 0;
711
+ const callKey = invokeCallKey === void 0 ? void 0 : `${invokeCallKey}.${attemptRequest.attempts?.length ?? 0}`;
712
+ await runCtx.awaitJournal?.();
713
+ const result = await runCtx.decide(runCtx.runId !== void 0 ? {
714
+ ...attemptRequest,
715
+ runId: runCtx.runId
716
+ } : attemptRequest, {
717
+ ...info,
718
+ ...runCtx.runId !== void 0 ? { runId: runCtx.runId } : {},
719
+ ...info?.requestId === void 0 && id !== "" ? { requestId: id } : {},
720
+ ...info?.callKey === void 0 && callKey !== void 0 ? { callKey } : {}
721
+ });
722
+ const usage = getCallUsage(result);
723
+ const finishReason = getCallFinishReason(result);
724
+ if (usage) {
725
+ const { src } = selfIdAndSrc(self);
726
+ runCtx.recordUsage?.(usage, {
727
+ kind: "decision",
728
+ ...attemptRequest.id ? { id: attemptRequest.id } : {},
729
+ ...src !== "" ? { src } : {},
730
+ model: attemptRequest.model
731
+ }, self);
732
+ }
733
+ runCtx.emitTrace?.({
734
+ type: "request.end",
735
+ request: attemptRequest,
736
+ output: result.event,
737
+ raw: result,
738
+ ...usage !== void 0 ? { usage } : {},
739
+ ...finishReason !== void 0 ? { finishReason } : {}
740
+ }, self);
741
+ return result;
742
+ } catch (error) {
743
+ runCtx.emitTrace?.({
744
+ type: "request.error",
745
+ request: attemptRequest,
746
+ error
747
+ }, self);
748
+ throw error;
749
+ }
750
+ };
751
+ }
752
+ /**
753
+ * Builds the decision actor logic runAgent installs in place of a
754
+ * `DecisionLogic`/`agent.decide` source. `DecisionLogic.withExecutor(...)`
755
+ * can only swap the innermost per-attempt executor — the `resolveDecision(...)`
756
+ * call (and its `canTake`) is hardwired inside the original logic's `run`.
757
+ * To supply `canTake` (mode-3, §2.6), runAgent instead builds a fresh async
758
+ * logic here that calls `resolveDecision` itself, reusing `logic.request(...)`
759
+ * to build the request the same way the original logic would have.
760
+ *
761
+ * On success it SENDS the chosen event to the invoking actor (auto-delivery)
762
+ * and then completes with that event
763
+ * as its output — so callers never wire an `onDone` to deliver it. See the
764
+ * send-then-complete note inside `run` for how exit-cancels-invoke interacts
765
+ * with `onDone`.
766
+ */
767
+ function bindDecisionLogic(logic, runCtx) {
768
+ const decisionLogic = createAsyncLogic({ run: async ({ input, signal, self: selfArg }) => {
769
+ if (!runCtx.decide) throw new Error("No 'decide' executor provided.");
770
+ const self = selfArg;
771
+ const { id } = selfIdAndSrc(self);
772
+ const declaredEventTypes = logic.allowedEventTypes?.(input);
773
+ await Promise.resolve();
774
+ const actorRef = invokingActorOf(self, runCtx);
775
+ const events = actorRef ? getAcceptedEvents(actorRef.getSnapshot(), {
776
+ schemas: runCtx.schemas,
777
+ eventTypes: declaredEventTypes
778
+ }) : [];
779
+ const lowered = logic.request(input);
780
+ const chosen = await resolveDecision({
781
+ ...lowered,
782
+ id,
783
+ name: lowered.name ?? id,
784
+ input,
785
+ events
786
+ }, { decide: createCountingDecide(runCtx, self) }, {
787
+ maxRetries: logic.maxRetries,
788
+ signal,
789
+ canTake: (event) => actorRef ? actorRef.getSnapshot().can(event) : true
790
+ });
791
+ actorRef?.send(chosen);
792
+ await Promise.resolve();
793
+ return chosen;
794
+ } });
795
+ return Object.assign(decisionLogic, {
796
+ kind: "statelyai.decisionLogic",
797
+ maxRetries: logic.maxRetries,
798
+ request: logic.request,
799
+ withExecutor: (nextExecute) => bindDecisionLogic(logic.withExecutor(nextExecute), runCtx)
800
+ });
801
+ }
802
+ /**
803
+ * The set of string-keyed actor `src`s the machine's own config invokes
804
+ * (top-level, recursing into child STATES but not into invoked child
805
+ * machines). {@link provideExecutors} uses it to require an executor only for a
806
+ * source the machine actually invokes — the always-registered `agent.*`
807
+ * builtins that go unused must not force their executors to be supplied.
808
+ * @internal
809
+ */
810
+ function getConfiguredInvokeSrcs(machine) {
811
+ const invokes = [];
812
+ collectConfiguredInvokeSrcs(machine.config, machine.config.id ?? "(root)", invokes);
813
+ const srcs = /* @__PURE__ */ new Set();
814
+ for (const { src } of invokes) if (typeof src === "string") srcs.add(src);
815
+ return srcs;
816
+ }
817
+ const rootTraceRegistry = /* @__PURE__ */ new WeakMap();
818
+ let nextProvideRunId = 1;
819
+ /** Walks `self._parent` from an invoked async leaf actor up to its root actor. */
820
+ function rootActorOf(self) {
821
+ let ref = self;
822
+ while (ref?._parent) ref = ref._parent;
823
+ return ref;
824
+ }
825
+ /** The per-root envelope state, minted on first use (runId `run_<n>`, matching runAgent). */
826
+ function rootTraceState(root) {
827
+ let state = rootTraceRegistry.get(root);
828
+ if (!state) {
829
+ const logic = root.logic;
830
+ const machineId = (logic?.config)?.id ?? logic?.id ?? "(machine)";
831
+ const machineVersion = logic ? resolveMachineVersion(logic) : "";
832
+ state = {
833
+ runId: `run_${nextProvideRunId++}`,
834
+ seq: 0,
835
+ machineId,
836
+ machineVersion
837
+ };
838
+ rootTraceRegistry.set(root, state);
839
+ }
840
+ return state;
841
+ }
842
+ /** Stamps a per-root-actor envelope onto a bare trace payload. */
843
+ function stampRootTrace(root, payload) {
844
+ const state = rootTraceState(root);
845
+ return {
846
+ schemaVersion: 1,
847
+ runId: state.runId,
848
+ seq: ++state.seq,
849
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
850
+ machineId: state.machineId,
851
+ machineVersion: state.machineVersion,
852
+ ...payload
853
+ };
854
+ }
855
+ /** Adapts a public `onTrace` into the payload-level trace sink a {@link TraceDispatch} fans out to. */
856
+ function provideTraceSink(onTrace) {
857
+ if (!onTrace) return;
858
+ return (payload, self) => {
859
+ const root = rootActorOf(self);
860
+ if (root) onTrace(stampRootTrace(root, payload));
861
+ };
862
+ }
863
+ /**
864
+ * A minimal {@link RunAgentBindContext} for `provideExecutors` (uncontrolled
865
+ * `createActor`): the same wrappers runAgent installs, MINUS the run-scoped
866
+ * model-call counter. `consumeModelCall` is a no-op (no budget), and
867
+ * `actorHolder.actorRef` is left undefined — the wrappers read the invoking
868
+ * actor off `self._parent`, always present under a live `createActor` tree.
869
+ * `onTrace` (when given) mints a per-root-actor envelope. `schemas` come from
870
+ * the machine's registered `setupAgent` execution options.
871
+ *
872
+ * `recordUsage` has no run-level aggregate to fold into here (there is no
873
+ * run), so it does one thing: deliver the reserved `@agent.usage` event, gated
874
+ * exactly like runAgent's — see {@link deliverUsageEvent}.
875
+ */
876
+ function provideBindContext(machine, executors, options) {
877
+ const traceSink = provideTraceSink(options.onTrace);
878
+ const onChunk = options.onChunk;
879
+ return {
880
+ generateText: executors.generateText,
881
+ streamText: executors.streamText,
882
+ decide: executors.decide,
883
+ emitTrace: traceSink || onChunk ? createTraceDispatch({
884
+ onTrace: traceSink,
885
+ onChunk: onChunk ? (chunk) => onChunk(chunk) : void 0
886
+ }) : void 0,
887
+ consumeModelCall: () => {},
888
+ recordUsage: (usage, source, self) => {
889
+ deliverUsageEvent({
890
+ type: AGENT_USAGE_EVENT_TYPE,
891
+ ...source,
892
+ usage
893
+ }, () => self?._parent);
894
+ },
895
+ actorHolder: { actorRef: void 0 },
896
+ schemas: getRegisteredAgentExecutionOptions(machine).schemas
897
+ };
898
+ }
899
+ /**
900
+ * The single reserved-`@agent.usage` DELIVERY seam, shared by both bind paths:
901
+ * after a bound call settles with reported usage, send the prebuilt `event` to
902
+ * the machine actor `resolveActorRef` names — the run's root actor on the `runAgent` path,
903
+ * the settling request actor's `self._parent` (always the invoking machine
904
+ * under a live `createActor` tree) on the `provideExecutors` path.
905
+ *
906
+ * Journaling is separate and unconditional (see `recordUsage`): a call's tokens
907
+ * are recorded in the event log whether or not the machine reacts to them.
908
+ *
909
+ * Gating is identical on both: the target snapshot must be active, must declare
910
+ * an `'@agent.usage'` transition — explicitly, or through a catch-all
911
+ * `on: { '*' }` (see {@link declaresUsageTransition}) — and must be able to
912
+ * take the event. `onDropped` is the run path's straggler gate: it returns `true` for a
913
+ * call that settled after the cycle resolved, which drops the event (traced as
914
+ * `usage.dropped`) rather than delivering it. Uncontrolled mode has no cycle to
915
+ * settle, so it passes no gate and has no dropped stragglers.
916
+ *
917
+ * Delivery follows each path's binding boundary: only sources IT bound report
918
+ * here, so an invoked child machine that was not itself passed through
919
+ * `provideExecutors` reports nothing. @internal
920
+ */
921
+ function deliverUsageEvent(event, resolveActorRef, onDropped) {
922
+ const actorRef = resolveActorRef();
923
+ if (!actorRef) return;
924
+ const snapshot = actorRef.getSnapshot();
925
+ if (snapshot?.status !== "active" || !declaresUsageTransition(snapshot)) return;
926
+ if (onDropped?.(event)) return;
927
+ if (!snapshot.can(event)) return;
928
+ actorRef.send(event);
929
+ }
930
+ /**
931
+ * Host-binds one text/stream source for {@link provideExecutors} using the SAME
932
+ * emission helper as `runAgent` ({@link bindTextLogic}), so a bound
933
+ * text request emits request.start/stream.chunk/request.end/request.error with
934
+ * identical shapes. @internal
935
+ */
936
+ function bindTextForProvide(machine, logic, executors, options) {
937
+ return bindTextLogic(logic, provideBindContext(machine, executors, options));
938
+ }
939
+ /**
940
+ * Host-binds one `DecisionLogic`/`agent.decide` source for
941
+ * {@link provideExecutors}: runAgent's decision wrapper (snapshot-driven
942
+ * candidate events, `canTake`, auto-delivery of the chosen event) with the same
943
+ * request-level tracing runAgent emits, minus run-scoped counting. @internal
944
+ */
945
+ function bindDecisionForProvide(machine, logic, executors, options) {
946
+ return bindDecisionLogic(logic, provideBindContext(machine, executors, options));
947
+ }
948
+ /**
949
+ * Recursively binds an invoked child state machine for {@link provideExecutors},
950
+ * with the same semantics `runAgent` applies ({@link rebindChildMachine}):
951
+ * string-keyed text/decision sources at any depth inherit the host executors,
952
+ * a source that carries its own executor is left alone, and a cycle is
953
+ * returned as-is. Each machine in the tree is bound with its own registered
954
+ * `setupAgent` schemas. Returns the original machine when nothing needed
955
+ * wrapping. @internal
956
+ */
957
+ function bindChildMachineForProvide(childMachine, executors, options, visited) {
958
+ const ctxFor = (target) => provideBindContext(target, executors, options);
959
+ return rebindChildMachine(childMachine, ctxFor(childMachine), visited, ctxFor);
960
+ }
961
+ /**
962
+ * Validates `input` against the machine's registered input schema, returning
963
+ * the schema's output — so defaults are filled and transforms applied before
964
+ * the value reaches `createActor` or the replayable event log.
965
+ *
966
+ * Standard Schema only (no validation library is referenced), so this works for
967
+ * whatever the machine was declared with. Omitted input stays omitted rather
968
+ * than being validated as `{}`: "started with no input" keeps meaning what it
969
+ * has always meant, instead of newly failing schemas with required fields.
970
+ */
971
+ function resolveMachineInput(machine, input) {
972
+ if (input === void 0) return input;
973
+ const schema = getRegisteredAgentExecutionOptions(machine).schemas?.input;
974
+ if (!isStandardSchema(schema)) return input;
975
+ try {
976
+ return validateSchemaSync(schema, input);
977
+ } catch (error) {
978
+ throw new AgentError("invalid-machine-input", `runAgent: machine input failed validation against the declared input schema: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
979
+ }
980
+ }
981
+ /**
982
+ * Recursively rebinds an invoked child machine's own agent sources with the
983
+ * SAME host-backed wrappers runAgent applies to the top-level machine, so a
984
+ * child's text/stream/decision requests inherit runAgent's executors and
985
+ * participate in maxModelCalls counting, onTrace/onChunk/onResult exactly like
986
+ * parent requests. Returns the child machine to invoke: a `.provide`-rebound
987
+ * copy when any inner source needed wrapping, else the original untouched.
988
+ *
989
+ * Only string-keyed sources are visited — a direct-object invoke src cannot be
990
+ * swapped via `.provide` (assertBindable already rejected an unbound request
991
+ * under one). A source that already carries its own executor
992
+ * (`executorBoundLogics`) is left as-is: explicit binding shadows inheritance.
993
+ * Cycle-safe via `visited` (a machine that invokes itself is returned as-is).
994
+ */
995
+ function rebindChildMachine(childMachine, runCtx, visited, ctxFor) {
996
+ if (visited.has(childMachine)) return childMachine;
997
+ const childVisited = new Set([...visited, childMachine]);
998
+ runCtx = ctxFor ? ctxFor(childMachine) : runCtx;
999
+ const sources = childMachine.sources.actors;
1000
+ const wrapped = {};
1001
+ for (const [key, logic] of Object.entries(sources)) {
1002
+ if (isDecisionLogic(logic)) {
1003
+ if (!executorBoundLogics.has(logic)) wrapped[key] = bindDecisionLogic(logic, runCtx);
1004
+ continue;
1005
+ }
1006
+ if (isTextLogic(logic)) {
1007
+ if (!executorBoundLogics.has(logic)) wrapped[key] = bindTextLogic(logic, runCtx);
1008
+ continue;
1009
+ }
1010
+ if (isStateMachineLogic(logic)) {
1011
+ const rebound = rebindChildMachine(logic, runCtx, childVisited, ctxFor);
1012
+ if (rebound !== logic) wrapped[key] = rebound;
1013
+ continue;
1014
+ }
1015
+ }
1016
+ return Object.keys(wrapped).length > 0 ? childMachine.provide({ actors: wrapped }) : childMachine;
1017
+ }
1018
+ /**
1019
+ * Runs an agent machine to completion or idle: a `createActor` host that
1020
+ * binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
1021
+ * `DecisionLogic` actor sources, starts (or resumes) the actor, and drives
1022
+ * it until it settles — {@link RunAgentResult} `done | idle | error`. Unlike
1023
+ * the step helpers ({@link initialAgentStep} etc — a pure
1024
+ * transition-at-a-time path for durable hosts), `runAgent` owns a live actor
1025
+ * internally; there is no continuation callback, so **idle always settles**
1026
+ * and the caller resumes explicitly by passing the settled `{ snapshot,
1027
+ * event }` back in. The actor is stopped on every settle path (`done`,
1028
+ * `idle`, and `error` alike) — resume is always by snapshot, never by
1029
+ * holding a reference to a live actor.
1030
+ *
1031
+ * Binding happens **before** the actor starts: every invoke the machine
1032
+ * could reach is walked and checked against the effective actor sources
1033
+ * (`options.actors` merged onto the machine), so a missing
1034
+ * `streamText`/`decide` executor or any other unbound actor source throws
1035
+ * immediately — a bind-time error, not a mid-run failure.
1036
+ *
1037
+ * @example
1038
+ * ```ts
1039
+ * const executors = createAiSdkExecutors({ models });
1040
+ * let r = await runAgent(machine, { input, executors });
1041
+ * while (r.status === 'idle') {
1042
+ * const event = await promptUser(getAcceptedEvents(r.snapshot));
1043
+ * r = await runAgent(machine, { snapshot: r.snapshot, event, executors });
1044
+ * }
1045
+ * if (r.status !== 'done') throw new Error(`Run did not complete: ${r.status}`);
1046
+ * console.log(r.output);
1047
+ * ```
1048
+ *
1049
+ * Each executor is a plain function returning `{ result }` (plus optional `messages`/`usage`), or
1050
+ * an adapter's set: `createAiSdkExecutors` from '@statelyai/agent/ai-sdk' or
1051
+ * `createOpenAiExecutors` from '@statelyai/agent/openai' supply all three.
1052
+ */
1053
+ async function runAgent(machine, options) {
1054
+ const store = options.store;
1055
+ if (store === void 0) return createAgentSession(machine, options).settled();
1056
+ const threadId = options.threadId;
1057
+ if (threadId === void 0 || threadId === "") throw new AgentError("missing-thread-id", "runAgent: `threadId` is required when `store` is given — it names the log thread to read and append to.");
1058
+ if (options.events !== void 0) {
1059
+ const storedThread = await store.read(threadId);
1060
+ if (storedThread.length !== options.events.length) throw new AgentEventLogConflictError(threadId, options.events.length, storedThread.length);
1061
+ assertThreadMatchesEvents(threadId, storedThread, options.events);
1062
+ return createAgentSession(machine, options).settled();
1063
+ }
1064
+ const stored = await store.read(threadId);
1065
+ return createAgentSession(machine, stored.length > 0 ? {
1066
+ ...options,
1067
+ events: stored
1068
+ } : options).settled();
1069
+ }
1070
+ /**
1071
+ * Entry-by-entry check that the caller's `events` IS the store's thread. Equal
1072
+ * lengths prove nothing: a fork, a rolled-back replay, or a concurrent writer
1073
+ * that appended and truncated all produce a divergent log of the same size,
1074
+ * and appending this run's entries onto it would splice two lineages together.
1075
+ */
1076
+ function assertThreadMatchesEvents(threadId, stored, events) {
1077
+ for (let index = 0; index < stored.length; index++) {
1078
+ const storedEntry = stored[index];
1079
+ const givenEntry = events[index];
1080
+ const storedHash = storedEntry.verification?.stateHash;
1081
+ const givenHash = givenEntry.verification?.stateHash;
1082
+ if (!(storedEntry.id === givenEntry.id && storedEntry.index === givenEntry.index && canonicalEventJson(storedEntry.event) === canonicalEventJson(givenEntry.event) && (storedHash === void 0 || givenHash === void 0 || storedHash === givenHash))) throw new AgentError("event-log-conflict", `runAgent: the given \`events\` diverge from thread "${threadId}" at index ${index} (stored entry '${storedEntry.id}', given '${givenEntry.id}') — the log passed in is not this thread's log.`);
1083
+ }
1084
+ }
1085
+ function createAgentSession(machine, options) {
1086
+ const maxModelCalls = options.maxModelCalls ?? 100;
1087
+ let modelCallCount = 0;
1088
+ let budgetExceeded = false;
1089
+ let warnedNonSerializable = false;
1090
+ const runId = `run_${nextRunAgentTraceId++}`;
1091
+ let traceSeq = 0;
1092
+ const resolvedInput = resolveMachineInput(machine, options.input);
1093
+ const machineId = machine.config.id ?? machine.id ?? "(machine)";
1094
+ const machineVersion = resolveMachineVersion(machine);
1095
+ const onTrace = createTraceDispatch({
1096
+ onTrace: (payload) => {
1097
+ options.onTrace?.({
1098
+ schemaVersion: 1,
1099
+ runId,
1100
+ seq: ++traceSeq,
1101
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1102
+ machineId,
1103
+ machineVersion,
1104
+ ...payload
1105
+ });
1106
+ },
1107
+ onChunk: options.onChunk,
1108
+ onResult: options.onResult,
1109
+ onTransition: options.onTransition
1110
+ });
1111
+ const consumeModelCall = () => {
1112
+ if (budgetExceeded) throw new AgentMaxModelCallsExceededError(maxModelCalls);
1113
+ if (modelCallCount + 1 > maxModelCalls) {
1114
+ budgetExceeded = true;
1115
+ throw new AgentMaxModelCallsExceededError(maxModelCalls);
1116
+ }
1117
+ modelCallCount += 1;
1118
+ };
1119
+ const cycleGate = { isResolved: () => false };
1120
+ const logEntries = [];
1121
+ const store = options.store;
1122
+ const threadId = options.threadId;
1123
+ if (store !== void 0 && (threadId === void 0 || threadId === "")) throw new AgentError("missing-thread-id", "runAgent: `threadId` is required when `store` is given — it names the log thread to read and append to.");
1124
+ let journalChain = Promise.resolve();
1125
+ let journalPending = 0;
1126
+ let journalError;
1127
+ const journalEntry = (entry) => {
1128
+ if (store === void 0) return;
1129
+ journalPending++;
1130
+ journalChain = journalChain.then(async () => {
1131
+ if (journalError !== void 0) return;
1132
+ await store.append({
1133
+ threadId,
1134
+ expectedIndex: entry.index,
1135
+ entries: [entry]
1136
+ });
1137
+ }).catch((error) => {
1138
+ journalError ??= error;
1139
+ failRunOnJournalError(error);
1140
+ }).finally(() => {
1141
+ journalPending--;
1142
+ });
1143
+ };
1144
+ /**
1145
+ * Every journal write ISSUED SO FAR, including the stragglers appended after
1146
+ * the run settled. Re-reads the chain tail until it stops moving, so a write
1147
+ * queued while an earlier one was in flight is covered too. Never rejects: a
1148
+ * failed write already settled the run with `cause: 'journal'`.
1149
+ */
1150
+ const drainJournal = async () => {
1151
+ if (store === void 0) return;
1152
+ let tail = journalChain;
1153
+ for (;;) {
1154
+ await tail;
1155
+ if (journalPending === 0 && journalChain === tail) return;
1156
+ tail = journalChain;
1157
+ }
1158
+ };
1159
+ /** The barrier: settle the pending chain, then surface any failure. */
1160
+ const awaitJournal = async () => {
1161
+ if (store === void 0) return;
1162
+ while (journalPending > 0) await journalChain;
1163
+ if (journalError !== void 0) throw journalError;
1164
+ };
1165
+ const failRunOnJournalError = (error) => {
1166
+ if (settled) return;
1167
+ settle({
1168
+ status: "error",
1169
+ cause: "journal",
1170
+ error,
1171
+ snapshot: actor.getSnapshot()
1172
+ });
1173
+ };
1174
+ let resumedLogLength = 0;
1175
+ let logExecutionId;
1176
+ const verificationEnabled = options.verification !== false;
1177
+ let lastRootSnapshot;
1178
+ let logMachine = machine;
1179
+ let loggingEnabled = true;
1180
+ const appendLogEntry = (event, snapshot) => {
1181
+ if (!loggingEnabled) return;
1182
+ const entry = createReplayEntry(logMachine, logEntries, event, {
1183
+ machineVersion,
1184
+ verification: verificationEnabled,
1185
+ ...verificationEnabled && snapshot !== void 0 ? { snapshot } : {}
1186
+ });
1187
+ logEntries.push(entry);
1188
+ journalEntry(entry);
1189
+ options.onEvent?.(entry);
1190
+ return entry;
1191
+ };
1192
+ const usageEntrySnapshot = () => {
1193
+ const current = lastRootSnapshot;
1194
+ if (current && (current.status !== "active" || !declaresUsageTransition(current))) return current;
1195
+ };
1196
+ const recordUsage = (usage, source = {}) => {
1197
+ const event = {
1198
+ type: AGENT_USAGE_EVENT_TYPE,
1199
+ ...source,
1200
+ usage
1201
+ };
1202
+ const journal = { event };
1203
+ pendingUsageJournal = journal;
1204
+ try {
1205
+ deliverUsageEvent(event, () => actorHolder.actorRef, (dropped) => {
1206
+ if (!cycleGate.isResolved()) return false;
1207
+ onTrace({
1208
+ type: "usage.dropped",
1209
+ event: dropped,
1210
+ reason: "settled"
1211
+ });
1212
+ return true;
1213
+ });
1214
+ } finally {
1215
+ pendingUsageJournal = void 0;
1216
+ }
1217
+ if (journal.entry === void 0) appendLogEntry(event, usageEntrySnapshot());
1218
+ };
1219
+ let pendingUsageJournal;
1220
+ const runUsage = () => ({
1221
+ ...getUsageFromEvents(logEntries.slice(resumedLogLength)),
1222
+ modelCalls: modelCallCount
1223
+ });
1224
+ const warnNonSerializableContext = (snapshot) => {
1225
+ if (warnedNonSerializable || process.env.NODE_ENV === "production") return;
1226
+ let offending = [];
1227
+ try {
1228
+ offending = findNonSerializableContextPaths(snapshot.context);
1229
+ } catch {
1230
+ return;
1231
+ }
1232
+ if (offending.length === 0) return;
1233
+ warnedNonSerializable = true;
1234
+ console.warn(`runAgent: context holds value(s) that will not survive snapshot persist/resume (JSON round-trip): ${offending.join(", ")}. Persist only JSON-serializable context, or convert these before the run settles.`);
1235
+ };
1236
+ const provided = machine.provide({ actors: options.actors });
1237
+ logMachine = provided;
1238
+ const effectiveSources = provided.sources.actors;
1239
+ const executors = { ...options.executors };
1240
+ assertBindable(provided, effectiveSources, executors);
1241
+ const actorHolder = { actorRef: void 0 };
1242
+ const runCtx = {
1243
+ generateText: executors.generateText,
1244
+ streamText: executors.streamText,
1245
+ decide: executors.decide,
1246
+ emitTrace: onTrace,
1247
+ consumeModelCall,
1248
+ recordUsage,
1249
+ actorHolder,
1250
+ awaitJournal,
1251
+ runId,
1252
+ schemas: getRegisteredAgentExecutionOptions(machine).schemas
1253
+ };
1254
+ const wrappedSources = {};
1255
+ for (const [key, logic] of Object.entries(effectiveSources)) {
1256
+ if (isDecisionLogic(logic)) {
1257
+ wrappedSources[key] = bindDecisionLogic(logic, runCtx);
1258
+ continue;
1259
+ }
1260
+ if (isTextLogic(logic)) {
1261
+ if (!executorBoundLogics.has(logic)) wrappedSources[key] = bindTextLogic(logic, runCtx);
1262
+ continue;
1263
+ }
1264
+ if (isStateMachineLogic(logic)) {
1265
+ const rebound = rebindChildMachine(logic, runCtx, new Set([machine]));
1266
+ if (rebound !== logic) wrappedSources[key] = rebound;
1267
+ continue;
1268
+ }
1269
+ }
1270
+ const boundMachine = provided.provide({ actors: wrappedSources });
1271
+ const isIdle = getMachineIdlePredicate(machine) ?? isAgentIdle;
1272
+ const isIntentionalIdle = (snapshot) => isIdle(snapshot);
1273
+ const resumeEvents = options.events;
1274
+ let effectiveSnapshot = options.snapshot;
1275
+ /** Deferred until after the illegal-resume check, so a rejected resume emits no entries. */
1276
+ let seedInitEntry;
1277
+ const restoredPersistedSnapshot = () => {
1278
+ try {
1279
+ const restored = logMachine.restoreSnapshot(options.snapshot);
1280
+ return logMachine.getPersistedSnapshot(restored);
1281
+ } catch {
1282
+ return;
1283
+ }
1284
+ };
1285
+ /**
1286
+ * Appends the log's reserved first entry, trying each candidate `init` in
1287
+ * turn and, for each, an unverified entry if the hash cannot be computed.
1288
+ * A machine or snapshot that defeats every attempt leaves the run WITHOUT a
1289
+ * log rather than failing it: `runAgent` predates the log, and an exotic
1290
+ * machine that cannot be folded must still run.
1291
+ */
1292
+ const appendInitEntry = (candidates, metadata) => {
1293
+ for (const init of candidates) for (const verification of verificationEnabled ? [true, false] : [false]) try {
1294
+ const entry = initEntry(logMachine, init, {
1295
+ machineVersion,
1296
+ verification,
1297
+ metadata
1298
+ });
1299
+ logEntries.push(entry);
1300
+ journalEntry(entry);
1301
+ options.onEvent?.(entry);
1302
+ return;
1303
+ } catch {}
1304
+ loggingEnabled = false;
1305
+ };
1306
+ /** Init forms for a snapshot resume, most faithful first. */
1307
+ const snapshotInitCandidates = () => {
1308
+ const restored = restoredPersistedSnapshot();
1309
+ return [...restored !== void 0 ? [{ snapshot: restored }] : [], { snapshot: options.snapshot }];
1310
+ };
1311
+ if (resumeEvents !== void 0 && resumeEvents.length > 0) {
1312
+ validateReplayEntries(resumeEvents);
1313
+ const tail = resumeEvents[resumeEvents.length - 1];
1314
+ const inheritedExecutionId = getLogExecutionId(resumeEvents);
1315
+ if (resumeEvents[0].machineId !== machineId) throw new AgentMachineVersionMismatchError(tail.id, tail.index, {
1316
+ machineId,
1317
+ machineVersion
1318
+ }, {
1319
+ machineId: resumeEvents[0].machineId,
1320
+ machineVersion: tail.machineVersion
1321
+ });
1322
+ if (tail.machineVersion === machineVersion) {
1323
+ logEntries.push(...resumeEvents);
1324
+ resumedLogLength = logEntries.length;
1325
+ logExecutionId = inheritedExecutionId;
1326
+ const cachedMeta = readAgentMeta(options.snapshot);
1327
+ const tailStateHash = tail.verification?.stateHash;
1328
+ if (!(options.snapshot !== void 0 && inheritedExecutionId !== void 0 && cachedMeta?.logId === inheritedExecutionId && cachedMeta.logIndex === resumeEvents.length && tailStateHash !== void 0 && hashResumeSnapshot(options.snapshot) === tailStateHash)) {
1329
+ const cachedIndex = cachedMeta?.logIndex;
1330
+ if (options.snapshot !== void 0 && typeof cachedIndex === "number" && cachedIndex >= 1 && cachedIndex <= resumeEvents.length && resumeEvents[cachedIndex - 1].verification?.stateHash !== void 0) {
1331
+ const expected = getSnapshotStateHash(replay(logMachine, resumeEvents.slice(0, cachedIndex), {
1332
+ machineVersion,
1333
+ verify: false
1334
+ }).persistedSnapshot);
1335
+ const actual = hashResumeSnapshot(options.snapshot);
1336
+ if (expected !== actual) throw new AgentSnapshotDivergedError(expected, actual, cachedIndex);
1337
+ }
1338
+ effectiveSnapshot = replay(logMachine, resumeEvents, {
1339
+ machineVersion,
1340
+ verify: true
1341
+ }).persistedSnapshot;
1342
+ }
1343
+ } else {
1344
+ if (options.snapshot === void 0) throw new AgentMachineVersionMismatchError(tail.id, tail.index, {
1345
+ machineId,
1346
+ machineVersion
1347
+ }, {
1348
+ machineId: tail.machineId,
1349
+ machineVersion: tail.machineVersion
1350
+ });
1351
+ const bridgeMeta = readAgentMeta(options.snapshot);
1352
+ if (inheritedExecutionId === void 0 || bridgeMeta?.logId !== inheritedExecutionId) throw new AgentMachineVersionMismatchError(tail.id, tail.index, {
1353
+ machineId,
1354
+ machineVersion
1355
+ }, {
1356
+ machineId: tail.machineId,
1357
+ machineVersion: tail.machineVersion
1358
+ });
1359
+ const bridgeTailHash = tail.verification?.stateHash;
1360
+ const bridgeSnapshotHash = hashResumeSnapshot(options.snapshot);
1361
+ if (bridgeMeta.logIndex !== resumeEvents.length) throw new AgentSnapshotDivergedError(bridgeTailHash ?? "(unrecorded)", bridgeSnapshotHash, resumeEvents.length);
1362
+ if (bridgeTailHash !== void 0 && bridgeSnapshotHash !== bridgeTailHash) throw new AgentSnapshotDivergedError(bridgeTailHash, bridgeSnapshotHash, resumeEvents.length);
1363
+ logExecutionId = inheritedExecutionId;
1364
+ const migratedFrom = {
1365
+ machineVersion: tail.machineVersion,
1366
+ logIndex: resumeEvents.length
1367
+ };
1368
+ seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), {
1369
+ ...logExecutionId !== void 0 ? { executionId: logExecutionId } : {},
1370
+ migratedFrom
1371
+ });
1372
+ }
1373
+ } else if (options.snapshot !== void 0) {
1374
+ logExecutionId = crypto.randomUUID();
1375
+ seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), { executionId: logExecutionId });
1376
+ } else {
1377
+ logExecutionId = crypto.randomUUID();
1378
+ seedInitEntry = () => appendInitEntry([resolvedInput !== void 0 ? { input: resolvedInput } : {}], { executionId: logExecutionId });
1379
+ }
1380
+ const resumedHistory = [...logEntries];
1381
+ const siteCallCounts = /* @__PURE__ */ new Map();
1382
+ const mintedCallKeys = /* @__PURE__ */ new WeakMap();
1383
+ runCtx.callKey = (siteId, self) => {
1384
+ if (logExecutionId === void 0) return;
1385
+ const memoized = self === void 0 ? void 0 : mintedCallKeys.get(self);
1386
+ if (memoized !== void 0) return memoized;
1387
+ const startedHere = siteCallCounts.get(siteId) ?? 0;
1388
+ siteCallCounts.set(siteId, startedHere + 1);
1389
+ const key = `${logExecutionId}:${siteId}#${agentCallOccurrence(resumedHistory, siteId) + startedHere}`;
1390
+ if (self !== void 0) mintedCallKeys.set(self, key);
1391
+ return key;
1392
+ };
1393
+ const resumeEventToSend = options.event;
1394
+ let ignoredEvent;
1395
+ seedInitEntry?.();
1396
+ let settled = false;
1397
+ let journalAtSettle;
1398
+ cycleGate.isResolved = () => settled;
1399
+ let lastResult;
1400
+ const waiters = [];
1401
+ let idleTimer;
1402
+ let actor;
1403
+ let actorStarted = false;
1404
+ let deliveringResumeEvent = resumeEventToSend !== void 0;
1405
+ const settle = (outcome) => {
1406
+ if (settled) return;
1407
+ settled = true;
1408
+ let persistedSnapshot;
1409
+ let persistenceError;
1410
+ if (actorStarted && outcome.status !== "done") try {
1411
+ persistedSnapshot = actor.getPersistedSnapshot();
1412
+ } catch (error) {
1413
+ persistenceError = error;
1414
+ }
1415
+ const logIndexAtSettle = logEntries.length;
1416
+ journalAtSettle = journalChain;
1417
+ const persist = () => {
1418
+ if (persistenceError !== void 0) throw persistenceError;
1419
+ persistedSnapshot ??= actor.getPersistedSnapshot();
1420
+ persistedSnapshot.agentMeta = {
1421
+ machineId,
1422
+ version: machineVersion,
1423
+ ...logExecutionId !== void 0 ? { logId: logExecutionId } : {},
1424
+ logIndex: logIndexAtSettle
1425
+ };
1426
+ return persistedSnapshot;
1427
+ };
1428
+ const result = {
1429
+ ...outcome,
1430
+ events: [...logEntries],
1431
+ persist,
1432
+ drain: drainJournal,
1433
+ usage: runUsage(),
1434
+ ...ignoredEvent !== void 0 ? { ignored: ignoredEvent } : {}
1435
+ };
1436
+ if (idleTimer !== void 0) clearTimeout(idleTimer);
1437
+ onTrace({
1438
+ type: "run.end",
1439
+ ...outcome
1440
+ });
1441
+ if (options.signal) options.signal.removeEventListener("abort", onAbort);
1442
+ actor.stop();
1443
+ lastResult = result;
1444
+ for (const resolve of waiters.splice(0)) resolve(result);
1445
+ };
1446
+ const onAbort = () => {
1447
+ settle({
1448
+ status: "error",
1449
+ cause: "aborted",
1450
+ error: options.signal?.reason ?? /* @__PURE__ */ new Error("Aborted"),
1451
+ snapshot: actor.getSnapshot()
1452
+ });
1453
+ };
1454
+ const settleIdle = (current) => {
1455
+ warnNonSerializableContext(current);
1456
+ settle({
1457
+ status: "idle",
1458
+ snapshot: current
1459
+ });
1460
+ };
1461
+ const runErrorCause = (error) => budgetExceeded ? "max-model-calls" : wrapsDecisionExhausted(error) ? "decision-exhausted" : "machine";
1462
+ const scheduleIdleCheck = () => {
1463
+ if (idleTimer !== void 0) clearTimeout(idleTimer);
1464
+ idleTimer = setTimeout(() => {
1465
+ idleTimer = void 0;
1466
+ if (settled) return;
1467
+ const current = actor.getSnapshot();
1468
+ if (isIntentionalIdle(current) && isIdleSnapshot(current)) settleIdle(current);
1469
+ }, 0);
1470
+ };
1471
+ actor = createActor(boundMachine, {
1472
+ input: resolvedInput,
1473
+ snapshot: effectiveSnapshot,
1474
+ inspect: (event) => {
1475
+ if (typeof options.inspect === "function") options.inspect(event);
1476
+ else options.inspect?.next?.(event);
1477
+ if (event.type !== "@xstate.transition" || event.actorRef !== actor.ref) return;
1478
+ if (settled) return;
1479
+ const snapshot = event.snapshot;
1480
+ lastRootSnapshot = snapshot;
1481
+ if (resumeEventToSend !== void 0 && event.event === resumeEventToSend && event.microsteps.length === 0 && event.actions.length === 0 && event.sent.length === 0) ignoredEvent = resumeEventToSend;
1482
+ if (pendingUsageJournal !== void 0 && event.event === pendingUsageJournal.event) pendingUsageJournal.entry = appendLogEntry(event.event, snapshot);
1483
+ else if (event.event.type !== "@xstate.init" && (event.sourceRef !== event.actorRef || event.event.type === "xstate.timer")) appendLogEntry(event.event, snapshot);
1484
+ onTrace({
1485
+ type: "machine.transition",
1486
+ snapshot,
1487
+ event: event.event
1488
+ });
1489
+ if (snapshot.status === "done") {
1490
+ settle({
1491
+ status: "done",
1492
+ output: snapshot.output,
1493
+ snapshot
1494
+ });
1495
+ return;
1496
+ }
1497
+ if (snapshot.status === "error") {
1498
+ settle({
1499
+ status: "error",
1500
+ cause: runErrorCause(snapshot.error),
1501
+ error: snapshot.error,
1502
+ snapshot
1503
+ });
1504
+ return;
1505
+ }
1506
+ if (snapshot.status === "stopped") {
1507
+ settle({
1508
+ status: "error",
1509
+ cause: "stopped",
1510
+ error: /* @__PURE__ */ new Error("Actor stopped externally."),
1511
+ snapshot
1512
+ });
1513
+ return;
1514
+ }
1515
+ if (!deliveringResumeEvent && isIntentionalIdle(snapshot) && isIdleSnapshot(snapshot)) {
1516
+ queueMicrotask(() => {
1517
+ if (settled) return;
1518
+ const current = actor.getSnapshot();
1519
+ if (isIntentionalIdle(current) && isIdleSnapshot(current)) settleIdle(current);
1520
+ else scheduleIdleCheck();
1521
+ });
1522
+ return;
1523
+ }
1524
+ scheduleIdleCheck();
1525
+ }
1526
+ });
1527
+ actorHolder.actorRef = actor;
1528
+ actor.subscribe({ error: () => {} });
1529
+ actor.on("*", (event) => {
1530
+ onTrace({
1531
+ type: "emit",
1532
+ event
1533
+ });
1534
+ });
1535
+ for (const [type, handler] of Object.entries(options.on ?? {})) if (typeof handler === "function") actor.on(type, handler);
1536
+ const sessionApi = { settled: async () => {
1537
+ const result = settled && lastResult !== void 0 ? lastResult : await new Promise((resolve) => {
1538
+ waiters.push(resolve);
1539
+ });
1540
+ await journalAtSettle;
1541
+ return result;
1542
+ } };
1543
+ if (options.signal) {
1544
+ if (options.signal.aborted) {
1545
+ settle({
1546
+ status: "error",
1547
+ cause: "aborted",
1548
+ error: options.signal.reason ?? /* @__PURE__ */ new Error("Aborted"),
1549
+ snapshot: actor.getSnapshot()
1550
+ });
1551
+ return sessionApi;
1552
+ }
1553
+ options.signal.addEventListener("abort", onAbort);
1554
+ }
1555
+ onTrace({
1556
+ type: "run.start",
1557
+ ...resolvedInput !== void 0 ? { input: resolvedInput } : {},
1558
+ ...effectiveSnapshot !== void 0 ? { snapshot: effectiveSnapshot } : {},
1559
+ ...resumeEventToSend !== void 0 ? { event: resumeEventToSend } : {}
1560
+ });
1561
+ actorStarted = true;
1562
+ actor.start();
1563
+ if (!settled) {
1564
+ const startedSnapshot = actor.getSnapshot();
1565
+ lastRootSnapshot ??= startedSnapshot;
1566
+ if (startedSnapshot.status === "done") settle({
1567
+ status: "done",
1568
+ output: startedSnapshot.output,
1569
+ snapshot: startedSnapshot
1570
+ });
1571
+ else if (startedSnapshot.status === "error") settle({
1572
+ status: "error",
1573
+ cause: runErrorCause(startedSnapshot.error),
1574
+ error: startedSnapshot.error,
1575
+ snapshot: startedSnapshot
1576
+ });
1577
+ else if (startedSnapshot.status === "stopped") settle({
1578
+ status: "error",
1579
+ cause: "stopped",
1580
+ error: /* @__PURE__ */ new Error("Actor stopped externally."),
1581
+ snapshot: startedSnapshot
1582
+ });
1583
+ }
1584
+ if (resumeEventToSend && !settled) {
1585
+ deliveringResumeEvent = false;
1586
+ actor.send(resumeEventToSend);
1587
+ }
1588
+ return sessionApi;
1589
+ }
1590
+ /**
1591
+ * Wraps a `(snapshot, actorRef) => void` handler into a function usable as
1592
+ * {@link RunAgentOptions.inspect}: it filters the raw inspection stream to
1593
+ * `@xstate.transition` events and hands the handler the typed
1594
+ * {@link AnyMachineSnapshot} and the {@link InspectedActorRef} that
1595
+ * transitioned. Attribute a child actor via `actorRef.id`/`actorRef.src`. Saves
1596
+ * the manual `event.type === '@xstate.transition'` filtering and the snapshot/
1597
+ * actorRef casts.
1598
+ */
1599
+ function inspectTransitions(handler) {
1600
+ return (inspectionEvent) => {
1601
+ if (inspectionEvent.type !== "@xstate.transition") return;
1602
+ handler(inspectionEvent.snapshot, inspectionEvent.actorRef);
1603
+ };
1604
+ }
1605
+ /**
1606
+ * An xstate `inspect` handler that emits `machine.transition` trace events onto
1607
+ * `onTrace`, sharing the SAME versioned envelope and per-root-actor `seq`
1608
+ * registry as {@link provideExecutors}' `onTrace`. Pair the two on one actor to
1609
+ * get a single ordered trace stream (request + transition events) for the
1610
+ * uncontrolled path:
1611
+ *
1612
+ * ```ts
1613
+ * const bound = provideExecutors(machine, executors, { onTrace });
1614
+ * const actor = createActor(bound, { inspect: traceTransitions(onTrace) });
1615
+ * ```
1616
+ *
1617
+ * Only ROOT-actor transitions are traced (matching `runAgent`'s
1618
+ * `machine.transition`); child-actor transitions are ignored. Attribute the
1619
+ * event via its envelope `runId`.
1620
+ *
1621
+ * By design this path has NO `run.start`/`run.end` events: `createActor` has no
1622
+ * run boundary the way `runAgent` does, so the stream starts at the actor's
1623
+ * first transition. It also does NOT emit `emit` trace events: in this xstate
1624
+ * build emitted events are delivered through `actor.on(...)`, not the inspection
1625
+ * protocol, so they are not observable from an `inspect` handler — subscribe
1626
+ * with `actor.on('*', ...)` if you need them.
1627
+ */
1628
+ function traceTransitions(onTrace) {
1629
+ return (inspectionEvent) => {
1630
+ if (inspectionEvent.type !== "@xstate.transition") return;
1631
+ const actorRef = inspectionEvent.actorRef;
1632
+ if (actorRef?._parent) return;
1633
+ onTrace(stampRootTrace(actorRef, {
1634
+ type: "machine.transition",
1635
+ snapshot: inspectionEvent.snapshot,
1636
+ event: inspectionEvent.event
1637
+ }));
1638
+ };
1639
+ }
1640
+ function isIdleSnapshot(snapshot) {
1641
+ if (snapshot.status !== "active") return false;
1642
+ if (Object.values(snapshot.children ?? {}).some((child) => {
1643
+ const childSnapshot = child?.getSnapshot?.();
1644
+ if (childSnapshot?.status !== "active") return false;
1645
+ if (isMachineSnapshot(childSnapshot)) return !isIdleSnapshot(childSnapshot);
1646
+ return true;
1647
+ })) return false;
1648
+ return !getNextTransitions(snapshot).some((transitionDef) => transitionDef.eventType === "" || transitionDef.eventType.startsWith("xstate.after"));
1649
+ }
1650
+ /**
1651
+ * Default machine-owned idle signal used by {@link runAgent}: an active
1652
+ * snapshot that accepts an external event anywhere in its active hierarchy,
1653
+ * or declares interaction metadata on an active state.
1654
+ *
1655
+ * Compose this in `setupAgent({ isIdle })` when the application has additional
1656
+ * wait states: `isIdle: (snapshot) => isAgentIdle(snapshot) || snapshot.hasTag('waiting')`.
1657
+ * Pending work and active invoked children are checked separately by the
1658
+ * runner, so this function only answers whether the state is an intentional
1659
+ * external wait.
1660
+ */
1661
+ function isAgentIdle(snapshot) {
1662
+ if (snapshot.status !== "active") return false;
1663
+ return snapshot.nodes.some((node) => {
1664
+ const meta = node.meta;
1665
+ return typeof meta === "object" && meta !== null && "interaction" in meta;
1666
+ }) || getAcceptedEvents(snapshot).length > 0;
1667
+ }
1668
+ //#endregion
1669
+ export { rejectAgentStep as _, bindDecisionForProvide as a, inspectTransitions as c, runAgent as d, serializeTraceEvent as f, initialAgentStep as g, getPendingInvokes as h, bindChildMachineForProvide as i, isAgentIdle as l, executeAgentRequest as m, AgentMaxModelCallsExceededError as n, bindTextForProvide as o, traceTransitions as p, AgentSnapshotDivergedError as r, getConfiguredInvokeSrcs as s, AGENT_TRACE_SCHEMA_VERSION as t, isStateMachineLogic as u, resolveAgentStep as v, transitionAgentStep as y };