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

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