@statelyai/agent 2.0.0-alpha.22 → 2.0.0-alpha.24

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 (48) hide show
  1. package/dist/ai-sdk.cjs +53 -25
  2. package/dist/ai-sdk.d.cts +20 -12
  3. package/dist/ai-sdk.d.mts +20 -12
  4. package/dist/ai-sdk.mjs +53 -25
  5. package/dist/{decision-DxSTqzgZ.mjs → decision-BBZ2jMO1.mjs} +444 -79
  6. package/dist/{decision-1o45_ZrS.cjs → decision-Cv6SfNWl.cjs} +525 -94
  7. package/dist/index.cjs +2224 -1032
  8. package/dist/index.d.cts +413 -275
  9. package/dist/index.d.mts +413 -275
  10. package/dist/index.mjs +2163 -983
  11. package/dist/machines.cjs +30 -2
  12. package/dist/machines.d.cts +1 -1
  13. package/dist/machines.d.mts +1 -1
  14. package/dist/machines.mjs +30 -2
  15. package/dist/openai.cjs +447 -0
  16. package/dist/openai.d.cts +177 -0
  17. package/dist/openai.d.mts +177 -0
  18. package/dist/openai.mjs +437 -0
  19. package/dist/otel.cjs +3 -6
  20. package/dist/otel.d.cts +1 -1
  21. package/dist/otel.d.mts +1 -1
  22. package/dist/otel.mjs +3 -6
  23. package/dist/run-agent-Ck7Sa3Tb.d.mts +968 -0
  24. package/dist/run-agent-DWqA8KiI.d.cts +968 -0
  25. package/dist/setup-agent-CeO2fARv.mjs +639 -0
  26. package/dist/setup-agent-Dl2VELLi.cjs +663 -0
  27. package/dist/{text-logic-BaxPrcLk.d.cts → text-logic-C7bSnH_B.d.cts} +195 -44
  28. package/dist/{text-logic-DhfFWzu9.d.mts → text-logic-DJBK3LbG.d.mts} +195 -44
  29. package/dist/{types-DSdj2tGs.d.cts → types-CjHk5OdH.d.cts} +4 -19
  30. package/dist/{types-CvWRGFxP.d.mts → types-DWA6X9R-.d.mts} +4 -19
  31. package/package.json +17 -21
  32. package/readme.md +32 -17
  33. package/dist/errors-BQRk9eiZ.d.cts +0 -19
  34. package/dist/errors-C9rxnWbX.d.mts +0 -19
  35. package/dist/errors-CeSXQx0v.mjs +0 -23
  36. package/dist/errors-DUBBzRLP.cjs +0 -28
  37. package/dist/event-log-store-Bz7HDBkE.d.cts +0 -145
  38. package/dist/event-log-store-DmIDosD6.mjs +0 -427
  39. package/dist/event-log-store-a_TKy1gk.cjs +0 -468
  40. package/dist/event-log-store-hrA1vqtN.d.mts +0 -145
  41. package/dist/run-agent-0fpEZ1wJ.d.mts +0 -1098
  42. package/dist/run-agent-Zbkx7XP8.d.cts +0 -1098
  43. package/dist/setup-agent-DkCTy5Eu.cjs +0 -1707
  44. package/dist/setup-agent-nSFYrNTP.mjs +0 -1587
  45. package/dist/sqlite.cjs +0 -129
  46. package/dist/sqlite.d.cts +0 -57
  47. package/dist/sqlite.d.mts +0 -57
  48. package/dist/sqlite.mjs +0 -127
