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

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 (54) hide show
  1. package/dist/ai-sdk.cjs +4 -4
  2. package/dist/ai-sdk.d.cts +6 -6
  3. package/dist/ai-sdk.d.mts +6 -6
  4. package/dist/ai-sdk.mjs +4 -4
  5. package/dist/{decision-CM9CYZ6t.cjs → decision-CmM8-HHz.cjs} +10 -9
  6. package/dist/{decision-DzSv1NpD.mjs → decision-RQ0iv0oZ.mjs} +10 -9
  7. package/dist/{event-log-store-Ba2fsc4E.mjs → event-log-store-2pAFiWuc.mjs} +1 -1
  8. package/dist/{event-log-store-DvOcs10J.d.cts → event-log-store-2xzFmgr2.d.cts} +1 -1
  9. package/dist/{event-log-store-DxyVgnas.d.mts → event-log-store-BIPOz-di.d.mts} +1 -1
  10. package/dist/{event-log-store-DQmImLYk.cjs → event-log-store-C-COhIXP.cjs} +1 -1
  11. package/dist/index.cjs +13 -195
  12. package/dist/index.d.cts +25 -105
  13. package/dist/index.d.mts +25 -105
  14. package/dist/index.mjs +12 -189
  15. package/dist/log.cjs +1 -1
  16. package/dist/log.d.cts +1 -1
  17. package/dist/log.d.mts +1 -1
  18. package/dist/log.mjs +1 -1
  19. package/dist/machines.cjs +4 -7
  20. package/dist/machines.d.cts +5 -7
  21. package/dist/machines.d.mts +5 -7
  22. package/dist/machines.mjs +4 -7
  23. package/dist/openai.cjs +3 -3
  24. package/dist/openai.d.cts +5 -5
  25. package/dist/openai.d.mts +5 -5
  26. package/dist/openai.mjs +3 -3
  27. package/dist/otel.cjs +2 -2
  28. package/dist/otel.d.cts +3 -3
  29. package/dist/otel.d.mts +3 -3
  30. package/dist/otel.mjs +2 -2
  31. package/dist/{run-agent-CG343kFs.d.mts → run-agent-ByO-Bxyd.d.cts} +184 -179
  32. package/dist/{run-agent-BOfoJg5B.d.cts → run-agent-COXXc0RW.d.mts} +184 -179
  33. package/dist/{run-agent-Cb1-LS5P.cjs → run-agent-Dmf8GV2d.cjs} +539 -737
  34. package/dist/{run-agent-DvDQd4If.mjs → run-agent-xNTxpt82.mjs} +537 -705
  35. package/dist/{setup-agent-CFW-jPI8.mjs → setup-agent-BuanDXeh.mjs} +6 -28
  36. package/dist/{setup-agent-CPf7MxnG.cjs → setup-agent-DV4cTou-.cjs} +6 -28
  37. package/dist/testing.cjs +276 -27
  38. package/dist/testing.d.cts +17 -15
  39. package/dist/testing.d.mts +17 -15
  40. package/dist/testing.mjs +260 -12
  41. package/dist/{text-logic-Bl_ZRxDi.mjs → text-logic-CIqHAmBi.mjs} +10 -26
  42. package/dist/{text-logic-BFEOxyxv.d.cts → text-logic-D-czVPYp.d.mts} +27 -28
  43. package/dist/{text-logic-hZSiRUo1.d.mts → text-logic-IjfYy9DP.d.cts} +27 -28
  44. package/dist/{text-logic-C8xyr6Ag.cjs → text-logic-f5F5sCdc.cjs} +9 -43
  45. package/dist/{types-B1Qs2q3q.d.cts → types-BgNbNKnJ.d.mts} +3 -3
  46. package/dist/{types-tA3SdczG.d.mts → types-hR5f5YXa.d.cts} +3 -3
  47. package/dist/{utils-C2DPqomn.d.mts → utils-_q7F-AZu.d.mts} +2 -2
  48. package/dist/{utils-ceStNCOh.d.cts → utils-o4YRdHJX.d.cts} +2 -2
  49. package/dist/validate.cjs +0 -8
  50. package/dist/validate.mjs +0 -8
  51. package/package.json +3 -3
  52. package/readme.md +26 -18
  53. package/schemas/agent-workflow.json +0 -8
  54. package/skills/generate-machine/SKILL.md +6 -8
@@ -1,284 +1,13 @@
1
- const require_text_logic = require("./text-logic-C8xyr6Ag.cjs");
2
- const require_decision = require("./decision-CM9CYZ6t.cjs");
1
+ const require_text_logic = require("./text-logic-f5F5sCdc.cjs");
2
+ const require_decision = require("./decision-CmM8-HHz.cjs");
3
3
  const require_usage = require("./usage-efOQPdf_.cjs");
4
- const require_event_log_store = require("./event-log-store-DQmImLYk.cjs");
4
+ const require_event_log_store = require("./event-log-store-C-COhIXP.cjs");
5
5
  require("./validate.cjs");
6
6
  let xstate = require("xstate");
