@statelyai/agent 2.0.0-alpha.20 → 2.0.0-alpha.21

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.
@@ -424,7 +424,7 @@ function createBuiltinTextActor(src, mode, outputSchema) {
424
424
  messages: ({ input }) => input.messages,
425
425
  tools: ({ input }) => input.tools,
426
426
  toolChoice: ({ input }) => input.toolChoice,
427
- reasoning: ({ input }) => input.reasoning,
427
+ includeReasoning: ({ input }) => input.includeReasoning,
428
428
  temperature: ({ input }) => input.temperature,
429
429
  maxOutputTokens: ({ input }) => input.maxOutputTokens,
430
430
  topP: ({ input }) => input.topP,
@@ -496,7 +496,7 @@ function createTextLogic(config, execute) {
496
496
  tools: resolveTextLogicValue(config.tools, args),
497
497
  toolChoice: resolveTextLogicValue(config.toolChoice, args),
498
498
  outputSchema: schemas.output,
499
- reasoning: resolveTextLogicValue(config.reasoning, args),
499
+ includeReasoning: resolveTextLogicValue(config.includeReasoning, args),
500
500
  temperature: resolveTextLogicValue(config.temperature, args),
501
501
  maxOutputTokens: resolveTextLogicValue(config.maxOutputTokens, args),
502
502
  topP: resolveTextLogicValue(config.topP, args),
@@ -643,7 +643,7 @@ function buildEnvelopeSchema(inner, options = {}) {
643
643
  */
644
644
  function parseStructuredEnvelope(request, value) {
645
645
  if (!request.outputSchema) throw new Error("parseStructuredEnvelope: the request declares no outputSchema.");
646
- return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.reasoning }), value);
646
+ return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning }), value);
647
647
  }
648
648
  /**
649
649
  * Merges request-declared and call-site `tools`, dispatches to the
@@ -1048,12 +1048,24 @@ Object.defineProperty(exports, "DECIDE_ACTOR", {
1048
1048
  return DECIDE_ACTOR;
1049
1049
  }
1050
1050
  });
1051
+ Object.defineProperty(exports, "GENERATE_TEXT_ACTOR", {
1052
+ enumerable: true,
1053
+ get: function() {
1054
+ return GENERATE_TEXT_ACTOR;
1055
+ }
1056
+ });
1051
1057
  Object.defineProperty(exports, "INTERPRET_SOURCE", {
1052
1058
  enumerable: true,
1053
1059
  get: function() {
1054
1060
  return INTERPRET_SOURCE;
1055
1061
  }
1056
1062
  });
1063
+ Object.defineProperty(exports, "STREAM_TEXT_ACTOR", {
1064
+ enumerable: true,
1065
+ get: function() {
1066
+ return STREAM_TEXT_ACTOR;
1067
+ }
1068
+ });
1057
1069
  Object.defineProperty(exports, "USER_INPUT_ACTOR", {
1058
1070
  enumerable: true,
1059
1071
  get: function() {
@@ -423,7 +423,7 @@ function createBuiltinTextActor(src, mode, outputSchema) {
423
423
  messages: ({ input }) => input.messages,
424
424
  tools: ({ input }) => input.tools,
425
425
  toolChoice: ({ input }) => input.toolChoice,
426
- reasoning: ({ input }) => input.reasoning,
426
+ includeReasoning: ({ input }) => input.includeReasoning,
427
427
  temperature: ({ input }) => input.temperature,
428
428
  maxOutputTokens: ({ input }) => input.maxOutputTokens,
429
429
  topP: ({ input }) => input.topP,
@@ -495,7 +495,7 @@ function createTextLogic(config, execute) {
495
495
  tools: resolveTextLogicValue(config.tools, args),
496
496
  toolChoice: resolveTextLogicValue(config.toolChoice, args),
497
497
  outputSchema: schemas.output,
498
- reasoning: resolveTextLogicValue(config.reasoning, args),
498
+ includeReasoning: resolveTextLogicValue(config.includeReasoning, args),
499
499
  temperature: resolveTextLogicValue(config.temperature, args),
500
500
  maxOutputTokens: resolveTextLogicValue(config.maxOutputTokens, args),
501
501
  topP: resolveTextLogicValue(config.topP, args),
@@ -642,7 +642,7 @@ function buildEnvelopeSchema(inner, options = {}) {
642
642
  */
