@statelyai/agent 2.0.0-alpha.19 → 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.
package/dist/index.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import { t as AgentError } from "./errors-CeSXQx0v.mjs";
2
- import { _ as resolveAgentStep, a as AGENT_USAGE_EVENT_TYPE, b as messagesSchema, c as createReplayEntry, d as initEntry, f as replay, g as initialAgentStep, h as getInvokeEffectMetadata, i as AGENT_INIT_EVENT_TYPE, l as diffEventLogs, m as executeAgentRequest, n as getAgentSchemas, o as AgentReplayDivergenceError, p as validateReplayEntries, r as setupAgent, s as AgentReplayMachineMismatchError, t as createAgentSchemas, u as getAgentEffects, v as transitionAgentStep, y as appendMessages } from "./setup-agent-CPFPN06s.mjs";
3
- import { A as isUnboundPlaceholder, B as getMachineStructuralHash, C as parseStructuredEnvelope, D as getMachineIdlePredicate, E as executorBoundLogics, G as toolMessage, H as isStandardSchema, I as findNonSerializableContextPaths, K as userMessage, L as getAgentMessages, O as getMachineStaticTransitionTargets, P as assistantMessage, R as getJsonSchema, S as parseOutput, U as resolveMachineVersion, V as getStateMeta, W as systemMessage, _ as getAgentOutputMode, a as resolveDecision, b as normalizeGeneratorResult, c as AGENT_USAGE_TOKEN_FIELDS, f as bindRequestExecutor, h as createTextLogic, i as renderDecisionAttempts, k as getRegisteredAgentExecutionOptions, o as getAcceptedEvents, p as buildEnvelopeSchema, q as validateSchemaSync, r as isDecisionLogic, s as parseAgentEvent, t as AgentDecisionExhaustedError, u as INTERPRET_SOURCE, v as getCallUsage, x as parseModelRef, y as isTextLogic, z as getJsonSchemaSync } from "./decision-DsIkEuHz.mjs";
2
+ import { _ as resolveAgentStep, a as AGENT_USAGE_EVENT_TYPE, b as messagesSchema, c as createReplayEntry, d as initEntry, f as replay, g as initialAgentStep, h as getInvokeEffectMetadata, i as AGENT_INIT_EVENT_TYPE, l as diffEventLogs, m as executeAgentRequest, n as getAgentSchemas, o as AgentReplayDivergenceError, p as validateReplayEntries, r as setupAgent, s as AgentReplayMachineMismatchError, t as createAgentSchemas, u as getAgentEffects, v as transitionAgentStep, y as appendMessages } from "./setup-agent-DqqdcdNh.mjs";
3
+ import { A as getMachineStaticTransitionTargets, B as getJsonSchema, C as parseModelRef, G as resolveMachineVersion, H as getMachineStructuralHash, I as assistantMessage, J as userMessage, K as systemMessage, M as isUnboundPlaceholder, O as executorBoundLogics, R as findNonSerializableContextPaths, S as normalizeGeneratorResult, T as parseStructuredEnvelope, U as getStateMeta, V as getJsonSchemaSync, W as isStandardSchema, Y as validateSchemaSync, _ as createTextLogic, a as resolveDecision, b as getCallUsage, c as AGENT_USAGE_TOKEN_FIELDS, d as INTERPRET_SOURCE, h as buildEnvelopeSchema, i as renderDecisionAttempts, j as getRegisteredAgentExecutionOptions, k as getMachineIdlePredicate, m as bindRequestExecutor, o as getAcceptedEvents, q as toolMessage, r as isDecisionLogic, s as parseAgentEvent, t as AgentDecisionExhaustedError, w as parseOutput, x as isTextLogic, y as getAgentOutputMode, z as getAgentMessages } from "./decision-JWx6n3xR.mjs";
4
4
  import { a as assertJsonSerializable, i as assertAgentLogEntry, n as AgentEventLogConflictError, o as createInMemoryEventLogStore, r as NonSerializableAgentEventError, s as assertEventLogStoreConformance, t as AGENT_EVENT_SCHEMA_VERSION } from "./event-log-store-DmIDosD6.mjs";
5
- import { createActor, createAsyncLogic, getNextTransitions, isMachineSnapshot } from "xstate";
5
+ import { createActor, createAsyncLogic, deliverEvent, getNextTransitions, isMachineSnapshot } from "xstate";
6
+ import { createDurable } from "xstate/durable";
6
7
  //#region src/internal/state-request-pass.ts