7
- //#region src/steps.ts
8
- /**
9
- * The step API: the pure `(state, event) => (nextState, requests)` view of an
10
- * agent machine. An {@link AgentStep} is a snapshot plus the model requests
11
- * the machine is now waiting on; nothing here executes anything. A host
12
- * resolves each request however it likes ({@link executeAgentRequest},
13
- * `resolveDecision`, a queue, a durable workflow, a replayed log) and feeds
14
- * the result back with {@link resolveAgentStep} or {@link rejectAgentStep}.
15
- * `runAgent` is the in-process host built for the common case.
16
- * @module
17
- */
18
- /** @internal Normalizes current and legacy XState invoke effect shapes. */
19
- function getInvokeEffectMetadata(action) {
20
- if (action.type === "@xstate.spawn") return action;
21
- if (action.type === "xstate.spawnChild") {
22
- const params = action.params;
23
- return params ? {
24
- ...params,
25
- logic: action.logic
26
- } : void 0;
27
- }
28
- if (action.type === "@xstate.start" && typeof action.src === "string") return action;
29
- }
30
- /**
31
- * The invokes a snapshot is still waiting on, lowered to the same spawn-effect
32
- * shape {@link getAgentRequests} reads. Derived from the snapshot's live
33
- * children rather than the last transition's actions, so a state that invokes
34
- * several actors at once (an `invoke: [...]` array, or parallel regions each
35
- * invoking) keeps reporting the siblings after the first one settles —
36
- * including when the settled invoke's `onDone` is targetless and starts
37
- * nothing new.
38
- *
39
- * Entries are ordered by invoke id, so a walker that resolves one invoke per
40
- * step is deterministic.
41
- *
42
- * @internal
43
- */
44
- function getPendingInvokes(snapshot) {
45
- const children = snapshot.children ?? {};
46
- return Object.keys(children).sort().flatMap((id) => {
47
- const child = children[id];
48
- const childSnapshot = child?.getSnapshot?.();
49
- if (!child || childSnapshot?.status !== "active") return [];
50
- return [{
51
- type: "@xstate.spawn",
52
- id,
53
- src: child.src,
54
- input: childSnapshot.input,
55
- logic: child.logic
56
- }];
57
- });
58
- }
59
- /**
60
- * Scans a set of executable actions (as returned by xstate's `transition`/
61
- * `initialTransition`) for spawned `TextLogic`/`DecisionLogic` invokes and
62
- * lowers each into an {@link AgentStepRequest}. Pass `options.machine` to
63
- * pre-fill `schemas`/`actors` from the machine's registered `setupAgent`
64
- * options instead of passing them by hand.
65
- * `options.snapshot` is required to resolve a decision's candidate events
66
- * (intersecting declared `allowedEvents` with what's currently legal) — omit
67
- * it and decision requests report an empty `events` list.
68
- *
69
- * @internal
70
- */
71
- function getAgentRequests(actions, { machine, ...options } = {}) {
72
- if (machine) options = {
73
- ...require_text_logic.getRegisteredAgentExecutionOptions(machine),
74
- ...options
75
- };
76
- return actions.flatMap((action) => {
77
- const params = getInvokeEffectMetadata(action);
78
- if (!params || typeof params.src !== "string") return [];
79
- if (typeof params.id !== "string" || params.id.length === 0) throw new Error(`Agent invoke '${params.src}' must define a durable string id.`);
80
- const registeredLogic = require_text_logic.isTextLogic(params.logic) || require_decision.isDecisionLogic(params.logic) ? params.logic : options.actors?.[params.src];
81
- if (require_decision.isDecisionLogic(registeredLogic)) {
82
- const decisionRequest = registeredLogic.request(params.input);
83
- const allowedEventTypes = registeredLogic.allowedEventTypes?.(params.input);
84
- const events = options.snapshot ? require_decision.getAcceptedEvents(options.snapshot, {
85
- events: options.events,
86
- schemas: options.schemas,
87
- eventTypes: allowedEventTypes
88
- }) : [];
89
- return [{
90
- ...decisionRequest,
91
- id: params.id,
92
- events
93
- }];
94
- }
95
- const textLogic = require_text_logic.isTextLogic(registeredLogic) ? registeredLogic : void 0;
96
- const input = textLogic ? textLogic.request(params.input) : void 0;
97
- if (!input) return [];
98
- return [{
99
- kind: "text",
100
- id: params.id,
101
- src: params.src,
102
- ...textLogic ? { mode: textLogic.mode } : {},
103
- input,
104
- tools: input.tools ?? {},
105
- events: []
106
- }];
107
- });
108
- }
109
- /**
110
- * Builds the canonical `xstate.done.actor` event xstate's `transition()`
111
- * expects to resolve a spawned invoke — including the child session identity
112
- * that rejects a stale completion from an earlier incarnation.
113
- *
114
- * @internal
115
- */
116
- function doneEvent(snapshot, request, output) {
117
- const id = typeof request === "string" ? request : request.id;
118
- const child = snapshot.children[id];
119
- return {
120
- type: "xstate.done.actor",
121
- actorId: id,
122
- ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {},
123
- output
124
- };
125
- }
126
- /**
127
- * The `xstate.error.actor` counterpart of {@link doneEvent} — the event a
128
- * failed invoke delivers, which `onError` transitions observe. Carries the
129
- * same child session identity, so xstate does not discard it as stale.
130
- *
131
- * @internal
132
- */
133
- function errorEvent(snapshot, request, error) {
134
- const id = typeof request === "string" ? request : request.id;
135
- const child = snapshot.children[id];
136
- return {
137
- type: "xstate.error.actor",
138
- actorId: id,
139
- ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {},
140
- error
141
- };
142
- }
143
- /**
144
- * Applies a request's `output` as a done event (or, with `outcome: 'error'`,
145
- * its `output` as the invoke's error) via `transition(...)`, returning the raw
146
- * `[snapshot, actions]` tuple. Lower-level than {@link resolveAgentStep} /
147
- * {@link rejectAgentStep} — those helpers wrap this and also run
148
- * {@link getAgentRequests} to produce the next {@link AgentStep}.
149
- *
150
- * @internal
151
- */
152
- function transitionResult(logic, snapshot, request, output, outcome = "output") {
153
- const event = outcome === "error" ? errorEvent(snapshot, request, output) : doneEvent(snapshot, request, output);
154
- const result = (0, xstate.transition)(logic, snapshot, event);
155
- applyFinalStateOutput(logic, result[0], event);
156
- return result;
157
- }
158
- /**
159
- * Starts a machine and returns its first {@link AgentStep} — the step-path
160
- * equivalent of `initialTransition` plus request discovery. Begins the
161
- * durable/per-model-call-checkpoint loop: resolve each `step.requests` entry
162
- * (via {@link executeAgentRequest} for `kind: 'text'`, or
163
- * {@link resolveDecision} for `kind: 'decision'`), then advance with
164
- * {@link resolveAgentStep} or {@link transitionAgentStep}.
165
- */
166
- function initialAgentStep(machine, input, options) {
167
- const [snapshot, actions] = (0, xstate.initialTransition)(machine, input);
168
- return createAgentStep(machine, snapshot, actions, require_text_logic.getRegisteredAgentExecutionOptions(machine, options));
169
- }
170
- /**
171
- * Applies an externally-sent event (e.g. a decision's chosen event, or a
172
- * human's reply) and returns the next {@link AgentStep}. Accepts **either**
173
- * a raw snapshot **or** a prior `AgentStep` as the second argument —
174
- * `.snapshot` is unwrapped automatically, so callers can thread the whole
175
- * step object through without manually plucking the snapshot out.
176
- */
177
- function transitionAgentStep(machine, snapshotOrStep, event, options) {
178
- const [nextSnapshot, actions] = (0, xstate.transition)(machine, isAgentStep(snapshotOrStep) ? snapshotOrStep.snapshot : snapshotOrStep, event);
179
- return createAgentStep(machine, nextSnapshot, actions, require_text_logic.getRegisteredAgentExecutionOptions(machine, options));
180
- }
181
- /**
182
- * Applies a resolved text request's output (a `kind: 'text'`
183
- * {@link AgentRequest} — not a decision) as a done event and returns the
184
- * next {@link AgentStep}. For decisions, resolve with `resolveDecision`
185
- * (which returns a {@link ChosenEvent}) and apply it with
186
- * {@link transitionAgentStep} instead — a decision has no output value of
187
- * its own to feed here.
188
- */
189
- function resolveAgentStep(machine, step, request, output, options) {
190
- const [snapshot, actions] = transitionResult(machine, step.snapshot, request, output);
191
- return createAgentStep(machine, snapshot, actions, require_text_logic.getRegisteredAgentExecutionOptions(machine, options));
192
- }
193
- /**
194
- * Rejects a pending invoke — the failure counterpart of
195
- * {@link resolveAgentStep}. Delivers `error` as the invoke's
196
- * `xstate.error.actor` event, so the machine takes that invoke's `onError`
197
- * transition and returns the next {@link AgentStep}. With no `onError` in
198
- * scope the returned step's snapshot has `status: 'error'`, exactly as a live
199
- * run's failed invoke does.
200
- *
201
- * A durable host replays a failed call with this: the log says the call
202
- * failed, so the replay rejects the invoke instead of resolving it. Scripted
203
- * playthroughs use it too — see `simulateAgent`'s `script.errors`.
204
- *
205
- * `error` can be any value. An `Error` instance is the usual one, but a plain
206
- * object (`{ code: 'truncated' }`) reaches the `onError` transition as
207
- * `event.error` untouched, so a machine that branches on a failure code is
208
- * testable without constructing a provider's error class.
209
- */
210
- function rejectAgentStep(machine, step, request, error, options) {
211
- const [snapshot, actions] = transitionResult(machine, step.snapshot, request, error, "error");
212
- return createAgentStep(machine, snapshot, actions, require_text_logic.getRegisteredAgentExecutionOptions(machine, options));
213
- }
214
- /**
215
- * Resolves one **text** request ({@link AgentRequest}, from
216
- * {@link AgentStep.requests}) against a host's {@link AgentRequestExecutors}
217
- * — merges the request's tools, dispatches to `generateText`/`streamText`
218
- * per `mode`, and validates the result against the request's
219
- * `outputSchema` if present. **Text-only**: passing a `kind: 'decision'`
220
- * request throws, directing the caller to `resolveDecision(request,
221
- * executors, ...)` instead. Returns the invoke's output — `{ result,
222
- * messages }`, ready for {@link resolveAgentStep} — plus the `raw` executor
223
- * result (tool calls, usage, finish reason).
224
- */
225
- async function executeAgentRequest(request, executors) {
226
- if (request.kind === "decision") throw new Error("executeAgentRequest(...) is text-only. Resolve a 'decision' request with resolveDecision(request, executors, ...) instead.");
227
- assertTextExecutor(request, executors);
228
- const { result, raw } = await require_text_logic.executeAgentTextRequest(request.mode ?? "generate", request.id, request.input, executors, request.tools);
229
- return {
230
- result: request.input.outputSchema ? require_text_logic.validateSchemaSync(request.input.outputSchema, result) : result,
231
- messages: require_text_logic.responseMessagesOf(raw),
232
- raw
233
- };
234
- }
235
- function assertTextExecutor(request, executors) {
236
- const mode = request.mode ?? "generate";
237
- const kind = mode === "stream" ? "streamText" : "generateText";
238
- 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.`);
239
- }
240
- function createAgentStep(machine, snapshot, actions, options) {
241
- applyFinalStateOutput(machine, snapshot);
242
- return {
243
- snapshot,
244
- actions,
245
- requests: getAgentRequests(getPendingInvokes(snapshot), {
246
- ...options,
247
- snapshot
248
- }),
249
- done: snapshot.status === "done"
250
- };
251
- }
252
- function resolveStateValueConfig(config, value) {
253
- if (typeof value === "string") return config.states?.[value];
254
- if (!value || typeof value !== "object") return;
255
- for (const [key, childValue] of Object.entries(value)) {
256
- const childConfig = config.states?.[key];
257
- if (!childConfig) continue;
258
- if (childConfig.type === "final") return childConfig;
259
- const nested = resolveStateValueConfig(childConfig, childValue);
260
- if (nested) return nested;
261
- }
262
- }
263
- function applyFinalStateOutput(logic, snapshot, event) {
264
- const machineSnapshot = snapshot;
265
- if (machineSnapshot.status !== "done" || machineSnapshot.output !== void 0 || !("config" in logic)) return;
266
- const config = logic.config;
267
- if (!config) return;
268
- const output = resolveStateValueConfig(config, machineSnapshot.value)?.output;
269
- if (output === void 0) return;
270
- machineSnapshot.output = typeof output === "function" ? output({
271
- context: machineSnapshot.context,
272
- event
273
- }) : output;
274
- }
275
- function isAgentStep(value) {
276
- return !!value && typeof value === "object" && "snapshot" in value && "actions" in value && "requests" in value;
277
- }
278
- //#endregion
7
+ let xstate_durable = require("xstate/durable");
279
8
  //#region src/run-agent.ts
280
9
  /**
281
- * Thrown by {@link runAgent} when a resume is given BOTH an `events` log and a
10
+ * Thrown by {@link AgentRuntime.start} when a resume is given BOTH an `events` log and a
282
11
  * `snapshot` that claims a position in that log (`agentMeta.logIndex`), and the
283
12
  * two disagree about the state at that position. The log is the source of
284
13
  * truth, so this is a host bug (a snapshot cached from a different lineage, or
@@ -287,7 +16,7 @@ function isAgentStep(value) {
287
16
  */
288
17
  var AgentSnapshotDivergedError = class extends require_text_logic.AgentError {
289
18
  constructor(expected, actual, logIndex) {
290
- 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}'.`);
19
+ super("snapshot-diverged", `createAgentRuntime: the resume snapshot disagrees with the event log at index ${logIndex}: the log replays to state hash '${expected}', the snapshot hashes '${actual}'.`);
291
20
  this.expected = expected;
292
21
  this.actual = actual;
293
22
  this.logIndex = logIndex;
