@statelyai/agent 1.1.5 → 2.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ai-sdk.cjs +342 -0
  3. package/dist/ai-sdk.d.cts +206 -0
  4. package/dist/ai-sdk.d.mts +206 -0
  5. package/dist/ai-sdk.mjs +331 -0
  6. package/dist/cli.cjs +64 -0
  7. package/dist/cli.d.cts +1 -0
  8. package/dist/cli.d.mts +1 -0
  9. package/dist/cli.mjs +65 -0
  10. package/dist/decision-CQdrKc8k.mjs +978 -0
  11. package/dist/decision-b-lkcs4L.cjs +1295 -0
  12. package/dist/index.cjs +59 -0
  13. package/dist/index.d.cts +212 -0
  14. package/dist/index.d.mts +201 -417
  15. package/dist/index.mjs +4 -583
  16. package/dist/openai-compat.cjs +319 -0
  17. package/dist/openai-compat.d.cts +98 -0
  18. package/dist/openai-compat.d.mts +98 -0
  19. package/dist/openai-compat.mjs +312 -0
  20. package/dist/run-agent-BFMkuI1F.cjs +1599 -0
  21. package/dist/run-agent-BVMd--1l.d.cts +1103 -0
  22. package/dist/run-agent-BoAOq_0Z.mjs +1540 -0
  23. package/dist/run-agent-DzYJb3CK.d.mts +1103 -0
  24. package/dist/src-D-77Ha5p.cjs +1087 -0
  25. package/dist/src-DUeIFjv-.mjs +1016 -0
  26. package/dist/text-logic-C7WJpCIc.d.mts +710 -0
  27. package/dist/text-logic-CZjyACzQ.d.cts +710 -0
  28. package/dist/types-C9QiMjre.d.cts +219 -0
  29. package/dist/types-qm00QF91.d.mts +219 -0
  30. package/dist/utils-Dri7aeEG.d.cts +108 -0
  31. package/dist/utils-Y6GDRGGE.d.mts +108 -0
  32. package/dist/zod.cjs +31 -0
  33. package/dist/zod.d.cts +30 -0
  34. package/dist/zod.d.mts +30 -0
  35. package/dist/zod.mjs +30 -0
  36. package/package.json +110 -29
  37. package/readme.md +143 -6
  38. package/schemas/agent-workflow.json +527 -0
  39. package/.changeset/README.md +0 -8
  40. package/.changeset/config.json +0 -11
  41. package/.env.template +0 -3
  42. package/.github/actions/ci-setup/action.yml +0 -24
  43. package/.github/workflows/release.yml +0 -46
  44. package/.vscode/launch.json +0 -28
  45. package/CHANGELOG.md +0 -215
  46. package/dist/index.d.ts +0 -428
  47. package/dist/index.js +0 -616
  48. package/examples/chatbot.ts +0 -71
  49. package/examples/cot.ts +0 -89
  50. package/examples/email.ts +0 -118
  51. package/examples/example.ts +0 -81
  52. package/examples/goal.ts +0 -94
  53. package/examples/helpers/helpers.ts +0 -17
  54. package/examples/helpers/loader.ts +0 -32
  55. package/examples/helpers/runner.ts +0 -27
  56. package/examples/joke.ts +0 -225
  57. package/examples/multi.ts +0 -103
  58. package/examples/newspaper.ts +0 -324
  59. package/examples/number.ts +0 -102
  60. package/examples/raffle.ts +0 -105
  61. package/examples/sandbox.ts +0 -28
  62. package/examples/simple.ts +0 -39
  63. package/examples/support.ts +0 -147
  64. package/examples/ticTacToe.ts +0 -224
  65. package/examples/todo.ts +0 -137
  66. package/examples/tutor.ts +0 -100
  67. package/examples/verify.ts +0 -120
  68. package/examples/weather.ts +0 -178
  69. package/examples/wiki.ts +0 -30
  70. package/examples/word.ts +0 -171
  71. package/src/adapters/vercel.ts +0 -7
  72. package/src/agent-experimental.ts +0 -221
  73. package/src/agent.test.ts +0 -506
  74. package/src/agent.ts +0 -300
  75. package/src/decision.test.ts +0 -179
  76. package/src/decision.ts +0 -84
  77. package/src/index.ts +0 -4
  78. package/src/memory.ts +0 -25
  79. package/src/planners/shortestPathPlanner.ts +0 -22
  80. package/src/planners/simplePlanner.ts +0 -139
  81. package/src/schemas.ts +0 -11
  82. package/src/strategies/chain-of-note.ts +0 -155
  83. package/src/templates/defaultText.ts +0 -18
  84. package/src/text.ts +0 -236
  85. package/src/types.ts +0 -499
  86. package/src/utils.ts +0 -72
  87. package/tsconfig.json +0 -109
  88. package/vitest.config.ts +0 -9