643
643
  function parseStructuredEnvelope(request, value) {
644
644
  if (!request.outputSchema) throw new Error("parseStructuredEnvelope: the request declares no outputSchema.");
645
- return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.reasoning }), value);
645
+ return validateSchemaSync(buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning }), value);
646
646
  }
647
647
  /**
648
648
  * Merges request-declared and call-site `tools`, dispatches to the
@@ -1029,4 +1029,4 @@ async function resolveDecision(request, executors, options = {}) {
1029
1029
  throw new AgentDecisionExhaustedError(attempts);
1030
1030
  }
1031
1031
  //#endregion
1032
- export { isUnboundPlaceholder as A, getMachineStructuralHash as B, parseStructuredEnvelope as C, getMachineIdlePredicate as D, executorBoundLogics as E, djb2Hex as F, toolMessage as G, isStandardSchema as H, findNonSerializableContextPaths as I, userMessage as K, getAgentMessages as L, machineStaticTransitionTargets as M, missingActor as N, getMachineStaticTransitionTargets as O, assistantMessage as P, getJsonSchema as R, parseOutput as S, agentExecutionOptions as T, resolveMachineVersion as U, getStateMeta as V, systemMessage as W, getAgentOutputMode as _, resolveDecision as a, normalizeGeneratorResult as b, AGENT_USAGE_TOKEN_FIELDS as c, USER_INPUT_ACTOR as d, bindRequestExecutor as f, executeAgentTextRequest as g, createTextLogic as h, renderDecisionAttempts as i, machineIdlePredicates as j, getRegisteredAgentExecutionOptions as k, DECIDE_ACTOR as l, builtinTextActors as m, createDecideActor as n, getAcceptedEvents as o, buildEnvelopeSchema as p, validateSchemaSync as q, isDecisionLogic as r, parseAgentEvent as s, AgentDecisionExhaustedError as t, INTERPRET_SOURCE as u, getCallUsage as v, userInputActor as w, parseModelRef as x, isTextLogic as y, getJsonSchemaSync as z };
1032
+ export { getMachineStaticTransitionTargets as A, getJsonSchema as B, parseModelRef as C, agentExecutionOptions as D, userInputActor as E, missingActor as F, resolveMachineVersion as G, getMachineStructuralHash as H, assistantMessage as I, userMessage as J, systemMessage as K, djb2Hex as L, isUnboundPlaceholder as M, machineIdlePredicates as N, executorBoundLogics as O, machineStaticTransitionTargets as P, findNonSerializableContextPaths as R, normalizeGeneratorResult as S, parseStructuredEnvelope as T, getStateMeta as U, getJsonSchemaSync as V, isStandardSchema as W, validateSchemaSync as Y, createTextLogic as _, resolveDecision as a, getCallUsage as b, AGENT_USAGE_TOKEN_FIELDS as c, INTERPRET_SOURCE as d, STREAM_TEXT_ACTOR as f, builtinTextActors as g, buildEnvelopeSchema as h, renderDecisionAttempts as i, getRegisteredAgentExecutionOptions as j, getMachineIdlePredicate as k, DECIDE_ACTOR as l, bindRequestExecutor as m, createDecideActor as n, getAcceptedEvents as o, USER_INPUT_ACTOR as p, toolMessage as q, isDecisionLogic as r, parseAgentEvent as s, AgentDecisionExhaustedError as t, GENERATE_TEXT_ACTOR as u, executeAgentTextRequest as v, parseOutput as w, isTextLogic as x, getAgentOutputMode as y, getAgentMessages as z };
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_errors = require("./errors-DUBBzRLP.cjs");
3
- const require_setup_agent = require("./setup-agent-gISRLxRe.cjs");
4
- const require_decision = require("./decision-DhsKLYAI.cjs");
3
+ const require_setup_agent = require("./setup-agent-91FSuZbB.cjs");
4
+ const require_decision = require("./decision-BnTCsuJv.cjs");
5
5
  const require_event_log_store = require("./event-log-store-a_TKy1gk.cjs");
6
6
  require("./validate.cjs");
7
7
  let xstate = require("xstate");
@@ -570,9 +570,13 @@ function invokingActorOf(self, runCtx) {
570
570
  * identical event shapes by construction. @internal
571
571
  */