7
8
  async function runTextPhase(stateRequest, baseMessages, deps) {
8
9
  const { model, system } = stateRequest;
@@ -284,7 +285,7 @@ function serializeTraceEvent(event, options = {}) {
284
285
  return out;
285
286
  }
286
287
  function snapshotNodes(snapshot) {
287
- return (snapshot._nodes ?? []).map((raw) => {
288
+ return (snapshot.nodes ?? []).map((raw) => {
288
289
  const node = raw;
289
290
  return {
290
291
  id: node.id ?? "",
@@ -567,9 +568,13 @@ function invokingActorOf(self, runCtx) {
567
568
  * identical event shapes by construction. @internal
568
569
  */
569
570
  function bindTextLogic(logic, runCtx) {
570
- return logic.withExecutor(async ({ request, self: selfArg, signal }) => {
571
+ return logic.withExecutor(async ({ request: rawRequest, self: selfArg, signal }) => {
571
572
  const self = selfArg;
572
573
  const { id, src } = selfIdAndSrc(self);
574
+ const request = rawRequest.name === void 0 && src !== "" && src !== "agent.generateText" && src !== "agent.streamText" ? {
575
+ ...rawRequest,
576
+ name: src
577
+ } : rawRequest;
573
578
  const executor = logic.mode === "stream" ? runCtx.streamText : runCtx.generateText;
574
579
  if (!executor) throw new Error(`No '${logic.mode === "stream" ? "streamText" : "generateText"}' executor provided.`);
575
580
  const requestWithTools = {
@@ -1159,6 +1164,7 @@ function createAgentSession(machine, options, lifecycle) {
1159
1164
  const aligned = Object.assign(Object.create(Object.getPrototypeOf(effectiveSnapshot)), effectiveSnapshot);
1160
1165
  if (machineOwnVersion === void 0) delete aligned.version;
1161
1166
  else aligned.version = machineOwnVersion;
1167
+ delete aligned.machine;
1162
1168
  effectiveSnapshot = aligned;
1163
1169
  }
1164
1170
  const priorMessages = getAgentMessages(effectiveSnapshot);
@@ -2082,8 +2088,8 @@ function lintAgentMachine(machine, options = {}) {
2082
2088
  return diagnostics;
2083
2089
  }
2084
2090
  /**
2085
- * Thrown by `lintAgentMachine(machine, { throw: true })` when lint finds
2086
- * failing diagnostics.
2091
+ * Thrown by `lintAgentMachine(machine, { throw: true })` (and its
2092
+ * {@link assertAgentMachine} alias) when lint finds failing diagnostics.
2087
2093
  * `diagnostics` holds the findings; the message lists them one per finding,
2088
2094
  * so a test runner's failure output reads like the CLI's lint report.
2089
2095
  */
@@ -2096,6 +2102,26 @@ var AgentLintError = class extends AgentError {
2096
2102
  this.diagnostics = diagnostics;
2097
2103
  }
2098
2104
  };
2105
+ /**
2106
+ * Asserts a machine passes {@link lintAgentMachine}: returns silently when
2107
+ * clean, throws {@link AgentLintError} (with the findings on `.diagnostics`)
2108
+ * otherwise — sugar for `lintAgentMachine(machine, { ...options, throw: true })`.
2109
+ * Fails on error-severity findings; set `warnings: true` to fail on warnings
2110
+ * too. The one-liner for tests and generation loops:
2111
+ *
2112
+ * @example
2113
+ * ```ts
2114
+ * test('agent machine is structurally sound', () => {
2115
+ * assertAgentMachine(machine);
2116
+ * });
2117
+ * ```
2118
+ */
2119
+ function assertAgentMachine(machine, options = {}) {
2120
+ lintAgentMachine(machine, {
2121
+ ...options,
2122
+ throw: true
2123
+ });
2124
+ }
2099
2125
  function pendingInvokes(step) {
2100
2126
  const out = [];
2101
2127
  for (const action of step.actions) {
@@ -2122,6 +2148,21 @@ function takeFromQueue(channel, src) {
2122
2148
  * the real transition logic. Returns the terminal `status`, final `snapshot`,
2123
2149
  * and a `trail` of every step taken.
2124
2150
  *
2151
+ * Decisions run through the live run's own validation/retry core,
2152
+ * {@link resolveDecision}, with the script standing in for the model: each
2153
+ * attempt consumes the next queued {@link ChosenEvent} for that src, so an
2154
+ * unknown, payload-invalid, or guard-rejected event is NOT silently swallowed
2155
+ * — the next queued decision is tried, exactly as a live run re-asks the
2156
+ * model. The decision logic's `maxRetries` caps attempts as it would live;
2157
+ * when retries continue past the end of the queue, the last queued decision
2158
+ * repeats (a scripted model that insists). The repeat applies only within one
2159
+ * decision request's retries — each new decision request must have its own
2160
+ * queued entry, or the dry-script error throws as usual. Exhausting all
2161
+ * attempts delivers
2162
+ * the resulting {@link AgentDecisionExhaustedError} to the machine as the
2163
+ * decision invoke's error (so an `onError` transition observes it, as it
2164
+ * would live); with no `onError` to catch it, it is thrown.
2165
+ *
2125
2166
  * Throws a descriptive error when the script runs dry mid-request, naming the
2126
2167
  * pending request's kind, src, and id so the missing scripted response is
2127
2168
  * obvious.
@@ -2130,7 +2171,10 @@ function takeFromQueue(channel, src) {
2130
2171
  * ```ts
2131
2172
  * const { status, snapshot } = simulateAgent(machine, {
2132
2173
  * input: { topic: 'state machines' },
2133
- * script: { decisions: { 'agent.decide': [{ type: 'END' }] } },
2174
+ * script: {
2175
+ * decisions: { 'agent.decide': [{ type: 'ESCALATE' }] },
2176
+ * events: [{ type: 'APPROVE' }], // crosses the human gate
2177
+ * },
2134
2178
  * });
2135
2179
  * ```
2136
2180
  */
@@ -2139,11 +2183,12 @@ async function simulateAgent(machine, options) {
2139
2183
  const script = {
2140
2184
  text: mapValues(options.script.text ?? {}, (arr) => [...arr]),
2141
2185
  decisions: mapValues(options.script.decisions ?? {}, (arr) => [...arr]),
2142
- invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr])
2186
+ invokes: mapValues(options.script.invokes ?? {}, (arr) => [...arr]),
2187
+ events: [...options.script.events ?? []]
2143
2188
  };
2144
2189
  if (options.script.userInput?.length) script.invokes[USER_INPUT_SRC] = [...options.script.userInput, ...script.invokes[USER_INPUT_SRC] ?? []];
2145
2190
  let step = initialAgentStep(machine, options.input);
2146
- const trail = [];
2191
+ const trail = [{ state: step.snapshot.value }];
2147
2192
  for (let i = 0; i < maxSteps; i++) {
2148
2193
  if (step.done) return {
2149
2194
  status: "done",
@@ -2153,14 +2198,10 @@ async function simulateAgent(machine, options) {
2153
2198
  const request = step.requests[0];
2154
2199
  if (request) {
2155
2200
  if (request.kind === "decision") {
2156
- const decisionSrc = new Map(pendingInvokes(step).map((invoke) => [invoke.id, invoke.src])).get(request.id) ?? request.id;
2157
- const taken = takeFromQueue(script.decisions, decisionSrc);
2158
- if (!taken.found) throw scriptDryError("decision", decisionSrc, request.id, request);
2159
- step = transitionAgentStep(machine, step, taken.value);
2160
- trail.push({
2161
- state: step.snapshot.value,
2162
- appliedEvent: taken.value
2163
- });
2201
+ const invokeMeta = findInvokeMetadata(step, request.id);
2202
+ const src = invokeMeta?.src ?? request.id;
2203
+ const decisionSrc = src in (script.decisions ?? {}) ? src : request.id in (script.decisions ?? {}) ? request.id : src;
2204
+ step = await applyScriptedDecision(machine, step, request, decisionSrc, invokeMeta?.logic, script, trail);
2164
2205
  continue;
2165
2206
  }
2166
2207
  const taken = takeFromQueue(script.text, request.src);
@@ -2191,6 +2232,18 @@ async function simulateAgent(machine, options) {
2191
2232
  });
2192
2233
  continue;
2193
2234
  }
2235
+ const external = script.events;
2236
+ if (external.length > 0) {
2237
+ const event = external.shift();
2238
+ 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.`);
2239
+ step = transitionAgentStep(machine, step, event);
2240
+ trail.push({
2241
+ state: step.snapshot.value,
2242
+ appliedEvent: event,
2243
+ external: true
2244
+ });
2245
+ continue;
2246
+ }
2194
2247
  return {
2195
2248
  status: "idle",
2196
2249
  snapshot: step.snapshot,
@@ -2203,6 +2256,66 @@ async function simulateAgent(machine, options) {
2203
2256
  trail
2204
2257
  };
2205
2258
  }
2259
+ async function applyScriptedDecision(machine, step, request, decisionSrc, invokeLogic, script, trail) {
2260
+ const dequeued = [];
2261
+ const decide = async () => {
2262
+ const taken = takeFromQueue(script.decisions, decisionSrc);
2263
+ if (taken.found) {
2264
+ dequeued.push(taken.value);
2265
+ return { event: taken.value };
2266
+ }
2267
+ if (dequeued.length === 0) throw scriptDryError("decision", decisionSrc, request.id, request);
2268
+ return { event: dequeued[dequeued.length - 1] };
2269
+ };
2270
+ const maxRetries = (isDecisionLogic(invokeLogic) ? invokeLogic : resolveRegisteredDecisionLogic(machine, decisionSrc))?.maxRetries;
2271
+ let chosen;
2272
+ try {
2273
+ chosen = await resolveDecision(request, { decide }, {
2274
+ maxRetries,
2275
+ canTake: (event) => step.snapshot.can(event)
2276
+ });
2277
+ } catch (error) {
2278
+ if (!(error instanceof AgentDecisionExhaustedError)) throw error;
2279
+ const next = transitionAgentStep(machine, step, {
2280
+ type: "xstate.error.actor",
2281
+ actorId: request.id,
2282
+ ...sessionIdOf(step.snapshot, request.id),
2283
+ error
2284
+ });
2285
+ if (next.snapshot.status === "error") throw error;
2286
+ trail.push({
2287
+ state: next.snapshot.value,
2288
+ rejectedEvents: dequeued
2289
+ });
2290
+ return next;
2291
+ }
2292
+ const next = transitionAgentStep(machine, step, chosen);
2293
+ const rejected = dequeued.slice(0, -1);
2294
+ trail.push({
2295
+ state: next.snapshot.value,
2296
+ appliedEvent: chosen,
2297
+ ...rejected.length > 0 ? { rejectedEvents: rejected } : {}
2298
+ });
2299
+ return next;
2300
+ }
2301
+ function findInvokeMetadata(step, id) {
2302
+ for (const action of step.actions) {
2303
+ const metadata = getInvokeEffectMetadata(action);
2304
+ if (metadata?.id !== id) continue;
2305
+ return {
2306
+ ...typeof metadata.src === "string" ? { src: metadata.src } : {},
2307
+ logic: metadata.logic ?? (typeof metadata.src === "object" ? metadata.src : void 0)
2308
+ };
2309
+ }
2310
+ }
2311
+ function resolveRegisteredDecisionLogic(machine, src) {
2312
+ const candidate = getRegisteredAgentExecutionOptions(machine).actors?.[src] ?? machine.sources?.actors?.[src];
2313
+ return isDecisionLogic(candidate) ? candidate : void 0;
2314
+ }
2315
+ function sessionIdOf(snapshot, id) {
2316
+ const child = snapshot.children[id];
2317
+ return typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {};
2318
+ }
2206
2319
  function mapValues(obj, fn) {
2207
2320
  return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, fn(value)]));
2208
2321
  }
@@ -2239,6 +2352,10 @@ async function explore(machine, options, stopWhen) {
2239
2352
  const advance = (step) => {
2240
2353
  let current = step;
2241
2354
  for (let i = 0; i < MAX_ADVANCE_STEPS; i++) {
2355
+ if (stopWhen?.(current.snapshot)) return {
2356
+ step: current,
2357
+ hit: true
2358
+ };
2242
2359
  if (current.done) return { step: current };
2243
2360
  const request = current.requests[0];
2244
2361
  if (request && request.kind === "text") {
@@ -2271,8 +2388,8 @@ async function explore(machine, options, stopWhen) {
2271
2388
  hitPathCap = true;
2272
2389
  return;
2273
2390
  }
2274
- const { step: settled, blockedSrc } = advance(step);
2275
- if (stopWhen?.(settled.snapshot)) {
2391
+ const { step: settled, blockedSrc, hit } = advance(step);
2392
+ if (hit) {
2276
2393
  witness = path;
2277
2394
  return;
2278
2395
  }
@@ -2367,8 +2484,11 @@ async function explorePaths(machine, options = {}) {
2367
2484
  return (await explore(machine, options)).report;
2368
2485
  }
2369
2486
  /**
2370
- * Answers "can the machine reach `statePath`?" by exploring its branches (a
2371
- * thin wrapper over {@link explorePaths}). Returns
2487
+ * Answers "can the machine reach this?" by exploring its branches (a thin
2488
+ * wrapper over {@link explorePaths}). The target is either a state path string
2489
+ * (`snapshot.matches(...)` semantics) or a snapshot predicate — the predicate
2490
+ * form checks any property (a context invariant, a tag, a state+context
2491
+ * combination) without reifying a sentinel state for it. Returns
2372
2492
  * `{ reachable: true, witness }` with the event sequence that reaches it, or
2373
2493
  * `{ reachable: false }`.
2374
2494
  *
@@ -2377,11 +2497,21 @@ async function explorePaths(machine, options = {}) {
2377
2497
  * const { reachable, witness } = await canReach(refundMachine, 'denied', { input: { request: 'x', amount: 5000 } });
2378
2498
  * // reachable → true; witness → [{ type: 'NEEDS_REVIEW' }, { type: 'DENY' }]
2379
2499
  * ```
2500
+ *
2501
+ * @example Predicate target — a violation property, no sentinel state needed
2502
+ * ```ts
2503
+ * const violation = await canReach(
2504
+ * refundMachine,
2505
+ * (snapshot) => snapshot.matches('issued') && !snapshot.context.approved,
2506
+ * { input: { amount: 5000 } },
2507
+ * );
2508
+ * // violation.reachable → false is the safety proof
2509
+ * ```
2380
2510
  */
2381
- async function canReach(machine, statePath, options = {}) {
2382
- const { witness } = await explore(machine, options, (snapshot) => {
2511
+ async function canReach(machine, target, options = {}) {
2512
+ const { witness } = await explore(machine, options, typeof target === "function" ? target : (snapshot) => {
2383
2513
  try {
2384
- return snapshot.matches(statePath);
2514
+ return snapshot.matches(target);
2385
2515
  } catch {
2386
2516
  return false;
2387
2517
  }
@@ -2713,6 +2843,8 @@ async function runSeam(machine, options) {
2713
2843
  let calls = 0;
2714
2844
  let seamMatches = 0;
2715
2845
  let seamOutput;
2846
+ let seamUsage;
2847
+ const callLog = [];
2716
2848
  let seamReached = false;
2717
2849
  let callsBeforeSeam = -1;
2718
2850
  let seamStateAt = 0;
@@ -2737,6 +2869,15 @@ async function runSeam(machine, options) {
2737
2869
  const route = async (request, info) => {
2738
2870
  const callIndex = calls++;
2739
2871
  const isSeam = request.name === seam.request && seamMatches++ === (seam.occurrence ?? 0);
2872
+ const ledger = (source) => {
2873
+ callLog.push({
2874
+ ...request.name !== void 0 ? { name: request.name } : {},
2875
+ model: request.model,
2876
+ key: queueKeyOf(request),
2877
+ source,
2878
+ seam: isSeam
2879
+ });
2880
+ };
2740
2881
  if (isSeam && candidate) {
2741
2882
  await takeScriptedSlot(request, info);
2742
2883
  seamReached = true;
@@ -2745,15 +2886,19 @@ async function runSeam(machine, options) {
2745
2886
  seamEventAt = liveEvents;
2746
2887
  const result = await candidate(request, info);
2747
2888
  seamOutput = await seamOutputOf(result, request);
2889
+ seamUsage = getCallUsage(result);
2890
+ ledger("candidate");
2748
2891
  return result;
2749
2892
  }
2750
2893
  const scripted = await scriptedAnswer(request, info);
2894
+ ledger("script");
2751
2895
  if (!isSeam) return scripted;
2752
2896
  seamReached = true;
2753
2897
  callsBeforeSeam = callIndex;
2754
2898
  seamStateAt = statePath.length;
2755
2899
  seamEventAt = liveEvents;
2756
2900
  seamOutput = scripted.output;
2901
+ seamUsage = scripted.usage;
2757
2902
  return scripted;
2758
2903
  };
2759
2904
  const executors = {
@@ -2815,7 +2960,9 @@ async function runSeam(machine, options) {
2815
2960
  return {
2816
2961
  result,
2817
2962
  seamOutput,
2963
+ ...seamUsage !== void 0 ? { seamUsage } : {},
2818
2964
  callsBeforeSeam,
2965
+ calls: callLog,
2819
2966
  before: {
2820
2967
  statePath: statePath.slice(0, splitStateAt),
2821
2968
  events: events.slice(0, splitAt)
@@ -2827,4 +2974,209 @@ async function runSeam(machine, options) {
2827
2974
  };
2828
2975
  }
2829
2976
  //#endregion
2830
- export { AGENT_EVENT_SCHEMA_VERSION, AGENT_INIT_EVENT_TYPE, AGENT_TRACE_SCHEMA_VERSION, AGENT_USAGE_EVENT_TYPE, AgentDecisionExhaustedError, AgentError, AgentEventLogConflictError, AgentIdleError, AgentIllegalResumeEventError, AgentLintError, AgentMaxModelCallsExceededError, AgentReplayDivergenceError, AgentReplayMachineMismatchError, AgentSnapshotVersionMismatchError, NonSerializableAgentEventError, appendMessages, assertAgentLogEntry, assertEventLogStoreConformance, assertJsonSerializable, assistantMessage, bindRequestExecutor, buildEnvelopeSchema, canReach, createAgentActor, createAgentRun, createAgentSchemas, createInMemoryEventLogStore, createReplayEntry, createScriptedExecutors, createTextLogic, diffEventLogs, executeAgentRequest, explorePaths, generateResult, getAcceptedEvents, getAgentEffects, getAgentMessages, getAgentOutputMode, getAgentSchemas, getCallUsage, getJsonSchema, getJsonSchemaSync, getMachineStructuralHash, getSnapshotNodes, getSnapshotRequests, getStateMeta, initEntry, inspectTransitions, isStandardSchema, lintAgentMachine, matchesTrajectory, messagesSchema, parseAgentEvent, parseModelRef, parseOutput, parseStructuredEnvelope, provideExecutors, renderDecisionAttempts, replay, resolveDecision, runAgent, runSeam, serializeTraceEvent, setupAgent, simulateAgent, systemMessage, toolMessage, traceTransitions, userMessage };
2977
+ //#region src/durable.ts
2978
+ /**
2979
+ * The durable host runner: {@link runDurableAgent} drives an executor-bound
2980
+ * agent machine on xstate's `createDurable` execution (`xstate/durable`),
2981
+ * with the agent event log as the journal.
2982
+ *
2983
+ * Where {@link replay} + `getAgentEffects` hand a host an effect list to run
2984
+ * itself, `runDurableAgent` owns the whole loop on the durable runtime:
2985
+ * invoked actors execute live through xstate's own runtime, every EXTERNAL
2986
+ * event (invoke completions included) is appended to the log, and a resume
2987
+ * folds the log back through pure transitions — an invoke whose completion is
2988
+ * already journaled is never re-started, so recorded model calls are never
2989
+ * re-executed. Crash recovery re-runs only the work that was still in flight.
2990
+ *
2991
+ * @module
2992
+ */
2993
+ const DONE_ACTOR_EVENT_TYPE = "xstate.done.actor";
2994
+ const ERROR_ACTOR_EVENT_TYPE = "xstate.error.actor";
2995
+ function completionActorId(event) {
2996
+ if (event.type !== DONE_ACTOR_EVENT_TYPE && event.type !== ERROR_ACTOR_EVENT_TYPE) return;
2997
+ const actorId = event.actorId;
2998
+ return typeof actorId === "string" ? actorId : void 0;
2999
+ }
3000
+ /** Thrown by the adapter's `waitForEvent` when nothing can produce an event. */
3001
+ const IDLE = Symbol("agent.durable.idle");
3002
+ function createMailbox() {
3003
+ const queue = [];
3004
+ const waiters = [];
3005
+ return {
3006
+ push(event) {
3007
+ const waiter = waiters.shift();
3008
+ if (waiter) waiter(event);
3009
+ else queue.push(event);
3010
+ },
3011
+ take() {
3012
+ const next = queue.shift();
3013
+ if (next !== void 0) return Promise.resolve(next);
3014
+ return new Promise((resolve) => waiters.push(resolve));
3015
+ },
3016
+ size: () => queue.length
3017
+ };
3018
+ }
3019
+ /**
3020
+ * Runs an agent machine as a durable execution: journal in, journal out.
3021
+ *
3022
+ * A fresh call starts from `input` and appends a reserved init entry; a
3023
+ * resume call folds `entries` through pure transitions first — invokes whose
3024
+ * completions are journaled are suppressed (their recorded results replay
3025
+ * instead of re-executing), while work that was in flight at the crash
3026
+ * re-executes live. After the journal, an optional `options.event` is
3027
+ * delivered. The call settles:
3028
+ *
3029
+ * - `done` when the machine reaches a final state, with `output`;
3030
+ * - `idle` when the frontier needs an external event the host has not
3031
+ * supplied (no live work pending, or `isIdle` says the pending work is a
3032
+ * human wait). Persist `entries` and call again with them later.
3033
+ *
3034
+ * ```ts
3035
+ * const first = await runDurableAgent(machine, { input, executors });
3036
+ * // ... persist first.entries; later, in a new process:
3037
+ * const next = await runDurableAgent(machine, {
3038
+ * entries: first.entries,
3039
+ * event: { type: "APPROVE" },
3040
+ * executors,
3041
+ * });
3042
+ * ```
3043
+ *
3044
+ * @experimental Built on xstate's experimental `xstate/durable` entrypoint.
3045
+ */
3046
+ async function runDurableAgent(machine, options = {}) {
3047
+ const bound = options.executors ? provideExecutors(machine, options.executors, {
3048
+ actors: options.actors,
3049
+ onChunk: options.onChunk,
3050
+ onTrace: options.onTrace
3051
+ }) : options.actors ? machine.provide({ actors: options.actors }) : machine;
3052
+ const machineId = machine.config.id ?? machine.id ?? "(machine)";
3053
+ const machineVersion = options.machineVersion ?? resolveMachineVersion(machine);
3054
+ const priorEntries = options.entries ?? [];
3055
+ if (priorEntries.length > 0) validateReplayEntries(priorEntries, {
3056
+ machineId,
3057
+ machineVersion
3058
+ }, "Durable journal entries");
3059
+ const hasInit = priorEntries[0]?.event.type === AGENT_INIT_EVENT_TYPE;
3060
+ const input = hasInit ? priorEntries[0].event.input : options.input;
3061
+ const journal = priorEntries.slice(hasInit ? 1 : 0).map((entry) => entry.event);
3062
+ const journaledCompletions = /* @__PURE__ */ new Map();
3063
+ for (const event of journal) {
3064
+ const actorId = completionActorId(event);
3065
+ if (actorId !== void 0) journaledCompletions.set(actorId, (journaledCompletions.get(actorId) ?? 0) + 1);
3066
+ }
3067
+ const storedExecutionId = hasInit ? priorEntries[0].metadata?.executionId : void 0;
3068
+ const executionId = typeof storedExecutionId === "string" ? storedExecutionId : hasInit ? priorEntries[0].id : crypto.randomUUID();
3069
+ const mailbox = createMailbox();
3070
+ const rootAddress = machineId;
3071
+ const suppressedChildren = /* @__PURE__ */ new WeakSet();
3072
+ const startsSeen = /* @__PURE__ */ new Map();
3073
+ const liveInFlight = /* @__PURE__ */ new Set();
3074
+ const findChildRef = (effect) => {
3075
+ const raw = effect;
3076
+ const candidates = [raw.actor, ...Array.isArray(raw.args) ? raw.args : []];
3077
+ for (const candidate of candidates) {
3078
+ const ref = candidate;
3079
+ if (ref && typeof ref.sessionId === "string" && typeof ref.id === "string") return ref;
3080
+ }
3081
+ };
3082
+ let replaying = journal.length > 0;
3083
+ let liveEventConsumed = false;
3084
+ let latestSnapshot;
3085
+ const execution = createDurable(bound, {
3086
+ executionId,
3087
+ sendEvent(source, target, event) {
3088
+ if (target.address === rootAddress) {
3089
+ mailbox.push(event);
3090
+ return;
3091
+ }
3092
+ deliverEvent(source, target, event);
3093
+ },
3094
+ runtime(_metadata, effect) {
3095
+ const type = effect.type;
3096
+ if (type === "@xstate.spawn" || type === "@xstate.start") {
3097
+ const child = findChildRef(effect);
3098
+ if (!child) return {};
3099
+ if (type === "@xstate.spawn") {
3100
+ const seen = (startsSeen.get(child.id) ?? 0) + 1;
3101
+ startsSeen.set(child.id, seen);
3102
+ if (seen <= (journaledCompletions.get(child.id) ?? 0)) suppressedChildren.add(child);
3103
+ else liveInFlight.add(child.id);
3104
+ }
3105
+ if (suppressedChildren.has(child)) return {
3106
+ spawnActor() {},
3107
+ startActor() {}
3108
+ };
3109
+ }
3110
+ return {};
3111
+ },
3112
+ executeAction(action) {
3113
+ if (replaying) return;
3114
+ action.exec?.();
3115
+ },
3116
+ async waitForEvent() {
3117
+ if (mailbox.size() > 0) return await mailbox.take();
3118
+ if (liveInFlight.size > 0 && !(options.isIdle?.(latestSnapshot) ?? false)) return await mailbox.take();
3119
+ if (!liveEventConsumed && options.event !== void 0) {
3120
+ liveEventConsumed = true;
3121
+ return options.event;
3122
+ }
3123
+ throw IDLE;
3124
+ }
3125
+ });
3126
+ const entries = [...priorEntries];
3127
+ const entryOptions = {
3128
+ machineVersion,
3129
+ verification: options.verification ?? false
3130
+ };
3131
+ const appendEntry = (event) => {
3132
+ const entry = createReplayEntry(machine, entries, event, entryOptions);
3133
+ entries.push(entry);
3134
+ options.onEntry?.(entry);
3135
+ };
3136
+ if (!hasInit) {
3137
+ const entry = initEntry(machine, input, {
3138
+ ...entryOptions,
3139
+ metadata: { executionId }
3140
+ });
3141
+ entries.push(entry);
3142
+ options.onEntry?.(entry);
3143
+ }
3144
+ let journalIndex = 0;
3145
+ let [snapshot, effects] = execution.initialTransition(input);
3146
+ latestSnapshot = snapshot;
3147
+ for (;;) {
3148
+ await execution.executeEffects(effects);
3149
+ const machineSnapshot = snapshot;
3150
+ if (machineSnapshot.status === "done") return {
3151
+ status: "done",
3152
+ output: machineSnapshot.output,
3153
+ snapshot,
3154
+ entries
3155
+ };
3156
+ if (machineSnapshot.status === "error") throw machineSnapshot.error;
3157
+ let event;
3158
+ let fromJournal = false;
3159
+ if (journalIndex < journal.length) {
3160
+ event = journal[journalIndex];
3161
+ journalIndex++;
3162
+ fromJournal = true;
3163
+ replaying = journalIndex < journal.length;
3164
+ } else try {
3165
+ event = await execution.waitForEvent();
3166
+ } catch (error) {
3167
+ if (error === IDLE) return {
3168
+ status: "idle",
3169
+ snapshot,
3170
+ entries
3171
+ };
3172
+ throw error;
3173
+ }
3174
+ const completedId = completionActorId(event);
3175
+ if (completedId !== void 0) liveInFlight.delete(completedId);
3176
+ if (!fromJournal) appendEntry(event);
3177
+ [snapshot, effects] = execution.transition(snapshot, event);
3178
+ latestSnapshot = snapshot;
3179
+ }
3180
+ }
3181
+ //#endregion
3182
+ export { AGENT_EVENT_SCHEMA_VERSION, AGENT_INIT_EVENT_TYPE, AGENT_TRACE_SCHEMA_VERSION, AGENT_USAGE_EVENT_TYPE, AgentDecisionExhaustedError, AgentError, AgentEventLogConflictError, AgentIdleError, AgentIllegalResumeEventError, AgentLintError, AgentMaxModelCallsExceededError, AgentReplayDivergenceError, AgentReplayMachineMismatchError, AgentSnapshotVersionMismatchError, NonSerializableAgentEventError, appendMessages, assertAgentLogEntry, assertAgentMachine, assertEventLogStoreConformance, assertJsonSerializable, assistantMessage, bindRequestExecutor, buildEnvelopeSchema, canReach, createAgentActor, createAgentRun, createAgentSchemas, createInMemoryEventLogStore, createReplayEntry, createScriptedExecutors, createTextLogic, diffEventLogs, executeAgentRequest, explorePaths, generateResult, getAcceptedEvents, getAgentEffects, getAgentMessages, getAgentOutputMode, getAgentSchemas, getCallUsage, getJsonSchema, getJsonSchemaSync, getMachineStructuralHash, getSnapshotNodes, getSnapshotRequests, getStateMeta, initEntry, inspectTransitions, isStandardSchema, lintAgentMachine, matchesTrajectory, messagesSchema, parseAgentEvent, parseModelRef, parseOutput, parseStructuredEnvelope, provideExecutors, renderDecisionAttempts, replay, resolveDecision, runAgent, runDurableAgent, runSeam, serializeTraceEvent, setupAgent, simulateAgent, systemMessage, toolMessage, traceTransitions, userMessage };
package/dist/machines.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_setup_agent = require("./setup-agent-BFA4VKpN.cjs");
2
+ const require_setup_agent = require("./setup-agent-91FSuZbB.cjs");
3
3
  //#region src/machines/internal.ts
4
4
  /** The builtin inline text request every preset lowers a request entry to. */
5
5
  const GENERATE_TEXT_SRC = "agent.generateText";
@@ -1,4 +1,4 @@
1
- import { c as AgentTools, v as StandardSchemaV1 } from "./types-pJ5Hn8fv.cjs";
1
+ import { c as AgentTools, v as StandardSchemaV1 } from "./types-DSdj2tGs.cjs";
2
2
  import { AnyStateMachine } from "xstate";
3
3
 
4
4
  //#region src/machines/tool-loop.d.ts
@@ -1,4 +1,4 @@
1
- import { c as AgentTools, v as StandardSchemaV1 } from "./types-DYpK3QF4.mjs";
1
+ import { c as AgentTools, v as StandardSchemaV1 } from "./types-CvWRGFxP.mjs";
2
2
  import { AnyStateMachine } from "xstate";
3
3
 
4
4
  //#region src/machines/tool-loop.d.ts
package/dist/machines.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as setupAgent } from "./setup-agent-CPFPN06s.mjs";
1
+ import { r as setupAgent } from "./setup-agent-DqqdcdNh.mjs";
2
2
  //#region src/machines/internal.ts
3
3
  /** The builtin inline text request every preset lowers a request entry to. */
4
4
  const GENERATE_TEXT_SRC = "agent.generateText";
package/dist/otel.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { d as AgentTraceEvent } from "./run-agent--4bbms-D.cjs";
1
+ import { d as AgentTraceEvent } from "./run-agent-Do094mGu.cjs";
2
2
  import { Attributes, Tracer, TracerProvider } from "@opentelemetry/api";
3
3
 
4
4
  //#region src/otel/index.d.ts
package/dist/otel.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { d as AgentTraceEvent } from "./run-agent-CwmzAZwj.mjs";
1
+ import { d as AgentTraceEvent } from "./run-agent-DBNI8ETM.mjs";
2
2
  import { Attributes, Tracer, TracerProvider } from "@opentelemetry/api";
3
3
 
4
4
  //#region src/otel/index.d.ts
@@ -1,6 +1,6 @@
1
- import { T as WithAgentInputSchema, c as AgentTools, d as ChosenEvent, h as InferInput, n as AgentMessage, v as StandardSchemaV1 } from "./types-DYpK3QF4.mjs";
1
+ import { T as WithAgentInputSchema, c as AgentTools, d as ChosenEvent, h as InferInput, n as AgentMessage, v as StandardSchemaV1 } from "./types-CvWRGFxP.mjs";
2
2
  import { t as AgentError } from "./errors-C9rxnWbX.mjs";
3
- import { H as AgentRequestSource, N as AgentDecisionRequest, V as AgentRequestOptions, d as AgentTextRequest, f as AgentUsage, l as AgentRequestExecutors, p as AgentUserInput, t as AgentCallUsage, u as AgentRequestMode, z as AgentEventDescriptor } from "./text-logic-Er5KkTX6.mjs";
3
+ import { H as AgentRequestSource, N as AgentDecisionRequest, V as AgentRequestOptions, d as AgentTextRequest, f as AgentUsage, l as AgentRequestExecutors, p as AgentUserInput, t as AgentCallUsage, u as AgentRequestMode, z as AgentEventDescriptor } from "./text-logic-BR5twXCv.mjs";
4
4
  import { i as AgentLogEntry, o as JsonValue } from "./event-log-store-hrA1vqtN.mjs";
5
5
  import { AnyActorLogic, AnyActorRef, AnyMachineSnapshot, AnyStateMachine, AsyncActorLogic, EmittedFrom, EventFromLogic, EventObject, ExecutableActionObject, InputFrom, InspectionEvent, OutputFrom, Snapshot, SnapshotFrom, createActor } from "xstate";
6
6
 
@@ -934,7 +934,7 @@ declare class AgentMaxModelCallsExceededError extends AgentError {
934
934
  * declared input schema — and machines reached through `.provide(...)`, which
935
935
  * drops the brand — fall back to xstate's `InputFrom`.
936
936
  */
937
- type AgentInputFrom<TMachine extends AnyStateMachine> = InputFrom<TMachine> extends WithAgentInputSchema<infer TInputSchema> ? [TInputSchema] extends [StandardSchemaV1] ? InferInput<TInputSchema> : InputFrom<TMachine> : InputFrom<TMachine>;
937
+ type AgentInputFrom<TMachine extends AnyStateMachine> = [NonNullable<InputFrom<TMachine>>] extends [WithAgentInputSchema<infer TInputSchema>] ? [TInputSchema] extends [StandardSchemaV1] ? InferInput<TInputSchema> : InputFrom<TMachine> : InputFrom<TMachine>;
938
938
  /**
939
939
  * Runs an agent machine to completion or idle: a `createActor` host that
940
940
  * binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
@@ -1,6 +1,6 @@
1
- import { T as WithAgentInputSchema, c as AgentTools, d as ChosenEvent, h as InferInput, n as AgentMessage, v as StandardSchemaV1 } from "./types-pJ5Hn8fv.cjs";
1
+ import { T as WithAgentInputSchema, c as AgentTools, d as ChosenEvent, h as InferInput, n as AgentMessage, v as StandardSchemaV1 } from "./types-DSdj2tGs.cjs";
2
2
  import { t as AgentError } from "./errors-BQRk9eiZ.cjs";
3
- import { H as AgentRequestSource, N as AgentDecisionRequest, V as AgentRequestOptions, d as AgentTextRequest, f as AgentUsage, l as AgentRequestExecutors, p as AgentUserInput, t as AgentCallUsage, u as AgentRequestMode, z as AgentEventDescriptor } from "./text-logic-Cavva1W6.cjs";
3
+ import { H as AgentRequestSource, N as AgentDecisionRequest, V as AgentRequestOptions, d as AgentTextRequest, f as AgentUsage, l as AgentRequestExecutors, p as AgentUserInput, t as AgentCallUsage, u as AgentRequestMode, z as AgentEventDescriptor } from "./text-logic-Mmbgb2jy.cjs";
4
4
  import { i as AgentLogEntry, o as JsonValue } from "./event-log-store-Bz7HDBkE.cjs";
5
5
  import { AnyActorLogic, AnyActorRef, AnyMachineSnapshot, AnyStateMachine, AsyncActorLogic, EmittedFrom, EventFromLogic, EventObject, ExecutableActionObject, InputFrom, InspectionEvent, OutputFrom, Snapshot, SnapshotFrom, createActor } from "xstate";
6
6
 
@@ -934,7 +934,7 @@ declare class AgentMaxModelCallsExceededError extends AgentError {
934
934
  * declared input schema — and machines reached through `.provide(...)`, which
935
935
  * drops the brand — fall back to xstate's `InputFrom`.
936
936
  */
937
- type AgentInputFrom<TMachine extends AnyStateMachine> = InputFrom<TMachine> extends WithAgentInputSchema<infer TInputSchema> ? [TInputSchema] extends [StandardSchemaV1] ? InferInput<TInputSchema> : InputFrom<TMachine> : InputFrom<TMachine>;
937
+ type AgentInputFrom<TMachine extends AnyStateMachine> = [NonNullable<InputFrom<TMachine>>] extends [WithAgentInputSchema<infer TInputSchema>] ? [TInputSchema] extends [StandardSchemaV1] ? InferInput<TInputSchema> : InputFrom<TMachine> : InputFrom<TMachine>;
938
938
  /**
939
939
  * Runs an agent machine to completion or idle: a `createActor` host that
940
940
  * binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
@@ -1,5 +1,5 @@
1
1
  const require_errors = require("./errors-DUBBzRLP.cjs");
2
- const require_decision = require("./decision-t26zsnSR.cjs");
2
+ const require_decision = require("./decision-BnTCsuJv.cjs");
3
3
  const require_event_log_store = require("./event-log-store-a_TKy1gk.cjs");
4
4
  require("./validate.cjs");
5
5
  let xstate = require("xstate");
@@ -919,7 +919,7 @@ function createRequestsFromWorkflowConfig(config, compileSchema) {
919
919
  messages: resolver(request.messages),
920
920
  tools: request.tools,
921
921
  toolChoice: request.toolChoice,
922
- reasoning: request.reasoning,
922
+ includeReasoning: request.includeReasoning,
923
923
  temperature: resolver(request.temperature),
924
924
  maxOutputTokens: resolver(request.maxOutputTokens),
925
925
  topP: resolver(request.topP),