@@ -0,0 +1,639 @@
1
+ import { A as userInputActor, L as machineIdlePredicates, N as getAgentExecutionOptions, R as missingActor, b as createTextLogic, et as validateSchemaSync, g as USER_INPUT_ACTOR, n as createDecideActor, nt as agentMessagesEventSchema, p as DECIDE_ACTOR, rt as appendMessages, tt as AGENT_MESSAGES_EVENT_TYPE, y as builtinTextActors, z as setAgentExecutionOptions } from "./decision-BBZ2jMO1.mjs";
2
+ import { createMachineFromConfig, setup } from "xstate";
3
+ //#region src/usage.ts
4
+ /** Reserved event delivered after a model call reports token usage. */
5
+ const AGENT_USAGE_EVENT_TYPE = "@agent.usage";
6
+ //#endregion
7
+ //#region src/workflow-config.ts
8
+ /**
9
+ * The machines-as-data lowering: `setupAgent(...).fromConfig(config, options)`.
10
+ *
11
+ * Takes a serializable `AgentWorkflowConfig` (the JSON form of an agent
12
+ * machine — published schema at `schemas/agent-workflow.json`, docs at
13
+ * docs/machines-as-data.md), compiles its embedded JSON Schemas with the
14
+ * host-provided `compileSchema`, resolves named guards/actions/actors from
15
+ * `options`, and lowers the whole thing to an ordinary XState machine plus its
16
+ * schema pack. This is what makes LLM-generated and stored-as-JSON machines
17
+ * first-class: the config validates against the shipped schema before any
18
+ * model call, and the resulting machine lints, simulates, and runs like a
19
+ * hand-authored one.
20
+ */
21
+ const DECIDE_SRC = "agent.decide";
22
+ const workflowConfigWholeExpressionPattern = /^\{\{\s*([\s\S]*?)\s*\}\}$/;
23
+ const workflowConfigTemplateExpressionPattern = /\{\{\s*([\s\S]*?)\s*\}\}/g;
24
+ const workflowConfigHasTemplatePattern = /\{\{[\s\S]*?\}\}/;
25
+ function toArray(value) {
26
+ return Array.isArray(value) ? value : [value];
27
+ }
28
+ function evaluateWorkflowConfigPath(expression, scope) {
29
+ const parts = expression.trim().split(".").filter(Boolean);
30
+ let current = scope;
31
+ for (const part of parts) {
32
+ if (!current || typeof current !== "object") return;
33
+ current = current[part];
34
+ }
35
+ return current;
36
+ }
37
+ function evaluateWorkflowConfigValue(value, scope) {
38
+ if (typeof value === "string") {
39
+ const wholeMatch = value.match(workflowConfigWholeExpressionPattern);
40
+ if (wholeMatch?.[1]) return evaluateWorkflowConfigPath(wholeMatch[1], scope);
41
+ return value.replace(workflowConfigTemplateExpressionPattern, (_match, expression) => {
42
+ const resolved = evaluateWorkflowConfigPath(expression, scope);
43
+ return resolved === void 0 || resolved === null ? "" : String(resolved);
44
+ });
45
+ }
46
+ if (Array.isArray(value)) return value.map((item) => evaluateWorkflowConfigValue(item, scope));
47
+ if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, evaluateWorkflowConfigValue(item, scope)]));
48
+ return value;
49
+ }
50
+ function createSchemasFromWorkflowConfig(config, compileSchema) {
51
+ return createAgentSchemas({
52
+ context: compileSchema(config.schemas?.context ?? { type: "object" }, "context"),
53
+ events: Object.fromEntries(Object.entries(config.schemas?.events ?? {}).map(([key, schema]) => [key, compileSchema(schema, `event.${key}`)])),
54
+ emitted: Object.fromEntries(Object.entries(config.schemas?.emitted ?? {}).map(([key, schema]) => [key, compileSchema(schema, `emitted.${key}`)])),
55
+ input: compileSchema(config.schemas?.input ?? {}, "input"),
56
+ output: compileSchema(config.schemas?.output ?? {}, "output"),
57
+ meta: compileSchema(config.schemas?.meta ?? {}, "meta")
58
+ });
59
+ }
60
+ function createRequestsFromWorkflowConfig(config, compileSchema) {
61
+ const resolver = (value) => value === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(value, { input });
62
+ return Object.fromEntries(Object.entries(config.requests ?? {}).map(([key, request]) => [key, {
63
+ mode: request.mode,
64
+ description: request.description,
65
+ schemas: {
66
+ input: compileSchema(request.input, `${key}.input`),
67
+ output: compileSchema(request.output, `${key}.output`)
68
+ },
69
+ model: ({ input }) => String(evaluateWorkflowConfigValue(request.model, { input }) ?? ""),
70
+ system: resolver(request.system),
71
+ prompt: resolver(request.prompt),
72
+ messages: resolver(request.messages),
73
+ tools: request.tools,
74
+ toolChoice: request.toolChoice,
75
+ includeReasoning: request.includeReasoning,
76
+ temperature: resolver(request.temperature),
77
+ maxOutputTokens: resolver(request.maxOutputTokens),
78
+ topP: resolver(request.topP),
79
+ topK: resolver(request.topK),
80
+ seed: resolver(request.seed),
81
+ stopSequences: resolver(request.stopSequences),
82
+ metadata: resolver(request.metadata)
83
+ }]));
84
+ }
85
+ function createActorPlaceholdersFromWorkflowConfig(config) {
86
+ return Object.fromEntries(Object.keys(config.actors ?? {}).map((key) => [key, missingActor(key)]));
87
+ }
88
+ const AGENT_EXPRESSION_LANG = "agent-template";
89
+ function containsTemplateExpression(value) {
90
+ if (typeof value === "string") return workflowConfigHasTemplatePattern.test(value);
91
+ if (Array.isArray(value)) return value.some(containsTemplateExpression);
92
+ if (value && typeof value === "object") return Object.values(value).some(containsTemplateExpression);
93
+ return false;
94
+ }
95
+ function toWorkflowExpression(value) {
96
+ if (!containsTemplateExpression(value)) return value;
97
+ return { "@expr": JSON.stringify(value) };
98
+ }
99
+ function createWorkflowConfigEvaluator(contextSchema) {
100
+ const decoded = /* @__PURE__ */ new Map();
101
+ const decode = (source) => {
102
+ if (!decoded.has(source)) decoded.set(source, JSON.parse(source));
103
+ return decoded.get(source);
104
+ };
105
+ return ({ source, slot, scope }) => {
106
+ const value = decode(source);
107
+ if (slot === "context") return validateSchemaSync(contextSchema, evaluateWorkflowConfigValue(value, { input: scope.input }));
108
+ return evaluateWorkflowConfigValue(value, {
109
+ context: scope.context,
110
+ event: scope.event,
111
+ input: scope.input
112
+ });
113
+ };
114
+ }
115
+ function translateWorkflowGuard(guard, translation, location) {
116
+ if (guard === void 0) return;
117
+ if (typeof guard === "string") {
118
+ if (workflowConfigHasTemplatePattern.test(guard)) return { "@expr": JSON.stringify(guard) };
119
+ if (!(guard in translation.guards)) throw new Error(`setupAgent.fromConfig: ${location} references guard '${guard}', which has no implementation. Provide one via fromConfig options: setupAgent.fromConfig(config, { guards: { '${guard}': ({ context, event }) => ... } }).`);
120
+ return { type: guard };
121
+ }
122
+ if (typeof guard === "function") {
123
+ const name = `__fromConfigGuard${Object.keys(translation.syntheticGuards).length}`;
124
+ translation.syntheticGuards[name] = guard;
125
+ return { type: name };
126
+ }
127
+ throw new Error(`setupAgent.fromConfig: ${location} has an unsupported guard value. Use a '{{ ... }}' template string, a named guard reference (string), or a function.`);
128
+ }
129
+ function translateWorkflowAction(action, translation, location) {
130
+ if (action.assign !== void 0) return {
131
+ type: "@xstate.assign",
132
+ context: toWorkflowExpression(action.assign)
133
+ };
134
+ if (action.emit !== void 0) return {
135
+ type: "@xstate.emit",
136
+ event: toWorkflowExpression(action.emit)
137
+ };
138
+ if (action.type) {
139
+ if (!(action.type in translation.actions)) throw new Error(`setupAgent.fromConfig: ${location} uses named action type '${action.type}', which has no implementation. Provide one via fromConfig options: setupAgent.fromConfig(config, { actions: { '${action.type}': (params) => ... } }).`);
140
+ return {
141
+ type: action.type,
142
+ ...action.params !== void 0 ? { params: toWorkflowExpression(action.params) } : {}
143
+ };
144
+ }
145
+ throw new Error(`setupAgent.fromConfig: ${location} action must declare 'assign', 'emit', or 'type'.`);
146
+ }
147
+ function translateWorkflowTransition(transitionConfig, translation, location) {
148
+ const actionConfigs = transitionConfig.actions ? toArray(transitionConfig.actions) : [];
149
+ const assignConfigs = [...transitionConfig.assign !== void 0 ? [transitionConfig.assign] : [], ...actionConfigs.filter((action) => action.assign !== void 0).map((action) => action.assign)];
150
+ const contextPatch = assignConfigs.length ? toWorkflowExpression(Object.assign({}, ...assignConfigs)) : void 0;
151
+ const actions = actionConfigs.filter((action) => action.assign === void 0).map((action) => translateWorkflowAction(action, translation, location));
152
+ const guard = translateWorkflowGuard(transitionConfig.guard, translation, location);
153
+ return {
154
+ ...transitionConfig.target !== void 0 ? { target: transitionConfig.target } : {},
155
+ ...guard ? { guard } : {},
156
+ ...contextPatch !== void 0 ? { context: contextPatch } : {},
157
+ ...actions.length ? { actions } : {},
158
+ ...transitionConfig.description !== void 0 ? { description: transitionConfig.description } : {},
159
+ ...transitionConfig.reenter !== void 0 ? { reenter: transitionConfig.reenter } : {},
160
+ ...transitionConfig.meta !== void 0 ? { meta: transitionConfig.meta } : {}
161
+ };
162
+ }
163
+ function translateWorkflowTransitions(transitionConfig, translation, location) {
164
+ if (!transitionConfig) return;
165
+ return Array.isArray(transitionConfig) ? transitionConfig.map((candidate) => translateWorkflowTransition(candidate, translation, location)) : translateWorkflowTransition(transitionConfig, translation, location);
166
+ }
167
+ function addTransitionMatch(transition, matches) {
168
+ if (Array.isArray(transition)) return transition.map((candidate) => addTransitionMatch(candidate, matches));
169
+ return transition ? {
170
+ ...transition,
171
+ matches: {
172
+ ...transition.matches,
173
+ ...matches
174
+ }
175
+ } : void 0;
176
+ }
177
+ function translateWorkflowInvoke(invokeConfig, translation, stateKey) {
178
+ if (invokeConfig.src === DECIDE_SRC && invokeConfig.onDone !== void 0) throw new Error(`setupAgent.fromConfig: state '${stateKey}' declares an 'onDone' on its 'agent.decide' invoke, which is always a config error. A decision has no output of its own — the chosen event is delivered automatically and handled by the state's 'on' transitions. Remove the 'onDone' (use 'on' for the chosen event; 'onError' still handles retries exhausted).`);
179
+ const location = `state '${stateKey}'`;
180
+ return {
181
+ ...invokeConfig.id !== void 0 ? { id: invokeConfig.id } : {},
182
+ src: invokeConfig.src,
183
+ ...invokeConfig.input !== void 0 ? { input: toWorkflowExpression(invokeConfig.input) } : {},
184
+ ...invokeConfig.onDone !== void 0 ? { onDone: translateWorkflowTransitions(invokeConfig.onDone, translation, location) } : {},
185
+ ...invokeConfig.onError !== void 0 ? { onError: translateWorkflowTransitions(invokeConfig.onError, translation, location) } : {}
186
+ };
187
+ }
188
+ function assertValidTransitionTargets(stateKey, location, transitionConfig, siblingKeys, declaredTargets) {
189
+ if (!transitionConfig) return;
190
+ for (const transition of toArray(transitionConfig)) {
191
+ const targets = transition.target === void 0 ? [] : toArray(transition.target);
192
+ for (const target of targets) {
193
+ if (typeof target !== "string") continue;
194
+ declaredTargets.push(target);
195
+ if (target.startsWith("#") || target.startsWith(".")) continue;
196
+ const head = target.split(".")[0];
197
+ if (!siblingKeys.has(head)) throw new Error(`setupAgent.fromConfig: state '${stateKey}' has a ${location} transition targeting '${target}', which is not a state at that level. Valid targets: ${[...siblingKeys].join(", ") || "(none)"}.`);
198
+ }
199
+ }
200
+ }
201
+ function assertStateTransitionTargets(stateKey, stateConfig, siblingKeys) {
202
+ const declaredTargets = [];
203
+ const invokes = stateConfig.invoke ? toArray(stateConfig.invoke) : [];
204
+ const sources = [
205
+ ...Object.entries(stateConfig.on ?? {}).map(([eventType, transition]) => [`'on.${eventType}'`, transition]),
206
+ ...Object.entries(stateConfig.after ?? {}).map(([delay, transition]) => [`'after.${delay}'`, transition]),
207
+ ["'always'", stateConfig.always],
208
+ ["'onDone'", stateConfig.onDone],
209
+ ["'choice'", stateConfig.choice],
210
+ ...invokes.flatMap((invoke) => [["invoke 'onDone'", invoke.onDone], ["invoke 'onError'", invoke.onError]])
211
+ ];
212
+ for (const [location, transition] of sources) assertValidTransitionTargets(stateKey, location, transition, siblingKeys, declaredTargets);
213
+ return declaredTargets;
214
+ }
215
+ function translateWorkflowState(stateKey, stateConfig, siblingKeys, path, translation) {
216
+ const location = `state '${stateKey}'`;
217
+ if (stateKey.includes(".")) throw new Error(`setupAgent.fromConfig: state key '${stateKey}' contains a '.', which is reserved as the state-path separator. Rename the state (e.g. '${stateKey.replace(/\./g, "_")}').`);
218
+ const childKeys = new Set(Object.keys(stateConfig.states ?? {}));
219
+ const childPath = [...path, stateKey];
220
+ translation.transitionTargets[childPath.join(".")] = assertStateTransitionTargets(stateKey, stateConfig, siblingKeys);
221
+ const doneStateId = stateConfig.onDone !== void 0 ? `@state.${childPath.join(".")}` : void 0;
222
+ const translatedOn = {
223
+ ...Object.fromEntries(Object.entries(stateConfig.on ?? {}).map(([eventType, transitionConfig]) => [eventType, translateWorkflowTransitions(transitionConfig, translation, location)])),
224
+ ...doneStateId ? { "xstate.done.state": addTransitionMatch(translateWorkflowTransitions(stateConfig.onDone, translation, location), { stateId: doneStateId }) } : {}
225
+ };
226
+ return {
227
+ ...stateConfig.description !== void 0 ? { description: stateConfig.description } : {},
228
+ ...stateConfig.type !== void 0 ? { type: stateConfig.type } : {},
229
+ ...doneStateId ? { id: doneStateId } : {},
230
+ ...stateConfig.initial !== void 0 ? { initial: stateConfig.initial } : {},
231
+ ...stateConfig.states !== void 0 ? { states: Object.fromEntries(Object.entries(stateConfig.states).map(([key, child]) => [key, translateWorkflowState(key, child, childKeys, childPath, translation)])) } : {},
232
+ ...stateConfig.choice !== void 0 ? { choice: toArray(stateConfig.choice).map((branch) => {
233
+ if (branch.actions !== void 0) throw new Error(`setupAgent.fromConfig: state '${stateKey}' has a 'choice' branch with 'actions', which is not supported. Use 'assign' on the branch, or move the actions to the target state's 'entry'.`);
234
+ const when = translateWorkflowGuard(branch.guard, translation, location);
235
+ return {
236
+ ...when ? { when } : {},
237
+ target: branch.target,
238
+ ...branch.assign !== void 0 ? { context: toWorkflowExpression(branch.assign) } : {},
239
+ ...branch.description !== void 0 ? { description: branch.description } : {},
240
+ ...branch.reenter !== void 0 ? { reenter: branch.reenter } : {},
241
+ ...branch.meta !== void 0 ? { meta: branch.meta } : {}
242
+ };
243
+ }) } : {},
244
+ ...stateConfig.invoke !== void 0 ? { invoke: Array.isArray(stateConfig.invoke) ? stateConfig.invoke.map((invoke) => translateWorkflowInvoke(invoke, translation, stateKey)) : translateWorkflowInvoke(stateConfig.invoke, translation, stateKey) } : {},
245
+ ...Object.keys(translatedOn).length ? { on: translatedOn } : {},
246
+ ...stateConfig.always !== void 0 ? { always: translateWorkflowTransitions(stateConfig.always, translation, location) } : {},
247
+ ...stateConfig.after !== void 0 ? { after: Object.fromEntries(Object.entries(stateConfig.after).map(([delay, transitionConfig]) => [delay, translateWorkflowTransitions(transitionConfig, translation, location)])) } : {},
248
+ ...stateConfig.entry !== void 0 ? { entry: toArray(stateConfig.entry).map((action) => translateWorkflowAction(action, translation, location)) } : {},
249
+ ...stateConfig.exit !== void 0 ? { exit: toArray(stateConfig.exit).map((action) => translateWorkflowAction(action, translation, location)) } : {},
250
+ ...stateConfig.tags !== void 0 ? { tags: stateConfig.tags } : {},
251
+ ...stateConfig.output !== void 0 ? { output: toWorkflowExpression(stateConfig.output) } : {},
252
+ ...stateConfig.meta !== void 0 ? { meta: stateConfig.meta } : {}
253
+ };
254
+ }
255
+ function collectTranslatedFinalOutputs(states, outputs = []) {
256
+ for (const state of Object.values(states ?? {})) {
257
+ if (state?.type === "final" && state.output !== void 0) outputs.push(state.output);
258
+ collectTranslatedFinalOutputs(state?.states, outputs);
259
+ }
260
+ return outputs;
261
+ }
262
+ function translateWorkflowConfig(config, translation) {
263
+ const rootKeys = new Set(Object.keys(config.states));
264
+ const states = Object.fromEntries(Object.entries(config.states).map(([key, state]) => [key, translateWorkflowState(key, state, rootKeys, [], translation)]));
265
+ const json = {
266
+ "@exprLang": AGENT_EXPRESSION_LANG,
267
+ ...config.id !== void 0 ? { id: config.id } : {},
268
+ ...config.description !== void 0 ? { description: config.description } : {},
269
+ ...config.context !== void 0 ? { context: { "@expr": JSON.stringify(config.context) } } : {},
270
+ initial: config.initial,
271
+ states,
272
+ ...config.meta !== void 0 ? { meta: config.meta } : {}
273
+ };
274
+ const finalOutputs = collectTranslatedFinalOutputs(states);
275
+ if (json.output === void 0 && finalOutputs.length === 1) json.output = finalOutputs[0];
276
+ return json;
277
+ }
278
+ function collectDeclaredStateTags(states, tags = /* @__PURE__ */ new Set()) {
279
+ for (const state of Object.values(states ?? {})) {
280
+ for (const tag of state.tags ?? []) tags.add(tag);
281
+ collectDeclaredStateTags(state.states, tags);
282
+ }
283
+ return tags;
284
+ }
285
+ function resolveIdlePredicate(config, options) {
286
+ if (options.isIdle) return options.isIdle;
287
+ const idleTags = config.idleTags ?? [];
288
+ if (!idleTags.length) return;
289
+ const declaredTags = collectDeclaredStateTags(config.states);
290
+ const unknown = idleTags.filter((tag) => !declaredTags.has(tag));
291
+ if (unknown.length) throw new Error(`setupAgent.fromConfig: 'idleTags' lists ${unknown.map((tag) => `'${tag}'`).join(", ")}, which no state declares in its 'tags'. Tag the waiting state(s) — e.g. "tags": ["${unknown[0]}"] — or remove the entry.`);
292
+ return (snapshot) => idleTags.some((tag) => snapshot.hasTag(tag));
293
+ }
294
+ function setupAgentFromConfig(config, options) {
295
+ 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.");
296
+ const { compileSchema } = options;
297
+ const schemas = createSchemasFromWorkflowConfig(config, compileSchema);
298
+ const requestActors = createRequestActors(createRequestsFromWorkflowConfig(config, compileSchema));
299
+ const actors = createAgentActors(createActorPlaceholdersFromWorkflowConfig(config), requestActors);
300
+ const translation = {
301
+ guards: options.guards ?? {},
302
+ actions: options.actions ?? {},
303
+ syntheticGuards: {},
304
+ transitionTargets: {}
305
+ };
306
+ const machine = createMachineFromConfig(translateWorkflowConfig(config, translation), {
307
+ guards: Object.fromEntries(Object.entries({
308
+ ...translation.guards,
309
+ ...translation.syntheticGuards
310
+ }).map(([name, implementation]) => [name, (args) => Boolean(implementation({
311
+ context: args.context,
312
+ event: args.event
313
+ }))])),
314
+ ...options.actions ? { actions: options.actions } : {},
315
+ actors: Object.fromEntries(Object.keys(actors).map((key) => [key, key])),
316
+ evaluators: { [AGENT_EXPRESSION_LANG]: createWorkflowConfigEvaluator(schemas.context) }
317
+ }).provide({ actors });
318
+ setAgentExecutionOptions(machine, {
319
+ schemas,
320
+ actors,
321
+ models: {}
322
+ });
323
+ const isIdle = resolveIdlePredicate(config, options);
324
+ if (isIdle && machine.config) machineIdlePredicates.set(machine.config, isIdle);
325
+ return {
326
+ machine,
327
+ schemas
328
+ };
329
+ }
330
+ //#endregion
331
+ //#region src/setup-agent.ts
332
+ const emptyEventSchema = { "~standard": {
333
+ version: 1,
334
+ vendor: "statelyai-agent",
335
+ validate(value) {
336
+ return value !== null && typeof value === "object" && Object.keys(value).length === 0 ? { value: {} } : { issues: [{ message: "Expected an empty event payload" }] };
337
+ }
338
+ } };
339
+ const USAGE_TOKEN_FIELDS = [
340
+ "inputTokens",
341
+ "outputTokens",
342
+ "totalTokens",
343
+ "reasoningTokens",
344
+ "cachedInputTokens"
345
+ ];
346
+ const USAGE_ATTRIBUTION_FIELDS = [
347
+ "id",
348
+ "src",
349
+ "model",
350
+ "name"
351
+ ];
352
+ const USAGE_KINDS = ["text", "decision"];
353
+ /**
354
+ * Standard Schema for the reserved `'@agent.usage'` payload. Hand-rolled (no
355
+ * validation-library dependency in core) and deliberately permissive about
356
+ * unknown fields, so a newer runtime adding an attribution field cannot fail
357
+ * an older machine's validation.
358
+ */
359
+ const agentUsageEventSchema = { "~standard": {
360
+ version: 1,
361
+ vendor: "statelyai-agent",
362
+ validate(value) {
363
+ const issues = [];
364
+ if (!value || typeof value !== "object") return { issues: [{ message: "Expected an '@agent.usage' payload object" }] };
365
+ const event = value;
366
+ const usage = event.usage;
367
+ if (!usage || typeof usage !== "object") issues.push({
368
+ message: "Expected 'usage' to be an object",
369
+ path: ["usage"]
370
+ });
371
+ else for (const field of USAGE_TOKEN_FIELDS) {
372
+ const token = usage[field];
373
+ if (token !== void 0 && (typeof token !== "number" || !Number.isFinite(token))) issues.push({
374
+ message: `Expected a finite number`,
375
+ path: ["usage", field]
376
+ });
377
+ }
378
+ if (event.kind !== void 0 && !USAGE_KINDS.some((kind) => kind === event.kind)) issues.push({
379
+ message: `Expected one of ${USAGE_KINDS.join(", ")}`,
380
+ path: ["kind"]
381
+ });
382
+ for (const field of USAGE_ATTRIBUTION_FIELDS) if (event[field] !== void 0 && typeof event[field] !== "string") issues.push({
383
+ message: "Expected a string",
384
+ path: [field]
385
+ });
386
+ return issues.length > 0 ? { issues } : { value: event };
387
+ }
388
+ } };
389
+ /**
390
+ * Adds the reserved `'@agent.usage'` schema to an authored event map. A
391
+ * user-declared entry under that key is rejected: the `@agent.*` namespace
392
+ * belongs to the library (same rule as the reserved `agent.*` actor keys), and
393
+ * a custom payload schema would silently disagree with what `runAgent`
394
+ * delivers.
395
+ */
396
+ function withAgentUsageEventSchema(events) {
397
+ const declared = events?.[AGENT_USAGE_EVENT_TYPE];
398
+ if (declared !== void 0 && declared !== agentUsageEventSchema) throw new Error(`setupAgent: event type '${AGENT_USAGE_EVENT_TYPE}' is in the reserved '@agent.' namespace and cannot be declared in 'events' — setupAgent registers it for you with the usage payload schema. Remove it from 'events'; to receive it, declare a transition instead: on: { '${AGENT_USAGE_EVENT_TYPE}': … }.`);
399
+ const declaredMessages = events?.[AGENT_MESSAGES_EVENT_TYPE];
400
+ if (declaredMessages !== void 0 && declaredMessages !== agentMessagesEventSchema) throw new Error(`setupAgent: event type '${AGENT_MESSAGES_EVENT_TYPE}' is reserved and cannot be declared in 'events' — setupAgent registers it for you. Add a transition instead: on: { '${AGENT_MESSAGES_EVENT_TYPE}': appendMessages() }.`);
401
+ return {
402
+ ...events,
403
+ [AGENT_USAGE_EVENT_TYPE]: agentUsageEventSchema,
404
+ [AGENT_MESSAGES_EVENT_TYPE]: agentMessagesEventSchema
405
+ };
406
+ }
407
+ function normalizeEventSchemas(events) {
408
+ return Object.fromEntries(Object.entries(events).map(([type, schema]) => [type, schema && typeof schema === "object" && "~standard" in schema ? schema : emptyEventSchema]));
409
+ }
410
+ /**
411
+ * Builds a machine's {@link AgentSchemaPack} from a partial schema
412
+ * declaration — only `context` is required; `events`/`input`/`output`/`meta`
413
+ * default to empty/unknown schemas when omitted. Pass the result as
414
+ * `setupAgent({ schemas })`'s `schemas` (or spread the individual fields
415
+ * directly into `setupAgent({ context, events, ... })` — both forms are
416
+ * accepted).
417
+ */
418
+ function createAgentSchemas(schemas) {
419
+ return {
420
+ context: schemas.context,
421
+ events: normalizeEventSchemas(withAgentUsageEventSchema(schemas.events)),
422
+ input: schemas.input,
423
+ output: schemas.output,
424
+ meta: schemas.meta,
425
+ emitted: schemas.emitted
426
+ };
427
+ }
428
+ /**
429
+ * Schema-first `setup(...)` for agent machines — the standard entry point
430
+ * for authoring a machine (the blueprint) that this library then runs (via
431
+ * {@link runAgent} or the step helpers) against host-supplied model/decision
432
+ * executors. Context, events, machine input, machine output, and
433
+ * state/transition meta are all standard schemas — no `{} as Type` casts —
434
+ * and are retained on `result.schemas` for runtime validation. Also
435
+ * registers the `agent.generateText`/`agent.streamText`/`agent.userInput`/
436
+ * `agent.decide` builtin actors and lowers `requests`/`actors` into the
437
+ * machine's actor sources. The result is the xstate `setup(...)` object with
438
+ * a wrapped `result.createMachine(...)` plus `result.schemas`/`models`/
439
+ * `requests`/`appendMessages` attached. Also has a
440
+ * `setupAgent.fromConfig(...)` namespace member for building a machine from
441
+ * a serializable {@link AgentWorkflowConfig} instead of this TS API.
442
+ *
443
+ * @example
444
+ * ```ts
445
+ * const schemas = createAgentSchemas({
446
+ * context: z.object({ topic: z.string(), joke: z.string().nullable() }),
447
+ * input: z.object({ topic: z.string() }),
448
+ * output: z.object({ joke: z.string() }),
449
+ * });
450
+ *
451
+ * const agent = setupAgent({
452
+ * schemas,
453
+ * actors: { tellJoke },
454
+ * });
455
+ *
456
+ * const jokeMachine = agent.createMachine({
457
+ * context: ({ input }) => ({ topic: input.topic, joke: null }),
458
+ * initial: 'telling',
459
+ * states: {
460
+ * telling: {
461
+ * invoke: {
462
+ * id: 'joke',
463
+ * src: 'tellJoke',
464
+ * input: ({ context }) => ({ topic: context.topic }),
465
+ * onDone: ({ output }) => ({ target: 'done', context: { joke: output } }),
466
+ * },
467
+ * },
468
+ * done: { type: 'final', output: ({ context }) => ({ joke: context.joke ?? '' }) },
469
+ * },
470
+ * });
471
+ * ```
472
+ */
473
+ function setupAgent(config) {
474
+ const schemas = normalizeAgentSchemas(config);
475
+ const requestActors = createRequestActors(config.requests ?? {});
476
+ const actors = createAgentActors(config.actors, requestActors);
477
+ const base = setup({
478
+ schemas: {
479
+ context: schemas.context,
480
+ events: schemas.events,
481
+ input: schemas.input,
482
+ output: schemas.output,
483
+ meta: schemas.meta,
484
+ ...schemas.emitted && Object.keys(schemas.emitted).length > 0 ? { emitted: schemas.emitted } : {}
485
+ },
486
+ ...config.states ? { states: config.states } : {},
487
+ actors,
488
+ actions: config.actions,
489
+ guards: config.guards,
490
+ delays: config.delays
491
+ });
492
+ const createBaseMachine = base.createMachine.bind(base);
493
+ const models = config.models ?? {};
494
+ const machineOptions = {
495
+ schemas,
496
+ actors,
497
+ models
498
+ };
499
+ return Object.assign(base, {
500
+ createMachine(machineConfig) {
501
+ assertStateSchemaKeysExist(config.states, machineConfig?.states);
502
+ const machine = createBaseMachine(withRootOutputFromSingleFinal(machineConfig));
503
+ setAgentExecutionOptions(machine, machineOptions);
504
+ if (config.isIdle) {
505
+ const rootConfig = machine.config;
506
+ if (rootConfig) machineIdlePredicates.set(rootConfig, config.isIdle);
507
+ }
508
+ return machine;
509
+ },
510
+ schemas,
511
+ models,
512
+ requests: requestActors,
513
+ appendMessages
514
+ });
515
+ }
516
+ function collectFinalStateOutputs(states, outputs = []) {
517
+ for (const state of Object.values(states ?? {})) {
518
+ if (state?.type === "final" && state.output !== void 0) outputs.push(state.output);
519
+ collectFinalStateOutputs(state?.states, outputs);
520
+ }
521
+ return outputs;
522
+ }
523
+ function withRootOutputFromSingleFinal(config) {
524
+ if (!config || typeof config !== "object" || "output" in config || !("states" in config)) return config;
525
+ const outputs = collectFinalStateOutputs(config.states);
526
+ return outputs.length === 1 ? {
527
+ ...config,
528
+ output: outputs[0]
529
+ } : config;
530
+ }
531
+ (function(_setupAgent) {
532
+ function fromConfig(config, options) {
533
+ return setupAgentFromConfig(config, options);
534
+ }
535
+ _setupAgent.fromConfig = fromConfig;
536
+ })(setupAgent || (setupAgent = {}));
537
+ /**
538
+ * The schema pack a machine was built with — `setupAgent(...).createMachine`
539
+ * and `setupAgent.fromConfig(...)` both register one, so hosts can read a
540
+ * machine's input/event schemas at runtime without knowing how it was
541
+ * authored. Returns `undefined` for machines not built by either (a plain
542
+ * xstate `createMachine`/`setup` machine).
543
+ *
544
+ * Registration also travels through `machine.provide(...)`: the pack is keyed
545
+ * on the machine's root `config`, which `.provide` shares by reference.
546
+ */
547
+ function getAgentSchemas(machine) {
548
+ return getAgentExecutionOptions(machine)?.schemas;
549
+ }
550
+ /** Builds one TextLogic actor per `setupAgent({ requests })` entry. @internal */
551
+ function createRequestActors(requests) {
552
+ return Object.fromEntries(Object.entries(requests).map(([key, request]) => {
553
+ return [key, createTextLogic({
554
+ ...request,
555
+ name: key,
556
+ mode: request.mode ?? "generate"
557
+ })];
558
+ }));
559
+ }
560
+ function normalizeAgentSchemas(config) {
561
+ if ("schemas" in config && config.schemas) return {
562
+ ...config.schemas,
563
+ events: normalizeEventSchemas(withAgentUsageEventSchema(config.schemas.events))
564
+ };
565
+ const loose = config;
566
+ return createAgentSchemas({
567
+ ...loose,
568
+ context: loose.context
569
+ });
570
+ }
571
+ /**
572
+ * Runtime guard: every key of the `setupAgent({ states })` schema map must
573
+ * name a real state node in the machine config. A typo'd key is otherwise a
574
+ * silent no-op — the narrowing simply never applies — so fail fast at
575
+ * `createMachine` time. Walks nested `states` maps in parallel with the
576
+ * machine config, since narrowing entries nest the same way.
577
+ */
578
+ function assertStateSchemaKeysExist(stateSchemas, machineStates, path = []) {
579
+ if (!stateSchemas) return;
580
+ for (const [key, stateSchema] of Object.entries(stateSchemas)) {
581
+ const machineState = machineStates?.[key];
582
+ if (!machineState || typeof machineState !== "object") {
583
+ const validKeys = Object.keys(machineStates ?? {});
584
+ const parent = path.length > 0 ? ` of state '${path.join(".")}'` : "";
585
+ throw new Error(`setupAgent: 'states' key '${[...path, key].join(".")}' does not name a state in the machine config, so its state schema would silently never apply. Valid child states${parent}: ${validKeys.join(", ") || "(none)"}. Fix the key to match a state in createMachine({ states }), or remove it from setupAgent({ states }).`);
586
+ }
587
+ if (stateSchema && typeof stateSchema === "object" && "states" in stateSchema && stateSchema.states) assertStateSchemaKeysExist(stateSchema.states, machineState.states, [...path, key]);
588
+ }
589
+ }
590
+ const RESERVED_AGENT_ACTOR_KEYS = [
591
+ ...Object.keys(builtinTextActors),
592
+ USER_INPUT_ACTOR,
593
+ DECIDE_ACTOR
594
+ ];
595
+ /**
596
+ * The whole `agent.` actor-source namespace is reserved for the library, not
597
+ * just the shipped builtins: a key starting with this prefix is rejected at
598
+ * setup time so a future builtin can never collide with (or be shadowed by) a
599
+ * user source. Name your own sources without it.
600
+ */
601
+ const RESERVED_AGENT_KEY_PREFIX = "agent.";
602
+ /**
603
+ * Runtime guards over the user-supplied `actors`/`requests` keys, in one walk
604
+ * of both groups:
605
+ *
606
+ * 1. A key in the reserved `agent.` namespace is rejected — every key with
607
+ * that prefix, not only today's builtins. Without this, the builtins-first
608
+ * spread in {@link createAgentActors} lets such a key overwrite the builtin
609
+ * (`agent.decide`, …) silently, and a builtin added later would start
610
+ * colliding with user code. Deliberate override of a builtin is still
611
+ * possible after the machine is created, via
612
+ * `machine.provide({ actors: { 'agent.decide': ... } })`.
613
+ * 2. A key appearing in BOTH groups is almost certainly a mistake (whichever
614
+ * spread applies last would silently win) — fail fast with a clear message
615
+ * rather than let one implementation shadow another.
616
+ */
617
+ function assertActorKeys(actors, requests) {
618
+ const seenIn = /* @__PURE__ */ new Map();
619
+ const groups = [["actors", actors], ["requests", requests]];
620
+ for (const [groupName, group] of groups) for (const key of Object.keys(group ?? {})) {
621
+ if (RESERVED_AGENT_ACTOR_KEYS.some((reserved) => reserved === 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({ actors: { '${key}': ... } }).`);
622
+ if (key.startsWith(RESERVED_AGENT_KEY_PREFIX)) throw new Error(`setupAgent: '${groupName}' key '${key}' uses the reserved '${RESERVED_AGENT_KEY_PREFIX}' namespace, which belongs to the library (${RESERVED_AGENT_ACTOR_KEYS.join(", ")}, and anything added later). Rename it without the '${RESERVED_AGENT_KEY_PREFIX}' prefix.`);
623
+ const existingGroup = seenIn.get(key);
624
+ if (existingGroup) throw new Error(`setupAgent: key '${key}' is defined in both '${existingGroup}' and '${groupName}'. Each actor source key must be unique across 'actors' and 'requests'.`);
625
+ seenIn.set(key, groupName);
626
+ }
627
+ }
628
+ function createAgentActors(actors, requestActors) {
629
+ assertActorKeys(actors, requestActors);
630
+ return {
631
+ ...builtinTextActors,
632
+ [USER_INPUT_ACTOR]: userInputActor,
633
+ [DECIDE_ACTOR]: createDecideActor(),
634
+ ...actors,
635
+ ...requestActors
636
+ };
637
+ }
638
+ //#endregion
639
+ export { AGENT_USAGE_EVENT_TYPE as i, getAgentSchemas as n, setupAgent as r, createAgentSchemas as t };