572
572
  function bindTextLogic(logic, runCtx) {
573
- return logic.withExecutor(async ({ request, self: selfArg, signal }) => {
573
+ return logic.withExecutor(async ({ request: rawRequest, self: selfArg, signal }) => {
574
574
  const self = selfArg;
575
575
  const { id, src } = selfIdAndSrc(self);
576
+ const request = rawRequest.name === void 0 && src !== "" && src !== "agent.generateText" && src !== "agent.streamText" ? {
577
+ ...rawRequest,
578
+ name: src
579
+ } : rawRequest;
576
580
  const executor = logic.mode === "stream" ? runCtx.streamText : runCtx.generateText;
577
581
  if (!executor) throw new Error(`No '${logic.mode === "stream" ? "streamText" : "generateText"}' executor provided.`);
578
582
  const requestWithTools = {
@@ -2086,8 +2090,8 @@ function lintAgentMachine(machine, options = {}) {
2086
2090
  return diagnostics;
2087
2091
  }
2088
2092
  /**
2089
- * Thrown by `lintAgentMachine(machine, { throw: true })` when lint finds
2090
- * failing diagnostics.
2093
+ * Thrown by `lintAgentMachine(machine, { throw: true })` (and its
2094
+ * {@link assertAgentMachine} alias) when lint finds failing diagnostics.
2091
2095
  * `diagnostics` holds the findings; the message lists them one per finding,
2092
2096
  * so a test runner's failure output reads like the CLI's lint report.
2093
2097
  */
@@ -2100,6 +2104,26 @@ var AgentLintError = class extends require_errors.AgentError {
2100
2104
  this.diagnostics = diagnostics;
2101
2105
  }
2102
2106
  };
2107
+ /**
2108
+ * Asserts a machine passes {@link lintAgentMachine}: returns silently when
2109
+ * clean, throws {@link AgentLintError} (with the findings on `.diagnostics`)
2110
+ * otherwise — sugar for `lintAgentMachine(machine, { ...options, throw: true })`.
2111
+ * Fails on error-severity findings; set `warnings: true` to fail on warnings
2112
+ * too. The one-liner for tests and generation loops:
2113
+ *
2114
+ * @example
2115
+ * ```ts
2116
+ * test('agent machine is structurally sound', () => {
2117
+ * assertAgentMachine(machine);
2118
+ * });
2119
+ * ```
2120
+ */
2121
+ function assertAgentMachine(machine, options = {}) {
2122
+ lintAgentMachine(machine, {
2123
+ ...options,
2124
+ throw: true
2125
+ });
2126
+ }
2103
2127
  function pendingInvokes(step) {
2104
2128
  const out = [];
2105
2129
  for (const action of step.actions) {
@@ -2126,6 +2150,21 @@ function takeFromQueue(channel, src) {
2126
2150
  * the real transition logic. Returns the terminal `status`, final `snapshot`,
2127
2151
  * and a `trail` of every step taken.
2128
2152
  *
2153
+ * Decisions run through the live run's own validation/retry core,
2154
+ * {@link resolveDecision}, with the script standing in for the model: each
2155
+ * attempt consumes the next queued {@link ChosenEvent} for that src, so an
2156
+ * unknown, payload-invalid, or guard-rejected event is NOT silently swallowed
2157
+ * — the next queued decision is tried, exactly as a live run re-asks the
2158
+ * model. The decision logic's `maxRetries` caps attempts as it would live;
2159
+ * when retries continue past the end of the queue, the last queued decision
2160
+ * repeats (a scripted model that insists). The repeat applies only within one
2161
+ * decision request's retries — each new decision request must have its own
2162
+ * queued entry, or the dry-script error throws as usual. Exhausting all
2163
+ * attempts delivers
2164
+ * the resulting {@link AgentDecisionExhaustedError} to the machine as the
2165
+ * decision invoke's error (so an `onError` transition observes it, as it
2166
+ * would live); with no `onError` to catch it, it is thrown.
2167
+ *
2129
2168
  * Throws a descriptive error when the script runs dry mid-request, naming the
2130
2169
  * pending request's kind, src, and id so the missing scripted response is
2131
2170
  * obvious.
@@ -2134,7 +2173,10 @@ function takeFromQueue(channel, src) {
2134
2173
  * ```ts
2135
2174
  * const { status, snapshot } = simulateAgent(machine, {
2136
2175
  * input: { topic: 'state machines' },
2137
- * script: { decisions: { 'agent.decide': [{ type: 'END' }] } },
2176
+ * script: {
2177
+ * decisions: { 'agent.decide': [{ type: 'ESCALATE' }] },
2178
+ * events: [{ type: 'APPROVE' }], // crosses the human gate
2179
+ * },
2138
2180
  * });
2139
2181
  * ```
2140
2182
  */
@@ -2143,11 +2185,12 @@ async function simulateAgent(machine, options) {
2143
2185
  const script = {
2144
2186
  text: mapValues(options.script.text ?? {}, (arr) => [...arr]),
2145
2187
  decisions: mapValues(options.script.decisions ?? {}, (arr) => [...arr]),
2146
- invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr])
2188
+ invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr]),
2189
+ events: [...options.script.events ?? []]
2147
2190
  };
2148
2191
  if (options.script.userInput?.length) script.invokes[USER_INPUT_SRC] = [...options.script.userInput, ...script.invokes[USER_INPUT_SRC] ?? []];
2149
2192
  let step = require_setup_agent.initialAgentStep(machine, options.input);
2150
- const trail = [];
2193
+ const trail = [{ state: step.snapshot.value }];
2151
2194
  for (let i = 0; i < maxSteps; i++) {
2152
2195
  if (step.done) return {
2153
2196
  status: "done",
@@ -2157,14 +2200,10 @@ async function simulateAgent(machine, options) {
2157
2200
  const request = step.requests[0];
2158
2201
  if (request) {
2159
2202
  if (request.kind === "decision") {
2160
- const decisionSrc = new Map(pendingInvokes(step).map((invoke) => [invoke.id, invoke.src])).get(request.id) ?? request.id;
2161
- const taken = takeFromQueue(script.decisions, decisionSrc);
2162
- if (!taken.found) throw scriptDryError("decision", decisionSrc, request.id, request);
2163
- step = require_setup_agent.transitionAgentStep(machine, step, taken.value);
2164
- trail.push({
2165
- state: step.snapshot.value,
2166
- appliedEvent: taken.value
2167
- });
2203
+ const invokeMeta = findInvokeMetadata(step, request.id);
2204
+ const src = invokeMeta?.src ?? request.id;
2205
+ const decisionSrc = src in (script.decisions ?? {}) ? src : request.id in (script.decisions ?? {}) ? request.id : src;
2206
+ step = await applyScriptedDecision(machine, step, request, decisionSrc, invokeMeta?.logic, script, trail);
2168
2207
  continue;
2169
2208
  }
2170
2209
  const taken = takeFromQueue(script.text, request.src);
@@ -2195,6 +2234,18 @@ async function simulateAgent(machine, options) {
2195
2234
  });
2196
2235
  continue;
2197
2236
  }
2237
+ const external = script.events;
2238
+ if (external.length > 0) {
2239
+ const event = external.shift();
2240
+ if (!step.snapshot.can(event)) throw new Error(`simulateAgent: scripted external event '${event.type}' cannot be taken in state ${JSON.stringify(step.snapshot.value)} (no handler, or its guard rejected it). A live run's send would be silently dropped here; fix the script's \`events\` queue.`);
2241
+ step = require_setup_agent.transitionAgentStep(machine, step, event);
2242
+ trail.push({
2243
+ state: step.snapshot.value,
2244
+ appliedEvent: event,
2245
+ external: true
2246
+ });
2247
+ continue;
2248
+ }
2198
2249
  return {
2199
2250
  status: "idle",
2200
2251
  snapshot: step.snapshot,
@@ -2207,6 +2258,66 @@ async function simulateAgent(machine, options) {
2207
2258
  trail
2208
2259
  };
2209
2260
  }
2261
+ async function applyScriptedDecision(machine, step, request, decisionSrc, invokeLogic, script, trail) {
2262
+ const dequeued = [];
2263
+ const decide = async () => {
2264
+ const taken = takeFromQueue(script.decisions, decisionSrc);
2265
+ if (taken.found) {
2266
+ dequeued.push(taken.value);
2267
+ return { event: taken.value };
2268
+ }
2269
+ if (dequeued.length === 0) throw scriptDryError("decision", decisionSrc, request.id, request);
2270
+ return { event: dequeued[dequeued.length - 1] };
2271
+ };
2272
+ const maxRetries = (require_decision.isDecisionLogic(invokeLogic) ? invokeLogic : resolveRegisteredDecisionLogic(machine, decisionSrc))?.maxRetries;
2273
+ let chosen;
2274
+ try {
2275
+ chosen = await require_decision.resolveDecision(request, { decide }, {
2276
+ maxRetries,
2277
+ canTake: (event) => step.snapshot.can(event)
2278
+ });
2279
+ } catch (error) {
2280
+ if (!(error instanceof require_decision.AgentDecisionExhaustedError)) throw error;
2281
+ const next = require_setup_agent.transitionAgentStep(machine, step, {
2282
+ type: "xstate.error.actor",
2283
+ actorId: request.id,
2284
+ ...sessionIdOf(step.snapshot, request.id),
2285
+ error
2286
+ });
2287
+ if (next.snapshot.status === "error") throw error;
2288
+ trail.push({
2289
+ state: next.snapshot.value,
2290
+ rejectedEvents: dequeued
2291
+ });
2292
+ return next;
2293
+ }
2294
+ const next = require_setup_agent.transitionAgentStep(machine, step, chosen);
2295
+ const rejected = dequeued.slice(0, -1);
2296
+ trail.push({
2297
+ state: next.snapshot.value,
2298
+ appliedEvent: chosen,
2299
+ ...rejected.length > 0 ? { rejectedEvents: rejected } : {}
2300
+ });
2301
+ return next;
2302
+ }
2303
+ function findInvokeMetadata(step, id) {
2304
+ for (const action of step.actions) {
2305
+ const metadata = require_setup_agent.getInvokeEffectMetadata(action);
2306
+ if (metadata?.id !== id) continue;
2307
+ return {
2308
+ ...typeof metadata.src === "string" ? { src: metadata.src } : {},
2309
+ logic: metadata.logic ?? (typeof metadata.src === "object" ? metadata.src : void 0)
2310
+ };
2311
+ }
2312
+ }
2313
+ function resolveRegisteredDecisionLogic(machine, src) {
2314
+ const candidate = require_decision.getRegisteredAgentExecutionOptions(machine).actors?.[src] ?? machine.sources?.actors?.[src];
2315
+ return require_decision.isDecisionLogic(candidate) ? candidate : void 0;
2316
+ }
2317
+ function sessionIdOf(snapshot, id) {
2318
+ const child = snapshot.children[id];
2319
+ return typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {};
2320
+ }
2210
2321
  function mapValues(obj, fn) {
2211
2322
  return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value)]));
2212
2323
  }
@@ -2243,6 +2354,10 @@ async function explore(machine, options, stopWhen) {
2243
2354
  const advance = (step) => {
2244
2355
  let current = step;
2245
2356
  for (let i = 0; i < MAX_ADVANCE_STEPS; i++) {
2357
+ if (stopWhen?.(current.snapshot)) return {
2358
+ step: current,
2359
+ hit: true
2360
+ };
2246
2361
  if (current.done) return { step: current };
2247
2362
  const request = current.requests[0];
2248
2363
  if (request && request.kind === "text") {
@@ -2275,8 +2390,8 @@ async function explore(machine, options, stopWhen) {
2275
2390
  hitPathCap = true;
2276
2391
  return;
2277
2392
  }
2278
- const { step: settled, blockedSrc } = advance(step);
2279
- if (stopWhen?.(settled.snapshot)) {
2393
+ const { step: settled, blockedSrc, hit } = advance(step);
2394
+ if (hit) {
2280
2395
  witness = path;
2281
2396
  return;
2282
2397
  }
@@ -2371,8 +2486,11 @@ async function explorePaths(machine, options = {}) {
2371
2486
  return (await explore(machine, options)).report;
2372
2487
  }
2373
2488
  /**
2374
- * Answers "can the machine reach `statePath`?" by exploring its branches (a
2375
- * thin wrapper over {@link explorePaths}). Returns
2489
+ * Answers "can the machine reach this?" by exploring its branches (a thin
2490
+ * wrapper over {@link explorePaths}). The target is either a state path string
2491
+ * (`snapshot.matches(...)` semantics) or a snapshot predicate — the predicate
2492
+ * form checks any property (a context invariant, a tag, a state+context
2493
+ * combination) without reifying a sentinel state for it. Returns
2376
2494
  * `{ reachable: true, witness }` with the event sequence that reaches it, or
2377
2495
  * `{ reachable: false }`.
2378
2496
  *
@@ -2381,11 +2499,21 @@ async function explorePaths(machine, options = {}) {
2381
2499
  * const { reachable, witness } = await canReach(refundMachine, 'denied', { input: { request: 'x', amount: 5000 } });
2382
2500
  * // reachable → true; witness → [{ type: 'NEEDS_REVIEW' }, { type: 'DENY' }]
2383
2501
  * ```
2502
+ *
2503
+ * @example Predicate target — a violation property, no sentinel state needed
2504
+ * ```ts
2505
+ * const violation = await canReach(
2506
+ * refundMachine,
2507
+ * (snapshot) => snapshot.matches('issued') && !snapshot.context.approved,
2508
+ * { input: { amount: 5000 } },
2509
+ * );
2510
+ * // violation.reachable → false is the safety proof
2511
+ * ```
2384
2512
  */
2385
- async function canReach(machine, statePath, options = {}) {
2386
- const { witness } = await explore(machine, options, (snapshot) => {
2513
+ async function canReach(machine, target, options = {}) {
2514
+ const { witness } = await explore(machine, options, typeof target === "function" ? target : (snapshot) => {
2387
2515
  try {
2388
- return snapshot.matches(statePath);
2516
+ return snapshot.matches(target);
2389
2517
  } catch {
2390
2518
  return false;
2391
2519
  }
@@ -2717,6 +2845,8 @@ async function runSeam(machine, options) {
2717
2845
  let calls = 0;
2718
2846
  let seamMatches = 0;
2719
2847
  let seamOutput;
2848
+ let seamUsage;
2849
+ const callLog = [];
2720
2850
  let seamReached = false;
2721
2851
  let callsBeforeSeam = -1;
2722
2852
  let seamStateAt = 0;
@@ -2741,6 +2871,15 @@ async function runSeam(machine, options) {
2741
2871
  const route = async (request, info) => {
2742
2872
  const callIndex = calls++;
2743
2873
  const isSeam = request.name === seam.request && seamMatches++ === (seam.occurrence ?? 0);
2874
+ const ledger = (source) => {
2875
+ callLog.push({
2876
+ ...request.name !== void 0 ? { name: request.name } : {},
2877
+ model: request.model,
2878
+ key: queueKeyOf(request),
2879
+ source,
2880
+ seam: isSeam
2881
+ });
2882
+ };
2744
2883
  if (isSeam && candidate) {
2745
2884
  await takeScriptedSlot(request, info);
2746
2885
  seamReached = true;
@@ -2749,15 +2888,19 @@ async function runSeam(machine, options) {
2749
2888
  seamEventAt = liveEvents;
2750
2889
  const result = await candidate(request, info);
2751
2890
  seamOutput = await seamOutputOf(result, request);
2891
+ seamUsage = require_decision.getCallUsage(result);
2892
+ ledger("candidate");
2752
2893
  return result;
2753
2894
  }
2754
2895
  const scripted = await scriptedAnswer(request, info);
2896
+ ledger("script");
2755
2897
  if (!isSeam) return scripted;
2756
2898
  seamReached = true;
2757
2899
  callsBeforeSeam = callIndex;
2758
2900
  seamStateAt = statePath.length;
2759
2901
  seamEventAt = liveEvents;
2760
2902
  seamOutput = scripted.output;
2903
+ seamUsage = scripted.usage;
2761
2904
  return scripted;
2762
2905
  };
2763
2906
  const executors = {
@@ -2819,7 +2962,9 @@ async function runSeam(machine, options) {
2819
2962
  return {
2820
2963
  result,
2821
2964
  seamOutput,
2965
+ ...seamUsage !== void 0 ? { seamUsage } : {},
2822
2966
  callsBeforeSeam,
2967
+ calls: callLog,
2823
2968
  before: {
2824
2969
  statePath: statePath.slice(0, splitStateAt),
2825
2970
  events: events.slice(0, splitAt)
@@ -2854,6 +2999,8 @@ function completionActorId(event) {
2854
2999
  const actorId = event.actorId;
2855
3000
  return typeof actorId === "string" ? actorId : void 0;
2856
3001
  }
3002
+ /** Thrown by the adapter's `waitForEvent` when nothing can produce an event. */
3003
+ const IDLE = Symbol("agent.durable.idle");
2857
3004
  function createMailbox() {
2858
3005
  const queue = [];
2859
3006
  const waiters = [];
@@ -2919,6 +3066,8 @@ async function runDurableAgent(machine, options = {}) {
2919
3066
  const actorId = completionActorId(event);
2920
3067
  if (actorId !== void 0) journaledCompletions.set(actorId, (journaledCompletions.get(actorId) ?? 0) + 1);
2921
3068
  }
3069
+ const storedExecutionId = hasInit ? priorEntries[0].metadata?.executionId : void 0;
3070
+ const executionId = typeof storedExecutionId === "string" ? storedExecutionId : hasInit ? priorEntries[0].id : crypto.randomUUID();
2922
3071
  const mailbox = createMailbox();
2923
3072
  const rootAddress = machineId;
2924
3073
  const suppressedChildren = /* @__PURE__ */ new WeakSet();
@@ -2933,7 +3082,10 @@ async function runDurableAgent(machine, options = {}) {
2933
3082
  }
2934
3083
  };
2935
3084
  let replaying = journal.length > 0;
3085
+ let liveEventConsumed = false;
3086
+ let latestSnapshot;
2936
3087
  const execution = (0, xstate_durable.createDurable)(bound, {
3088
+ executionId,
2937
3089
  sendEvent(source, target, event) {
2938
3090
  if (target.address === rootAddress) {
2939
3091
  mailbox.push(event);
@@ -2963,8 +3115,14 @@ async function runDurableAgent(machine, options = {}) {
2963
3115
  if (replaying) return;
2964
3116
  action.exec?.();
2965
3117
  },
2966
- waitForEvent() {
2967
- return mailbox.take();
3118
+ async waitForEvent() {
3119
+ if (mailbox.size() > 0) return await mailbox.take();
3120
+ if (liveInFlight.size > 0 && !(options.isIdle?.(latestSnapshot) ?? false)) return await mailbox.take();
3121
+ if (!liveEventConsumed && options.event !== void 0) {
3122
+ liveEventConsumed = true;
3123
+ return options.event;
3124
+ }
3125
+ throw IDLE;
2968
3126
  }
2969
3127
  });
2970
3128
  const entries = [...priorEntries];
@@ -2978,17 +3136,18 @@ async function runDurableAgent(machine, options = {}) {
2978
3136
  options.onEntry?.(entry);
2979
3137
  };
2980
3138
  if (!hasInit) {
2981
- const entry = require_setup_agent.initEntry(machine, input, entryOptions);
3139
+ const entry = require_setup_agent.initEntry(machine, input, {
3140
+ ...entryOptions,
3141
+ metadata: { executionId }
3142
+ });
2982
3143
  entries.push(entry);
2983
3144
  options.onEntry?.(entry);
2984
3145
  }
2985
- const sessions = /* @__PURE__ */ new Map();
2986
3146
  let journalIndex = 0;
2987
- let liveEventConsumed = false;
2988
3147
  let [snapshot, effects] = execution.initialTransition(input);
3148
+ latestSnapshot = snapshot;
2989
3149
  for (;;) {
2990
- const captured = await execution.executeEffects(effects);
2991
- for (const rootEvent of captured) mailbox.push(rootEvent.event);
3150
+ await execution.executeEffects(effects);
2992
3151
  const machineSnapshot = snapshot;
2993
3152
  if (machineSnapshot.status === "done") return {
2994
3153
  status: "done",
@@ -3000,24 +3159,25 @@ async function runDurableAgent(machine, options = {}) {
3000
3159
  let event;
3001
3160
  let fromJournal = false;
3002
3161
  if (journalIndex < journal.length) {
3003
- event = require_setup_agent.rebindActorSession(journal[journalIndex], machineSnapshot, sessions);
3162
+ event = journal[journalIndex];
3004
3163
  journalIndex++;
3005
3164
  fromJournal = true;
3006
3165
  replaying = journalIndex < journal.length;
3007
- } else if (mailbox.size() > 0) event = await mailbox.take();
3008
- else if (liveInFlight.size > 0 && !(options.isIdle?.(snapshot) ?? false)) event = await mailbox.take();
3009
- else if (!liveEventConsumed && options.event !== void 0) {
3010
- event = options.event;
3011
- liveEventConsumed = true;
3012
- } else return {
3013
- status: "idle",
3014
- snapshot,
3015
- entries
3016
- };
3166
+ } else try {
3167
+ event = await execution.waitForEvent();
3168
+ } catch (error) {
3169
+ if (error === IDLE) return {
3170
+ status: "idle",
3171
+ snapshot,
3172
+ entries
3173
+ };
3174
+ throw error;
3175
+ }
3017
3176
  const completedId = completionActorId(event);
3018
3177
  if (completedId !== void 0) liveInFlight.delete(completedId);
3019
3178
  if (!fromJournal) appendEntry(event);
3020
3179
  [snapshot, effects] = execution.transition(snapshot, event);
3180
+ latestSnapshot = snapshot;
3021
3181
  }
3022
3182
  }
3023
3183
  //#endregion
@@ -3038,6 +3198,7 @@ exports.AgentSnapshotVersionMismatchError = AgentSnapshotVersionMismatchError;
3038
3198
  exports.NonSerializableAgentEventError = require_event_log_store.NonSerializableAgentEventError;
3039
3199
  exports.appendMessages = require_setup_agent.appendMessages;
3040
3200
  exports.assertAgentLogEntry = require_event_log_store.assertAgentLogEntry;
3201
+ exports.assertAgentMachine = assertAgentMachine;
3041
3202
  exports.assertEventLogStoreConformance = require_event_log_store.assertEventLogStoreConformance;
3042
3203
  exports.assertJsonSerializable = require_event_log_store.assertJsonSerializable;
3043
3204
  exports.assistantMessage = require_decision.assistantMessage;