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