@@ -0,0 +1,1599 @@
1
+ const require_decision = require("./decision-b-lkcs4L.cjs");
2
+ let xstate = require("xstate");
3
+ //#region src/messages.ts
4
+ function addMessages(resolve) {
5
+ return (args) => {
6
+ const resolved = typeof resolve === "function" ? resolve(args) : resolve;
7
+ return [...args.context.messages, ...Array.isArray(resolved) ? resolved : [resolved]];
8
+ };
9
+ }
10
+ /**
11
+ * Builds a transition-function result that appends one or more
12
+ * {@link AgentMessage}s to a context's `messages` array. `resolve` is either
13
+ * a message (or array of messages) or a function of `{ context, event }`
14
+ * returning them; the returned function is meant to be used directly as (or
15
+ * composed into) a transition's result, e.g. `on: { USER_REPLIED:
16
+ * agent.appendMessages(({ event }) => userMessage(event.text)) }`. Requires
17
+ * `messages: AgentMessage[]` on context — see {@link messagesSchema} for a
18
+ * ready-made schema for that field.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * on: {
23
+ * USER_REPLIED: appendMessages(({ event }) => userMessage(event.text)),
24
+ * }
25
+ * ```
26
+ */
27
+ function appendMessages(resolve) {
28
+ return (args) => ({ context: { messages: addMessages(resolve)(args) } });
29
+ }
30
+ const KNOWN_PART_TYPES = new Set([
31
+ "text",
32
+ "image",
33
+ "file",
34
+ "tool-call",
35
+ "tool-result"
36
+ ]);
37
+ function isKnownPart(part) {
38
+ return !!part && typeof part === "object" && KNOWN_PART_TYPES.has(part.type);
39
+ }
40
+ function validatePartsArray(content) {
41
+ if (!Array.isArray(content)) return "Expected content to be a string or an array of parts";
42
+ for (const part of content) if (!isKnownPart(part)) {
43
+ const type = part && typeof part === "object" ? part.type : void 0;
44
+ return `Unknown message part type: ${JSON.stringify(type)}`;
45
+ }
46
+ }
47
+ /**
48
+ * A {@link StandardSchemaV1} validating an `AgentMessage[]` context field —
49
+ * checks that every message has a known `role` (`system`/`user`/`assistant`/
50
+ * `tool`) and that `content` is either a string (where the role allows it) or
51
+ * an array of parts with a known `type`. Use it directly as a context
52
+ * schema's `messages` field when authoring with `createAgentSchemas`.
53
+ */
54
+ const messagesSchema = { "~standard": {
55
+ version: 1,
56
+ vendor: "statelyai-agent",
57
+ validate(value) {
58
+ if (!Array.isArray(value)) return { issues: [{ message: "Expected an array of agent messages" }] };
59
+ for (const message of value) {
60
+ if (!message || typeof message !== "object") return { issues: [{ message: "Expected an array of agent messages" }] };
61
+ const role = message.role;
62
+ const content = message.content;
63
+ if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") return { issues: [{ message: `Unknown message role: ${JSON.stringify(role)}` }] };
64
+ if (role === "system") {
65
+ if (typeof content !== "string") return { issues: [{ message: "system message content must be a string" }] };
66
+ continue;
67
+ }
68
+ if (role === "tool") {
69
+ const error = validatePartsArray(content) ?? (content.some((part) => part.type !== "tool-result") ? "tool message content must contain only tool-result parts" : void 0);
70
+ if (error) return { issues: [{ message: error }] };
71
+ continue;
72
+ }
73
+ if (typeof content === "string") continue;
74
+ const error = validatePartsArray(content);
75
+ if (error) return { issues: [{ message: error }] };
76
+ }
77
+ return { value };
78
+ }
79
+ } };
80
+ //#endregion
81
+ //#region src/workflow-config.ts
82
+ const workflowConfigWholeExpressionPattern = /^\{\{\s*([\s\S]*?)\s*\}\}$/;
83
+ const workflowConfigTemplateExpressionPattern = /\{\{\s*([\s\S]*?)\s*\}\}/g;
84
+ function evaluateWorkflowConfigPath(expression, scope) {
85
+ const parts = expression.trim().split(".").filter(Boolean);
86
+ let current = scope;
87
+ for (const part of parts) {
88
+ if (!current || typeof current !== "object") return;
89
+ current = current[part];
90
+ }
91
+ return current;
92
+ }
93
+ function evaluateWorkflowConfigValue(value, scope) {
94
+ if (typeof value === "string") {
95
+ const wholeMatch = value.match(workflowConfigWholeExpressionPattern);
96
+ if (wholeMatch?.[1]) return evaluateWorkflowConfigPath(wholeMatch[1], scope);
97
+ return value.replace(workflowConfigTemplateExpressionPattern, (_match, expression) => {
98
+ const resolved = evaluateWorkflowConfigPath(expression, scope);
99
+ return resolved === void 0 || resolved === null ? "" : String(resolved);
100
+ });
101
+ }
102
+ if (Array.isArray(value)) return value.map((item) => evaluateWorkflowConfigValue(item, scope));
103
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, evaluateWorkflowConfigValue(item, scope)]));
104
+ return value;
105
+ }
106
+ function createSchemasFromWorkflowConfig(config, compileSchema) {
107
+ return createAgentSchemas({
108
+ context: compileSchema(config.schemas?.context ?? { type: "object" }, "context"),
109
+ events: Object.fromEntries(Object.entries(config.schemas?.events ?? {}).map(([key, schema]) => [key, compileSchema(schema, `event.${key}`)])),
110
+ emitted: Object.fromEntries(Object.entries(config.schemas?.emitted ?? {}).map(([key, schema]) => [key, compileSchema(schema, `emitted.${key}`)])),
111
+ input: compileSchema(config.schemas?.input ?? {}, "input"),
112
+ output: compileSchema(config.schemas?.output ?? {}, "output"),
113
+ meta: compileSchema(config.schemas?.meta ?? {}, "meta")
114
+ });
115
+ }
116
+ function createRequestsFromWorkflowConfig(config, compileSchema) {
117
+ return Object.fromEntries(Object.entries(config.requests ?? {}).map(([key, request]) => [key, {
118
+ mode: request.mode,
119
+ description: request.description,
120
+ schemas: {
121
+ input: compileSchema(request.input, `${key}.input`),
122
+ output: compileSchema(request.output, `${key}.output`)
123
+ },
124
+ model: ({ input }) => String(evaluateWorkflowConfigValue(request.model, { input }) ?? ""),
125
+ system: request.system === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.system, { input }),
126
+ prompt: request.prompt === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.prompt, { input }),
127
+ messages: request.messages === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.messages, { input }),
128
+ tools: request.tools,
129
+ toolChoice: request.toolChoice,
130
+ reasoning: request.reasoning,
131
+ temperature: request.temperature === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.temperature, { input }),
132
+ maxOutputTokens: request.maxOutputTokens === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.maxOutputTokens, { input }),
133
+ topP: request.topP === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.topP, { input }),
134
+ topK: request.topK === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.topK, { input }),
135
+ seed: request.seed === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.seed, { input }),
136
+ stopSequences: request.stopSequences === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.stopSequences, { input }),
137
+ metadata: request.metadata === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(request.metadata, { input })
138
+ }]));
139
+ }
140
+ function createActorPlaceholdersFromWorkflowConfig(config) {
141
+ return Object.fromEntries(Object.keys(config.actors ?? {}).map((key) => [key, require_decision.missingActor(key)]));
142
+ }
143
+ function createAssignAction(assignConfig) {
144
+ return ({ context, event }) => ({ context: Object.fromEntries(Object.entries(assignConfig).map(([key, value]) => [key, evaluateWorkflowConfigValue(value, {
145
+ context,
146
+ event
147
+ })])) });
148
+ }
149
+ function lowerWorkflowActions(actionConfig) {
150
+ if (!actionConfig) return;
151
+ const lowered = (Array.isArray(actionConfig) ? actionConfig : [actionConfig]).map((action) => {
152
+ if (action.assign !== void 0) return createAssignAction(action.assign);
153
+ if (action.emit !== void 0) return ({ context, event }, enq) => {
154
+ enq.emit(evaluateWorkflowConfigValue(action.emit, {
155
+ context,
156
+ event
157
+ }));
158
+ };
159
+ if (!action.type) throw new Error("setupAgent.fromConfig: action must declare 'type', 'assign', or 'emit'.");
160
+ return {
161
+ type: action.type,
162
+ params: ({ context, event }) => evaluateWorkflowConfigValue(action.params, {
163
+ context,
164
+ event
165
+ })
166
+ };
167
+ });
168
+ return Array.isArray(actionConfig) ? lowered : lowered[0];
169
+ }
170
+ function workflowTransitionMatches(transitionConfig, scope) {
171
+ if (transitionConfig.guard === void 0) return true;
172
+ if (typeof transitionConfig.guard === "string") return Boolean(evaluateWorkflowConfigValue(transitionConfig.guard, scope));
173
+ return typeof transitionConfig.guard === "function" ? transitionConfig.guard(scope) : false;
174
+ }
175
+ function lowerWorkflowTransitionResult(transitionConfig, scope) {
176
+ return {
177
+ ...transitionConfig.target !== void 0 ? { target: transitionConfig.target } : {},
178
+ ...transitionConfig.assign ? { context: Object.fromEntries(Object.entries(transitionConfig.assign).map(([key, value]) => [key, evaluateWorkflowConfigValue(value, scope)])) } : {},
179
+ ...transitionConfig.description !== void 0 ? { description: transitionConfig.description } : {},
180
+ ...transitionConfig.reenter !== void 0 ? { reenter: transitionConfig.reenter } : {},
181
+ ...transitionConfig.meta !== void 0 ? { meta: transitionConfig.meta } : {}
182
+ };
183
+ }
184
+ function lowerWorkflowTransition(transitionConfig) {
185
+ return ({ context, event }) => {
186
+ const scope = {
187
+ context,
188
+ event
189
+ };
190
+ if (!workflowTransitionMatches(transitionConfig, scope)) return;
191
+ return lowerWorkflowTransitionResult(transitionConfig, scope);
192
+ };
193
+ }
194
+ function lowerWorkflowTransitionOrArray(transitionConfig) {
195
+ if (!transitionConfig) return;
196
+ return Array.isArray(transitionConfig) ? ({ context, event }) => {
197
+ const scope = {
198
+ context,
199
+ event
200
+ };
201
+ const transition = transitionConfig.find((candidate) => workflowTransitionMatches(candidate, scope));
202
+ if (!transition) return;
203
+ return lowerWorkflowTransitionResult(transition, scope);
204
+ } : lowerWorkflowTransition(transitionConfig);
205
+ }
206
+ function lowerWorkflowInvoke(invokeConfig) {
207
+ return {
208
+ ...invokeConfig.id !== void 0 ? { id: invokeConfig.id } : {},
209
+ src: invokeConfig.src,
210
+ ...invokeConfig.input !== void 0 ? { input: ({ context, event }) => evaluateWorkflowConfigValue(invokeConfig.input, {
211
+ context,
212
+ event
213
+ }) } : {},
214
+ ...invokeConfig.onDone !== void 0 ? { onDone: lowerWorkflowTransitionOrArray(invokeConfig.onDone) } : {},
215
+ ...invokeConfig.onError !== void 0 ? { onError: lowerWorkflowTransitionOrArray(invokeConfig.onError) } : {},
216
+ ...invokeConfig.meta !== void 0 ? { meta: invokeConfig.meta } : {}
217
+ };
218
+ }
219
+ function lowerWorkflowState(stateConfig) {
220
+ return {
221
+ ...stateConfig.description !== void 0 ? { description: stateConfig.description } : {},
222
+ ...stateConfig.type !== void 0 ? { type: stateConfig.type } : {},
223
+ ...stateConfig.initial !== void 0 ? { initial: stateConfig.initial } : {},
224
+ ...stateConfig.states !== void 0 ? { states: Object.fromEntries(Object.entries(stateConfig.states).map(([key, child]) => [key, lowerWorkflowState(child)])) } : {},
225
+ ...stateConfig.choice !== void 0 ? { choice: lowerWorkflowTransitionOrArray(stateConfig.choice) } : {},
226
+ ...stateConfig.invoke !== void 0 ? { invoke: Array.isArray(stateConfig.invoke) ? stateConfig.invoke.map(lowerWorkflowInvoke) : lowerWorkflowInvoke(stateConfig.invoke) } : {},
227
+ ...stateConfig.on !== void 0 ? { on: Object.fromEntries(Object.entries(stateConfig.on).map(([eventType, transitionConfig]) => [eventType, lowerWorkflowTransitionOrArray(transitionConfig)])) } : {},
228
+ ...stateConfig.always !== void 0 ? { always: lowerWorkflowTransitionOrArray(stateConfig.always) } : {},
229
+ ...stateConfig.onDone !== void 0 ? { onDone: lowerWorkflowTransitionOrArray(stateConfig.onDone) } : {},
230
+ ...stateConfig.after !== void 0 ? { after: Object.fromEntries(Object.entries(stateConfig.after).map(([delay, transitionConfig]) => [delay, lowerWorkflowTransitionOrArray(transitionConfig)])) } : {},
231
+ ...stateConfig.entry !== void 0 ? { entry: lowerWorkflowActions(stateConfig.entry) } : {},
232
+ ...stateConfig.exit !== void 0 ? { exit: lowerWorkflowActions(stateConfig.exit) } : {},
233
+ ...stateConfig.tags !== void 0 ? { tags: stateConfig.tags } : {},
234
+ ...stateConfig.output !== void 0 ? { output: ({ context, event }) => evaluateWorkflowConfigValue(stateConfig.output, {
235
+ context,
236
+ event
237
+ }) } : {},
238
+ ...stateConfig.meta !== void 0 ? { meta: stateConfig.meta } : {}
239
+ };
240
+ }
241
+ function setupAgentFromConfig(config, options) {
242
+ if (!options || typeof options.compileSchema !== "function") throw new Error("setupAgent.fromConfig(...) requires a 'compileSchema' option: { compileSchema: (jsonSchema, name) => StandardSchemaV1 }. Bring your own JSON Schema engine (Ajv, @cfworker/json-schema, a compiled-Zod-from-JSON-Schema pipeline, ...). Core intentionally ships no JSON Schema engine.");
243
+ const { compileSchema } = options;
244
+ const schemas = createSchemasFromWorkflowConfig(config, compileSchema);
245
+ const requestActors = createRequestActors(createRequestsFromWorkflowConfig(config, compileSchema));
246
+ return setupAgent({
247
+ schemas,
248
+ actorSources: {
249
+ ...createActorPlaceholdersFromWorkflowConfig(config),
250
+ ...requestActors
251
+ }
252
+ }).createMachine({
253
+ ...config.id !== void 0 ? { id: config.id } : {},
254
+ ...config.description !== void 0 ? { description: config.description } : {},
255
+ ...config.context !== void 0 ? { context: ({ input }) => require_decision.validateSchemaSync(schemas.context, evaluateWorkflowConfigValue(config.context, { input })) } : {},
256
+ initial: config.initial,
257
+ states: Object.fromEntries(Object.entries(config.states).map(([key, state]) => [key, lowerWorkflowState(state)])),
258
+ ...config.meta !== void 0 ? { meta: config.meta } : {}
259
+ });
260
+ }
261
+ //#endregion
262
+ //#region src/setup-agent.ts
263
+ const emptyEventSchema = { "~standard": {
264
+ version: 1,
265
+ vendor: "statelyai-agent",
266
+ validate(value) {
267
+ return value !== null && typeof value === "object" && Object.keys(value).length === 0 ? { value: {} } : { issues: [{ message: "Expected an empty event payload" }] };
268
+ }
269
+ } };
270
+ function normalizeEventSchemas(events) {
271
+ return Object.fromEntries(Object.entries(events).map(([type, schema]) => [type, schema && typeof schema === "object" && "~standard" in schema ? schema : emptyEventSchema]));
272
+ }
273
+ /**
274
+ * Builds a machine's {@link AgentSchemaPack} from a partial schema
275
+ * declaration — only `context` is required; `events`/`input`/`output`/`meta`
276
+ * default to empty/unknown schemas when omitted. Pass the result as
277
+ * `setupAgent({ schemas })`'s `schemas` (or spread the individual fields
278
+ * directly into `setupAgent({ context, events, ... })` — both forms are
279
+ * accepted).
280
+ */
281
+ function createAgentSchemas(schemas) {
282
+ return {
283
+ context: schemas.context,
284
+ events: normalizeEventSchemas(schemas.events ?? {}),
285
+ input: schemas.input,
286
+ output: schemas.output,
287
+ meta: schemas.meta,
288
+ emitted: schemas.emitted
289
+ };
290
+ }
291
+ function mergeContextSchema(base, fields) {
292
+ return { "~standard": {
293
+ version: 1,
294
+ vendor: "statelyai-agent",
295
+ validate(value) {
296
+ const baseResult = base["~standard"].validate(value);
297
+ if (baseResult instanceof Promise) throw new Error("setupAgent: async context schemas are not supported.");
298
+ if (baseResult.issues) return baseResult;
299
+ const merged = { ...baseResult.value };
300
+ const issues = [];
301
+ for (const [key, fieldSchema] of Object.entries(fields)) {
302
+ const fieldResult = fieldSchema["~standard"].validate(value[key]);
303
+ if (fieldResult instanceof Promise) throw new Error("setupAgent: async context schemas are not supported.");
304
+ if (fieldResult.issues) issues.push(...fieldResult.issues.map((issue) => ({
305
+ ...issue,
306
+ path: [key, ...issue.path ?? []]
307
+ })));
308
+ else merged[key] = fieldResult.value;
309
+ }
310
+ return issues.length > 0 ? { issues } : { value: merged };
311
+ }
312
+ } };
313
+ }
314
+ function resolveAgentStateSchemas(contextSchema, states) {
315
+ return Object.fromEntries(Object.entries(states).map(([key, state]) => {
316
+ if (!state || typeof state !== "object") return [key, state];
317
+ const children = "states" in state && state.states ? resolveAgentStateSchemas(contextSchema, state.states) : void 0;
318
+ if ("context" in state && state.context) return [key, {
319
+ schemas: { context: mergeContextSchema(contextSchema, state.context) },
320
+ ...children ? { states: children } : {}
321
+ }];
322
+ return [key, children ? {
323
+ ...state,
324
+ states: children
325
+ } : state];
326
+ }));
327
+ }
328
+ /**
329
+ * Schema-first `setup(...)` for agent machines — the standard entry point
330
+ * for authoring a machine (the blueprint) that this library then runs (via
331
+ * {@link runAgent} or the step helpers) against host-supplied model/decision
332
+ * executors. Context, events, machine input, machine output, and
333
+ * state/transition meta are all standard schemas — no `{} as Type` casts —
334
+ * and are retained on `result.schemas` for runtime validation. Also
335
+ * registers the `agent.generateText`/`agent.streamText`/`agent.userInput`/
336
+ * `agent.decide` builtin actors and lowers `requests`/`actorSources` into the
337
+ * machine's actor sources. The result is the xstate `setup(...)` object with
338
+ * a wrapped `result.createMachine(...)` plus `result.schemas`/`models`/
339
+ * `requests`/`appendMessages` attached. Also has a
340
+ * `setupAgent.fromConfig(...)` namespace member for building a machine from
341
+ * a serializable {@link AgentWorkflowConfig} instead of this TS API.
342
+ *
343
+ * @example
344
+ * ```ts
345
+ * const schemas = createAgentSchemas({
346
+ * context: z.object({ topic: z.string(), joke: z.string().nullable() }),
347
+ * input: z.object({ topic: z.string() }),
348
+ * output: z.object({ joke: z.string() }),
349
+ * });
350
+ *
351
+ * const agent = setupAgent({
352
+ * schemas,
353
+ * actorSources: { tellJoke },
354
+ * });
355
+ *
356
+ * const jokeMachine = agent.createMachine({
357
+ * context: ({ input }) => ({ topic: input.topic, joke: null }),
358
+ * initial: 'telling',
359
+ * states: {
360
+ * telling: {
361
+ * invoke: {
362
+ * id: 'joke',
363
+ * src: 'tellJoke',
364
+ * input: ({ context }) => ({ topic: context.topic }),
365
+ * onDone: ({ output }) => ({ target: 'done', context: { joke: output } }),
366
+ * },
367
+ * },
368
+ * done: { type: 'final', output: ({ context }) => ({ joke: context.joke ?? '' }) },
369
+ * },
370
+ * });
371
+ * ```
372
+ */
373
+ function setupAgent(config) {
374
+ return createSetupAgent(config);
375
+ }
376
+ function collectFinalStateOutputs(states, outputs = []) {
377
+ for (const state of Object.values(states ?? {})) {
378
+ if (state?.type === "final" && state.output !== void 0) outputs.push(state.output);
379
+ collectFinalStateOutputs(state?.states, outputs);
380
+ }
381
+ return outputs;
382
+ }
383
+ function withRootOutputFromSingleFinal(config) {
384
+ if (!config || typeof config !== "object" || "output" in config || !("states" in config)) return config;
385
+ const outputs = collectFinalStateOutputs(config.states);
386
+ return outputs.length === 1 ? {
387
+ ...config,
388
+ output: outputs[0]
389
+ } : config;
390
+ }
391
+ (function(_setupAgent) {
392
+ function fromConfig(config, options) {
393
+ return setupAgentFromConfig(config, options);
394
+ }
395
+ _setupAgent.fromConfig = fromConfig;
396
+ })(setupAgent || (setupAgent = {}));
397
+ /** Builds one TextLogic actor per `setupAgent({ requests })` entry. @internal */
398
+ function createRequestActors(requests) {
399
+ return Object.fromEntries(Object.entries(requests).map(([key, request]) => {
400
+ return [key, require_decision.createTextLogic({
401
+ ...request,
402
+ name: key,
403
+ mode: request.mode ?? "generate"
404
+ })];
405
+ }));
406
+ }
407
+ function normalizeAgentSchemas(config) {
408
+ if ("schemas" in config && config.schemas) return config.schemas;
409
+ const loose = config;
410
+ return createAgentSchemas({
411
+ ...loose,
412
+ context: loose.context
413
+ });
414
+ }
415
+ function normalizeAgentRequestInput(requests) {
416
+ return requests ?? {};
417
+ }
418
+ /**
419
+ * Runtime guard: a key appearing in both `actorSources`/`requests` is almost
420
+ * certainly a mistake (whichever spread applies last would silently win) —
421
+ * fail fast with a clear message rather than let one implementation shadow
422
+ * another.
423
+ */
424
+ function assertNoActorKeyCollisions(actorSources, requests) {
425
+ const seenIn = /* @__PURE__ */ new Map();
426
+ const groups = [["actorSources", actorSources], ["requests", requests]];
427
+ for (const [groupName, group] of groups) for (const key of Object.keys(group ?? {})) {
428
+ const existingGroup = seenIn.get(key);
429
+ if (existingGroup) throw new Error(`setupAgent: key '${key}' is defined in both '${existingGroup}' and '${groupName}'. Each actor source key must be unique across 'actorSources' and 'requests'.`);
430
+ seenIn.set(key, groupName);
431
+ }
432
+ }
433
+ const RESERVED_AGENT_ACTOR_KEYS = [
434
+ ...Object.keys(require_decision.builtinTextActors),
435
+ require_decision.USER_INPUT_ACTOR,
436
+ require_decision.DECIDE_ACTOR,
437
+ require_decision.PLAN_ACTOR
438
+ ];
439
+ /**
440
+ * Rejects a user-supplied `actorSources`/`requests` key in the reserved
441
+ * `agent.*` builtin namespace. Without this, the builtins-first spread in
442
+ * {@link createAgentActorSources} lets such a key overwrite the builtin
443
+ * (`agent.decide`, `agent.plan`, …) silently. Deliberate override of a builtin
444
+ * is still possible after the machine is created, via
445
+ * `machine.provide({ actorSources: { 'agent.decide': ... } })`.
446
+ */
447
+ function assertNoReservedAgentKeys(actorSources, requests) {
448
+ const groups = [["actorSources", actorSources], ["requests", requests]];
449
+ for (const [groupName, group] of groups) for (const key of Object.keys(group ?? {})) if (RESERVED_AGENT_ACTOR_KEYS.includes(key)) throw new Error(`setupAgent: '${groupName}' key '${key}' is a reserved builtin agent actor and cannot be redefined here (it would silently clobber the builtin). Reserved keys: ${RESERVED_AGENT_ACTOR_KEYS.join(", ")}. To deliberately override a builtin, do it on the created machine instead: machine.provide({ actorSources: { '${key}': ... } }).`);
450
+ }
451
+ function createAgentActorSources(actorSources, requestActors) {
452
+ assertNoActorKeyCollisions(actorSources, requestActors);
453
+ assertNoReservedAgentKeys(actorSources, requestActors);
454
+ return {
455
+ ...require_decision.builtinTextActors,
456
+ [require_decision.USER_INPUT_ACTOR]: require_decision.userInputActor,
457
+ [require_decision.DECIDE_ACTOR]: require_decision.createDecideActor(),
458
+ [require_decision.PLAN_ACTOR]: require_decision.createPlanActor(),
459
+ ...actorSources,
460
+ ...requestActors
461
+ };
462
+ }
463
+ function createAgentSetupConfig(schemas, actorSources, config) {
464
+ return {
465
+ schemas: {
466
+ context: schemas.context,
467
+ events: schemas.events,
468
+ input: schemas.input,
469
+ output: schemas.output,
470
+ meta: schemas.meta,
471
+ ...schemas.emitted && Object.keys(schemas.emitted).length > 0 ? { emitted: schemas.emitted } : {}
472
+ },
473
+ ...config.states ? { states: resolveAgentStateSchemas(schemas.context, config.states) } : {},
474
+ actorSources,
475
+ actions: config.actions,
476
+ guards: config.guards,
477
+ delays: config.delays
478
+ };
479
+ }
480
+ function createSetupAgent(config) {
481
+ const schemas = normalizeAgentSchemas(config);
482
+ const requestActors = createRequestActors(normalizeAgentRequestInput(config.requests));
483
+ const actorSources = createAgentActorSources(config.actorSources, requestActors);
484
+ const base = (0, xstate.setup)(createAgentSetupConfig(schemas, actorSources, config));
485
+ const createBaseMachine = base.createMachine.bind(base);
486
+ const models = config.models ?? {};
487
+ const machineOptions = {
488
+ schemas,
489
+ actorSources,
490
+ models
491
+ };
492
+ return Object.assign(base, {
493
+ createMachine(machineConfig) {
494
+ const machine = createBaseMachine(withRootOutputFromSingleFinal(machineConfig));
495
+ require_decision.agentExecutionOptions.set(machine, machineOptions);
496
+ if (config.isSuspended) {
497
+ const rootConfig = machine.config;
498
+ if (rootConfig) require_decision.machineSuspensionPredicates.set(rootConfig, config.isSuspended);
499
+ }
500
+ return machine;
501
+ },
502
+ schemas,
503
+ models,
504
+ requests: requestActors,
505
+ appendMessages(resolve) {
506
+ return appendMessages(resolve);
507
+ }
508
+ });
509
+ }
510
+ //#endregion
511
+ //#region src/internal/state-request-pass.ts
512
+ async function runTextPhase(stateRequest, baseMessages, deps) {
513
+ const { model, system } = stateRequest;
514
+ const id = stateRequest.id ?? deps.nextRequestId();
515
+ const promptMessage = require_decision.userMessage(stateRequest.prompt);
516
+ if (stateRequest.kind === "decision") return {
517
+ stateRequest,
518
+ id,
519
+ output: void 0,
520
+ appended: [promptMessage]
521
+ };
522
+ if (!deps.generateText) throw new Error("runAgent: a getRequests request needs a 'generateText' executor (or use kind: 'decision').");
523
+ const request = {
524
+ model,
525
+ ...system !== void 0 ? { system } : {},
526
+ messages: [...baseMessages, promptMessage],
527
+ tools: {}
528
+ };
529
+ const agentRequest = {
530
+ kind: "text",
531
+ id,
532
+ src: require_decision.INTERPRET_SOURCE,
533
+ mode: "generate",
534
+ input: request,
535
+ tools: {},
536
+ events: []
537
+ };
538
+ deps.consumeModelCall();
539
+ deps.onTrace?.({
540
+ type: "request.start",
541
+ request: agentRequest
542
+ });
543
+ let output;
544
+ try {
545
+ const raw = await deps.generateText(request, { signal: deps.signal });
546
+ output = await require_decision.normalizeGeneratorResult(raw, id, { request });
547
+ const rawReasoning = raw?.reasoning;
548
+ const reasoning = typeof rawReasoning === "string" ? rawReasoning : void 0;
549
+ deps.onResult?.(agentRequest, {
550
+ output,
551
+ raw
552
+ });
553
+ deps.onTrace?.({
554
+ type: "request.end",
555
+ request: agentRequest,
556
+ output,
557
+ raw,
558
+ ...reasoning !== void 0 ? { reasoning } : {}
559
+ });
560
+ } catch (error) {
561
+ deps.onTrace?.({
562
+ type: "request.error",
563
+ request: agentRequest,
564
+ error
565
+ });
566
+ throw error;
567
+ }
568
+ return {
569
+ stateRequest,
570
+ id,
571
+ output,
572
+ appended: [promptMessage, require_decision.assistantMessage(typeof output === "string" ? output : JSON.stringify(output))]
573
+ };
574
+ }
575
+ async function runAdvancePhase(plan, deps) {
576
+ const { stateRequest, id, output } = plan;
577
+ const { model, system } = stateRequest;
578
+ deps.appendToLog(...plan.appended);
579
+ if (stateRequest.kind !== "decision" && stateRequest.onDone !== void 0) {
580
+ const snapshot = deps.getSnapshot();
581
+ const resolved = typeof stateRequest.onDone === "function" ? stateRequest.onDone({
582
+ output,
583
+ snapshot,
584
+ messages: deps.messages
585
+ }) : stateRequest.onDone;
586
+ if (!resolved) return false;
587
+ const acceptedTypes = require_decision.getAcceptedEvents(snapshot, { schemas: deps.schemas }).map((descriptor) => descriptor.type);
588
+ if (!acceptedTypes.includes(resolved.type)) throw new Error(`runAgent: getRequests request '${id}' resolved onDone to event '${resolved.type}', which the current state does not accept. Accepted: ${acceptedTypes.join(", ") || "(none)"}.`);
589
+ if (!snapshot.can(resolved)) return false;
590
+ deps.send(resolved);
591
+ return true;
592
+ }
593
+ const events = require_decision.getAcceptedEvents(deps.getSnapshot(), {
594
+ schemas: deps.schemas,
595
+ ...stateRequest.allowedEvents ? { eventTypes: stateRequest.allowedEvents } : {}
596
+ });
597
+ if (events.length === 0) return false;
598
+ if (!deps.decide) throw new Error(`runAgent: a getRequests request without 'onDone' needs a 'decide' executor to choose between events ${events.map((descriptor) => `'${descriptor.type}'`).join(", ")}. Provide request.onDone for deterministic advancement, or a 'decide' executor.`);
599
+ const chosen = await require_decision.resolveDecision({
600
+ kind: "decision",
601
+ id,
602
+ model,
603
+ ...system !== void 0 ? { system } : {},
604
+ messages: [...deps.messages],
605
+ events,
606
+ attempts: []
607
+ }, deps.decide, {
608
+ signal: deps.signal,
609
+ canTake: (event) => deps.getSnapshot().can(event)
610
+ });
611
+ if (deps.isSettled()) return false;
612
+ deps.appendToLog(require_decision.assistantMessage(`[chose: ${chosen.type}]`));
613
+ deps.send(chosen);
614
+ return true;
615
+ }
616
+ /**
617
+ * Executes one getRequests pass: all text calls concurrently against the
618
+ * pass-start log, then per-request advancement sequentially in request
619
+ * order. Returns whether ANY request sent an event — the host settles idle
620
+ * when none did (otherwise an unchanged snapshot would re-produce the same
621
+ * pass forever). Stops early (skipping remaining appends/sends) once
622
+ * {@link StateRequestPassDeps.isSettled} reports the run is over. Throws on
623
+ * executor/`onDone` errors — the host maps them to its error settle.
624
+ */
625
+ async function runStateRequestPass(requests, deps) {
626
+ const baseMessages = [...deps.messages];
627
+ const plans = await Promise.all(requests.map((stateRequest) => runTextPhase(stateRequest, baseMessages, deps)));
628
+ let sentAny = false;
629
+ for (const plan of plans) {
630
+ if (deps.isSettled()) break;
631
+ sentAny = await runAdvancePhase(plan, deps) || sentAny;
632
+ }
633
+ return { sentAny };
634
+ }
635
+ //#endregion
636
+ //#region src/run-agent.ts
637
+ /**
638
+ * Thrown by {@link runAgent} when resuming with a `snapshot` + `event` whose
639
+ * `type` the restored state cannot accept (a type-level check via
640
+ * {@link getAcceptedEvents}). A programmer/integration error, in the same
641
+ * class as runAgent's bind-time throws — it throws rather than settling an
642
+ * `error` result. A type-legal event a guard rejects is NOT this error (the
643
+ * machine simply takes no transition). Opt out with
644
+ * {@link RunAgentOptions.onIllegalResumeEvent} `'ignore'`.
645
+ */
646
+ var IllegalResumeEventError = class extends Error {
647
+ eventType;
648
+ acceptedTypes;
649
+ constructor(eventType, acceptedTypes) {
650
+ super(`runAgent: cannot resume with event '${eventType}' — the restored state does not accept it. Accepted event types: ${acceptedTypes.length > 0 ? acceptedTypes.join(", ") : "(none)"}.`);
651
+ this.name = "IllegalResumeEventError";
652
+ this.eventType = eventType;
653
+ this.acceptedTypes = acceptedTypes;
654
+ }
655
+ };
656
+ /**
657
+ * Thrown by {@link runAgent} when resuming from a `snapshot` whose stamped
658
+ * `agentMeta.version` differs from the current machine's version, under the
659
+ * default `onVersionMismatch: 'throw'` and with no `migrateSnapshot` hook. The
660
+ * structural fingerprint of the machine changed since the snapshot was
661
+ * persisted (a state/transition/invoke was added, removed, or retargeted), so
662
+ * the snapshot may no longer resume cleanly. `from` is the snapshot's version,
663
+ * `to` the current machine's.
664
+ */
665
+ var SnapshotVersionMismatchError = class extends Error {
666
+ from;
667
+ to;
668
+ machineId;
669
+ constructor(from, to, machineId) {
670
+ super(`runAgent: cannot resume snapshot stamped with machine version '${from}' against machine '${machineId}' at version '${to}' — the machine's structure changed since the snapshot was persisted. Provide options.migrateSnapshot to adapt it, or set options.onVersionMismatch to 'warn'/'ignore' to proceed anyway.`);
671
+ this.name = "SnapshotVersionMismatchError";
672
+ this.from = from;
673
+ this.to = to;
674
+ this.machineId = machineId;
675
+ }
676
+ };
677
+ /**
678
+ * Thrown by {@link runAgentToCompletion} when the run settles `idle` instead of
679
+ * `done`: the machine paused for external input. Carries the idle `snapshot`
680
+ * and `acceptedTypes` (the event types that could resume it, via
681
+ * {@link getAcceptedEvents}). Use {@link runAgent} directly when idle is an
682
+ * expected outcome you handle.
683
+ */
684
+ var AgentIdleError = class extends Error {
685
+ snapshot;
686
+ acceptedTypes;
687
+ constructor(snapshot, acceptedTypes) {
688
+ super(`runAgentToCompletion: the machine paused (idle) instead of completing. Resume it by calling runAgent with one of these events: ${acceptedTypes.length > 0 ? acceptedTypes.join(", ") : "(none)"}.`);
689
+ this.name = "AgentIdleError";
690
+ this.snapshot = snapshot;
691
+ this.acceptedTypes = acceptedTypes;
692
+ }
693
+ };
694
+ let nextRunAgentTraceId = 1;
695
+ var MaxModelCallsExceededError = class extends Error {
696
+ constructor() {
697
+ super("runAgent exceeded maxModelCalls.");
698
+ this.name = "MaxModelCallsExceededError";
699
+ }
700
+ };
701
+ function wrapsDecisionExhausted(error) {
702
+ let current = error;
703
+ for (let depth = 0; depth < 10 && current != null; depth++) {
704
+ if (current instanceof require_decision.DecisionExhaustedError) return true;
705
+ current = current.cause;
706
+ }
707
+ return false;
708
+ }
709
+ /**
710
+ * Recursively collects every invoke's `src` from raw machine config (spike
711
+ * S6: `machine.config` preserves authored srcs; the built `machine.root`
712
+ * normalizes object srcs to synthetic string ids and loses the distinction
713
+ * this walk needs). Function-valued `src` resolvers are dynamic and are not
714
+ * statically analyzable, so they are skipped (pass-through, like any other
715
+ * non-agent actor).
716
+ */
717
+ function collectConfiguredInvokeSrcs(stateConfig, stateName, out) {
718
+ if (!stateConfig) return;
719
+ const invokes = stateConfig.invoke === void 0 ? [] : Array.isArray(stateConfig.invoke) ? stateConfig.invoke : [stateConfig.invoke];
720
+ for (const invokeConfig of invokes) {
721
+ const src = invokeConfig?.src;
722
+ if (typeof src === "string" || src && typeof src === "object") out.push({
723
+ stateName,
724
+ src
725
+ });
726
+ }
727
+ for (const [childName, childConfig] of Object.entries(stateConfig.states ?? {})) collectConfiguredInvokeSrcs(childConfig, `${stateName}.${childName}`, out);
728
+ }
729
+ /**
730
+ * Duck-types a state machine actor logic (an invoked child machine) vs. any
731
+ * other actor logic. xstate's `StateMachine` carries `.config`, `.root`, and
732
+ * a `.provide(...)` method plus an `implementations.actorSources` map — this
733
+ * combination is unique to machines and survives the dual-package/version
734
+ * boundary an `instanceof` check would not. Used to descend the bind-time
735
+ * walk into invoked child machines (their internal agent requests are opaque
736
+ * to the parent-level source walk otherwise).
737
+ */
738
+ function isStateMachine(logic) {
739
+ return !!logic && typeof logic === "object" && "config" in logic && "root" in logic && typeof logic.provide === "function" && typeof logic.implementations === "object" && !!logic.implementations?.actorSources;
740
+ }
741
+ /**
742
+ * Fails fast (throws) at bind time — before any actor runs — when the
743
+ * machine invokes an agent actor `runAgent` cannot execute. See §3.2 point 2.
744
+ *
745
+ * Recurses into invoked child state machines (arbitrarily deep). A child
746
+ * machine's agent requests reached through string-keyed invoke srcs DO inherit
747
+ * the parent runAgent's `generateText`/`streamText`/`decide` executors —
748
+ * runAgent rebinds them with the same host-backed wrappers (see
749
+ * {@link rebindChildMachine}) — so the only remaining bind-time errors are: a
750
+ * required executor kind missing entirely (naming the invoke chain and src),
751
+ * and an unbound request reached through a direct-object invoke src that can't
752
+ * be rebound ({@link unrebindableChildRequestError}). A request that carries
753
+ * its own executor (`.withExecutor(...)`, tracked in `executorBoundLogics`)
754
+ * always runs itself; explicit binding shadows inheritance.
755
+ */
756
+ function assertBindable(machine, effectiveSources, options) {
757
+ assertMachineBindable(machine, effectiveSources, options, {
758
+ isChild: false,
759
+ childPath: "",
760
+ rebindable: true,
761
+ visited: new Set([machine])
762
+ });
763
+ }
764
+ function assertMachineBindable(machine, effectiveSources, options, ctx) {
765
+ const invokes = [];
766
+ collectConfiguredInvokeSrcs(machine.config, machine.config.id ?? "(root)", invokes);
767
+ const where = ctx.isChild ? `child machine '${ctx.childPath}' state` : "state";
768
+ for (const { stateName, src } of invokes) {
769
+ if (typeof src !== "string") {
770
+ if (isStateMachine(src)) {
771
+ assertChildMachineBindable(src, src, stateName, options, ctx);
772
+ continue;
773
+ }
774
+ if ((require_decision.isTextLogic(src) || require_decision.isDecisionLogic(src) || require_decision.isPlanLogic(src)) && !require_decision.executorBoundLogics.has(src)) throw new Error(`runAgent: ${where} '${stateName}' invokes a direct-object actor logic (kind: '${src.kind}'). Direct-object invoke srcs cannot be rebound by runAgent — either call '.withExecutor(...)' on the logic before invoking it, or register it as a string-keyed actor source instead (machine.provide({ actorSources: { name: logic } })) and invoke it by name.`);
775
+ continue;
776
+ }
777
+ const logic = effectiveSources[src];
778
+ if (logic === void 0) throw new Error(`runAgent: ${where} '${stateName}' invokes unregistered actor source '${src}'. Provide it via machine.provide({ actorSources: { '${src}': ... } }) or runAgent(machine, { actorSources: { '${src}': ... } }).`);
779
+ if (isStateMachine(logic)) {
780
+ assertChildMachineBindable(logic, src, stateName, options, ctx);
781
+ continue;
782
+ }
783
+ if (src === "agent.userInput") continue;
784
+ if (require_decision.isDecisionLogic(logic)) {
785
+ if (require_decision.executorBoundLogics.has(logic)) continue;
786
+ if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, "decision");
787
+ if (!options.hasDecide) throw new Error(`runAgent: ${where} '${stateName}' invokes decision source '${src}' but no 'decide' executor was provided to runAgent(...).`);
788
+ continue;
789
+ }
790
+ if (require_decision.isPlanLogic(logic)) {
791
+ if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, "plan");
792
+ if (!options.hasDecide) throw new Error(`runAgent: ${where} '${stateName}' invokes plan source '${src}' but no 'decide' executor was provided to runAgent(...).`);
793
+ continue;
794
+ }
795
+ if (require_decision.isTextLogic(logic)) {
796
+ if (require_decision.executorBoundLogics.has(logic)) continue;
797
+ if (!ctx.rebindable) throw unrebindableChildRequestError(ctx.childPath, stateName, src, logic.mode === "stream" ? "streaming text" : "text");
798
+ if (logic.mode === "stream" && !options.hasStreamText) throw new Error(`runAgent: ${where} '${stateName}' invokes streaming text source '${src}' but no 'streamText' executor was provided to runAgent(...).`);
799
+ if (logic.mode !== "stream" && !options.hasGenerateText) throw new Error(`runAgent: ${where} '${stateName}' invokes text source '${src}' but no 'generateText' executor was provided to runAgent(...).`);
800
+ continue;
801
+ }
802
+ if (require_decision.isUnboundPlaceholder(logic)) throw new Error(`runAgent: ${where} '${stateName}' invokes actor source '${src}', which has no host execution. Provide it via machine.provide({ actorSources: { '${src}': ... } }) or runAgent(machine, { actorSources: { '${src}': ... } }).`);
803
+ }
804
+ }
805
+ /** Descends the bind-time walk into an invoked child state machine, guarding
806
+ * against a machine that (transitively) invokes itself. */
807
+ function assertChildMachineBindable(childMachine, childSrc, stateName, options, ctx) {
808
+ if (ctx.visited.has(childMachine)) return;
809
+ const childName = typeof childSrc === "string" ? childSrc : childMachine.config.id ?? "(child machine)";
810
+ const childPath = ctx.childPath ? `${ctx.childPath} > ${childName}` : childName;
811
+ const childSources = childMachine.implementations.actorSources;
812
+ assertMachineBindable(childMachine, childSources, options, {
813
+ isChild: true,
814
+ childPath,
815
+ rebindable: ctx.rebindable && typeof childSrc === "string",
816
+ visited: new Set([...ctx.visited, childMachine])
817
+ });
818
+ }
819
+ /** The loud bind-time error for an unbound agent request reached under a
820
+ * direct-object invoke src, which runAgent cannot rebind (only string-keyed
821
+ * sources can be swapped via `.provide`). Names the invoke chain AND the
822
+ * request src, and spells out the `.withExecutor`/string-keyed remedy. Note:
823
+ * requests reachable through string-keyed srcs at any depth DO inherit
824
+ * runAgent's executors — this error is only for the unrebindable direct-object
825
+ * case. */
826
+ function unrebindableChildRequestError(childPath, stateName, requestSrc, kind) {
827
+ return /* @__PURE__ */ new Error(`runAgent: child machine '${childPath}' (state '${stateName}') invokes ${kind} source '${requestSrc}', which has no host execution and is reached through a direct-object invoke src that runAgent cannot rebind. Requests reached through string-keyed actor sources inherit runAgent's generateText/streamText/decide executors automatically; a direct-object child machine does not. Either bind the request with its own executor (requestLogic.withExecutor(...)), or register the child as a string-keyed actor source (machine.provide({ actorSources: { <child>: childMachine } })) and invoke it by name.`);
828
+ }
829
+ /** Reads the durable invoke id/src off the async actor's own ref (`self`). */
830
+ function selfIdAndSrc(self) {
831
+ const ref = self;
832
+ return {
833
+ id: typeof ref?.id === "string" ? ref.id : "",
834
+ src: typeof ref?.src === "string" ? ref.src : ""
835
+ };
836
+ }
837
+ /**
838
+ * The machine actor that INVOKED a decision/plan request — the actor whose
839
+ * live snapshot supplies the candidate events and drives `canTake`/`send`.
840
+ * For a top-level request this is the root actor (identity-equal to
841
+ * `runCtx.actorHolder.actorRef`); for a request inside an invoked child
842
+ * machine it is that child's actor, so a child decision/plan reads and drives
843
+ * the CHILD's snapshot — not the root's. Read off `self._parent`, with the
844
+ * root actor as a fallback.
845
+ */
846
+ function invokingActorOf(self, runCtx) {
847
+ return self?._parent ?? runCtx.actorHolder.actorRef;
848
+ }
849
+ function wrapTextLogicForRunAgent(logic, runCtx) {
850
+ return logic.withExecutor(async ({ request, self, signal }) => {
851
+ const { id, src } = selfIdAndSrc(self);
852
+ const executor = logic.mode === "stream" ? runCtx.streamText : runCtx.generateText;
853
+ if (!executor) throw new Error(`runAgent: no '${logic.mode === "stream" ? "streamText" : "generateText"}' executor provided.`);
854
+ const requestWithTools = {
855
+ ...request,
856
+ tools: request.tools ?? {}
857
+ };
858
+ const agentRequest = {
859
+ kind: "text",
860
+ id,
861
+ src,
862
+ mode: logic.mode,
863
+ input: request,
864
+ tools: requestWithTools.tools,
865
+ events: []
866
+ };
867
+ runCtx.consumeModelCall();
868
+ runCtx.onTrace?.({
869
+ type: "request.start",
870
+ request: agentRequest
871
+ });
872
+ try {
873
+ const raw = await executor(requestWithTools, {
874
+ onChunk: (chunk) => {
875
+ runCtx.onTrace?.({
876
+ type: "stream.chunk",
877
+ request: agentRequest,
878
+ chunk
879
+ });
880
+ runCtx.onChunk?.(chunk, { request: agentRequest });
881
+ },
882
+ signal
883
+ });
884
+ const output = await require_decision.normalizeGeneratorResult(raw, id, {
885
+ request,
886
+ onChunk: (chunk) => {
887
+ runCtx.onTrace?.({
888
+ type: "stream.chunk",
889
+ request: agentRequest,
890
+ chunk
891
+ });
892
+ runCtx.onChunk?.(chunk, { request: agentRequest });
893
+ }
894
+ });
895
+ const rawReasoning = raw?.reasoning;
896
+ const reasoning = typeof rawReasoning === "string" ? rawReasoning : void 0;
897
+ runCtx.onResult?.(agentRequest, {
898
+ output,
899
+ raw
900
+ });
901
+ runCtx.onTrace?.({
902
+ type: "request.end",
903
+ request: agentRequest,
904
+ output,
905
+ raw,
906
+ ...reasoning !== void 0 ? { reasoning } : {}
907
+ });
908
+ return { output };
909
+ } catch (error) {
910
+ runCtx.onTrace?.({
911
+ type: "request.error",
912
+ request: agentRequest,
913
+ error
914
+ });
915
+ throw error;
916
+ }
917
+ });
918
+ }
919
+ function createCountingDecide(runCtx) {
920
+ return async (attemptRequest) => {
921
+ runCtx.consumeModelCall();
922
+ runCtx.onTrace?.({
923
+ type: "request.start",
924
+ request: attemptRequest
925
+ });
926
+ try {
927
+ const result = await runCtx.decide(attemptRequest);
928
+ runCtx.onResult?.(attemptRequest, {
929
+ output: result.event,
930
+ raw: result
931
+ });
932
+ runCtx.onTrace?.({
933
+ type: "request.end",
934
+ request: attemptRequest,
935
+ output: result.event,
936
+ raw: result
937
+ });
938
+ return result;
939
+ } catch (error) {
940
+ runCtx.onTrace?.({
941
+ type: "request.error",
942
+ request: attemptRequest,
943
+ error
944
+ });
945
+ throw error;
946
+ }
947
+ };
948
+ }
949
+ /**
950
+ * Builds the decision actor logic runAgent installs in place of a
951
+ * `DecisionLogic`/`agent.decide` source. `DecisionLogic.withExecutor(...)`
952
+ * can only swap the innermost per-attempt executor — the `resolveDecision(...)`
953
+ * call (and its `canTake`) is hardwired inside the original logic's `run`.
954
+ * To supply `canTake` (mode-3, §2.6), runAgent instead builds a fresh async
955
+ * logic here that calls `resolveDecision` itself, reusing `logic.request(...)`
956
+ * to build the request the same way the original logic would have.
957
+ *
958
+ * On success it SENDS the chosen event to the invoking actor (auto-delivery,
959
+ * mirroring {@link createRunAgentPlanLogic}) and then completes with that event
960
+ * as its output — so callers never wire an `onDone` to deliver it. See the
961
+ * send-then-complete note inside `run` for how exit-cancels-invoke interacts
962
+ * with `onDone`.
963
+ */
964
+ function createRunAgentDecisionLogic(logic, runCtx) {
965
+ const decisionLogic = (0, xstate.createAsyncLogic)({ run: async ({ input, signal, self }) => {
966
+ if (!runCtx.decide) throw new Error("runAgent: no 'decide' executor provided.");
967
+ const { id } = selfIdAndSrc(self);
968
+ const declaredEventTypes = logic.allowedEventTypes?.(input);
969
+ await Promise.resolve();
970
+ const actorRef = invokingActorOf(self, runCtx);
971
+ const events = actorRef ? require_decision.getAcceptedEvents(actorRef.getSnapshot(), {
972
+ schemas: runCtx.schemas,
973
+ eventTypes: declaredEventTypes
974
+ }) : [];
975
+ const chosen = await require_decision.resolveDecision({
976
+ ...logic.request(input),
977
+ id,
978
+ events
979
+ }, createCountingDecide(runCtx), {
980
+ maxRetries: logic.maxRetries,
981
+ signal,
982
+ canTake: (event) => actorRef ? actorRef.getSnapshot().can(event) : true
983
+ });
984
+ actorRef?.send(chosen);
985
+ await Promise.resolve();
986
+ return chosen;
987
+ } });
988
+ return Object.assign(decisionLogic, {
989
+ kind: "statelyai.decisionLogic",
990
+ maxRetries: logic.maxRetries,
991
+ request: logic.request,
992
+ withExecutor: (nextExecute) => createRunAgentDecisionLogic(logic.withExecutor(nextExecute), runCtx)
993
+ });
994
+ }
995
+ /**
996
+ * Builds the plan actor logic runAgent installs in place of the `agent.plan`
997
+ * builtin: iterated {@link resolveDecision}. Each step re-reads the live
998
+ * snapshot (so the candidate set reflects everything applied so far), asks
999
+ * the `decide` executor for one legal event with the same validation/retry
1000
+ * loop a decision gets, and sends it to the machine. The loop ends on a
1001
+ * `stopOn` event, at `maxSteps`, when no legal candidate remains, or when an
1002
+ * applied event exits the invoking state (xstate cancels this invoke — the
1003
+ * machine simply moves on and the pending output is discarded).
1004
+ *
1005
+ * The invoke's `input` is resolved once, so the prompt cannot re-render
1006
+ * context between steps; instead the applied trail is appended to the prompt
1007
+ * each step so the model can see plan progress.
1008
+ */
1009
+ function createRunAgentPlanLogic(logic, runCtx) {
1010
+ const planLogic = (0, xstate.createAsyncLogic)({ run: async ({ input, signal, self }) => {
1011
+ if (!runCtx.decide) throw new Error("runAgent: no 'decide' executor provided.");
1012
+ const { id } = selfIdAndSrc(self);
1013
+ const stopOn = new Set(input.stopOn ?? []);
1014
+ const countingDecide = createCountingDecide(runCtx);
1015
+ const base = logic.request(input);
1016
+ let ledger = require_decision.initialPlanLedger(logic, input);
1017
+ const end = (stopped) => {
1018
+ ledger = require_decision.advancePlanLedger(logic, ledger, {
1019
+ type: "plan.ended",
1020
+ stopped
1021
+ });
1022
+ return ledger.output;
1023
+ };
1024
+ await Promise.resolve();
1025
+ const invokingActor = invokingActorOf(self, runCtx);
1026
+ while (ledger.context.stepsRemaining > 0) {
1027
+ const actorRef = invokingActor;
1028
+ if (!actorRef || signal.aborted) break;
1029
+ const machineEvents = require_decision.getAcceptedEvents(actorRef.getSnapshot(), {
1030
+ schemas: runCtx.schemas,
1031
+ eventTypes: logic.allowedEventTypes(input)
1032
+ });
1033
+ if (machineEvents.length === 0) return end("no-legal-events");
1034
+ const doneDescriptor = {
1035
+ type: require_decision.PLAN_DONE_EVENT_TYPE,
1036
+ toolName: require_decision.sanitizeEventToolName(require_decision.PLAN_DONE_EVENT_TYPE)
1037
+ };
1038
+ const events = machineEvents.some((event) => event.type === "agent.plan.done") ? machineEvents : [...machineEvents, doneDescriptor];
1039
+ const applied = ledger.context.applied;
1040
+ const trail = applied.length === 0 ? "" : `\n\nEvents already applied in this plan, in order:\n${applied.map((step) => JSON.stringify(step)).join("\n")}\nContinue from here; do not repeat applied events.`;
1041
+ const doneHint = `\n\nWhen the request is fully handled (or no action is needed), choose '${require_decision.PLAN_DONE_EVENT_TYPE}'.`;
1042
+ const chosen = await require_decision.resolveDecision({
1043
+ ...base,
1044
+ id: `${id}[${applied.length}]`,
1045
+ events,
1046
+ prompt: `${base.prompt ?? ""}${trail}${doneHint}`,
1047
+ attempts: []
1048
+ }, countingDecide, {
1049
+ maxRetries: input.maxRetries ?? logic.maxRetries,
1050
+ signal,
1051
+ canTake: (event) => {
1052
+ if (event.type === "agent.plan.done" || stopOn.has(event.type)) return true;
1053
+ return invokingActor ? invokingActor.getSnapshot().can(event) : true;
1054
+ }
1055
+ });
1056
+ if (chosen.type === "agent.plan.done") return end("done");
1057
+ actorRef.send(chosen);
1058
+ ledger = require_decision.advancePlanLedger(logic, ledger, {
1059
+ type: "plan.applied",
1060
+ event: chosen
1061
+ });
1062
+ await Promise.resolve();
1063
+ if (stopOn.has(chosen.type)) return end("stop-event");
1064
+ }
1065
+ return end("max-steps");
1066
+ } });
1067
+ return Object.assign(planLogic, {
1068
+ kind: "statelyai.planLogic",
1069
+ maxRetries: logic.maxRetries,
1070
+ request: logic.request,
1071
+ allowedEventTypes: logic.allowedEventTypes
1072
+ });
1073
+ }
1074
+ /**
1075
+ * Recursively rebinds an invoked child machine's own agent sources with the
1076
+ * SAME host-backed wrappers runAgent applies to the top-level machine, so a
1077
+ * child's text/stream/decision/plan requests inherit runAgent's executors and
1078
+ * participate in maxModelCalls counting, onTrace/onChunk/onResult exactly like
1079
+ * parent requests. Returns the child machine to invoke: a `.provide`-rebound
1080
+ * copy when any inner source needed wrapping, else the original untouched.
1081
+ *
1082
+ * Only string-keyed sources are visited — a direct-object invoke src cannot be
1083
+ * swapped via `.provide` (assertBindable already rejected an unbound request
1084
+ * under one). A source that already carries its own executor
1085
+ * (`executorBoundLogics`) is left as-is: explicit binding shadows inheritance.
1086
+ * Cycle-safe via `visited` (a machine that invokes itself is returned as-is).
1087
+ */
1088
+ function rebindChildMachine(childMachine, runCtx, visited) {
1089
+ if (visited.has(childMachine)) return childMachine;
1090
+ const childVisited = new Set([...visited, childMachine]);
1091
+ const sources = childMachine.implementations.actorSources;
1092
+ const wrapped = {};
1093
+ for (const [key, logic] of Object.entries(sources)) {
1094
+ if (require_decision.isDecisionLogic(logic)) {
1095
+ if (!require_decision.executorBoundLogics.has(logic)) wrapped[key] = createRunAgentDecisionLogic(logic, runCtx);
1096
+ continue;
1097
+ }
1098
+ if (require_decision.isPlanLogic(logic)) {
1099
+ wrapped[key] = createRunAgentPlanLogic(logic, runCtx);
1100
+ continue;
1101
+ }
1102
+ if (require_decision.isTextLogic(logic)) {
1103
+ if (!require_decision.executorBoundLogics.has(logic)) wrapped[key] = wrapTextLogicForRunAgent(logic, runCtx);
1104
+ continue;
1105
+ }
1106
+ if (isStateMachine(logic)) {
1107
+ const rebound = rebindChildMachine(logic, runCtx, childVisited);
1108
+ if (rebound !== logic) wrapped[key] = rebound;
1109
+ continue;
1110
+ }
1111
+ }
1112
+ return Object.keys(wrapped).length > 0 ? childMachine.provide({ actorSources: wrapped }) : childMachine;
1113
+ }
1114
+ /**
1115
+ * Runs an agent machine to completion or idle: a `createActor` host that
1116
+ * binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
1117
+ * `DecisionLogic` actor sources, starts (or resumes) the actor, and drives
1118
+ * it until it settles — {@link RunAgentResult} `done | idle | error`. Unlike
1119
+ * the step helpers ({@link initialAgentStep} etc — a pure
1120
+ * transition-at-a-time path for durable hosts), `runAgent` owns a live actor
1121
+ * internally; there is no continuation callback, so **idle always settles**
1122
+ * and the caller resumes explicitly by passing the settled `{ snapshot,
1123
+ * event }` back in. The actor is stopped on every settle path (`done`,
1124
+ * `idle`, and `error` alike) — resume is always by snapshot, never by
1125
+ * holding a reference to a live actor.
1126
+ *
1127
+ * Binding happens **before** the actor starts: every invoke the machine
1128
+ * could reach is walked and checked against the effective actor sources
1129
+ * (`options.actorSources` merged onto the machine), so a missing
1130
+ * `streamText`/`decide` executor or any other unbound actor source throws
1131
+ * immediately — a bind-time error, not a mid-run failure. The one exception
1132
+ * is `agent.userInput`: unhandled, it binds as a pending placeholder that
1133
+ * settles the run idle (with `pendingUserInputs`) instead of erroring.
1134
+ *
1135
+ * @example
1136
+ * ```ts
1137
+ * const executors = createAiSdkExecutors({ models });
1138
+ * let r = await runAgent(machine, { input, executors });
1139
+ * while (r.status === 'idle') {
1140
+ * const event = await promptUser(getAcceptedEvents(r.snapshot));
1141
+ * r = await runAgent(machine, { snapshot: r.snapshot, event, executors });
1142
+ * }
1143
+ * if (r.status !== 'done') throw new Error(`Run did not complete: ${r.status}`);
1144
+ * console.log(r.output);
1145
+ * ```
1146
+ *
1147
+ * The `executors`' `generateText`/`streamText` accept the raw Vercel AI SDK
1148
+ * functions directly (`executors: { generateText, streamText }` with them
1149
+ * imported from `ai`) — their `{ text }`/`{ textStream }` results are unwrapped
1150
+ * natively. `decide` cannot be a raw AI SDK function: the tool-per-event mapping
1151
+ * lives in an adapter — use `createAiSdkExecutors` from '@statelyai/agent/ai-sdk'.
1152
+ */
1153
+ async function runAgent(machine, options) {
1154
+ const maxModelCalls = options.maxModelCalls ?? 100;
1155
+ let modelCallCount = 0;
1156
+ let budgetExceeded = false;
1157
+ let warnedNonSerializable = false;
1158
+ const runId = `run_${nextRunAgentTraceId++}`;
1159
+ let traceSeq = 0;
1160
+ const machineId = machine.config.id ?? machine.id ?? "(machine)";
1161
+ const machineVersion = options.machineVersion ?? require_decision.getMachineStructuralHash(machine);
1162
+ const agentMeta = {
1163
+ machineId,
1164
+ version: machineVersion
1165
+ };
1166
+ const stampAgentMeta = (snapshot) => {
1167
+ if (snapshot && typeof snapshot === "object") snapshot.agentMeta = agentMeta;
1168
+ };
1169
+ const onTrace = (event) => {
1170
+ options.onTrace?.({
1171
+ runId,
1172
+ seq: ++traceSeq,
1173
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1174
+ machineId,
1175
+ machineVersion,
1176
+ ...event
1177
+ });
1178
+ };
1179
+ const consumeModelCall = () => {
1180
+ if (budgetExceeded) throw new MaxModelCallsExceededError();
1181
+ modelCallCount += 1;
1182
+ if (modelCallCount > maxModelCalls) {
1183
+ budgetExceeded = true;
1184
+ throw new MaxModelCallsExceededError();
1185
+ }
1186
+ };
1187
+ const warnNonSerializableContext = (snapshot) => {
1188
+ if (warnedNonSerializable || process.env.NODE_ENV === "production") return;
1189
+ let offending = [];
1190
+ try {
1191
+ offending = require_decision.findNonSerializableContextPaths(snapshot.context);
1192
+ } catch {
1193
+ return;
1194
+ }
1195
+ if (offending.length === 0) return;
1196
+ warnedNonSerializable = true;
1197
+ console.warn(`runAgent: context holds value(s) that will not survive snapshot persist/resume (JSON round-trip): ${offending.join(", ")}. Persist only JSON-serializable context, or convert these before the run settles.`);
1198
+ };
1199
+ const provided = machine.provide({ actorSources: options.actorSources });
1200
+ const effectiveSources = provided.implementations.actorSources;
1201
+ assertBindable(provided, effectiveSources, {
1202
+ hasGenerateText: !!options.executors?.generateText,
1203
+ hasDecide: !!options.executors?.decide,
1204
+ hasStreamText: !!options.executors?.streamText
1205
+ });
1206
+ if (options.getRequests && !options.executors?.generateText && !options.executors?.decide) throw new Error("runAgent: 'getRequests' requires a 'generateText' and/or 'decide' executor — the returned requests run through them.");
1207
+ const actorHolder = { actorRef: void 0 };
1208
+ const runCtx = {
1209
+ generateText: options.executors?.generateText,
1210
+ streamText: options.executors?.streamText,
1211
+ decide: options.executors?.decide,
1212
+ onChunk: options.onChunk,
1213
+ onResult: options.onResult,
1214
+ onTrace,
1215
+ consumeModelCall,
1216
+ actorHolder,
1217
+ schemas: require_decision.getRegisteredAgentExecutionOptions(machine).schemas
1218
+ };
1219
+ let userInputIsPlaceholder = false;
1220
+ const wrappedSources = {};
1221
+ for (const [key, logic] of Object.entries(effectiveSources)) {
1222
+ if (key === "agent.userInput") {
1223
+ if (options.userInput) {
1224
+ const userInput = options.userInput;
1225
+ wrappedSources[key] = (0, xstate.createAsyncLogic)({ run: async ({ input }) => await userInput(input) });
1226
+ } else if (require_decision.isUnboundPlaceholder(logic)) {
1227
+ userInputIsPlaceholder = true;
1228
+ wrappedSources[key] = (0, xstate.createAsyncLogic)({ run: () => new Promise(() => {}) });
1229
+ }
1230
+ continue;
1231
+ }
1232
+ if (require_decision.isDecisionLogic(logic)) {
1233
+ wrappedSources[key] = createRunAgentDecisionLogic(logic, runCtx);
1234
+ continue;
1235
+ }
1236
+ if (require_decision.isPlanLogic(logic)) {
1237
+ wrappedSources[key] = createRunAgentPlanLogic(logic, runCtx);
1238
+ continue;
1239
+ }
1240
+ if (require_decision.isTextLogic(logic)) {
1241
+ if (!require_decision.executorBoundLogics.has(logic)) wrappedSources[key] = wrapTextLogicForRunAgent(logic, runCtx);
1242
+ continue;
1243
+ }
1244
+ if (isStateMachine(logic)) {
1245
+ const rebound = rebindChildMachine(logic, runCtx, new Set([machine]));
1246
+ if (rebound !== logic) wrappedSources[key] = rebound;
1247
+ continue;
1248
+ }
1249
+ }
1250
+ const boundMachine = provided.provide({ actorSources: wrappedSources });
1251
+ const isSuspended = options.isSuspended ?? require_decision.getMachineSuspensionPredicate(machine) ?? (() => false);
1252
+ let effectiveSnapshot = options.snapshot;
1253
+ if (effectiveSnapshot !== void 0) {
1254
+ const from = effectiveSnapshot.agentMeta?.version;
1255
+ if (from !== void 0 && from !== machineVersion) {
1256
+ const info = {
1257
+ from,
1258
+ to: machineVersion
1259
+ };
1260
+ if (options.migrateSnapshot) effectiveSnapshot = options.migrateSnapshot(effectiveSnapshot, info);
1261
+ else {
1262
+ const mode = options.onVersionMismatch ?? "throw";
1263
+ if (mode === "throw") throw new SnapshotVersionMismatchError(from, machineVersion, machineId);
1264
+ if (mode === "warn") console.warn(`runAgent: resuming a snapshot stamped with machine version '${from}' against machine '${machineId}' at version '${machineVersion}'. Structural changes may not resume cleanly.`);
1265
+ }
1266
+ }
1267
+ }
1268
+ const priorMessages = require_decision.getAgentMessages(effectiveSnapshot);
1269
+ const messages = typeof options.messages === "function" ? [...options.messages([...priorMessages])] : [...priorMessages, ...options.messages ?? []];
1270
+ const stampMessages = (snapshot) => {
1271
+ if (!options.getRequests && !options.messages && messages.length === 0) return;
1272
+ if (snapshot && typeof snapshot === "object") snapshot.messages = [...messages];
1273
+ };
1274
+ if (effectiveSnapshot !== void 0 && options.event !== void 0 && (options.onIllegalResumeEvent ?? "throw") === "throw") {
1275
+ const acceptedTypes = require_decision.getAcceptedEvents((0, xstate.createActor)(boundMachine, { snapshot: effectiveSnapshot }).getSnapshot(), { schemas: runCtx.schemas }).map((descriptor) => descriptor.type);
1276
+ const eventType = options.event.type;
1277
+ if (!acceptedTypes.includes(eventType)) throw new IllegalResumeEventError(eventType, acceptedTypes);
1278
+ }
1279
+ return new Promise((resolvePromise) => {
1280
+ let settled = false;
1281
+ let idleTimer;
1282
+ let actor;
1283
+ let deliveringResumeEvent = options.event !== void 0;
1284
+ const settle = (result) => {
1285
+ if (settled) return;
1286
+ settled = true;
1287
+ if (idleTimer !== void 0) clearTimeout(idleTimer);
1288
+ if (options.signal) options.signal.removeEventListener("abort", onAbort);
1289
+ stampAgentMeta(result.snapshot);
1290
+ stampMessages(result.snapshot);
1291
+ if ("persistedSnapshot" in result) {
1292
+ stampAgentMeta(result.persistedSnapshot);
1293
+ stampMessages(result.persistedSnapshot);
1294
+ }
1295
+ onTrace({
1296
+ type: "run.end",
1297
+ ...result
1298
+ });
1299
+ actor.stop();
1300
+ resolvePromise(result);
1301
+ };
1302
+ const onAbort = () => {
1303
+ settle({
1304
+ status: "error",
1305
+ cause: "aborted",
1306
+ error: options.signal?.reason ?? /* @__PURE__ */ new Error("Aborted"),
1307
+ snapshot: actor.getSnapshot()
1308
+ });
1309
+ };
1310
+ const settleIdle = (current) => {
1311
+ warnNonSerializableContext(current);
1312
+ const pendingUserInputs = userInputIsPlaceholder ? collectPendingUserInputs(current) : [];
1313
+ settle({
1314
+ status: "idle",
1315
+ snapshot: current,
1316
+ ...pendingUserInputs.length > 0 ? {
1317
+ pendingUserInputs,
1318
+ persistedSnapshot: actor.getPersistedSnapshot()
1319
+ } : {}
1320
+ });
1321
+ };
1322
+ let interpreting = false;
1323
+ let interpretSeq = 0;
1324
+ const appendToLog = (...items) => {
1325
+ messages.push(...items);
1326
+ if (options.onMessage) {
1327
+ const info = {
1328
+ runId,
1329
+ machineId,
1330
+ machineVersion
1331
+ };
1332
+ for (const item of items) options.onMessage(item, info);
1333
+ }
1334
+ };
1335
+ const runErrorCause = (error) => budgetExceeded ? "max-model-calls" : wrapsDecisionExhausted(error) ? "decision-exhausted" : "machine";
1336
+ const settleInterpretError = (error) => {
1337
+ settle({
1338
+ status: "error",
1339
+ cause: runErrorCause(error),
1340
+ error,
1341
+ snapshot: actor.getSnapshot()
1342
+ });
1343
+ };
1344
+ const passDeps = {
1345
+ getSnapshot: () => actor.getSnapshot(),
1346
+ send: (event) => actor.send(event),
1347
+ isSettled: () => settled,
1348
+ messages,
1349
+ appendToLog,
1350
+ generateText: runCtx.generateText,
1351
+ decide: runCtx.decide ? createCountingDecide(runCtx) : void 0,
1352
+ consumeModelCall,
1353
+ nextRequestId: () => `interpret_${++interpretSeq}`,
1354
+ onTrace,
1355
+ onResult: runCtx.onResult,
1356
+ schemas: runCtx.schemas,
1357
+ signal: options.signal
1358
+ };
1359
+ const maybeInterpret = (snapshot) => {
1360
+ if (!options.getRequests || settled) return false;
1361
+ if (interpreting) return true;
1362
+ let requested;
1363
+ try {
1364
+ requested = options.getRequests(snapshot, { messages });
1365
+ } catch (error) {
1366
+ settleInterpretError(error);
1367
+ return true;
1368
+ }
1369
+ const requests = (Array.isArray(requested) ? requested : requested ? [requested] : []).filter((stateRequest) => Boolean(stateRequest));
1370
+ if (requests.length === 0) return false;
1371
+ interpreting = true;
1372
+ runStateRequestPass(requests, passDeps).then(({ sentAny }) => {
1373
+ if (settled || sentAny) return;
1374
+ const current = actor.getSnapshot();
1375
+ if (isIdleSnapshot(current, { ignoreUserInputChildren: userInputIsPlaceholder })) settleIdle(current);
1376
+ }).catch((error) => settleInterpretError(error)).finally(() => {
1377
+ interpreting = false;
1378
+ if (!settled) scheduleIdleCheck();
1379
+ });
1380
+ return true;
1381
+ };
1382
+ const scheduleIdleCheck = () => {
1383
+ if (idleTimer !== void 0) clearTimeout(idleTimer);
1384
+ idleTimer = setTimeout(() => {
1385
+ idleTimer = void 0;
1386
+ if (settled) return;
1387
+ const current = actor.getSnapshot();
1388
+ if (isIdleSnapshot(current, { ignoreUserInputChildren: userInputIsPlaceholder })) {
1389
+ if (!maybeInterpret(current)) settleIdle(current);
1390
+ }
1391
+ }, 0);
1392
+ };
1393
+ actor = (0, xstate.createActor)(boundMachine, {
1394
+ input: options.input,
1395
+ snapshot: effectiveSnapshot,
1396
+ inspect: (event) => {
1397
+ options.inspect?.(event);
1398
+ if (settled || event.type !== "@xstate.transition" || event.actorRef !== actor.ref) return;
1399
+ const snapshot = event.snapshot;
1400
+ onTrace({
1401
+ type: "machine.transition",
1402
+ snapshot,
1403
+ event: event.event
1404
+ });
1405
+ options.onTransition?.(snapshot, event.event);
1406
+ if (snapshot.status === "done") {
1407
+ settle({
1408
+ status: "done",
1409
+ output: snapshot.output,
1410
+ snapshot
1411
+ });
1412
+ return;
1413
+ }
1414
+ if (snapshot.status === "error") {
1415
+ settle({
1416
+ status: "error",
1417
+ cause: runErrorCause(snapshot.error),
1418
+ error: snapshot.error,
1419
+ snapshot
1420
+ });
1421
+ return;
1422
+ }
1423
+ if (snapshot.status === "stopped") {
1424
+ settle({
1425
+ status: "error",
1426
+ cause: "stopped",
1427
+ error: /* @__PURE__ */ new Error("Actor stopped externally."),
1428
+ snapshot
1429
+ });
1430
+ return;
1431
+ }
1432
+ if (!deliveringResumeEvent && isSuspended(snapshot) && isIdleSnapshot(snapshot, { ignoreUserInputChildren: userInputIsPlaceholder })) {
1433
+ if (!maybeInterpret(snapshot)) settleIdle(snapshot);
1434
+ return;
1435
+ }
1436
+ scheduleIdleCheck();
1437
+ }
1438
+ });
1439
+ actorHolder.actorRef = actor;
1440
+ actor.subscribe({ error: () => {} });
1441
+ actor.on("*", (event) => {
1442
+ onTrace({
1443
+ type: "emit",
1444
+ event
1445
+ });
1446
+ });
1447
+ for (const [type, handler] of Object.entries(options.on ?? {})) if (typeof handler === "function") actor.on(type, handler);
1448
+ if (options.signal) {
1449
+ if (options.signal.aborted) {
1450
+ settle({
1451
+ status: "error",
1452
+ cause: "aborted",
1453
+ error: options.signal.reason ?? /* @__PURE__ */ new Error("Aborted"),
1454
+ snapshot: actor.getSnapshot()
1455
+ });
1456
+ return;
1457
+ }
1458
+ options.signal.addEventListener("abort", onAbort);
1459
+ }
1460
+ onTrace({
1461
+ type: "run.start",
1462
+ ...options.input !== void 0 ? { input: options.input } : {},
1463
+ ...effectiveSnapshot !== void 0 ? { snapshot: effectiveSnapshot } : {},
1464
+ ...options.event !== void 0 ? { event: options.event } : {}
1465
+ });
1466
+ actor.start();
1467
+ if (options.event) {
1468
+ deliveringResumeEvent = false;
1469
+ actor.send(options.event);
1470
+ }
1471
+ });
1472
+ }
1473
+ /**
1474
+ * Runs an agent machine to a **final state** and returns its output, for
1475
+ * run-to-done flows where an idle pause is unexpected. Wraps {@link runAgent}:
1476
+ *
1477
+ * - `done` → resolves with `result.output` (the machine's `OutputFrom`).
1478
+ * - `idle` → throws {@link AgentIdleError} carrying the idle snapshot and the
1479
+ * event types that could resume it.
1480
+ * - `error` → throws `result.error` when it is an `Error`; otherwise wraps it
1481
+ * in an `Error` whose `.cause` is the {@link RunAgentErrorCause} and whose
1482
+ * `.error` is the raw thrown value.
1483
+ *
1484
+ * Use {@link runAgent} directly when idle is an expected outcome you handle
1485
+ * (human-in-the-loop, resumable flows); use `runAgentToCompletion` when the
1486
+ * machine is meant to run straight through to a final state.
1487
+ */
1488
+ async function runAgentToCompletion(machine, options) {
1489
+ const result = await runAgent(machine, options);
1490
+ if (result.status === "done") return result.output;
1491
+ if (result.status === "idle") {
1492
+ const acceptedTypes = require_decision.getAcceptedEvents(result.snapshot, { schemas: require_decision.getRegisteredAgentExecutionOptions(machine).schemas }).map((descriptor) => descriptor.type);
1493
+ throw new AgentIdleError(result.snapshot, acceptedTypes);
1494
+ }
1495
+ if (result.error instanceof Error) throw result.error;
1496
+ const wrapped = /* @__PURE__ */ new Error(`runAgentToCompletion: run failed with cause '${result.cause}'.`);
1497
+ wrapped.cause = result.cause;
1498
+ wrapped.error = result.error;
1499
+ throw wrapped;
1500
+ }
1501
+ /**
1502
+ * Wraps a `(snapshot, actorRef) => void` handler into a function usable as
1503
+ * {@link RunAgentOptions.inspect}: it filters the raw inspection stream to
1504
+ * `@xstate.transition` events and hands the handler the typed
1505
+ * {@link AnyMachineSnapshot} and the {@link InspectedActorRef} that
1506
+ * transitioned. Attribute a child actor via `actorRef.id`/`actorRef.src`. Saves
1507
+ * the manual `event.type === '@xstate.transition'` filtering and the snapshot/
1508
+ * actorRef casts.
1509
+ */
1510
+ function inspectTransitions(handler) {
1511
+ return (inspectionEvent) => {
1512
+ if (inspectionEvent.type !== "@xstate.transition") return;
1513
+ handler(inspectionEvent.snapshot, inspectionEvent.actorRef);
1514
+ };
1515
+ }
1516
+ function isIdleSnapshot(snapshot, { ignoreUserInputChildren }) {
1517
+ if (snapshot.status !== "active") return false;
1518
+ if (Object.values(snapshot.children ?? {}).some((child) => {
1519
+ const ref = child;
1520
+ if (ignoreUserInputChildren && ref?.src === "agent.userInput") return false;
1521
+ return ref?.getSnapshot?.()?.status === "active";
1522
+ })) return false;
1523
+ return !(0, xstate.getNextTransitions)(snapshot).some((transitionDef) => transitionDef.eventType === "" || transitionDef.eventType.startsWith("xstate.after"));
1524
+ }
1525
+ function collectPendingUserInputs(snapshot) {
1526
+ const pending = [];
1527
+ for (const [id, child] of Object.entries(snapshot.children ?? {})) {
1528
+ const ref = child;
1529
+ if (ref?.src !== "agent.userInput") continue;
1530
+ const childSnapshot = ref.getSnapshot?.();
1531
+ if (childSnapshot?.status !== "active") continue;
1532
+ pending.push({
1533
+ id,
1534
+ input: childSnapshot.input
1535
+ });
1536
+ }
1537
+ return pending;
1538
+ }
1539
+ //#endregion
1540
+ Object.defineProperty(exports, "AgentIdleError", {
1541
+ enumerable: true,
1542
+ get: function() {
1543
+ return AgentIdleError;
1544
+ }
1545
+ });
1546
+ Object.defineProperty(exports, "IllegalResumeEventError", {
1547
+ enumerable: true,
1548
+ get: function() {
1549
+ return IllegalResumeEventError;
1550
+ }
1551
+ });
1552
+ Object.defineProperty(exports, "SnapshotVersionMismatchError", {
1553
+ enumerable: true,
1554
+ get: function() {
1555
+ return SnapshotVersionMismatchError;
1556
+ }
1557
+ });
1558
+ Object.defineProperty(exports, "appendMessages", {
1559
+ enumerable: true,
1560
+ get: function() {
1561
+ return appendMessages;
1562
+ }
1563
+ });
1564
+ Object.defineProperty(exports, "createAgentSchemas", {
1565
+ enumerable: true,
1566
+ get: function() {
1567
+ return createAgentSchemas;
1568
+ }
1569
+ });
1570
+ Object.defineProperty(exports, "inspectTransitions", {
1571
+ enumerable: true,
1572
+ get: function() {
1573
+ return inspectTransitions;
1574
+ }
1575
+ });
1576
+ Object.defineProperty(exports, "messagesSchema", {
1577
+ enumerable: true,
1578
+ get: function() {
1579
+ return messagesSchema;
1580
+ }
1581
+ });
1582
+ Object.defineProperty(exports, "runAgent", {
1583
+ enumerable: true,
1584
+ get: function() {
1585
+ return runAgent;
1586
+ }
1587
+ });
1588
+ Object.defineProperty(exports, "runAgentToCompletion", {
1589
+ enumerable: true,
1590
+ get: function() {
1591
+ return runAgentToCompletion;
1592
+ }
1593
+ });
1594
+ Object.defineProperty(exports, "setupAgent", {
1595
+ enumerable: true,
1596
+ get: function() {
1597
+ return setupAgent;
1598
+ }
1599
+ });