@@ -310,7 +39,7 @@ function readAgentMeta(snapshot) {
310
39
  * The version of the {@link AgentTraceEvent} envelope every trace event carries
311
40
  * as `schemaVersion`. Bumped only on a breaking change to the envelope or any
312
41
  * payload shape, so a consumer can gate on it. Emitted identically by
313
- * {@link runAgent}, {@link provideExecutors}' `onTrace`, and
42
+ * {@link createAgentRuntime}, {@link provideExecutors}' `onTrace`, and
314
43
  * {@link traceTransitions}.
315
44
  */
316
45
  const AGENT_TRACE_SCHEMA_VERSION = 1;
@@ -404,7 +133,7 @@ function serializeTraceEvent(event, options = {}) {
404
133
  let nextRunAgentTraceId = 1;
405
134
  /**
406
135
  * Thrown into the invoke that would have made the call once
407
- * {@link RunAgentOptions.maxModelCalls} is spent. It reaches the machine
136
+ * {@link AgentRuntimeOptions.maxModelCalls} is spent. It reaches the machine
408
137
  * through the normal error channel, so an invoke's `onError` can branch on it
409
138
  * (`error.code === 'max-model-calls'`, the same string the settled result's
410
139
  * `cause` uses) and route to a degraded/finish state instead of failing the
@@ -421,7 +150,7 @@ var AgentMaxModelCallsExceededError = class extends require_text_logic.AgentErro
421
150
  /** The budget that was exceeded (`options.maxModelCalls`). */
422
151
  maxModelCalls;
423
152
  constructor(maxModelCalls) {
424
- super("max-model-calls", `runAgent exceeded maxModelCalls (${maxModelCalls}). Raise the budget, or handle it in the invoke's onError (error.code === 'max-model-calls').`);
153
+ super("max-model-calls", `The run exceeded maxModelCalls (${maxModelCalls}). Raise the budget, or handle it in the invoke's onError (error.code === 'max-model-calls').`);
425
154
  this.name = "AgentMaxModelCallsExceededError";
426
155
  this.maxModelCalls = maxModelCalls;
427
156
  }
@@ -468,12 +197,12 @@ function isStateMachineLogic(logic) {
468
197
  }
469
198
  /**
470
199
  * Fails fast (throws) at bind time — before any actor runs — when the
471
- * machine invokes an agent actor `runAgent` cannot execute. See §3.2 point 2.
200
+ * machine invokes an agent actor the runtime cannot execute. See §3.2 point 2.
472
201
  *
473
202
  * Recurses into invoked child state machines (arbitrarily deep). A child
474
203
  * machine's agent requests reached through string-keyed invoke srcs DO inherit
475
- * the parent runAgent's `generateText`/`streamText`/`decide` executors —
476
- * runAgent rebinds them with the same host-backed wrappers (see
204
+ * the parent run's `generateText`/`streamText`/`decide` executors —
205
+ * the runtime rebinds them with the same host-backed wrappers (see
477
206
  * {@link rebindChildMachine}) — so the only remaining bind-time errors are: a
478
207
  * required executor kind missing entirely (naming the invoke chain and src),
479
208
  * and an unbound request reached through a direct-object invoke src that can't
@@ -499,11 +228,11 @@ function assertMachineBindable(machine, effectiveSources, executors, ctx) {
499
228
  assertChildMachineBindable(src, src, stateName, executors, ctx);
500
229
  continue;
501
230
  }
502
- if ((require_text_logic.isTextLogic(src) || require_decision.isDecisionLogic(src)) && !require_text_logic.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.`);
231
+ if ((require_text_logic.isTextLogic(src) || require_decision.isDecisionLogic(src)) && !require_text_logic.executorBoundLogics.has(src)) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes a direct-object actor logic (kind: '${src.kind}'). Direct-object invoke srcs cannot be rebound by the agent runtime — 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.`);
503
232
  continue;
504
233
  }
505
234
  const logic = effectiveSources[src];
506
- 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}': ... } }).`);
235
+ if (logic === void 0) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes unregistered actor source '${src}'. Provide it via machine.provide({ actors: { '${src}': ... } }) or createAgentRuntime(machine, { actors: { '${src}': ... } }).`);
507
236
  if (isStateMachineLogic(logic)) {
508
237
  assertChildMachineBindable(logic, src, stateName, executors, ctx);
509
238
  continue;
@@ -511,17 +240,17 @@ function assertMachineBindable(machine, effectiveSources, executors, ctx) {
511
240
  if (require_decision.isDecisionLogic(logic)) {
512
241
  if (require_text_logic.executorBoundLogics.has(logic)) continue;
513
242
  if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, "decision");
514
- if (!executors.decide) throw new Error(`runAgent: ${where} '${stateName}' invokes decision source '${src}' but no 'decide' executor was provided to runAgent(...).`);
243
+ if (!executors.decide) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes decision source '${src}' but no 'decide' executor was provided to createAgentRuntime(...).`);
515
244
  continue;
516
245
  }
517
246
  if (require_text_logic.isTextLogic(logic)) {
518
247
  if (require_text_logic.executorBoundLogics.has(logic)) continue;
519
248
  if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, logic.mode === "stream" ? "streaming text" : "text");
520
- 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(...).`);
521
- if (logic.mode !== "stream" && !executors.generateText) throw new Error(`runAgent: ${where} '${stateName}' invokes text source '${src}' but no 'generateText' executor was provided to runAgent(...).`);
249
+ if (logic.mode === "stream" && !executors.streamText) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes streaming text source '${src}' but no 'streamText' executor was provided to createAgentRuntime(...).`);
250
+ if (logic.mode !== "stream" && !executors.generateText) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes text source '${src}' but no 'generateText' executor was provided to createAgentRuntime(...).`);
522
251
  continue;
523
252
  }
524
- if (require_text_logic.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}': ... } }).`);
253
+ if (require_text_logic.isUnboundPlaceholder(logic)) throw new Error(`createAgentRuntime: ${where} '${stateName}' invokes actor source '${src}', which has no host execution. Provide it via machine.provide({ actors: { '${src}': ... } }) or createAgentRuntime(machine, { actors: { '${src}': ... } }).`);
525
254
  }
526
255
  }
527
256
  /** Descends the bind-time walk into an invoked child state machine, guarding
@@ -539,14 +268,14 @@ function assertChildMachineBindable(childMachine, childSrc, stateName, executors
539
268
  });
540
269
  }
541
270
  /** The loud bind-time error for an unbound agent request reached under a
542
- * direct-object invoke src, which runAgent cannot rebind (only string-keyed
271
+ * direct-object invoke src, which the runtime cannot rebind (only string-keyed
543
272
  * sources can be swapped via `.provide`). Names the invoke chain AND the
544
273
  * request src, and spells out the `.withExecutor`/string-keyed remedy. Note:
545
274
  * requests reachable through string-keyed srcs at any depth DO inherit
546
- * runAgent's executors — this error is only for the unrebindable direct-object
275
+ * the runtime's executors — this error is only for the unrebindable direct-object
547
276
  * case. */
548
277
  function unrebindableChildRequestError(childPath, stateName, requestSrc, kind) {
549
- 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.`);
278
+ return /* @__PURE__ */ new Error(`createAgentRuntime: child machine '${childPath}' (state '${stateName}') invokes ${kind} source '${requestSrc}', which has no host execution and is reached through a direct-object invoke src that the agent runtime cannot rebind. Requests reached through string-keyed actor sources inherit the agent runtime'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.`);
550
279
  }
551
280
  /**
552
281
  * True when the snapshot's active states declare a transition that would
@@ -563,8 +292,8 @@ function declaresUsageTransition(snapshot) {
563
292
  /**
564
293
  * Builds the ONE place a trace payload is emitted: it hands the payload to the
565
294
  * envelope-stamping trace sink and, from that same payload, invokes the sugar
566
- * callbacks that are projections of it — {@link RunAgentOptions.onChunk},
567
- * {@link RunAgentOptions.onResult}, {@link RunAgentOptions.onTransition}. Each
295
+ * callbacks that are projections of it — {@link AgentRuntimeOptions.onChunk},
296
+ * {@link AgentRuntimeOptions.onResult}, {@link AgentRuntimeOptions.onTransition}. Each
568
297
  * keeps its historical position relative to the trace: `onResult` fires just
569
298
  * BEFORE its `request.end`, `onChunk`/`onTransition` just AFTER their
570
299
  * `stream.chunk`/`machine.transition`. Sugar dispatch never depends on whether
@@ -611,13 +340,15 @@ function selfIdAndSrc(self) {
611
340
  * root actor as a fallback.
612
341
  */
613
342
  function invokingActorOf(self, runCtx) {
614
- return self?._parent ?? runCtx.actorHolder.actorRef;
343
+ const parent = self?._parent;
344
+ if (parent !== void 0 && parent._parent !== void 0) return parent;
345
+ return runCtx.actorHolder.actorRef ?? parent;
615
346
  }
616
347
  /**
617
348
  * The shared text/stream emission helper: binds a {@link TextLogic} to
618
349
  * `runCtx`'s executor and constructs the `request.start` / `stream.chunk` /
619
350
  * `request.end` (incl. the lifted `reasoning`) / `request.error` trace payloads.
620
- * Used by both `runAgent` and `provideExecutors` so the two paths produce
351
+ * Used by both `createAgentRuntime` and `provideExecutors` so the two paths produce
621
352
  * identical event shapes by construction. @internal
622
353
  */
623
354
  function bindTextLogic(logic, runCtx) {
@@ -751,11 +482,11 @@ function createCountingDecide(runCtx, self) {
751
482
  };
752
483
  }
753
484
  /**
754
- * Builds the decision actor logic runAgent installs in place of a
485
+ * Builds the decision actor logic the runtime installs in place of a
755
486
  * `DecisionLogic`/`agent.decide` source. `DecisionLogic.withExecutor(...)`
756
487
  * can only swap the innermost per-attempt executor — the `resolveDecision(...)`
757
488
  * call (and its `canTake`) is hardwired inside the original logic's `run`.
758
- * To supply `canTake` (mode-3, §2.6), runAgent instead builds a fresh async
489
+ * To supply `canTake` (mode-3, §2.6), the runtime instead builds a fresh async
759
490
  * logic here that calls `resolveDecision` itself, reusing `logic.request(...)`
760
491
  * to build the request the same way the original logic would have.
761
492
  *
@@ -823,7 +554,7 @@ function rootActorOf(self) {
823
554
  while (ref?._parent) ref = ref._parent;
824
555
  return ref;
825
556
  }
826
- /** The per-root envelope state, minted on first use (runId `run_<n>`, matching runAgent). */
557
+ /** The per-root envelope state, minted on first use (runId `run_<n>`, matching the runtime). */
827
558
  function rootTraceState(root) {
828
559
  let state = rootTraceRegistry.get(root);
829
560
  if (!state) {
@@ -863,7 +594,7 @@ function provideTraceSink(onTrace) {
863
594
  }
864
595
  /**
865
596
  * A minimal {@link RunAgentBindContext} for `provideExecutors` (uncontrolled
866
- * `createActor`): the same wrappers runAgent installs, MINUS the run-scoped
597
+ * `createActor`): the same wrappers the runtime installs, MINUS the run-scoped
867
598
  * model-call counter. `consumeModelCall` is a no-op (no budget), and
868
599
  * `actorHolder.actorRef` is left undefined — the wrappers read the invoking
869
600
  * actor off `self._parent`, always present under a live `createActor` tree.
@@ -872,7 +603,7 @@ function provideTraceSink(onTrace) {
872
603
  *
873
604
  * `recordUsage` has no run-level aggregate to fold into here (there is no
874
605
  * run), so it does one thing: deliver the reserved `@agent.usage` event, gated
875
- * exactly like runAgent's — see {@link deliverUsageEvent}.
606
+ * exactly like the runtime's — see {@link deliverUsageEvent}.
876
607
  */
877
608
  function provideBindContext(machine, executors, options) {
878
609
  const traceSink = provideTraceSink(options.onTrace);
@@ -900,7 +631,7 @@ function provideBindContext(machine, executors, options) {
900
631
  /**
901
632
  * The single reserved-`@agent.usage` DELIVERY seam, shared by both bind paths:
902
633
  * after a bound call settles with reported usage, send the prebuilt `event` to
903
- * the machine actor `resolveActorRef` names — the run's root actor on the `runAgent` path,
634
+ * the machine actor `resolveActorRef` names — the run's root actor on the `createAgentRuntime` path,
904
635
  * the settling request actor's `self._parent` (always the invoking machine
905
636
  * under a live `createActor` tree) on the `provideExecutors` path.
906
637
  *
@@ -930,7 +661,7 @@ function deliverUsageEvent(event, resolveActorRef, onDropped) {
930
661
  }
931
662
  /**
932
663
  * Host-binds one text/stream source for {@link provideExecutors} using the SAME
933
- * emission helper as `runAgent` ({@link bindTextLogic}), so a bound
664
+ * emission helper as `createAgentRuntime` ({@link bindTextLogic}), so a bound
934
665
  * text request emits request.start/stream.chunk/request.end/request.error with
935
666
  * identical shapes. @internal
936
667
  */
@@ -939,16 +670,16 @@ function bindTextForProvide(machine, logic, executors, options) {
939
670
  }
940
671
  /**
941
672
  * Host-binds one `DecisionLogic`/`agent.decide` source for
942
- * {@link provideExecutors}: runAgent's decision wrapper (snapshot-driven
673
+ * {@link provideExecutors}: the runtime's decision wrapper (snapshot-driven
943
674
  * candidate events, `canTake`, auto-delivery of the chosen event) with the same
944
- * request-level tracing runAgent emits, minus run-scoped counting. @internal
675
+ * request-level tracing the runtime emits, minus run-scoped counting. @internal
945
676
  */
946
677
  function bindDecisionForProvide(machine, logic, executors, options) {
947
678
  return bindDecisionLogic(logic, provideBindContext(machine, executors, options));
948
679
  }
949
680
  /**
950
681
  * Recursively binds an invoked child state machine for {@link provideExecutors},
951
- * with the same semantics `runAgent` applies ({@link rebindChildMachine}):
682
+ * with the same semantics `createAgentRuntime` applies ({@link rebindChildMachine}):
952
683
  * string-keyed text/decision sources at any depth inherit the host executors,
953
684
  * a source that carries its own executor is left alone, and a cycle is
954
685
  * returned as-is. Each machine in the tree is bound with its own registered
@@ -976,13 +707,13 @@ function resolveMachineInput(machine, input) {
976
707
  try {
977
708
  return require_text_logic.validateSchemaSync(schema, input);
978
709
  } catch (error) {
979
- throw new require_text_logic.AgentError("invalid-machine-input", `runAgent: machine input failed validation against the declared input schema: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
710
+ throw new require_text_logic.AgentError("invalid-machine-input", `createAgentRuntime: machine input failed validation against the declared input schema: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
980
711
  }
981
712
  }
982
713
  /**
983
714
  * Recursively rebinds an invoked child machine's own agent sources with the
984
- * SAME host-backed wrappers runAgent applies to the top-level machine, so a
985
- * child's text/stream/decision requests inherit runAgent's executors and
715
+ * SAME host-backed wrappers the runtime applies to the top-level machine, so a
716
+ * child's text/stream/decision requests inherit the runtime's executors and
986
717
  * participate in maxModelCalls counting, onTrace/onChunk/onResult exactly like
987
718
  * parent requests. Returns the child machine to invoke: a `.provide`-rebound
988
719
  * copy when any inner source needed wrapping, else the original untouched.
@@ -1017,31 +748,66 @@ function rebindChildMachine(childMachine, runCtx, visited, ctxFor) {
1017
748
  return Object.keys(wrapped).length > 0 ? childMachine.provide({ actors: wrapped }) : childMachine;
1018
749
  }
1019
750
  /**
1020
- * Runs an agent machine to completion or idle: a `createActor` host that
1021
- * binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
1022
- * `DecisionLogic` actor sources, starts (or resumes) the actor, and drives
1023
- * it until it settles — {@link RunAgentResult} `done | idle | error`. Unlike
1024
- * the step helpers ({@link initialAgentStep} etc — a pure
1025
- * transition-at-a-time path for durable hosts), `runAgent` owns a live actor
1026
- * internally; there is no continuation callback, so **idle always settles**
1027
- * and the caller resumes explicitly by passing the settled `{ snapshot,
1028
- * event }` back in. The actor is stopped on every settle path (`done`,
1029
- * `idle`, and `error` alike) — resume is always by snapshot, never by
1030
- * holding a reference to a live actor.
751
+ * The blocking host: opens the run, delivers `event` if given, then applies
752
+ * every event that arrives until the run is quiescent, and returns the
753
+ * outcome. A request handler or durable engine writes the same loop with its
754
+ * own stop policy; this one is for scripts and tests.
755
+ */
756
+ async function runToQuiescence(runtime, init = {}) {
757
+ let [state, effects] = await runtime.start(init);
758
+ await runtime.execute(effects);
759
+ if (init.event !== void 0 && state.status === "active") {
760
+ [state, effects] = runtime.transition(state, init.event);
761
+ await runtime.execute(effects);
762
+ }
763
+ for (let event; event = await runtime.nextEvent();) {
764
+ [state, effects] = runtime.transition(state, event);
765
+ await runtime.execute(effects);
766
+ }
767
+ return runtime.finish();
768
+ }
769
+ /**
770
+ * Entry-by-entry check that the caller's `events` IS the store's thread. Equal
771
+ * lengths prove nothing: a fork, a rolled-back replay, or a concurrent writer
772
+ * that appended and truncated all produce a divergent log of the same size,
773
+ * and appending this run's entries onto it would splice two lineages together.
774
+ */
775
+ function assertThreadMatchesEvents(threadId, stored, events) {
776
+ for (let index = 0; index < stored.length; index++) {
777
+ const storedEntry = stored[index];
778
+ const givenEntry = events[index];
779
+ const storedHash = storedEntry.verification?.stateHash;
780
+ const givenHash = givenEntry.verification?.stateHash;
781
+ if (!(storedEntry.id === givenEntry.id && storedEntry.index === givenEntry.index && require_event_log_store.canonicalEventJson(storedEntry.event) === require_event_log_store.canonicalEventJson(givenEntry.event) && (storedHash === void 0 || givenHash === void 0 || storedHash === givenHash))) throw new require_text_logic.AgentError("event-log-conflict", `createAgentRuntime: 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.`);
782
+ }
783
+ }
784
+ const QUIESCENT = Symbol("quiescent");
785
+ /**
786
+ * Creates the helpers for one run of `machine`: executors bound to its
787
+ * requests, the write-ahead log, traces, the budget, and a mailbox over
788
+ * XState's durable transition loop (`xstate/durable`). See
789
+ * {@link AgentRuntime} for the loop a host writes around it, and
790
+ * {@link runToQuiescence} for the blocking host. {@link AgentRuntime.finish}
791
+ * stops whatever is still running on every settle path (`done`, `idle`, and
792
+ * `error` alike) — resume is always by snapshot (or log), never by holding a
793
+ * reference to a live actor.
1031
794
  *
1032
- * Binding happens **before** the actor starts: every invoke the machine
795
+ * Binding happens **before** any actor starts: every invoke the machine
1033
796
  * could reach is walked and checked against the effective actor sources
1034
797
  * (`options.actors` merged onto the machine), so a missing
1035
798
  * `streamText`/`decide` executor or any other unbound actor source throws
1036
- * immediately — a bind-time error, not a mid-run failure.
799
+ * synchronously from this call — a bind-time error, not a mid-run failure.
1037
800
  *
1038
801
  * @example
1039
802
  * ```ts
1040
803
  * const executors = createAiSdkExecutors({ models });
1041
- * let r = await runAgent(machine, { input, executors });
804
+ * let r = await runToQuiescence(createAgentRuntime(machine, { executors }), { input });
1042
805
  * while (r.status === 'idle') {
1043
806
  * const event = await promptUser(getAcceptedEvents(r.snapshot));
1044
- * r = await runAgent(machine, { snapshot: r.snapshot, event, executors });
807
+ * r = await runToQuiescence(createAgentRuntime(machine, { executors }), {
808
+ * snapshot: r.snapshot,
809
+ * event,
810
+ * });
1045
811
  * }
1046
812
  * if (r.status !== 'done') throw new Error(`Run did not complete: ${r.status}`);
1047
813
  * console.log(r.output);
@@ -1051,46 +817,13 @@ function rebindChildMachine(childMachine, runCtx, visited, ctxFor) {
1051
817
  * an adapter's set: `createAiSdkExecutors` from '@statelyai/agent/ai-sdk' or
1052
818
  * `createOpenAiExecutors` from '@statelyai/agent/openai' supply all three.
1053
819
  */
1054
- async function runAgent(machine, options) {
1055
- const store = options.store;
1056
- if (store === void 0) return createAgentSession(machine, options).settled();
1057
- const threadId = options.threadId;
1058
- if (threadId === void 0 || threadId === "") throw new require_text_logic.AgentError("missing-thread-id", "runAgent: `threadId` is required when `store` is given — it names the log thread to read and append to.");
1059
- if (options.events !== void 0) {
1060
- const storedThread = await store.read(threadId);
1061
- if (storedThread.length !== options.events.length) throw new require_event_log_store.AgentEventLogConflictError(threadId, options.events.length, storedThread.length);
1062
- assertThreadMatchesEvents(threadId, storedThread, options.events);
1063
- return createAgentSession(machine, options).settled();
1064
- }
1065
- const stored = await store.read(threadId);
1066
- return createAgentSession(machine, stored.length > 0 ? {
1067
- ...options,
1068
- events: stored
1069
- } : options).settled();
1070
- }
1071
- /**
1072
- * Entry-by-entry check that the caller's `events` IS the store's thread. Equal
1073
- * lengths prove nothing: a fork, a rolled-back replay, or a concurrent writer
1074
- * that appended and truncated all produce a divergent log of the same size,
1075
- * and appending this run's entries onto it would splice two lineages together.
1076
- */
1077
- function assertThreadMatchesEvents(threadId, stored, events) {
1078
- for (let index = 0; index < stored.length; index++) {
1079
- const storedEntry = stored[index];
1080
- const givenEntry = events[index];
1081
- const storedHash = storedEntry.verification?.stateHash;
1082
- const givenHash = givenEntry.verification?.stateHash;
1083
- if (!(storedEntry.id === givenEntry.id && storedEntry.index === givenEntry.index && require_event_log_store.canonicalEventJson(storedEntry.event) === require_event_log_store.canonicalEventJson(givenEntry.event) && (storedHash === void 0 || givenHash === void 0 || storedHash === givenHash))) throw new require_text_logic.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.`);
1084
- }
1085
- }
1086
- function createAgentSession(machine, options) {
820
+ function createAgentRuntime(machine, options = {}) {
1087
821
  const maxModelCalls = options.maxModelCalls ?? 100;
1088
822
  let modelCallCount = 0;
1089
823
  let budgetExceeded = false;
1090
824
  let warnedNonSerializable = false;
1091
825
  const runId = `run_${nextRunAgentTraceId++}`;
1092
826
  let traceSeq = 0;
1093
- const resolvedInput = resolveMachineInput(machine, options.input);
1094
827
  const machineId = machine.config.id ?? machine.id ?? "(machine)";
1095
828
  const machineVersion = require_text_logic.resolveMachineVersion(machine);
1096
829
  const onTrace = createTraceDispatch({
@@ -1117,11 +850,10 @@ function createAgentSession(machine, options) {
1117
850
  }
1118
851
  modelCallCount += 1;
1119
852
  };
1120
- const cycleGate = { isResolved: () => false };
1121
853
  const logEntries = [];
1122
854
  const store = options.store;
1123
855
  const threadId = options.threadId;
1124
- if (store !== void 0 && (threadId === void 0 || threadId === "")) throw new require_text_logic.AgentError("missing-thread-id", "runAgent: `threadId` is required when `store` is given — it names the log thread to read and append to.");
856
+ if (store !== void 0 && (threadId === void 0 || threadId === "")) throw new require_text_logic.AgentError("missing-thread-id", "createAgentRuntime: `threadId` is required when `store` is given — it names the log thread to read and append to.");
1125
857
  let journalChain = Promise.resolve();
1126
858
  let journalPending = 0;
1127
859
  let journalError;
@@ -1137,7 +869,10 @@ function createAgentSession(machine, options) {
1137
869
  });
1138
870
  }).catch((error) => {
1139
871
  journalError ??= error;
1140
- failRunOnJournalError(error);
872
+ stopRun({
873
+ cause: "journal",
874
+ error
875
+ });
1141
876
  }).finally(() => {
1142
877
  journalPending--;
1143
878
  });
@@ -1163,19 +898,10 @@ function createAgentSession(machine, options) {
1163
898
  while (journalPending > 0) await journalChain;
1164
899
  if (journalError !== void 0) throw journalError;
1165
900
  };
1166
- const failRunOnJournalError = (error) => {
1167
- if (settled) return;
1168
- settle({
1169
- status: "error",
1170
- cause: "journal",
1171
- error,
1172
- snapshot: actor.getSnapshot()
1173
- });
1174
- };
1175
901
  let resumedLogLength = 0;
1176
902
  let logExecutionId;
1177
903
  const verificationEnabled = options.verification !== false;
1178
- let lastRootSnapshot;
904
+ let current;
1179
905
  let logMachine = machine;
1180
906
  let loggingEnabled = true;
1181
907
  const appendLogEntry = (event, snapshot) => {
@@ -1191,7 +917,6 @@ function createAgentSession(machine, options) {
1191
917
  return entry;
1192
918
  };
1193
919
  const usageEntrySnapshot = () => {
1194
- const current = lastRootSnapshot;
1195
920
  if (current && (current.status !== "active" || !declaresUsageTransition(current))) return current;
1196
921
  };
1197
922
  const recordUsage = (usage, source = {}) => {
@@ -1200,24 +925,18 @@ function createAgentSession(machine, options) {
1200
925
  ...source,
1201
926
  usage
1202
927
  };
1203
- const journal = { event };
1204
- pendingUsageJournal = journal;
1205
- try {
1206
- deliverUsageEvent(event, () => actorHolder.actorRef, (dropped) => {
1207
- if (!cycleGate.isResolved()) return false;
1208
- onTrace({
1209
- type: "usage.dropped",
1210
- event: dropped,
1211
- reason: "settled"
1212
- });
1213
- return true;
928
+ let delivered = false;
929
+ deliverUsageEvent(event, () => rootFacade(() => delivered = true), (dropped) => {
930
+ if (!finished) return false;
931
+ onTrace({
932
+ type: "usage.dropped",
933
+ event: dropped,
934
+ reason: "settled"
1214
935
  });
1215
- } finally {
1216
- pendingUsageJournal = void 0;
1217
- }
1218
- if (journal.entry === void 0) appendLogEntry(event, usageEntrySnapshot());
936
+ return true;
937
+ });
938
+ if (!delivered) appendLogEntry(event, usageEntrySnapshot());
1219
939
  };
1220
- let pendingUsageJournal;
1221
940
  const runUsage = () => ({
1222
941
  ...require_event_log_store.getUsageFromEvents(logEntries.slice(resumedLogLength)),
1223
942
  modelCalls: modelCallCount
@@ -1232,14 +951,21 @@ function createAgentSession(machine, options) {
1232
951
  }
1233
952
  if (offending.length === 0) return;
1234
953
  warnedNonSerializable = true;
1235
- 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.`);
954
+ console.warn(`createAgentRuntime: 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.`);
1236
955
  };
1237
956
  const provided = machine.provide({ actors: options.actors });
1238
957
  logMachine = provided;
1239
958
  const effectiveSources = provided.sources.actors;
1240
959
  const executors = { ...options.executors };
1241
960
  assertBindable(provided, effectiveSources, executors);
1242
- const actorHolder = { actorRef: void 0 };
961
+ const rootFacade = (onSend) => ({
962
+ getSnapshot: () => current,
963
+ send: (event) => {
964
+ onSend?.();
965
+ enqueue(event);
966
+ }
967
+ });
968
+ const actorHolder = { actorRef: rootFacade() };
1243
969
  const runCtx = {
1244
970
  generateText: executors.generateText,
1245
971
  streamText: executors.streamText,
@@ -1269,328 +995,446 @@ function createAgentSession(machine, options) {
1269
995
  }
1270
996
  }
1271
997
  const boundMachine = provided.provide({ actors: wrappedSources });
1272
- const isIdle = require_text_logic.getMachineIdlePredicate(machine) ?? isAgentIdle;
1273
- const isIntentionalIdle = (snapshot) => isIdle(snapshot);
1274
- const resumeEvents = options.events;
1275
- let effectiveSnapshot = options.snapshot;
1276
- /** Deferred until after the illegal-resume check, so a rejected resume emits no entries. */
1277
- let seedInitEntry;
1278
- const restoredPersistedSnapshot = () => {
1279
- try {
1280
- const restored = logMachine.restoreSnapshot(options.snapshot);
1281
- return logMachine.getPersistedSnapshot(restored);
1282
- } catch {
1283
- return;
1284
- }
998
+ const mailbox = [];
999
+ let wake;
1000
+ const fromMailbox = /* @__PURE__ */ new WeakSet();
1001
+ let stopReason;
1002
+ let started = false;
1003
+ let finished = false;
1004
+ let ignoredEvent;
1005
+ const enqueue = (event) => {
1006
+ if (finished) return;
1007
+ fromMailbox.add(event);
1008
+ const waiting = wake;
1009
+ if (waiting) {
1010
+ wake = void 0;
1011
+ waiting(event);
1012
+ } else mailbox.push(event);
1285
1013
  };
1286
- /**
1287
- * Appends the log's reserved first entry, trying each candidate `init` in
1288
- * turn and, for each, an unverified entry if the hash cannot be computed.
1289
- * A machine or snapshot that defeats every attempt leaves the run WITHOUT a
1290
- * log rather than failing it: `runAgent` predates the log, and an exotic
1291
- * machine that cannot be folded must still run.
1292
- */
1293
- const appendInitEntry = (candidates, metadata) => {
1294
- for (const init of candidates) for (const verification of verificationEnabled ? [true, false] : [false]) try {
1295
- const entry = require_event_log_store.initEntry(logMachine, init, {
1296
- machineVersion,
1297
- verification,
1298
- metadata
1014
+ const inProcessTimers = options.timers === void 0 || options.timers === "in-process";
1015
+ const timerHandles = /* @__PURE__ */ new Map();
1016
+ const timerKey = (source, id) => `${source?.address ?? "(root)"}::${id}`;
1017
+ const armTimer = (source, isRoot, id, delay) => {
1018
+ if (isRoot && !inProcessTimers) {
1019
+ options.timers.schedule({
1020
+ id,
1021
+ delay
1299
1022
  });
1300
- logEntries.push(entry);
1301
- journalEntry(entry);
1302
- options.onEvent?.(entry);
1303
1023
  return;
1024
+ }
1025
+ const key = timerKey(isRoot ? void 0 : source, id);
1026
+ clearTimeout(timerHandles.get(key));
1027
+ timerHandles.set(key, setTimeout(() => {
1028
+ timerHandles.delete(key);
1029
+ const timerEvent = {
1030
+ type: "xstate.timer",
1031
+ id
1032
+ };
1033
+ if (isRoot) enqueue(timerEvent);
1034
+ else source?.send(timerEvent);
1035
+ recheck();
1036
+ }, delay));
1037
+ };
1038
+ const childrenBusy = (snapshot) => Object.values(snapshot?.children ?? {}).some((child) => {
1039
+ const childSnapshot = child?.getSnapshot?.();
1040
+ if (childSnapshot?.status !== "active") return false;
1041
+ return (0, xstate.isMachineSnapshot)(childSnapshot) ? childrenBusy(childSnapshot) : true;
1042
+ });
1043
+ const workInFlight = () => childrenBusy(current) || inProcessTimers && timerHandles.size > 0;
1044
+ let recheckScheduled = false;
1045
+ const recheck = () => {
1046
+ if (wake === void 0 || recheckScheduled) return;
1047
+ if (stopReason === void 0 && workInFlight()) return;
1048
+ recheckScheduled = true;
1049
+ setTimeout(() => {
1050
+ recheckScheduled = false;
1051
+ if (wake !== void 0 && (stopReason !== void 0 || !workInFlight())) {
1052
+ const waiting = wake;
1053
+ wake = void 0;
1054
+ waiting(QUIESCENT);
1055
+ }
1056
+ }, 0);
1057
+ };
1058
+ const stopChildren = (snapshot) => {
1059
+ for (const child of Object.values(snapshot?.children ?? {})) try {
1060
+ if (child) (0, xstate.stopActor)(child);
1304
1061
  } catch {}
1305
- loggingEnabled = false;
1062
+ for (const handle of timerHandles.values()) clearTimeout(handle);
1063
+ timerHandles.clear();
1306
1064
  };
1307
- /** Init forms for a snapshot resume, most faithful first. */
1308
- const snapshotInitCandidates = () => {
1309
- const restored = restoredPersistedSnapshot();
1310
- return [...restored !== void 0 ? [{ snapshot: restored }] : [], { snapshot: options.snapshot }];
1065
+ let persistedAtStop;
1066
+ const stopRun = (reason) => {
1067
+ if (finished || stopReason !== void 0) return;
1068
+ stopReason = reason;
1069
+ try {
1070
+ persistedAtStop = current && boundMachine.getPersistedSnapshot(current);
1071
+ } catch {}
1072
+ stopChildren(current);
1073
+ recheck();
1311
1074
  };
1312
- if (resumeEvents !== void 0 && resumeEvents.length > 0) {
1313
- require_event_log_store.validateReplayEntries(resumeEvents);
1314
- const tail = resumeEvents[resumeEvents.length - 1];
1315
- const inheritedExecutionId = require_event_log_store.getLogExecutionId(resumeEvents);
1316
- if (resumeEvents[0].machineId !== machineId) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1317
- machineId,
1318
- machineVersion
1319
- }, {
1320
- machineId: resumeEvents[0].machineId,
1321
- machineVersion: tail.machineVersion
1075
+ const onAbort = () => stopRun({
1076
+ cause: "aborted",
1077
+ error: options.signal?.reason ?? /* @__PURE__ */ new Error("Aborted")
1078
+ });
1079
+ const emitFromRoot = (event) => {
1080
+ onTrace({
1081
+ type: "emit",
1082
+ event
1322
1083
  });
1323
- if (tail.machineVersion === machineVersion) {
1324
- logEntries.push(...resumeEvents);
1325
- resumedLogLength = logEntries.length;
1326
- logExecutionId = inheritedExecutionId;
1327
- const cachedMeta = readAgentMeta(options.snapshot);
1328
- const tailStateHash = tail.verification?.stateHash;
1329
- if (!(options.snapshot !== void 0 && inheritedExecutionId !== void 0 && cachedMeta?.logId === inheritedExecutionId && cachedMeta.logIndex === resumeEvents.length && tailStateHash !== void 0 && hashResumeSnapshot(options.snapshot) === tailStateHash)) {
1330
- const cachedIndex = cachedMeta?.logIndex;
1331
- if (options.snapshot !== void 0 && typeof cachedIndex === "number" && cachedIndex >= 1 && cachedIndex <= resumeEvents.length && resumeEvents[cachedIndex - 1].verification?.stateHash !== void 0) {
1332
- const expected = require_event_log_store.getSnapshotStateHash(require_event_log_store.replay(logMachine, resumeEvents.slice(0, cachedIndex), {
1333
- machineVersion,
1334
- verify: false
1335
- }).persistedSnapshot);
1336
- const actual = hashResumeSnapshot(options.snapshot);
1337
- if (expected !== actual) throw new AgentSnapshotDivergedError(expected, actual, cachedIndex);
1338
- }
1339
- effectiveSnapshot = require_event_log_store.replay(logMachine, resumeEvents, {
1340
- machineVersion,
1341
- verify: true
1342
- }).persistedSnapshot;
1343
- }
1344
- } else {
1345
- if (options.snapshot === void 0) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1346
- machineId,
1347
- machineVersion
1348
- }, {
1349
- machineId: tail.machineId,
1350
- machineVersion: tail.machineVersion
1351
- });
1352
- const bridgeMeta = readAgentMeta(options.snapshot);
1353
- if (inheritedExecutionId === void 0 || bridgeMeta?.logId !== inheritedExecutionId) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1354
- machineId,
1355
- machineVersion
1356
- }, {
1357
- machineId: tail.machineId,
1358
- machineVersion: tail.machineVersion
1084
+ const on = options.on ?? {};
1085
+ on[event.type]?.(event);
1086
+ if (event.type !== "*") on["*"]?.(event);
1087
+ };
1088
+ const inspect = options.inspect === void 0 ? void 0 : (event) => {
1089
+ if (typeof options.inspect === "function") options.inspect(event);
1090
+ else options.inspect?.next?.(event);
1091
+ };
1092
+ let execution;
1093
+ execution = (0, xstate_durable.createDurable)(boundMachine, {
1094
+ startActor: (actor) => {
1095
+ actor.subscribe({
1096
+ next: recheck,
1097
+ complete: recheck,
1098
+ error: recheck
1359
1099
  });
1360
- const bridgeTailHash = tail.verification?.stateHash;
1361
- const bridgeSnapshotHash = hashResumeSnapshot(options.snapshot);
1362
- if (bridgeMeta.logIndex !== resumeEvents.length) throw new AgentSnapshotDivergedError(bridgeTailHash ?? "(unrecorded)", bridgeSnapshotHash, resumeEvents.length);
1363
- if (bridgeTailHash !== void 0 && bridgeSnapshotHash !== bridgeTailHash) throw new AgentSnapshotDivergedError(bridgeTailHash, bridgeSnapshotHash, resumeEvents.length);
1364
- logExecutionId = inheritedExecutionId;
1365
- const migratedFrom = {
1366
- machineVersion: tail.machineVersion,
1367
- logIndex: resumeEvents.length
1368
- };
1369
- seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), {
1370
- ...logExecutionId !== void 0 ? { executionId: logExecutionId } : {},
1371
- migratedFrom
1100
+ actor.start();
1101
+ },
1102
+ enqueueRootEvent: (_source, event) => enqueue(event),
1103
+ executeAction: (action, _metadata, runtime) => action.exec(runtime),
1104
+ waitForEvent: () => {
1105
+ const queued = mailbox.shift();
1106
+ if (queued !== void 0) return queued;
1107
+ if (stopReason !== void 0 || finished || !workInFlight()) return QUIESCENT;
1108
+ return new Promise((resolve) => {
1109
+ wake = resolve;
1372
1110
  });
1111
+ },
1112
+ emitEvent: (source, event) => {
1113
+ if (source.address === execution.rootAddress) emitFromRoot(event);
1114
+ else source._emit?.(event);
1115
+ },
1116
+ scheduleTimer: (source, id, delay) => {
1117
+ armTimer(source, source.address === execution.rootAddress, id, delay);
1118
+ },
1119
+ cancelTimer: (source, id) => {
1120
+ const isRoot = source.address === execution.rootAddress;
1121
+ if (isRoot && !inProcessTimers) {
1122
+ options.timers.cancel(id);
1123
+ return;
1124
+ }
1125
+ const key = timerKey(isRoot ? void 0 : source, id);
1126
+ clearTimeout(timerHandles.get(key));
1127
+ timerHandles.delete(key);
1128
+ },
1129
+ cancelAllTimers: (source) => {
1130
+ const prefix = timerKey(source.address === execution.rootAddress ? void 0 : source, "");
1131
+ for (const [key, handle] of timerHandles) if (key.startsWith(prefix)) {
1132
+ clearTimeout(handle);
1133
+ timerHandles.delete(key);
1134
+ }
1373
1135
  }
1374
- } else if (options.snapshot !== void 0) {
1375
- logExecutionId = crypto.randomUUID();
1376
- seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), { executionId: logExecutionId });
1377
- } else {
1378
- logExecutionId = crypto.randomUUID();
1379
- seedInitEntry = () => appendInitEntry([resolvedInput !== void 0 ? { input: resolvedInput } : {}], { executionId: logExecutionId });
1380
- }
1381
- const resumedHistory = [...logEntries];
1382
- const siteCallCounts = /* @__PURE__ */ new Map();
1383
- const mintedCallKeys = /* @__PURE__ */ new WeakMap();
1384
- runCtx.callKey = (siteId, self) => {
1385
- if (logExecutionId === void 0) return;
1386
- const memoized = self === void 0 ? void 0 : mintedCallKeys.get(self);
1387
- if (memoized !== void 0) return memoized;
1388
- const startedHere = siteCallCounts.get(siteId) ?? 0;
1389
- siteCallCounts.set(siteId, startedHere + 1);
1390
- const key = `${logExecutionId}:${siteId}#${require_event_log_store.agentCallOccurrence(resumedHistory, siteId) + startedHere}`;
1391
- if (self !== void 0) mintedCallKeys.set(self, key);
1392
- return key;
1393
- };
1394
- const resumeEventToSend = options.event;
1395
- let ignoredEvent;
1396
- seedInitEntry?.();
1397
- let settled = false;
1398
- let journalAtSettle;
1399
- cycleGate.isResolved = () => settled;
1400
- let lastResult;
1401
- const waiters = [];
1402
- let idleTimer;
1403
- let actor;
1404
- let actorStarted = false;
1405
- let deliveringResumeEvent = resumeEventToSend !== void 0;
1406
- const settle = (outcome) => {
1407
- if (settled) return;
1408
- settled = true;
1409
- let persistedSnapshot;
1410
- let persistenceError;
1411
- if (actorStarted && outcome.status !== "done") try {
1412
- persistedSnapshot = actor.getPersistedSnapshot();
1413
- } catch (error) {
1414
- persistenceError = error;
1415
- }
1416
- const logIndexAtSettle = logEntries.length;
1417
- journalAtSettle = journalChain;
1418
- const persist = () => {
1419
- if (persistenceError !== void 0) throw persistenceError;
1420
- persistedSnapshot ??= actor.getPersistedSnapshot();
1421
- persistedSnapshot.agentMeta = {
1422
- machineId,
1423
- version: machineVersion,
1424
- ...logExecutionId !== void 0 ? { logId: logExecutionId } : {},
1425
- logIndex: logIndexAtSettle
1426
- };
1427
- return persistedSnapshot;
1428
- };
1429
- const result = {
1430
- ...outcome,
1431
- events: [...logEntries],
1432
- persist,
1433
- drain: drainJournal,
1434
- usage: runUsage(),
1435
- ...ignoredEvent !== void 0 ? { ignored: ignoredEvent } : {}
1436
- };
1437
- if (idleTimer !== void 0) clearTimeout(idleTimer);
1136
+ }, inspect ? { inspect } : void 0);
1137
+ const runErrorCause = (error) => budgetExceeded ? "max-model-calls" : wrapsDecisionExhausted(error) ? "decision-exhausted" : "machine";
1138
+ const commit = (snapshot, event) => {
1139
+ current = snapshot;
1438
1140
  onTrace({
1439
- type: "run.end",
1440
- ...outcome
1441
- });
1442
- if (options.signal) options.signal.removeEventListener("abort", onAbort);
1443
- actor.stop();
1444
- lastResult = result;
1445
- for (const resolve of waiters.splice(0)) resolve(result);
1446
- };
1447
- const onAbort = () => {
1448
- settle({
1449
- status: "error",
1450
- cause: "aborted",
1451
- error: options.signal?.reason ?? /* @__PURE__ */ new Error("Aborted"),
1452
- snapshot: actor.getSnapshot()
1453
- });
1454
- };
1455
- const settleIdle = (current) => {
1456
- warnNonSerializableContext(current);
1457
- settle({
1458
- status: "idle",
1459
- snapshot: current
1141
+ type: "machine.transition",
1142
+ snapshot,
1143
+ event
1460
1144
  });
1461
1145
  };
1462
- const runErrorCause = (error) => budgetExceeded ? "max-model-calls" : wrapsDecisionExhausted(error) ? "decision-exhausted" : "machine";
1463
- const scheduleIdleCheck = () => {
1464
- if (idleTimer !== void 0) clearTimeout(idleTimer);
1465
- idleTimer = setTimeout(() => {
1466
- idleTimer = void 0;
1467
- if (settled) return;
1468
- const current = actor.getSnapshot();
1469
- if (isIntentionalIdle(current) && isIdleSnapshot(current)) settleIdle(current);
1470
- }, 0);
1146
+ /** True for a child completion/failure whose child is no longer running under the current state. */
1147
+ const isStaleChildEvent = (event) => {
1148
+ if (!event.type.startsWith("xstate.done.actor") && !event.type.startsWith("xstate.error.actor")) return false;
1149
+ const { sessionId, actorId } = event;
1150
+ return !Object.values(current?.children ?? {}).some((child) => sessionId !== void 0 ? child?.sessionId === sessionId : child?.id === actorId);
1471
1151
  };
1472
- actor = (0, xstate.createActor)(boundMachine, {
1473
- input: resolvedInput,
1474
- snapshot: effectiveSnapshot,
1475
- inspect: (event) => {
1476
- if (typeof options.inspect === "function") options.inspect(event);
1477
- else options.inspect?.next?.(event);
1478
- if (event.type !== "@xstate.transition" || event.actorRef !== actor.ref) return;
1479
- if (settled) return;
1480
- const snapshot = event.snapshot;
1481
- lastRootSnapshot = snapshot;
1482
- if (resumeEventToSend !== void 0 && event.event === resumeEventToSend && event.microsteps.length === 0 && event.actions.length === 0 && event.sent.length === 0) ignoredEvent = resumeEventToSend;
1483
- if (pendingUsageJournal !== void 0 && event.event === pendingUsageJournal.event) pendingUsageJournal.entry = appendLogEntry(event.event, snapshot);
1484
- else if (event.event.type !== "@xstate.init" && (event.sourceRef !== event.actorRef || event.event.type === "xstate.timer")) appendLogEntry(event.event, snapshot);
1152
+ return {
1153
+ async start(init = {}) {
1154
+ if (started) throw new require_text_logic.AgentError("runtime-started", "createAgentRuntime: `start` was already called.");
1155
+ started = true;
1156
+ let resumeEvents = init.events;
1157
+ if (store !== void 0) {
1158
+ const storedThread = await store.read(threadId);
1159
+ if (resumeEvents !== void 0) {
1160
+ if (storedThread.length !== resumeEvents.length) throw new require_event_log_store.AgentEventLogConflictError(threadId, resumeEvents.length, storedThread.length);
1161
+ assertThreadMatchesEvents(threadId, storedThread, resumeEvents);
1162
+ } else if (storedThread.length > 0) resumeEvents = storedThread;
1163
+ }
1164
+ const resolvedInput = resolveMachineInput(machine, init.input);
1165
+ let effectiveSnapshot = init.snapshot;
1166
+ let seedInitEntry;
1167
+ const restoredPersistedSnapshot = () => {
1168
+ try {
1169
+ const restored = logMachine.restoreSnapshot(init.snapshot);
1170
+ return logMachine.getPersistedSnapshot(restored);
1171
+ } catch {
1172
+ return;
1173
+ }
1174
+ };
1175
+ /**
1176
+ * Appends the log's reserved first entry, trying each candidate `init`
1177
+ * in turn and, for each, an unverified entry if the hash cannot be
1178
+ * computed. A machine or snapshot that defeats every attempt leaves the
1179
+ * run WITHOUT a log rather than failing it.
1180
+ */
1181
+ const appendInitEntry = (candidates, metadata) => {
1182
+ for (const candidate of candidates) for (const verification of verificationEnabled ? [true, false] : [false]) try {
1183
+ const entry = require_event_log_store.initEntry(logMachine, candidate, {
1184
+ machineVersion,
1185
+ verification,
1186
+ metadata
1187
+ });
1188
+ logEntries.push(entry);
1189
+ journalEntry(entry);
1190
+ options.onEvent?.(entry);
1191
+ return;
1192
+ } catch {}
1193
+ loggingEnabled = false;
1194
+ };
1195
+ /** Init forms for a snapshot resume, most faithful first. */
1196
+ const snapshotInitCandidates = () => {
1197
+ const restored = restoredPersistedSnapshot();
1198
+ return [...restored !== void 0 ? [{ snapshot: restored }] : [], { snapshot: init.snapshot }];
1199
+ };
1200
+ if (resumeEvents !== void 0 && resumeEvents.length > 0) {
1201
+ require_event_log_store.validateReplayEntries(resumeEvents);
1202
+ const tail = resumeEvents[resumeEvents.length - 1];
1203
+ const inheritedExecutionId = require_event_log_store.getLogExecutionId(resumeEvents);
1204
+ if (resumeEvents[0].machineId !== machineId) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1205
+ machineId,
1206
+ machineVersion
1207
+ }, {
1208
+ machineId: resumeEvents[0].machineId,
1209
+ machineVersion: tail.machineVersion
1210
+ });
1211
+ if (tail.machineVersion === machineVersion) {
1212
+ logEntries.push(...resumeEvents);
1213
+ resumedLogLength = logEntries.length;
1214
+ logExecutionId = inheritedExecutionId;
1215
+ const cachedMeta = readAgentMeta(init.snapshot);
1216
+ const tailStateHash = tail.verification?.stateHash;
1217
+ if (!(init.snapshot !== void 0 && inheritedExecutionId !== void 0 && cachedMeta?.logId === inheritedExecutionId && cachedMeta.logIndex === resumeEvents.length && tailStateHash !== void 0 && hashResumeSnapshot(init.snapshot) === tailStateHash)) {
1218
+ const cachedIndex = cachedMeta?.logIndex;
1219
+ if (init.snapshot !== void 0 && typeof cachedIndex === "number" && cachedIndex >= 1 && cachedIndex <= resumeEvents.length && resumeEvents[cachedIndex - 1].verification?.stateHash !== void 0) {
1220
+ const expected = require_event_log_store.getSnapshotStateHash(require_event_log_store.replay(logMachine, resumeEvents.slice(0, cachedIndex), {
1221
+ machineVersion,
1222
+ verify: false
1223
+ }).persistedSnapshot);
1224
+ const actual = hashResumeSnapshot(init.snapshot);
1225
+ if (expected !== actual) throw new AgentSnapshotDivergedError(expected, actual, cachedIndex);
1226
+ }
1227
+ effectiveSnapshot = require_event_log_store.replay(logMachine, resumeEvents, {
1228
+ machineVersion,
1229
+ verify: true
1230
+ }).persistedSnapshot;
1231
+ }
1232
+ } else {
1233
+ if (init.snapshot === void 0) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1234
+ machineId,
1235
+ machineVersion
1236
+ }, {
1237
+ machineId: tail.machineId,
1238
+ machineVersion: tail.machineVersion
1239
+ });
1240
+ const bridgeMeta = readAgentMeta(init.snapshot);
1241
+ if (inheritedExecutionId === void 0 || bridgeMeta?.logId !== inheritedExecutionId) throw new require_event_log_store.AgentMachineVersionMismatchError(tail.id, tail.index, {
1242
+ machineId,
1243
+ machineVersion
1244
+ }, {
1245
+ machineId: tail.machineId,
1246
+ machineVersion: tail.machineVersion
1247
+ });
1248
+ const bridgeTailHash = tail.verification?.stateHash;
1249
+ const bridgeSnapshotHash = hashResumeSnapshot(init.snapshot);
1250
+ if (bridgeMeta.logIndex !== resumeEvents.length) throw new AgentSnapshotDivergedError(bridgeTailHash ?? "(unrecorded)", bridgeSnapshotHash, resumeEvents.length);
1251
+ if (bridgeTailHash !== void 0 && bridgeSnapshotHash !== bridgeTailHash) throw new AgentSnapshotDivergedError(bridgeTailHash, bridgeSnapshotHash, resumeEvents.length);
1252
+ logExecutionId = inheritedExecutionId;
1253
+ const migratedFrom = {
1254
+ machineVersion: tail.machineVersion,
1255
+ logIndex: resumeEvents.length
1256
+ };
1257
+ seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), {
1258
+ ...logExecutionId !== void 0 ? { executionId: logExecutionId } : {},
1259
+ migratedFrom
1260
+ });
1261
+ }
1262
+ } else if (init.snapshot !== void 0) {
1263
+ logExecutionId = crypto.randomUUID();
1264
+ seedInitEntry = () => appendInitEntry(snapshotInitCandidates(), { executionId: logExecutionId });
1265
+ } else {
1266
+ logExecutionId = crypto.randomUUID();
1267
+ seedInitEntry = () => appendInitEntry([resolvedInput !== void 0 ? { input: resolvedInput } : {}], { executionId: logExecutionId });
1268
+ }
1269
+ const resumedHistory = [...logEntries];
1270
+ const siteCallCounts = /* @__PURE__ */ new Map();
1271
+ const mintedCallKeys = /* @__PURE__ */ new WeakMap();
1272
+ runCtx.callKey = (siteId, self) => {
1273
+ if (logExecutionId === void 0) return;
1274
+ const memoized = self === void 0 ? void 0 : mintedCallKeys.get(self);
1275
+ if (memoized !== void 0) return memoized;
1276
+ const startedHere = siteCallCounts.get(siteId) ?? 0;
1277
+ siteCallCounts.set(siteId, startedHere + 1);
1278
+ const key = `${logExecutionId}:${siteId}#${require_event_log_store.agentCallOccurrence(resumedHistory, siteId) + startedHere}`;
1279
+ if (self !== void 0) mintedCallKeys.set(self, key);
1280
+ return key;
1281
+ };
1282
+ seedInitEntry?.();
1283
+ const resumeEvent = init.event;
1485
1284
  onTrace({
1486
- type: "machine.transition",
1487
- snapshot,
1488
- event: event.event
1285
+ type: "run.start",
1286
+ ...resolvedInput !== void 0 ? { input: resolvedInput } : {},
1287
+ ...effectiveSnapshot !== void 0 ? { snapshot: effectiveSnapshot } : {},
1288
+ ...resumeEvent !== void 0 ? { event: resumeEvent } : {}
1489
1289
  });
1490
- if (snapshot.status === "done") {
1491
- settle({
1492
- status: "done",
1493
- output: snapshot.output,
1494
- snapshot
1495
- });
1496
- return;
1290
+ if (options.signal) if (options.signal.aborted) stopReason = {
1291
+ cause: "aborted",
1292
+ error: options.signal.reason ?? /* @__PURE__ */ new Error("Aborted")
1293
+ };
1294
+ else options.signal.addEventListener("abort", onAbort);
1295
+ let snapshot;
1296
+ let effects = [];
1297
+ const initEvent = {
1298
+ type: "@xstate.init",
1299
+ ...resolvedInput !== void 0 ? { input: resolvedInput } : {}
1300
+ };
1301
+ if (effectiveSnapshot === void 0) [snapshot, effects] = execution.initialTransition(resolvedInput);
1302
+ else {
1303
+ try {
1304
+ [snapshot, effects] = execution.restore(effectiveSnapshot);
1305
+ } catch (error) {
1306
+ try {
1307
+ current = execution.initialTransition(resolvedInput)[0];
1308
+ } catch {
1309
+ current = {
1310
+ status: "error",
1311
+ error,
1312
+ context: void 0
1313
+ };
1314
+ }
1315
+ stopReason ??= {
1316
+ cause: "machine",
1317
+ error
1318
+ };
1319
+ return [current, []];
1320
+ }
1321
+ current = snapshot;
1497
1322
  }
1498
- if (snapshot.status === "error") {
1499
- settle({
1500
- status: "error",
1501
- cause: runErrorCause(snapshot.error),
1502
- error: snapshot.error,
1503
- snapshot
1323
+ commit(snapshot, initEvent);
1324
+ return [snapshot, effects];
1325
+ },
1326
+ transition(state, event) {
1327
+ if (finished) throw new require_text_logic.AgentError("runtime-finished", "createAgentRuntime: the run has finished; start a new runtime to continue.");
1328
+ if (stopReason !== void 0) return [state, []];
1329
+ const [next, effects] = execution.transition(state, event);
1330
+ if (!fromMailbox.has(event) && next === state && effects.length === 0) ignoredEvent = event;
1331
+ appendLogEntry(event, next);
1332
+ commit(next, event);
1333
+ return [next, effects];
1334
+ },
1335
+ async execute(effects) {
1336
+ if (stopReason !== void 0 || finished || effects.length === 0) return;
1337
+ try {
1338
+ await execution.executeEffects(effects);
1339
+ } catch (error) {
1340
+ stopRun({
1341
+ cause: "machine",
1342
+ error
1504
1343
  });
1505
- return;
1506
1344
  }
1507
- if (snapshot.status === "stopped") {
1508
- settle({
1509
- status: "error",
1510
- cause: "stopped",
1511
- error: /* @__PURE__ */ new Error("Actor stopped externally."),
1345
+ recheck();
1346
+ },
1347
+ async nextEvent() {
1348
+ for (;;) {
1349
+ if (finished || stopReason !== void 0 || current?.status !== "active") return;
1350
+ const event = await execution.waitForEvent();
1351
+ if (event === QUIESCENT || stopReason !== void 0) return;
1352
+ if (isStaleChildEvent(event)) continue;
1353
+ return event;
1354
+ }
1355
+ },
1356
+ async finish() {
1357
+ if (finished) throw new require_text_logic.AgentError("runtime-finished", "createAgentRuntime: `finish` was already called.");
1358
+ const snapshot = current;
1359
+ let outcome;
1360
+ if (stopReason !== void 0) outcome = {
1361
+ status: "error",
1362
+ cause: stopReason.cause === "machine" ? runErrorCause(stopReason.error) : stopReason.cause,
1363
+ error: stopReason.error,
1364
+ snapshot
1365
+ };
1366
+ else if (snapshot.status === "done") outcome = {
1367
+ status: "done",
1368
+ output: snapshot.output,
1369
+ snapshot
1370
+ };
1371
+ else if (snapshot.status === "error") outcome = {
1372
+ status: "error",
1373
+ cause: runErrorCause(snapshot.error),
1374
+ error: snapshot.error,
1375
+ snapshot
1376
+ };
1377
+ else if (snapshot.status === "stopped") outcome = {
1378
+ status: "error",
1379
+ cause: "stopped",
1380
+ error: /* @__PURE__ */ new Error("Actor stopped externally."),
1381
+ snapshot
1382
+ };
1383
+ else {
1384
+ warnNonSerializableContext(snapshot);
1385
+ outcome = {
1386
+ status: "idle",
1512
1387
  snapshot
1513
- });
1514
- return;
1388
+ };
1515
1389
  }
1516
- if (!deliveringResumeEvent && isIntentionalIdle(snapshot) && isIdleSnapshot(snapshot)) {
1517
- queueMicrotask(() => {
1518
- if (settled) return;
1519
- const current = actor.getSnapshot();
1520
- if (isIntentionalIdle(current) && isIdleSnapshot(current)) settleIdle(current);
1521
- else scheduleIdleCheck();
1522
- });
1523
- return;
1390
+ let persistedSnapshot = persistedAtStop;
1391
+ let persistenceError;
1392
+ if (outcome.status !== "done" && persistedSnapshot === void 0) try {
1393
+ persistedSnapshot = boundMachine.getPersistedSnapshot(snapshot);
1394
+ } catch (error) {
1395
+ persistenceError = error;
1524
1396
  }
1525
- scheduleIdleCheck();
1526
- }
1527
- });
1528
- actorHolder.actorRef = actor;
1529
- actor.subscribe({ error: () => {} });
1530
- actor.on("*", (event) => {
1531
- onTrace({
1532
- type: "emit",
1533
- event
1534
- });
1535
- });
1536
- for (const [type, handler] of Object.entries(options.on ?? {})) if (typeof handler === "function") actor.on(type, handler);
1537
- const sessionApi = { settled: async () => {
1538
- const result = settled && lastResult !== void 0 ? lastResult : await new Promise((resolve) => {
1539
- waiters.push(resolve);
1540
- });
1541
- await journalAtSettle;
1542
- return result;
1543
- } };
1544
- if (options.signal) {
1545
- if (options.signal.aborted) {
1546
- settle({
1547
- status: "error",
1548
- cause: "aborted",
1549
- error: options.signal.reason ?? /* @__PURE__ */ new Error("Aborted"),
1550
- snapshot: actor.getSnapshot()
1397
+ const logIndexAtSettle = logEntries.length;
1398
+ const persist = () => {
1399
+ if (persistenceError !== void 0) throw persistenceError;
1400
+ persistedSnapshot ??= boundMachine.getPersistedSnapshot(snapshot);
1401
+ persistedSnapshot.agentMeta = {
1402
+ machineId,
1403
+ version: machineVersion,
1404
+ ...logExecutionId !== void 0 ? { logId: logExecutionId } : {},
1405
+ logIndex: logIndexAtSettle
1406
+ };
1407
+ return persistedSnapshot;
1408
+ };
1409
+ finished = true;
1410
+ const journalAtSettle = journalChain;
1411
+ const result = {
1412
+ ...outcome,
1413
+ events: [...logEntries],
1414
+ persist,
1415
+ drain: drainJournal,
1416
+ usage: runUsage(),
1417
+ ...ignoredEvent !== void 0 ? { ignored: ignoredEvent } : {}
1418
+ };
1419
+ onTrace({
1420
+ type: "run.end",
1421
+ ...outcome
1551
1422
  });
1552
- return sessionApi;
1423
+ options.signal?.removeEventListener("abort", onAbort);
1424
+ stopChildren(snapshot);
1425
+ if (wake !== void 0) {
1426
+ const waiting = wake;
1427
+ wake = void 0;
1428
+ waiting(QUIESCENT);
1429
+ }
1430
+ await journalAtSettle;
1431
+ return result;
1553
1432
  }
1554
- options.signal.addEventListener("abort", onAbort);
1555
- }
1556
- onTrace({
1557
- type: "run.start",
1558
- ...resolvedInput !== void 0 ? { input: resolvedInput } : {},
1559
- ...effectiveSnapshot !== void 0 ? { snapshot: effectiveSnapshot } : {},
1560
- ...resumeEventToSend !== void 0 ? { event: resumeEventToSend } : {}
1561
- });
1562
- actorStarted = true;
1563
- actor.start();
1564
- if (!settled) {
1565
- const startedSnapshot = actor.getSnapshot();
1566
- lastRootSnapshot ??= startedSnapshot;
1567
- if (startedSnapshot.status === "done") settle({
1568
- status: "done",
1569
- output: startedSnapshot.output,
1570
- snapshot: startedSnapshot
1571
- });
1572
- else if (startedSnapshot.status === "error") settle({
1573
- status: "error",
1574
- cause: runErrorCause(startedSnapshot.error),
1575
- error: startedSnapshot.error,
1576
- snapshot: startedSnapshot
1577
- });
1578
- else if (startedSnapshot.status === "stopped") settle({
1579
- status: "error",
1580
- cause: "stopped",
1581
- error: /* @__PURE__ */ new Error("Actor stopped externally."),
1582
- snapshot: startedSnapshot
1583
- });
1584
- }
1585
- if (resumeEventToSend && !settled) {
1586
- deliveringResumeEvent = false;
1587
- actor.send(resumeEventToSend);
1588
- }
1589
- return sessionApi;
1433
+ };
1590
1434
  }
1591
1435
  /**
1592
1436
  * Wraps a `(snapshot, actorRef) => void` handler into a function usable as
1593
- * {@link RunAgentOptions.inspect}: it filters the raw inspection stream to
1437
+ * {@link AgentRuntimeOptions.inspect}: it filters the raw inspection stream to
1594
1438
  * `@xstate.transition` events and hands the handler the typed
1595
1439
  * {@link AnyMachineSnapshot} and the {@link InspectedActorRef} that
1596
1440
  * transitioned. Attribute a child actor via `actorRef.id`/`actorRef.src`. Saves
@@ -1615,12 +1459,12 @@ function inspectTransitions(handler) {
1615
1459
  * const actor = createActor(bound, { inspect: traceTransitions(onTrace) });
1616
1460
  * ```
1617
1461
  *
1618
- * Only ROOT-actor transitions are traced (matching `runAgent`'s
1462
+ * Only ROOT-actor transitions are traced (matching the runtime's
1619
1463
  * `machine.transition`); child-actor transitions are ignored. Attribute the
1620
1464
  * event via its envelope `runId`.
1621
1465
  *
1622
1466
  * By design this path has NO `run.start`/`run.end` events: `createActor` has no
1623
- * run boundary the way `runAgent` does, so the stream starts at the actor's
1467
+ * run boundary the way `createAgentRuntime` does, so the stream starts at the actor's
1624
1468
  * first transition. It also does NOT emit `emit` trace events: in this xstate
1625
1469
  * build emitted events are delivered through `actor.on(...)`, not the inspection
1626
1470
  * protocol, so they are not observable from an `inspect` handler — subscribe
@@ -1638,26 +1482,14 @@ function traceTransitions(onTrace) {
1638
1482
  }));
1639
1483
  };
1640
1484
  }
1641
- function isIdleSnapshot(snapshot) {
1642
- if (snapshot.status !== "active") return false;
1643
- if (Object.values(snapshot.children ?? {}).some((child) => {
1644
- const childSnapshot = child?.getSnapshot?.();
1645
- if (childSnapshot?.status !== "active") return false;
1646
- if ((0, xstate.isMachineSnapshot)(childSnapshot)) return !isIdleSnapshot(childSnapshot);
1647
- return true;
1648
- })) return false;
1649
- return !(0, xstate.getNextTransitions)(snapshot).some((transitionDef) => transitionDef.eventType === "" || transitionDef.eventType.startsWith("xstate.after"));
1650
- }
1651
1485
  /**
1652
- * Default machine-owned idle signal used by {@link runAgent}: an active
1486
+ * Whether a snapshot is asking the outside world for something: an active
1653
1487
  * snapshot that accepts an external event anywhere in its active hierarchy,
1654
1488
  * or declares interaction metadata on an active state.
1655
1489
  *
1656
- * Compose this in `setupAgent({ isIdle })` when the application has additional
1657
- * wait states: `isIdle: (snapshot) => isAgentIdle(snapshot) || snapshot.hasTag('waiting')`.
1658
- * Pending work and active invoked children are checked separately by the
1659
- * runner, so this function only answers whether the state is an intentional
1660
- * external wait.
1490
+ * The runtime does not use this to stop; a run settles when nothing is in
1491
+ * flight. Use it once the run is quiescent, to tell a human wait (render
1492
+ * `getInteraction(snapshot)`) from a machine that is simply stuck.
1661
1493
  */
1662
1494
  function isAgentIdle(snapshot) {
1663
1495
  if (snapshot.status !== "active") return false;
@@ -1703,10 +1535,10 @@ Object.defineProperty(exports, "bindTextForProvide", {
1703
1535
  return bindTextForProvide;
1704
1536
  }
1705
1537
  });
1706
- Object.defineProperty(exports, "executeAgentRequest", {
1538
+ Object.defineProperty(exports, "createAgentRuntime", {
1707
1539
  enumerable: true,
1708
1540
  get: function() {
1709
- return executeAgentRequest;
1541
+ return createAgentRuntime;
1710
1542
  }
1711
1543
  });
1712
1544
  Object.defineProperty(exports, "getConfiguredInvokeSrcs", {
@@ -1715,18 +1547,6 @@ Object.defineProperty(exports, "getConfiguredInvokeSrcs", {
1715
1547
  return getConfiguredInvokeSrcs;
1716
1548
  }
1717
1549
  });
1718
- Object.defineProperty(exports, "getPendingInvokes", {
1719
- enumerable: true,
1720
- get: function() {
1721
- return getPendingInvokes;
1722
- }
1723
- });
1724
- Object.defineProperty(exports, "initialAgentStep", {
1725
- enumerable: true,
1726
- get: function() {
1727
- return initialAgentStep;
1728
- }
1729
- });
1730
1550
  Object.defineProperty(exports, "inspectTransitions", {
1731
1551
  enumerable: true,
1732
1552
  get: function() {
@@ -1745,22 +1565,10 @@ Object.defineProperty(exports, "isStateMachineLogic", {
1745
1565
  return isStateMachineLogic;
1746
1566
  }
1747
1567
  });
1748
- Object.defineProperty(exports, "rejectAgentStep", {
1749
- enumerable: true,
1750
- get: function() {
1751
- return rejectAgentStep;
1752
- }
1753
- });
1754
- Object.defineProperty(exports, "resolveAgentStep", {
1568
+ Object.defineProperty(exports, "runToQuiescence", {
1755
1569
  enumerable: true,
1756
1570
  get: function() {
1757
- return resolveAgentStep;
1758
- }
1759
- });
1760
- Object.defineProperty(exports, "runAgent", {
1761
- enumerable: true,
1762
- get: function() {
1763
- return runAgent;
1571
+ return runToQuiescence;
1764
1572
  }
1765
1573
  });
1766
1574
  Object.defineProperty(exports, "serializeTraceEvent", {
@@ -1775,9 +1583,3 @@ Object.defineProperty(exports, "traceTransitions", {
1775
1583
  return traceTransitions;
1776
1584
  }
1777
1585
  });
1778
- Object.defineProperty(exports, "transitionAgentStep", {
1779
- enumerable: true,
1780
- get: function() {
1781
- return transitionAgentStep;
1782
- }
1783
- });