@statelyai/agent 2.0.0-alpha.21 → 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-JWx6n3xR.mjs → decision-BBZ2jMO1.mjs} +542 -84
  6. package/dist/{decision-BnTCsuJv.cjs → decision-Cv6SfNWl.cjs} +629 -99
  7. package/dist/index.cjs +2225 -1032
  8. package/dist/index.d.cts +415 -276
  9. package/dist/index.d.mts +415 -276
  10. package/dist/index.mjs +2163 -983
  11. package/dist/machines.cjs +30 -2
  12. package/dist/machines.d.cts +151 -54
  13. package/dist/machines.d.mts +151 -54
  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-Mmbgb2jy.d.cts → text-logic-C7bSnH_B.d.cts} +238 -44
  28. package/dist/{text-logic-BR5twXCv.d.mts → text-logic-DJBK3LbG.d.mts} +238 -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-DBNI8ETM.d.mts +0 -1098
  42. package/dist/run-agent-Do094mGu.d.cts +0 -1098
  43. package/dist/setup-agent-91FSuZbB.cjs +0 -1641
  44. package/dist/setup-agent-DqqdcdNh.mjs +0 -1521
  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
@@ -1,1641 +0,0 @@
1
- const require_errors = require("./errors-DUBBzRLP.cjs");
2
- const require_decision = require("./decision-BnTCsuJv.cjs");
3
- const require_event_log_store = require("./event-log-store-a_TKy1gk.cjs");
4
- require("./validate.cjs");
5
- let xstate = require("xstate");
6
- //#region src/messages.ts
7
- function addMessages(resolve) {
8
- return (args) => {
9
- const resolved = typeof resolve === "function" ? resolve(args) : resolve;
10
- return [...args.context.messages, ...Array.isArray(resolved) ? resolved : [resolved]];
11
- };
12
- }
13
- /**
14
- * Builds a transition-function result that appends one or more
15
- * {@link AgentMessage}s to a context's `messages` array. `resolve` is either
16
- * a message (or array of messages) or a function of `{ context, event }`
17
- * returning them; the returned function is meant to be used directly as (or
18
- * composed into) a transition's result, e.g. `on: { USER_REPLIED:
19
- * agent.appendMessages(({ event }) => userMessage(event.text)) }`. Requires
20
- * `messages: AgentMessage[]` on context — see {@link messagesSchema} for a
21
- * ready-made schema for that field.
22
- *
23
- * @example
24
- * ```ts
25
- * on: {
26
- * USER_REPLIED: appendMessages(({ event }) => userMessage(event.text)),
27
- * }
28
- * ```
29
- */
30
- function appendMessages(resolve) {
31
- return (args) => ({ context: { messages: addMessages(resolve)(args) } });
32
- }
33
- const KNOWN_PART_TYPES = new Set([
34
- "text",
35
- "image",
36
- "file",
37
- "tool-call",
38
- "tool-result"
39
- ]);
40
- function isKnownPart(part) {
41
- return !!part && typeof part === "object" && KNOWN_PART_TYPES.has(part.type);
42
- }
43
- function validatePartsArray(content) {
44
- if (!Array.isArray(content)) return "Expected content to be a string or an array of parts";
45
- for (const part of content) if (!isKnownPart(part)) {
46
- const type = part && typeof part === "object" ? part.type : void 0;
47
- return `Unknown message part type: ${JSON.stringify(type)}`;
48
- }
49
- }
50
- /**
51
- * A {@link StandardSchemaV1} validating an `AgentMessage[]` context field —
52
- * checks that every message has a known `role` (`system`/`user`/`assistant`/
53
- * `tool`) and that `content` is either a string (where the role allows it) or
54
- * an array of parts with a known `type`. Use it directly as a context
55
- * schema's `messages` field when authoring with `createAgentSchemas`.
56
- */
57
- const messagesSchema = { "~standard": {
58
- version: 1,
59
- vendor: "statelyai-agent",
60
- validate(value) {
61
- if (!Array.isArray(value)) return { issues: [{ message: "Expected an array of agent messages" }] };
62
- for (const message of value) {
63
- if (!message || typeof message !== "object") return { issues: [{ message: "Expected an array of agent messages" }] };
64
- const role = message.role;
65
- const content = message.content;
66
- if (role !== "system" && role !== "user" && role !== "assistant" && role !== "tool") return { issues: [{ message: `Unknown message role: ${JSON.stringify(role)}` }] };
67
- if (role === "system") {
68
- if (typeof content !== "string") return { issues: [{ message: "system message content must be a string" }] };
69
- continue;
70
- }
71
- if (role === "tool") {
72
- const error = validatePartsArray(content) ?? (content.some((part) => part.type !== "tool-result") ? "tool message content must contain only tool-result parts" : void 0);
73
- if (error) return { issues: [{ message: error }] };
74
- continue;
75
- }
76
- if (typeof content === "string") continue;
77
- const error = validatePartsArray(content);
78
- if (error) return { issues: [{ message: error }] };
79
- }
80
- return { value };
81
- }
82
- } };
83
- //#endregion
84
- //#region src/steps.ts
85
- /**
86
- * The step envelope: an INTERNAL, per-model-call-checkpoint view of an agent
87
- * machine (`AgentStep` = snapshot + actions + discovered requests + done). It
88
- * once backed a public step API; the public step path is now the thin
89
- * effect/replay loop in `./effects.ts` (re-exported from `@statelyai/agent`).
90
- * These helpers survive as internals that `runAgent`, `verify.ts`, and the
91
- * effect path build on — the only symbol still on the public surface is
92
- * {@link executeAgentRequest} (the `text`-effect resolver).
93
- * @module
94
- */
95
- /** @internal Normalizes current and legacy XState invoke effect shapes. */
96
- function getInvokeEffectMetadata(action) {
97
- if (action.type === "@xstate.spawn") return action;
98
- if (action.type === "xstate.spawnChild") {
99
- const params = action.params;
100
- return params ? {
101
- ...params,
102
- logic: action.logic
103
- } : void 0;
104
- }
105
- if (action.type === "@xstate.start" && typeof action.src === "string") return action;
106
- }
107
- /**
108
- * Scans a set of executable actions (as returned by xstate's `transition`/
109
- * `initialTransition`) for spawned `TextLogic`/`DecisionLogic` invokes and
110
- * lowers each into an {@link AgentStepRequest}. Pass `options.machine` to
111
- * pre-fill `schemas`/`actors` from the machine's registered `setupAgent`
112
- * options instead of passing them by hand.
113
- * `options.snapshot` is required to resolve a decision's candidate events
114
- * (intersecting declared `allowedEvents` with what's currently legal) — omit
115
- * it and decision requests report an empty `events` list.
116
- *
117
- * @internal
118
- */
119
- function getAgentRequests(actions, { machine, ...options } = {}) {
120
- if (machine) options = {
121
- ...require_decision.getRegisteredAgentExecutionOptions(machine),
122
- ...options
123
- };
124
- return actions.flatMap((action) => {
125
- const params = getInvokeEffectMetadata(action);
126
- if (!params || typeof params.src !== "string") return [];
127
- if (typeof params.id !== "string" || params.id.length === 0) throw new Error(`Agent invoke '${params.src}' must define a durable string id.`);
128
- const registeredLogic = require_decision.isTextLogic(params.logic) || require_decision.isDecisionLogic(params.logic) ? params.logic : options.actors?.[params.src];
129
- if (require_decision.isDecisionLogic(registeredLogic)) {
130
- const decisionRequest = registeredLogic.request(params.input);
131
- const allowedEventTypes = registeredLogic.allowedEventTypes?.(params.input);
132
- const events = options.snapshot ? require_decision.getAcceptedEvents(options.snapshot, {
133
- events: options.events,
134
- schemas: options.schemas,
135
- eventTypes: allowedEventTypes,
136
- eventToolName: options.eventToolName
137
- }) : [];
138
- return [{
139
- ...decisionRequest,
140
- id: params.id,
141
- events
142
- }];
143
- }
144
- const textLogic = require_decision.isTextLogic(registeredLogic) ? registeredLogic : void 0;
145
- const input = textLogic ? textLogic.request(params.input) : void 0;
146
- if (!input) return [];
147
- return [{
148
- kind: "text",
149
- id: params.id,
150
- src: params.src,
151
- ...textLogic ? { mode: textLogic.mode } : {},
152
- input,
153
- tools: input.tools ?? {},
154
- events: []
155
- }];
156
- });
157
- }
158
- /**
159
- * Builds the canonical `xstate.done.actor` event xstate's `transition()`
160
- * expects to resolve a spawned invoke — including the child session identity
161
- * that rejects a stale completion from an earlier incarnation.
162
- *
163
- * @internal
164
- */
165
- function doneEvent(snapshot, request, output) {
166
- const id = typeof request === "string" ? request : request.id;
167
- const child = snapshot.children[id];
168
- return {
169
- type: "xstate.done.actor",
170
- actorId: id,
171
- ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {},
172
- output
173
- };
174
- }
175
- /**
176
- * Applies a request's `output` as a done event via `transition(...)`,
177
- * returning the raw `[snapshot, actions]` tuple. Lower-level than
178
- * {@link resolveAgentStep} — that helper wraps this and also runs
179
- * {@link getAgentRequests} to produce the next {@link AgentStep}.
180
- *
181
- * @internal
182
- */
183
- function transitionResult(logic, snapshot, request, output) {
184
- const event = doneEvent(snapshot, request, output);
185
- const result = (0, xstate.transition)(logic, snapshot, event);
186
- applyFinalStateOutput(logic, result[0], event);
187
- return result;
188
- }
189
- /**
190
- * Starts a machine and returns its first {@link AgentStep} — the step-path
191
- * equivalent of `initialTransition` plus request discovery. Begins the
192
- * durable/per-model-call-checkpoint loop: resolve each `step.requests` entry
193
- * (via {@link executeAgentRequest} for `kind: 'text'`, or
194
- * {@link resolveDecision} for `kind: 'decision'`), then advance with
195
- * {@link resolveAgentStep} or {@link transitionAgentStep}.
196
- */
197
- function initialAgentStep(machine, input, options) {
198
- const [snapshot, actions] = (0, xstate.initialTransition)(machine, input);
199
- return createAgentStep(machine, snapshot, actions, require_decision.getRegisteredAgentExecutionOptions(machine, options));
200
- }
201
- /**
202
- * Applies an externally-sent event (e.g. a decision's chosen event, or a
203
- * human's reply) and returns the next {@link AgentStep}. Accepts **either**
204
- * a raw snapshot **or** a prior `AgentStep` as the second argument —
205
- * `.snapshot` is unwrapped automatically, so callers can thread the whole
206
- * step object through without manually plucking the snapshot out.
207
- */
208
- function transitionAgentStep(machine, snapshotOrStep, event, options) {
209
- const [nextSnapshot, actions] = (0, xstate.transition)(machine, isAgentStep(snapshotOrStep) ? snapshotOrStep.snapshot : snapshotOrStep, event);
210
- return createAgentStep(machine, nextSnapshot, actions, require_decision.getRegisteredAgentExecutionOptions(machine, options));
211
- }
212
- /**
213
- * Applies a resolved text request's output (a `kind: 'text'`
214
- * {@link AgentRequest} — not a decision) as a done event and returns the
215
- * next {@link AgentStep}. For decisions, resolve with `resolveDecision`
216
- * (which returns a {@link ChosenEvent}) and apply it with
217
- * {@link transitionAgentStep} instead — a decision has no output value of
218
- * its own to feed here.
219
- */
220
- function resolveAgentStep(machine, step, request, output, options) {
221
- const [snapshot, actions] = transitionResult(machine, step.snapshot, request, output);
222
- return createAgentStep(machine, snapshot, actions, require_decision.getRegisteredAgentExecutionOptions(machine, options));
223
- }
224
- async function executeAgentRequest(requestOrEffect, executors) {
225
- if (requestOrEffect.kind === "decision") throw new Error("executeAgentRequest(...) is text-only. Resolve a 'decision' request with resolveDecision(request, executors, ...) instead.");
226
- const request = "requestId" in requestOrEffect ? {
227
- kind: "text",
228
- id: requestOrEffect.requestId,
229
- src: "",
230
- mode: requestOrEffect.mode,
231
- input: requestOrEffect.request,
232
- tools: requestOrEffect.request.tools ?? {},
233
- events: []
234
- } : requestOrEffect;
235
- assertTextExecutor(request, executors);
236
- const { output, raw } = await require_decision.executeAgentTextRequest(request.mode ?? "generate", request.id, request.input, executors, request.tools);
237
- return {
238
- output: request.input.outputSchema ? require_decision.validateSchemaSync(request.input.outputSchema, output) : output,
239
- raw
240
- };
241
- }
242
- function assertTextExecutor(request, executors) {
243
- const mode = request.mode ?? "generate";
244
- const kind = mode === "stream" ? "streamText" : "generateText";
245
- if (!(mode === "stream" ? executors.streamText : executors.generateText)) throw new Error(`this step's text request '${request.src}' needs a '${kind}' executor but none was provided.`);
246
- }
247
- function createAgentStep(machine, snapshot, actions, options) {
248
- applyFinalStateOutput(machine, snapshot);
249
- return {
250
- snapshot,
251
- actions,
252
- requests: getAgentRequests(actions, {
253
- ...options,
254
- snapshot
255
- }),
256
- done: snapshot.status === "done"
257
- };
258
- }
259
- function resolveStateValueConfig(config, value) {
260
- if (typeof value === "string") return config.states?.[value];
261
- if (!value || typeof value !== "object") return;
262
- for (const [key, childValue] of Object.entries(value)) {
263
- const childConfig = config.states?.[key];
264
- if (!childConfig) continue;
265
- if (childConfig.type === "final") return childConfig;
266
- const nested = resolveStateValueConfig(childConfig, childValue);
267
- if (nested) return nested;
268
- }
269
- }
270
- function applyFinalStateOutput(logic, snapshot, event) {
271
- const machineSnapshot = snapshot;
272
- if (machineSnapshot.status !== "done" || machineSnapshot.output !== void 0 || !("config" in logic)) return;
273
- const config = logic.config;
274
- if (!config) return;
275
- const output = resolveStateValueConfig(config, machineSnapshot.value)?.output;
276
- if (output === void 0) return;
277
- machineSnapshot.output = typeof output === "function" ? output({
278
- context: machineSnapshot.context,
279
- event
280
- }) : output;
281
- }
282
- function isAgentStep(value) {
283
- return !!value && typeof value === "object" && "snapshot" in value && "actions" in value && "requests" in value;
284
- }
285
- //#endregion
286
- //#region src/effects.ts
287
- /**
288
- * The effect/replay path: the library's new append-only-log core. Two
289
- * primitives sit under every host loop:
290
- *
291
- * - {@link getAgentEffects} maps a transition's ordered executable actions
292
- * (reconciled with the still-owed effects visible only on the snapshot) into
293
- * an ordered {@link AgentEffect} list a host starts at the frontier.
294
- * - {@link replay} folds a journal of EXTERNAL inputs through xstate's pure
295
- * `initialTransition`/`transition` WITHOUT executing anything, returning the
296
- * final snapshot plus the effects still owed — crash recovery, fork resume,
297
- * and time travel in one function.
298
- *
299
- * The journal of external inputs (effect completions with outputs inline, user
300
- * events, timer firings) is the authoritative artifact; raised/internal events
301
- * are never journaled (replay re-derives them). A reserved first entry
302
- * {@link initEntry} carries the machine input so a log is self-contained.
303
- * @module
304
- */
305
- /**
306
- * The reserved journal event type of the {@link initEntry} first entry: it
307
- * carries the machine `input` so a log replays with no side-channel. Named in
308
- * the `agent.*` builtin-actor namespace so it never collides with a machine's
309
- * own event vocabulary. Consumed by {@link replay}; never fed to `transition`.
310
- */
311
- const AGENT_INIT_EVENT_TYPE = "@agent.init";
312
- /**
313
- * The reserved event type `runAgent` delivers to the running machine after
314
- * every settled model call that reported usage — the one seam that puts a
315
- * call's tokens in reach of ordinary `context` and guards, so a token budget
316
- * is a plain machine transition instead of host bookkeeping.
317
- *
318
- * Like {@link AGENT_INIT_EVENT_TYPE} it lives in the reserved `@agent.*`
319
- * namespace: it can never collide with a machine's own vocabulary, and
320
- * `getAcceptedEvents`/`parseAgentEvent` never offer it — a model can neither
321
- * be shown it as a decision candidate nor forge one.
322
- *
323
- * Delivery is opt-in BY CONSTRUCTION: the event is sent only when the live
324
- * snapshot can currently take it (i.e. the machine declares an
325
- * `'@agent.usage'` transition, usually machine-level `on`). A machine without
326
- * one sees no extra transition, no extra trace event, and no extra log entry.
327
- * When it IS taken it rides the event log like any other external input, so
328
- * events-only recovery (`runAgent({ events })`) replays the folded tokens
329
- * without re-calling a model.
330
- */
331
- const AGENT_USAGE_EVENT_TYPE = "@agent.usage";
332
- /**
333
- * Creates a JSON-safe, self-describing entry and records the state/effect
334
- * hashes produced after replaying it. `entries` must be the complete prefix.
335
- */
336
- function createReplayEntry(machine, entries, event, options = {}) {
337
- const index = entries.length;
338
- const machineId = machine.config.id ?? machine.id ?? "(machine)";
339
- const machineVersion = options.machineVersion ?? require_decision.resolveMachineVersion(machine);
340
- const entry = {
341
- schemaVersion: 1,
342
- id: options.id ?? `evt_${String(index).padStart(8, "0")}`,
343
- index,
344
- recordedAt: options.recordedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
345
- machineId,
346
- machineVersion,
347
- event: normalizeEventErrors(event),
348
- ...options.causationId !== void 0 ? { causationId: options.causationId } : {},
349
- ...options.correlationId !== void 0 ? { correlationId: options.correlationId } : {},
350
- ...options.metadata !== void 0 ? { metadata: options.metadata } : {}
351
- };
352
- require_event_log_store.assertAgentLogEntry(entry);
353
- if (options.verification !== false) {
354
- const result = replay(machine, [...entries, entry], {
355
- machineVersion,
356
- verify: false
357
- });
358
- entry.verification = replayVerification(result.snapshot, result.effects);
359
- }
360
- return entry;
361
- }
362
- /** Reserved first replay entry carrying machine input and verification hashes. */
363
- function initEntry(machine, input, options = {}) {
364
- return createReplayEntry(machine, [], {
365
- type: AGENT_INIT_EVENT_TYPE,
366
- ...input !== void 0 ? { input } : {}
367
- }, options);
368
- }
369
- /** Normalizes a mixed `EventObject | AgentLogEntry` history into bare events. */
370
- function toEvents(history) {
371
- if (!history) return [];
372
- return history.map((entry) => {
373
- const candidate = entry;
374
- return candidate && typeof candidate === "object" && "event" in candidate && candidate.event ? candidate.event : entry;
375
- });
376
- }
377
- function rebindActorSession(event, snapshot, sessions) {
378
- const actorEvent = event;
379
- if (typeof actorEvent.actorId !== "string" || typeof actorEvent.sessionId !== "string") return event;
380
- const key = `${actorEvent.actorId}\0${actorEvent.sessionId}`;
381
- let sessionId = sessions.get(key);
382
- if (!sessionId) {
383
- const child = snapshot.children[actorEvent.actorId];
384
- if (typeof child?.sessionId !== "string") return event;
385
- sessionId = child.sessionId;
386
- sessions.set(key, sessionId);
387
- }
388
- return {
389
- ...event,
390
- sessionId
391
- };
392
- }
393
- const DONE_ACTOR_EVENT_TYPE = "xstate.done.actor";
394
- const ERROR_ACTOR_EVENT_TYPE = "xstate.error.actor";
395
- function isInvokeCompletion(event, id) {
396
- return (event.type === DONE_ACTOR_EVENT_TYPE || event.type === ERROR_ACTOR_EVENT_TYPE) && event.actorId === id;
397
- }
398
- /**
399
- * 1-based occurrence for an invoke/spawn site: `1 + completions` (done AND
400
- * error both count — an error is a semantic completion) for `id` in `events`.
401
- */
402
- function invokeOccurrence(events, id) {
403
- let count = 0;
404
- for (const event of events) if (isInvokeCompletion(event, id)) count++;
405
- return count + 1;
406
- }
407
- /** The exact canonical done/error events xstate's actor system delivers for an invoke `id`. */
408
- function invokeEventMinters(id, snapshot) {
409
- const child = snapshot.children[id];
410
- const identity = {
411
- actorId: id,
412
- ...typeof child?.sessionId === "string" ? { sessionId: child.sessionId } : {}
413
- };
414
- return {
415
- toDoneEvent: (output) => ({
416
- type: DONE_ACTOR_EVENT_TYPE,
417
- output,
418
- ...identity
419
- }),
420
- toErrorEvent: (error) => ({
421
- type: ERROR_ACTOR_EVENT_TYPE,
422
- error,
423
- ...identity
424
- })
425
- };
426
- }
427
- /** Splits an `xstate.after.<delayKey>.<statePath>` id into its parts. */
428
- function parseAfterId(afterId) {
429
- if (!afterId.startsWith("xstate.after.")) return;
430
- const rest = afterId.slice(13);
431
- const dot = rest.indexOf(".");
432
- if (dot === -1) return;
433
- return {
434
- delayKey: rest.slice(0, dot),
435
- statePath: rest.slice(dot + 1)
436
- };
437
- }
438
- function buildInvokeEffect(meta, mapped, events, snapshot, options) {
439
- const id = typeof meta.id === "string" ? meta.id : void 0;
440
- if (!id) return;
441
- const requestId = `${id}#${invokeOccurrence(events, id)}`;
442
- if (mapped?.kind === "text") return {
443
- kind: "text",
444
- requestId,
445
- request: mapped.input,
446
- mode: mapped.mode,
447
- ...invokeEventMinters(id, snapshot)
448
- };
449
- if (mapped?.kind === "decision") return {
450
- kind: "decision",
451
- requestId,
452
- request: mapped
453
- };
454
- const logic = require_decision.isTextLogic(meta.logic) || require_decision.isDecisionLogic(meta.logic) ? meta.logic : typeof meta.src === "string" ? options.actors?.[meta.src] : void 0;
455
- if (require_decision.isTextLogic(logic)) return {
456
- kind: "text",
457
- requestId,
458
- request: logic.request(meta.input),
459
- mode: logic.mode,
460
- ...invokeEventMinters(id, snapshot)
461
- };
462
- if (require_decision.isDecisionLogic(logic)) {
463
- const base = logic.request(meta.input);
464
- const eventTypes = logic.allowedEventTypes?.(meta.input);
465
- const candidateEvents = require_decision.getAcceptedEvents(snapshot, {
466
- events: options.schemas?.events,
467
- schemas: options.schemas,
468
- eventTypes
469
- });
470
- return {
471
- kind: "decision",
472
- requestId,
473
- request: {
474
- ...base,
475
- id,
476
- events: candidateEvents
477
- }
478
- };
479
- }
480
- return {
481
- kind: "task",
482
- requestId,
483
- id,
484
- src: typeof meta.src === "string" ? meta.src : id,
485
- input: meta.input,
486
- ...invokeEventMinters(id, snapshot)
487
- };
488
- }
489
- /**
490
- * Maps a transition's ORDERED executable actions (plus the still-owed effects
491
- * visible only on the snapshot) into an ordered {@link AgentEffect} list the
492
- * host starts at the frontier.
493
- *
494
- * Ordering is load-bearing: a single transition's actions are emitted in
495
- * document order (a custom entry action, a spawn, and a `sendTo` in that order
496
- * yield `execute`, then `task`/agent effect, then `execute` — never a
497
- * reordered set). Effects visible only on the snapshot (children spawned by
498
- * an EARLIER transition that
499
- * have not completed yet — the fan-out / crash-resume case) are appended after
500
- * the action-derived effects, deduped by site id.
501
- *
502
- * Every `requestId` is `${siteId}#${n}`, `n` the 1-based occurrence derived
503
- * from `options.history` — so the same log yields identical requestIds on every
504
- * replay. XState alpha.24 prunes a child when its matching completion is
505
- * folded; the history check also prevents older/restored snapshots from
506
- * re-surfacing completed work. A re-entered invoke site instead re-derives
507
- * from the action list each fresh entry (so `#2`, `#3`, … stay correct).
508
- */
509
- function getAgentEffects(machine, snapshot, actions, options = {}) {
510
- const resolved = require_decision.getRegisteredAgentExecutionOptions(machine, options);
511
- const events = toEvents(options.history);
512
- const rawActions = actions;
513
- const requests = getAgentRequests(rawActions, {
514
- ...resolved,
515
- snapshot
516
- });
517
- const requestById = new Map(requests.map((request) => [request.id, request]));
518
- const effects = [];
519
- const emitted = /* @__PURE__ */ new Set();
520
- for (const rawAction of rawActions) {
521
- const meta = getInvokeEffectMetadata(rawAction);
522
- if (meta) {
523
- const effect = buildInvokeEffect(meta, typeof meta.id === "string" ? requestById.get(meta.id) : void 0, events, snapshot, resolved);
524
- if (effect && typeof meta.id === "string") {
525
- effects.push(effect);
526
- emitted.add(meta.id);
527
- }
528
- continue;
529
- }
530
- if (rawAction.type === "@xstate.raise" && typeof rawAction.delay === "number") {
531
- const afterId = typeof rawAction.id === "string" ? rawAction.id : "";
532
- const parsed = parseAfterId(afterId);
533
- const siteId = parsed ? `${parsed.statePath}#${parsed.delayKey}` : afterId;
534
- const event = {
535
- type: "xstate.timer",
536
- id: afterId
537
- };
538
- const firings = events.filter((candidate) => candidate.type === event.type && candidate.id === afterId).length;
539
- effects.push({
540
- kind: "delay",
541
- requestId: `${siteId}#${firings + 1}`,
542
- id: afterId,
543
- delayMs: rawAction.delay,
544
- event
545
- });
546
- continue;
547
- }
548
- if (rawAction.type === "@xstate.start" || rawAction.type === "@xstate.stop" || rawAction.type === "@xstate.terminate" || rawAction.type === "@xstate.raise" || rawAction.type === "registerChild") continue;
549
- if (typeof rawAction.exec === "function") {
550
- const action = rawAction;
551
- effects.push({
552
- kind: "execute",
553
- action: rawAction,
554
- exec: () => {
555
- action.exec();
556
- }
557
- });
558
- }
559
- }
560
- const children = snapshot.children;
561
- for (const [id, child] of Object.entries(children ?? {})) {
562
- if (emitted.has(id) || invokeOccurrence(events, id) > 1) continue;
563
- const ref = child;
564
- if (typeof ref?.getSnapshot !== "function") continue;
565
- const effect = buildInvokeEffect({
566
- id,
567
- src: ref.src,
568
- input: ref.getSnapshot().input,
569
- logic: ref.logic
570
- }, requestById.get(id), events, snapshot, resolved);
571
- if (effect) {
572
- effects.push(effect);
573
- emitted.add(id);
574
- }
575
- }
576
- return effects;
577
- }
578
- var AgentReplayMachineMismatchError = class extends require_errors.AgentError {
579
- constructor(eventId, index, expected, actual) {
580
- super("replay-machine-mismatch", `Replay entry '${eventId}' at index ${index} targets machine '${actual.machineId}'@'${actual.machineVersion}', expected '${expected.machineId}'@'${expected.machineVersion}'.`);
581
- this.eventId = eventId;
582
- this.index = index;
583
- this.expected = expected;
584
- this.actual = actual;
585
- this.name = "AgentReplayMachineMismatchError";
586
- }
587
- };
588
- var AgentReplayDivergenceError = class extends require_errors.AgentError {
589
- constructor(eventId, index, kind, expected, actual) {
590
- super("replay-divergence", kind === "missing-verification" ? `Replay entry '${eventId}' at index ${index} has no verification hashes.` : `Replay diverged after '${eventId}' at index ${index} (${kind}): expected '${expected}', got '${actual}'.`);
591
- this.eventId = eventId;
592
- this.index = index;
593
- this.kind = kind;
594
- this.expected = expected;
595
- this.actual = actual;
596
- this.name = "AgentReplayDivergenceError";
597
- }
598
- };
599
- /**
600
- * Folds a journal through `initialTransition`/`transition` WITHOUT executing
601
- * anything, then returns the final snapshot plus the still-owed effects
602
- * ({@link getAgentEffects} of the final frontier, occurrence counts taken from
603
- * the whole log). Crash recovery, fork resume, and time travel in one call.
604
- *
605
- * `entries` is a versioned {@link AgentLogEntry} array. A reserved
606
- * {@link initEntry} first envelope carries `{ type: '@agent.init', input }`,
607
- * so a complete log replays with no side-channel; when absent,
608
- * `options.input` is used instead.
609
- * Raised/internal events are never in the journal — replay re-derives them
610
- * deterministically from the machine's own logic.
611
- */
612
- /**
613
- * Validates a replay entry sequence: envelope shape, contiguity from index 0,
614
- * unique event ids, and machine identity.
615
- *
616
- * @internal
617
- */
618
- function validateReplayEntries(entries, expected, label) {
619
- const eventIds = /* @__PURE__ */ new Set();
620
- for (let index = 0; index < entries.length; index++) {
621
- const entry = entries[index];
622
- require_event_log_store.assertAgentLogEntry(entry);
623
- if (entry.index !== index) throw new Error(`${label} must be contiguous from index 0; found entry.index ${entry.index} at position ${index}.`);
624
- if (eventIds.has(entry.id)) throw new Error(`${label} contain duplicate event id '${entry.id}'.`);
625
- eventIds.add(entry.id);
626
- if (entry.machineId !== expected.machineId || entry.machineVersion !== expected.machineVersion) throw new AgentReplayMachineMismatchError(entry.id, entry.index, expected, {
627
- machineId: entry.machineId,
628
- machineVersion: entry.machineVersion
629
- });
630
- }
631
- }
632
- function replay(machine, entries, options = {}) {
633
- validateReplayEntries(entries, {
634
- machineId: machine.config.id ?? machine.id ?? "(machine)",
635
- machineVersion: options.machineVersion ?? require_decision.resolveMachineVersion(machine)
636
- }, "Replay entries");
637
- const events = toEvents(entries);
638
- const initOffset = events[0]?.type === "@agent.init" ? 1 : 0;
639
- const input = initOffset ? events[0].input : options.input;
640
- const journal = events.slice(initOffset);
641
- const journalEntries = entries.slice(initOffset);
642
- let [snapshot, actions] = (0, xstate.initialTransition)(machine, input);
643
- let effects = getAgentEffects(machine, snapshot, actions, {
644
- ...options,
645
- history: entries.slice(0, initOffset)
646
- });
647
- if (initOffset) verifyEntry(entries[0], snapshot, effects, options.verify);
648
- const sessions = /* @__PURE__ */ new Map();
649
- for (let index = 0; index < journal.length; index++) {
650
- const event = journal[index];
651
- const reboundEvent = rebindActorSession(event, snapshot, sessions);
652
- [snapshot, actions] = (0, xstate.transition)(machine, snapshot, reboundEvent);
653
- const consumed = entries.slice(0, initOffset + index + 1);
654
- effects = getAgentEffects(machine, snapshot, actions, {
655
- ...options,
656
- history: consumed
657
- });
658
- verifyEntry(journalEntries[index], snapshot, effects, options.verify);
659
- }
660
- return {
661
- snapshot,
662
- effects
663
- };
664
- }
665
- /** Structural event-tail, logical-state, and owed-effect comparison. */
666
- function diffEventLogs(machine, parentEntries, forkEntries, options = {}) {
667
- let commonLength = 0;
668
- while (commonLength < parentEntries.length && commonLength < forkEntries.length && stableJson(parentEntries[commonLength]) === stableJson(forkEntries[commonLength])) commonLength++;
669
- const parent = replay(machine, parentEntries, options);
670
- const fork = replay(machine, forkEntries, options);
671
- const parentState = logicalReplayState(parent.snapshot);
672
- const forkState = logicalReplayState(fork.snapshot);
673
- return {
674
- commonPrefix: {
675
- length: commonLength,
676
- ...commonLength > 0 ? { throughEventId: parentEntries[commonLength - 1].id } : {}
677
- },
678
- parentOnly: parentEntries.slice(commonLength),
679
- forkOnly: forkEntries.slice(commonLength),
680
- parent,
681
- fork,
682
- stateChanges: diffJson(parentState, forkState),
683
- effectChanges: diffEffects(parent.effects, fork.effects)
684
- };
685
- }
686
- function verifyEntry(entry, snapshot, effects, mode) {
687
- if (mode === false) return;
688
- if (!entry.verification) {
689
- if (mode === "strict") throw new AgentReplayDivergenceError(entry.id, entry.index, "missing-verification");
690
- return;
691
- }
692
- const actual = replayVerification(snapshot, effects);
693
- if (actual.stateHash !== entry.verification.stateHash) throw new AgentReplayDivergenceError(entry.id, entry.index, "state", entry.verification.stateHash, actual.stateHash);
694
- if (actual.effectsHash !== entry.verification.effectsHash) throw new AgentReplayDivergenceError(entry.id, entry.index, "effects", entry.verification.effectsHash, actual.effectsHash);
695
- }
696
- function replayVerification(snapshot, effects) {
697
- return {
698
- stateHash: hashStableJson(logicalReplayState(snapshot)),
699
- effectsHash: hashStableJson(serializableEffects(effects))
700
- };
701
- }
702
- function logicalReplayState(snapshot) {
703
- const state = {
704
- status: snapshot.status,
705
- value: snapshot.value,
706
- context: snapshot.context
707
- };
708
- if (snapshot.output !== void 0) state.output = snapshot.output;
709
- if (snapshot.error !== void 0) state.error = snapshot.error;
710
- const canonical = canonicalizeForHash(state);
711
- require_event_log_store.assertJsonSerializable(canonical, "snapshot");
712
- return canonical;
713
- }
714
- function serializableEffects(effects) {
715
- return effects.map((effect) => canonicalizeEffect(effect));
716
- }
717
- function canonicalizeEffect(effect) {
718
- if (effect.kind === "execute") return {
719
- kind: effect.kind,
720
- type: String(effect.action.type)
721
- };
722
- const value = { ...effect };
723
- delete value.toDoneEvent;
724
- delete value.toErrorEvent;
725
- delete value.exec;
726
- delete value.action;
727
- return canonicalizeForHash(value);
728
- }
729
- function canonicalizeForHash(value, seen = /* @__PURE__ */ new WeakSet()) {
730
- if (value === void 0) return "[undefined]";
731
- if (typeof value === "function") return "[function]";
732
- if (typeof value === "bigint") return `[bigint:${String(value)}]`;
733
- if (typeof value === "symbol") return `[symbol:${String(value)}]`;
734
- if (value === null || typeof value !== "object") return value;
735
- if (value instanceof Date) return `[Date:${value.toISOString()}]`;
736
- if (value instanceof Error) return {
737
- errorName: value.name,
738
- message: value.message,
739
- ...value.cause !== void 0 ? { cause: canonicalizeForHash(value.cause, seen) } : {}
740
- };
741
- if (value instanceof Set) return [...value].map((item) => canonicalizeForHash(item, seen)).sort((a, b) => stableJson(a).localeCompare(stableJson(b)));
742
- if (value instanceof Map) return [...value.entries()].map(([key, item]) => [canonicalizeForHash(key, seen), canonicalizeForHash(item, seen)]).sort(([a], [b]) => stableJson(a).localeCompare(stableJson(b)));
743
- if (seen.has(value)) return "[circular]";
744
- seen.add(value);
745
- if (Array.isArray(value)) {
746
- const result = value.map((item) => canonicalizeForHash(item, seen));
747
- seen.delete(value);
748
- return result;
749
- }
750
- const standard = value["~standard"];
751
- if (standard) {
752
- seen.delete(value);
753
- return {
754
- schemaVendor: standard.vendor,
755
- schemaVersion: standard.version
756
- };
757
- }
758
- const result = {};
759
- for (const key of Object.keys(value).sort()) result[key] = canonicalizeForHash(value[key], seen);
760
- seen.delete(value);
761
- return result;
762
- }
763
- function normalizeEventErrors(value, seen = /* @__PURE__ */ new WeakMap()) {
764
- if (value instanceof Error) {
765
- const normalized = {
766
- name: value.name,
767
- message: value.message
768
- };
769
- seen.set(value, normalized);
770
- if (value.cause !== void 0) normalized.cause = normalizeEventErrors(value.cause, seen);
771
- return normalized;
772
- }
773
- if (value === null || typeof value !== "object") return value;
774
- const existing = seen.get(value);
775
- if (existing !== void 0) return existing;
776
- if (Array.isArray(value)) {
777
- const result = [];
778
- seen.set(value, result);
779
- for (const item of value) result.push(normalizeEventErrors(item, seen));
780
- return result;
781
- }
782
- const prototype = Object.getPrototypeOf(value);
783
- if (prototype !== Object.prototype && prototype !== null) return value;
784
- const result = {};
785
- seen.set(value, result);
786
- for (const [key, item] of Object.entries(value)) result[key] = normalizeEventErrors(item, seen);
787
- return result;
788
- }
789
- function stableJson(value) {
790
- return JSON.stringify(sortJson(value));
791
- }
792
- function sortJson(value) {
793
- if (Array.isArray(value)) return value.map(sortJson);
794
- if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortJson(value[key])]));
795
- return value;
796
- }
797
- function hashStableJson(value) {
798
- return require_decision.djb2Hex(stableJson(value));
799
- }
800
- function diffJson(before, after, path = "") {
801
- if (stableJson(before) === stableJson(after)) return [];
802
- if (before === null || after === null || typeof before !== "object" || typeof after !== "object" || Array.isArray(before) || Array.isArray(after)) return [{
803
- op: "replace",
804
- path,
805
- value: after
806
- }];
807
- const changes = [];
808
- const beforeObject = before;
809
- const afterObject = after;
810
- const keys = new Set([...Object.keys(beforeObject), ...Object.keys(afterObject)]);
811
- for (const key of [...keys].sort()) {
812
- const childPath = `${path}/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`;
813
- if (!(key in afterObject)) changes.push({
814
- op: "remove",
815
- path: childPath
816
- });
817
- else if (!(key in beforeObject)) changes.push({
818
- op: "add",
819
- path: childPath,
820
- value: afterObject[key]
821
- });
822
- else changes.push(...diffJson(beforeObject[key], afterObject[key], childPath));
823
- }
824
- return changes;
825
- }
826
- function diffEffects(before, after) {
827
- const beforeValues = serializableEffects(before);
828
- const afterValues = serializableEffects(after);
829
- const key = (value, index) => {
830
- const record = value;
831
- return typeof record.requestId === "string" ? record.requestId : `${String(record.kind ?? "effect")}:${index}`;
832
- };
833
- const beforeMap = new Map(beforeValues.map((value, index) => [key(value, index), value]));
834
- const afterMap = new Map(afterValues.map((value, index) => [key(value, index), value]));
835
- const added = [];
836
- const removed = [];
837
- const changed = [];
838
- for (const [id, value] of beforeMap) {
839
- const next = afterMap.get(id);
840
- if (next === void 0) removed.push(value);
841
- else if (stableJson(value) !== stableJson(next)) changed.push({
842
- before: value,
843
- after: next
844
- });
845
- }
846
- for (const [id, value] of afterMap) if (!beforeMap.has(id)) added.push(value);
847
- return {
848
- added,
849
- removed,
850
- changed
851
- };
852
- }
853
- //#endregion
854
- //#region src/workflow-config.ts
855
- /**
856
- * The machines-as-data lowering: `setupAgent(...).fromConfig(config, options)`.
857
- *
858
- * Takes a serializable `AgentWorkflowConfig` (the JSON form of an agent
859
- * machine — published schema at `schemas/agent-workflow.json`, docs at
860
- * docs/machines-as-data.md), compiles its embedded JSON Schemas with the
861
- * host-provided `compileSchema`, resolves named guards/actions/actors from
862
- * `options`, and lowers the whole thing to an ordinary XState machine plus its
863
- * schema pack. This is what makes LLM-generated and stored-as-JSON machines
864
- * first-class: the config validates against the shipped schema before any
865
- * model call, and the resulting machine lints, simulates, and runs like a
866
- * hand-authored one.
867
- */
868
- const DECIDE_SRC = "agent.decide";
869
- const workflowConfigWholeExpressionPattern = /^\{\{\s*([\s\S]*?)\s*\}\}$/;
870
- const workflowConfigTemplateExpressionPattern = /\{\{\s*([\s\S]*?)\s*\}\}/g;
871
- const workflowConfigHasTemplatePattern = /\{\{[\s\S]*?\}\}/;
872
- function toArray(value) {
873
- return Array.isArray(value) ? value : [value];
874
- }
875
- function evaluateWorkflowConfigPath(expression, scope) {
876
- const parts = expression.trim().split(".").filter(Boolean);
877
- let current = scope;
878
- for (const part of parts) {
879
- if (!current || typeof current !== "object") return;
880
- current = current[part];
881
- }
882
- return current;
883
- }
884
- function evaluateWorkflowConfigValue(value, scope) {
885
- if (typeof value === "string") {
886
- const wholeMatch = value.match(workflowConfigWholeExpressionPattern);
887
- if (wholeMatch?.[1]) return evaluateWorkflowConfigPath(wholeMatch[1], scope);
888
- return value.replace(workflowConfigTemplateExpressionPattern, (_match, expression) => {
889
- const resolved = evaluateWorkflowConfigPath(expression, scope);
890
- return resolved === void 0 || resolved === null ? "" : String(resolved);
891
- });
892
- }
893
- if (Array.isArray(value)) return value.map((item) => evaluateWorkflowConfigValue(item, scope));
894
- if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, evaluateWorkflowConfigValue(item, scope)]));
895
- return value;
896
- }
897
- function createSchemasFromWorkflowConfig(config, compileSchema) {
898
- return createAgentSchemas({
899
- context: compileSchema(config.schemas?.context ?? { type: "object" }, "context"),
900
- events: Object.fromEntries(Object.entries(config.schemas?.events ?? {}).map(([key, schema]) => [key, compileSchema(schema, `event.${key}`)])),
901
- emitted: Object.fromEntries(Object.entries(config.schemas?.emitted ?? {}).map(([key, schema]) => [key, compileSchema(schema, `emitted.${key}`)])),
902
- input: compileSchema(config.schemas?.input ?? {}, "input"),
903
- output: compileSchema(config.schemas?.output ?? {}, "output"),
904
- meta: compileSchema(config.schemas?.meta ?? {}, "meta")
905
- });
906
- }
907
- function createRequestsFromWorkflowConfig(config, compileSchema) {
908
- const resolver = (value) => value === void 0 ? void 0 : ({ input }) => evaluateWorkflowConfigValue(value, { input });
909
- return Object.fromEntries(Object.entries(config.requests ?? {}).map(([key, request]) => [key, {
910
- mode: request.mode,
911
- description: request.description,
912
- schemas: {
913
- input: compileSchema(request.input, `${key}.input`),
914
- output: compileSchema(request.output, `${key}.output`)
915
- },
916
- model: ({ input }) => String(evaluateWorkflowConfigValue(request.model, { input }) ?? ""),
917
- system: resolver(request.system),
918
- prompt: resolver(request.prompt),
919
- messages: resolver(request.messages),
920
- tools: request.tools,
921
- toolChoice: request.toolChoice,
922
- includeReasoning: request.includeReasoning,
923
- temperature: resolver(request.temperature),
924
- maxOutputTokens: resolver(request.maxOutputTokens),
925
- topP: resolver(request.topP),
926
- topK: resolver(request.topK),
927
- seed: resolver(request.seed),
928
- stopSequences: resolver(request.stopSequences),
929
- metadata: resolver(request.metadata)
930
- }]));
931
- }
932
- function createActorPlaceholdersFromWorkflowConfig(config) {
933
- return Object.fromEntries(Object.keys(config.actors ?? {}).map((key) => [key, require_decision.missingActor(key)]));
934
- }
935
- const AGENT_EXPRESSION_LANG = "agent-template";
936
- function containsTemplateExpression(value) {
937
- if (typeof value === "string") return workflowConfigHasTemplatePattern.test(value);
938
- if (Array.isArray(value)) return value.some(containsTemplateExpression);
939
- if (value && typeof value === "object") return Object.values(value).some(containsTemplateExpression);
940
- return false;
941
- }
942
- function toWorkflowExpression(value) {
943
- if (!containsTemplateExpression(value)) return value;
944
- return { "@expr": JSON.stringify(value) };
945
- }
946
- function createWorkflowConfigEvaluator(contextSchema) {
947
- const decoded = /* @__PURE__ */ new Map();
948
- const decode = (source) => {
949
- if (!decoded.has(source)) decoded.set(source, JSON.parse(source));
950
- return decoded.get(source);
951
- };
952
- return ({ source, slot, scope }) => {
953
- const value = decode(source);
954
- if (slot === "context") return require_decision.validateSchemaSync(contextSchema, evaluateWorkflowConfigValue(value, { input: scope.input }));
955
- return evaluateWorkflowConfigValue(value, {
956
- context: scope.context,
957
- event: scope.event,
958
- input: scope.input
959
- });
960
- };
961
- }
962
- function translateWorkflowGuard(guard, translation, location) {
963
- if (guard === void 0) return;
964
- if (typeof guard === "string") {
965
- if (workflowConfigHasTemplatePattern.test(guard)) return { "@expr": JSON.stringify(guard) };
966
- 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 }) => ... } }).`);
967
- return { type: guard };
968
- }
969
- if (typeof guard === "function") {
970
- const name = `__fromConfigGuard${Object.keys(translation.syntheticGuards).length}`;
971
- translation.syntheticGuards[name] = guard;
972
- return { type: name };
973
- }
974
- throw new Error(`setupAgent.fromConfig: ${location} has an unsupported guard value. Use a '{{ ... }}' template string, a named guard reference (string), or a function.`);
975
- }
976
- function translateWorkflowAction(action, translation, location) {
977
- if (action.assign !== void 0) return {
978
- type: "@xstate.assign",
979
- context: toWorkflowExpression(action.assign)
980
- };
981
- if (action.emit !== void 0) return {
982
- type: "@xstate.emit",
983
- event: toWorkflowExpression(action.emit)
984
- };
985
- if (action.type) {
986
- 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) => ... } }).`);
987
- return {
988
- type: action.type,
989
- ...action.params !== void 0 ? { params: toWorkflowExpression(action.params) } : {}
990
- };
991
- }
992
- throw new Error(`setupAgent.fromConfig: ${location} action must declare 'assign', 'emit', or 'type'.`);
993
- }
994
- function translateWorkflowTransition(transitionConfig, translation, location) {
995
- const actionConfigs = transitionConfig.actions ? toArray(transitionConfig.actions) : [];
996
- const assignConfigs = [...transitionConfig.assign !== void 0 ? [transitionConfig.assign] : [], ...actionConfigs.filter((action) => action.assign !== void 0).map((action) => action.assign)];
997
- const contextPatch = assignConfigs.length ? toWorkflowExpression(Object.assign({}, ...assignConfigs)) : void 0;
998
- const actions = actionConfigs.filter((action) => action.assign === void 0).map((action) => translateWorkflowAction(action, translation, location));
999
- const guard = translateWorkflowGuard(transitionConfig.guard, translation, location);
1000
- return {
1001
- ...transitionConfig.target !== void 0 ? { target: transitionConfig.target } : {},
1002
- ...guard ? { guard } : {},
1003
- ...contextPatch !== void 0 ? { context: contextPatch } : {},
1004
- ...actions.length ? { actions } : {},
1005
- ...transitionConfig.description !== void 0 ? { description: transitionConfig.description } : {},
1006
- ...transitionConfig.reenter !== void 0 ? { reenter: transitionConfig.reenter } : {},
1007
- ...transitionConfig.meta !== void 0 ? { meta: transitionConfig.meta } : {}
1008
- };
1009
- }
1010
- function translateWorkflowTransitions(transitionConfig, translation, location) {
1011
- if (!transitionConfig) return;
1012
- return Array.isArray(transitionConfig) ? transitionConfig.map((candidate) => translateWorkflowTransition(candidate, translation, location)) : translateWorkflowTransition(transitionConfig, translation, location);
1013
- }
1014
- function addTransitionMatch(transition, matches) {
1015
- if (Array.isArray(transition)) return transition.map((candidate) => addTransitionMatch(candidate, matches));
1016
- return transition ? {
1017
- ...transition,
1018
- matches: {
1019
- ...transition.matches,
1020
- ...matches
1021
- }
1022
- } : void 0;
1023
- }
1024
- function translateWorkflowInvoke(invokeConfig, translation, stateKey) {
1025
- 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).`);
1026
- const location = `state '${stateKey}'`;
1027
- return {
1028
- ...invokeConfig.id !== void 0 ? { id: invokeConfig.id } : {},
1029
- src: invokeConfig.src,
1030
- ...invokeConfig.input !== void 0 ? { input: toWorkflowExpression(invokeConfig.input) } : {},
1031
- ...invokeConfig.onDone !== void 0 ? { onDone: translateWorkflowTransitions(invokeConfig.onDone, translation, location) } : {},
1032
- ...invokeConfig.onError !== void 0 ? { onError: translateWorkflowTransitions(invokeConfig.onError, translation, location) } : {}
1033
- };
1034
- }
1035
- function assertValidTransitionTargets(stateKey, location, transitionConfig, siblingKeys, declaredTargets) {
1036
- if (!transitionConfig) return;
1037
- for (const transition of toArray(transitionConfig)) {
1038
- const targets = transition.target === void 0 ? [] : toArray(transition.target);
1039
- for (const target of targets) {
1040
- if (typeof target !== "string") continue;
1041
- declaredTargets.push(target);
1042
- if (target.startsWith("#") || target.startsWith(".")) continue;
1043
- const head = target.split(".")[0];
1044
- 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)"}.`);
1045
- }
1046
- }
1047
- }
1048
- function assertStateTransitionTargets(stateKey, stateConfig, siblingKeys) {
1049
- const declaredTargets = [];
1050
- const invokes = stateConfig.invoke ? toArray(stateConfig.invoke) : [];
1051
- const sources = [
1052
- ...Object.entries(stateConfig.on ?? {}).map(([eventType, transition]) => [`'on.${eventType}'`, transition]),
1053
- ...Object.entries(stateConfig.after ?? {}).map(([delay, transition]) => [`'after.${delay}'`, transition]),
1054
- ["'always'", stateConfig.always],
1055
- ["'onDone'", stateConfig.onDone],
1056
- ["'choice'", stateConfig.choice],
1057
- ...invokes.flatMap((invoke) => [["invoke 'onDone'", invoke.onDone], ["invoke 'onError'", invoke.onError]])
1058
- ];
1059
- for (const [location, transition] of sources) assertValidTransitionTargets(stateKey, location, transition, siblingKeys, declaredTargets);
1060
- return declaredTargets;
1061
- }
1062
- function translateWorkflowState(stateKey, stateConfig, siblingKeys, path, translation) {
1063
- const location = `state '${stateKey}'`;
1064
- 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, "_")}').`);
1065
- const childKeys = new Set(Object.keys(stateConfig.states ?? {}));
1066
- const childPath = [...path, stateKey];
1067
- translation.transitionTargets[childPath.join(".")] = assertStateTransitionTargets(stateKey, stateConfig, siblingKeys);
1068
- const doneStateId = stateConfig.onDone !== void 0 ? `@state.${childPath.join(".")}` : void 0;
1069
- const translatedOn = {
1070
- ...Object.fromEntries(Object.entries(stateConfig.on ?? {}).map(([eventType, transitionConfig]) => [eventType, translateWorkflowTransitions(transitionConfig, translation, location)])),
1071
- ...doneStateId ? { "xstate.done.state": addTransitionMatch(translateWorkflowTransitions(stateConfig.onDone, translation, location), { stateId: doneStateId }) } : {}
1072
- };
1073
- return {
1074
- ...stateConfig.description !== void 0 ? { description: stateConfig.description } : {},
1075
- ...stateConfig.type !== void 0 ? { type: stateConfig.type } : {},
1076
- ...doneStateId ? { id: doneStateId } : {},
1077
- ...stateConfig.initial !== void 0 ? { initial: stateConfig.initial } : {},
1078
- ...stateConfig.states !== void 0 ? { states: Object.fromEntries(Object.entries(stateConfig.states).map(([key, child]) => [key, translateWorkflowState(key, child, childKeys, childPath, translation)])) } : {},
1079
- ...stateConfig.choice !== void 0 ? { choice: toArray(stateConfig.choice).map((branch) => {
1080
- 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'.`);
1081
- const when = translateWorkflowGuard(branch.guard, translation, location);
1082
- return {
1083
- ...when ? { when } : {},
1084
- target: branch.target,
1085
- ...branch.assign !== void 0 ? { context: toWorkflowExpression(branch.assign) } : {},
1086
- ...branch.description !== void 0 ? { description: branch.description } : {},
1087
- ...branch.reenter !== void 0 ? { reenter: branch.reenter } : {},
1088
- ...branch.meta !== void 0 ? { meta: branch.meta } : {}
1089
- };
1090
- }) } : {},
1091
- ...stateConfig.invoke !== void 0 ? { invoke: Array.isArray(stateConfig.invoke) ? stateConfig.invoke.map((invoke) => translateWorkflowInvoke(invoke, translation, stateKey)) : translateWorkflowInvoke(stateConfig.invoke, translation, stateKey) } : {},
1092
- ...Object.keys(translatedOn).length ? { on: translatedOn } : {},
1093
- ...stateConfig.always !== void 0 ? { always: translateWorkflowTransitions(stateConfig.always, translation, location) } : {},
1094
- ...stateConfig.after !== void 0 ? { after: Object.fromEntries(Object.entries(stateConfig.after).map(([delay, transitionConfig]) => [delay, translateWorkflowTransitions(transitionConfig, translation, location)])) } : {},
1095
- ...stateConfig.entry !== void 0 ? { entry: toArray(stateConfig.entry).map((action) => translateWorkflowAction(action, translation, location)) } : {},
1096
- ...stateConfig.exit !== void 0 ? { exit: toArray(stateConfig.exit).map((action) => translateWorkflowAction(action, translation, location)) } : {},
1097
- ...stateConfig.tags !== void 0 ? { tags: stateConfig.tags } : {},
1098
- ...stateConfig.output !== void 0 ? { output: toWorkflowExpression(stateConfig.output) } : {},
1099
- ...stateConfig.meta !== void 0 ? { meta: stateConfig.meta } : {}
1100
- };
1101
- }
1102
- function collectTranslatedFinalOutputs(states, outputs = []) {
1103
- for (const state of Object.values(states ?? {})) {
1104
- if (state?.type === "final" && state.output !== void 0) outputs.push(state.output);
1105
- collectTranslatedFinalOutputs(state?.states, outputs);
1106
- }
1107
- return outputs;
1108
- }
1109
- function translateWorkflowConfig(config, translation) {
1110
- const rootKeys = new Set(Object.keys(config.states));
1111
- const states = Object.fromEntries(Object.entries(config.states).map(([key, state]) => [key, translateWorkflowState(key, state, rootKeys, [], translation)]));
1112
- const json = {
1113
- "@exprLang": AGENT_EXPRESSION_LANG,
1114
- ...config.id !== void 0 ? { id: config.id } : {},
1115
- ...config.description !== void 0 ? { description: config.description } : {},
1116
- ...config.context !== void 0 ? { context: { "@expr": JSON.stringify(config.context) } } : {},
1117
- initial: config.initial,
1118
- states,
1119
- ...config.meta !== void 0 ? { meta: config.meta } : {}
1120
- };
1121
- const finalOutputs = collectTranslatedFinalOutputs(states);
1122
- if (json.output === void 0 && finalOutputs.length === 1) json.output = finalOutputs[0];
1123
- return json;
1124
- }
1125
- function collectDeclaredStateTags(states, tags = /* @__PURE__ */ new Set()) {
1126
- for (const state of Object.values(states ?? {})) {
1127
- for (const tag of state.tags ?? []) tags.add(tag);
1128
- collectDeclaredStateTags(state.states, tags);
1129
- }
1130
- return tags;
1131
- }
1132
- function resolveIdlePredicate(config, options) {
1133
- if (options.isIdle) return options.isIdle;
1134
- const idleTags = config.idleTags ?? [];
1135
- if (!idleTags.length) return;
1136
- const declaredTags = collectDeclaredStateTags(config.states);
1137
- const unknown = idleTags.filter((tag) => !declaredTags.has(tag));
1138
- 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.`);
1139
- return (snapshot) => idleTags.some((tag) => snapshot.hasTag(tag));
1140
- }
1141
- function setupAgentFromConfig(config, options) {
1142
- 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.");
1143
- const { compileSchema } = options;
1144
- const schemas = createSchemasFromWorkflowConfig(config, compileSchema);
1145
- const requestActors = createRequestActors(createRequestsFromWorkflowConfig(config, compileSchema));
1146
- const actors = createAgentActors(createActorPlaceholdersFromWorkflowConfig(config), requestActors);
1147
- const translation = {
1148
- guards: options.guards ?? {},
1149
- actions: options.actions ?? {},
1150
- syntheticGuards: {},
1151
- transitionTargets: {}
1152
- };
1153
- const machine = (0, xstate.createMachineFromConfig)(translateWorkflowConfig(config, translation), {
1154
- guards: Object.fromEntries(Object.entries({
1155
- ...translation.guards,
1156
- ...translation.syntheticGuards
1157
- }).map(([name, implementation]) => [name, (args) => Boolean(implementation({
1158
- context: args.context,
1159
- event: args.event
1160
- }))])),
1161
- ...options.actions ? { actions: options.actions } : {},
1162
- actors: Object.fromEntries(Object.keys(actors).map((key) => [key, key])),
1163
- evaluators: { [AGENT_EXPRESSION_LANG]: createWorkflowConfigEvaluator(schemas.context) }
1164
- }).provide({ actors });
1165
- require_decision.agentExecutionOptions.set(machine, {
1166
- schemas,
1167
- actors,
1168
- models: {}
1169
- });
1170
- if (machine.config) require_decision.machineStaticTransitionTargets.set(machine.config, translation.transitionTargets);
1171
- const isIdle = resolveIdlePredicate(config, options);
1172
- if (isIdle && machine.config) require_decision.machineIdlePredicates.set(machine.config, isIdle);
1173
- return {
1174
- machine,
1175
- schemas
1176
- };
1177
- }
1178
- //#endregion
1179
- //#region src/setup-agent.ts
1180
- const emptyEventSchema = { "~standard": {
1181
- version: 1,
1182
- vendor: "statelyai-agent",
1183
- validate(value) {
1184
- return value !== null && typeof value === "object" && Object.keys(value).length === 0 ? { value: {} } : { issues: [{ message: "Expected an empty event payload" }] };
1185
- }
1186
- } };
1187
- const USAGE_TOKEN_FIELDS = [
1188
- "inputTokens",
1189
- "outputTokens",
1190
- "totalTokens",
1191
- "reasoningTokens",
1192
- "cachedInputTokens"
1193
- ];
1194
- const USAGE_ATTRIBUTION_FIELDS = [
1195
- "id",
1196
- "src",
1197
- "model",
1198
- "name"
1199
- ];
1200
- const USAGE_KINDS = ["text", "decision"];
1201
- /**
1202
- * Standard Schema for the reserved `'@agent.usage'` payload. Hand-rolled (no
1203
- * validation-library dependency in core) and deliberately permissive about
1204
- * unknown fields, so a newer runtime adding an attribution field cannot fail
1205
- * an older machine's validation.
1206
- */
1207
- const agentUsageEventSchema = { "~standard": {
1208
- version: 1,
1209
- vendor: "statelyai-agent",
1210
- validate(value) {
1211
- const issues = [];
1212
- if (!value || typeof value !== "object") return { issues: [{ message: "Expected an '@agent.usage' payload object" }] };
1213
- const event = value;
1214
- const usage = event.usage;
1215
- if (!usage || typeof usage !== "object") issues.push({
1216
- message: "Expected 'usage' to be an object",
1217
- path: ["usage"]
1218
- });
1219
- else for (const field of USAGE_TOKEN_FIELDS) {
1220
- const token = usage[field];
1221
- if (token !== void 0 && (typeof token !== "number" || !Number.isFinite(token))) issues.push({
1222
- message: `Expected a finite number`,
1223
- path: ["usage", field]
1224
- });
1225
- }
1226
- if (event.kind !== void 0 && !USAGE_KINDS.some((kind) => kind === event.kind)) issues.push({
1227
- message: `Expected one of ${USAGE_KINDS.join(", ")}`,
1228
- path: ["kind"]
1229
- });
1230
- for (const field of USAGE_ATTRIBUTION_FIELDS) if (event[field] !== void 0 && typeof event[field] !== "string") issues.push({
1231
- message: "Expected a string",
1232
- path: [field]
1233
- });
1234
- return issues.length > 0 ? { issues } : { value: event };
1235
- }
1236
- } };
1237
- /**
1238
- * Adds the reserved `'@agent.usage'` schema to an authored event map. A
1239
- * user-declared entry under that key is rejected: the `@agent.*` namespace
1240
- * belongs to the library (same rule as the reserved `agent.*` actor keys), and
1241
- * a custom payload schema would silently disagree with what `runAgent`
1242
- * delivers.
1243
- */
1244
- function withAgentUsageEventSchema(events) {
1245
- const declared = events?.[AGENT_USAGE_EVENT_TYPE];
1246
- 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}': … }.`);
1247
- return {
1248
- ...events,
1249
- [AGENT_USAGE_EVENT_TYPE]: agentUsageEventSchema
1250
- };
1251
- }
1252
- function normalizeEventSchemas(events) {
1253
- return Object.fromEntries(Object.entries(events).map(([type, schema]) => [type, schema && typeof schema === "object" && "~standard" in schema ? schema : emptyEventSchema]));
1254
- }
1255
- /**
1256
- * Builds a machine's {@link AgentSchemaPack} from a partial schema
1257
- * declaration — only `context` is required; `events`/`input`/`output`/`meta`
1258
- * default to empty/unknown schemas when omitted. Pass the result as
1259
- * `setupAgent({ schemas })`'s `schemas` (or spread the individual fields
1260
- * directly into `setupAgent({ context, events, ... })` — both forms are
1261
- * accepted).
1262
- */
1263
- function createAgentSchemas(schemas) {
1264
- return {
1265
- context: schemas.context,
1266
- events: normalizeEventSchemas(withAgentUsageEventSchema(schemas.events)),
1267
- input: schemas.input,
1268
- output: schemas.output,
1269
- meta: schemas.meta,
1270
- emitted: schemas.emitted
1271
- };
1272
- }
1273
- function mergeContextSchema(base, fields) {
1274
- return { "~standard": {
1275
- version: 1,
1276
- vendor: "statelyai-agent",
1277
- validate(value) {
1278
- const baseResult = base["~standard"].validate(value);
1279
- if (baseResult instanceof Promise) throw new Error("setupAgent: async context schemas are not supported.");
1280
- if (baseResult.issues) return baseResult;
1281
- const merged = { ...baseResult.value };
1282
- const issues = [];
1283
- for (const [key, fieldSchema] of Object.entries(fields)) {
1284
- const fieldResult = fieldSchema["~standard"].validate(value[key]);
1285
- if (fieldResult instanceof Promise) throw new Error("setupAgent: async context schemas are not supported.");
1286
- if (fieldResult.issues) issues.push(...fieldResult.issues.map((issue) => ({
1287
- ...issue,
1288
- path: [key, ...issue.path ?? []]
1289
- })));
1290
- else merged[key] = fieldResult.value;
1291
- }
1292
- return issues.length > 0 ? { issues } : { value: merged };
1293
- }
1294
- } };
1295
- }
1296
- function resolveAgentStateSchemas(contextSchema, states) {
1297
- return Object.fromEntries(Object.entries(states).map(([key, state]) => {
1298
- if (!state || typeof state !== "object") return [key, state];
1299
- const children = "states" in state && state.states ? resolveAgentStateSchemas(contextSchema, state.states) : void 0;
1300
- if ("context" in state && state.context) return [key, {
1301
- schemas: { context: mergeContextSchema(contextSchema, state.context) },
1302
- ...children ? { states: children } : {}
1303
- }];
1304
- return [key, children ? {
1305
- ...state,
1306
- states: children
1307
- } : state];
1308
- }));
1309
- }
1310
- /**
1311
- * Schema-first `setup(...)` for agent machines — the standard entry point
1312
- * for authoring a machine (the blueprint) that this library then runs (via
1313
- * {@link runAgent} or the step helpers) against host-supplied model/decision
1314
- * executors. Context, events, machine input, machine output, and
1315
- * state/transition meta are all standard schemas — no `{} as Type` casts —
1316
- * and are retained on `result.schemas` for runtime validation. Also
1317
- * registers the `agent.generateText`/`agent.streamText`/`agent.userInput`/
1318
- * `agent.decide` builtin actors and lowers `requests`/`actors` into the
1319
- * machine's actor sources. The result is the xstate `setup(...)` object with
1320
- * a wrapped `result.createMachine(...)` plus `result.schemas`/`models`/
1321
- * `requests`/`appendMessages` attached. Also has a
1322
- * `setupAgent.fromConfig(...)` namespace member for building a machine from
1323
- * a serializable {@link AgentWorkflowConfig} instead of this TS API.
1324
- *
1325
- * @example
1326
- * ```ts
1327
- * const schemas = createAgentSchemas({
1328
- * context: z.object({ topic: z.string(), joke: z.string().nullable() }),
1329
- * input: z.object({ topic: z.string() }),
1330
- * output: z.object({ joke: z.string() }),
1331
- * });
1332
- *
1333
- * const agent = setupAgent({
1334
- * schemas,
1335
- * actors: { tellJoke },
1336
- * });
1337
- *
1338
- * const jokeMachine = agent.createMachine({
1339
- * context: ({ input }) => ({ topic: input.topic, joke: null }),
1340
- * initial: 'telling',
1341
- * states: {
1342
- * telling: {
1343
- * invoke: {
1344
- * id: 'joke',
1345
- * src: 'tellJoke',
1346
- * input: ({ context }) => ({ topic: context.topic }),
1347
- * onDone: ({ output }) => ({ target: 'done', context: { joke: output } }),
1348
- * },
1349
- * },
1350
- * done: { type: 'final', output: ({ context }) => ({ joke: context.joke ?? '' }) },
1351
- * },
1352
- * });
1353
- * ```
1354
- */
1355
- function setupAgent(config) {
1356
- const schemas = normalizeAgentSchemas(config);
1357
- const requestActors = createRequestActors(config.requests ?? {});
1358
- const actors = createAgentActors(config.actors, requestActors);
1359
- const base = (0, xstate.setup)({
1360
- schemas: {
1361
- context: schemas.context,
1362
- events: schemas.events,
1363
- input: schemas.input,
1364
- output: schemas.output,
1365
- meta: schemas.meta,
1366
- ...schemas.emitted && Object.keys(schemas.emitted).length > 0 ? { emitted: schemas.emitted } : {}
1367
- },
1368
- ...config.states ? { states: resolveAgentStateSchemas(schemas.context, config.states) } : {},
1369
- actors,
1370
- actions: config.actions,
1371
- guards: config.guards,
1372
- delays: config.delays
1373
- });
1374
- const createBaseMachine = base.createMachine.bind(base);
1375
- const models = config.models ?? {};
1376
- const machineOptions = {
1377
- schemas,
1378
- actors,
1379
- models
1380
- };
1381
- return Object.assign(base, {
1382
- createMachine(machineConfig) {
1383
- assertStateSchemaKeysExist(config.states, machineConfig?.states);
1384
- const machine = createBaseMachine(withRootOutputFromSingleFinal(machineConfig));
1385
- require_decision.agentExecutionOptions.set(machine, machineOptions);
1386
- if (config.isIdle) {
1387
- const rootConfig = machine.config;
1388
- if (rootConfig) require_decision.machineIdlePredicates.set(rootConfig, config.isIdle);
1389
- }
1390
- return machine;
1391
- },
1392
- schemas,
1393
- models,
1394
- requests: requestActors,
1395
- appendMessages
1396
- });
1397
- }
1398
- function collectFinalStateOutputs(states, outputs = []) {
1399
- for (const state of Object.values(states ?? {})) {
1400
- if (state?.type === "final" && state.output !== void 0) outputs.push(state.output);
1401
- collectFinalStateOutputs(state?.states, outputs);
1402
- }
1403
- return outputs;
1404
- }
1405
- function withRootOutputFromSingleFinal(config) {
1406
- if (!config || typeof config !== "object" || "output" in config || !("states" in config)) return config;
1407
- const outputs = collectFinalStateOutputs(config.states);
1408
- return outputs.length === 1 ? {
1409
- ...config,
1410
- output: outputs[0]
1411
- } : config;
1412
- }
1413
- (function(_setupAgent) {
1414
- function fromConfig(config, options) {
1415
- return setupAgentFromConfig(config, options);
1416
- }
1417
- _setupAgent.fromConfig = fromConfig;
1418
- })(setupAgent || (setupAgent = {}));
1419
- /**
1420
- * The schema pack a machine was built with — `setupAgent(...).createMachine`
1421
- * and `setupAgent.fromConfig(...)` both register one, so hosts can read a
1422
- * machine's input/event schemas at runtime without knowing how it was
1423
- * authored. Returns `undefined` for machines not built by either (a plain
1424
- * xstate `createMachine`/`setup` machine).
1425
- *
1426
- * Registration is keyed on the machine object, so a machine returned by
1427
- * `machine.provide(...)` carries no pack — read it from the machine the setup
1428
- * returned.
1429
- */
1430
- function getAgentSchemas(machine) {
1431
- return require_decision.agentExecutionOptions.get(machine)?.schemas;
1432
- }
1433
- /** Builds one TextLogic actor per `setupAgent({ requests })` entry. @internal */
1434
- function createRequestActors(requests) {
1435
- return Object.fromEntries(Object.entries(requests).map(([key, request]) => {
1436
- return [key, require_decision.createTextLogic({
1437
- ...request,
1438
- name: key,
1439
- mode: request.mode ?? "generate"
1440
- })];
1441
- }));
1442
- }
1443
- function normalizeAgentSchemas(config) {
1444
- if ("schemas" in config && config.schemas) return {
1445
- ...config.schemas,
1446
- events: normalizeEventSchemas(withAgentUsageEventSchema(config.schemas.events))
1447
- };
1448
- const loose = config;
1449
- return createAgentSchemas({
1450
- ...loose,
1451
- context: loose.context
1452
- });
1453
- }
1454
- /**
1455
- * Runtime guard: every key of the `setupAgent({ states })` narrowing map must
1456
- * name a real state node in the machine config. A typo'd key is otherwise a
1457
- * silent no-op — the narrowing simply never applies — so fail fast at
1458
- * `createMachine` time. Walks nested `states` maps in parallel with the
1459
- * machine config, since narrowing entries nest the same way.
1460
- */
1461
- function assertStateSchemaKeysExist(stateSchemas, machineStates, path = []) {
1462
- if (!stateSchemas) return;
1463
- for (const [key, stateSchema] of Object.entries(stateSchemas)) {
1464
- const machineState = machineStates?.[key];
1465
- if (!machineState || typeof machineState !== "object") {
1466
- const validKeys = Object.keys(machineStates ?? {});
1467
- const parent = path.length > 0 ? ` of state '${path.join(".")}'` : "";
1468
- throw new Error(`setupAgent: 'states' key '${[...path, key].join(".")}' does not name a state in the machine config, so its context narrowing 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 }).`);
1469
- }
1470
- if (stateSchema && typeof stateSchema === "object" && "states" in stateSchema && stateSchema.states) assertStateSchemaKeysExist(stateSchema.states, machineState.states, [...path, key]);
1471
- }
1472
- }
1473
- const RESERVED_AGENT_ACTOR_KEYS = [
1474
- ...Object.keys(require_decision.builtinTextActors),
1475
- require_decision.USER_INPUT_ACTOR,
1476
- require_decision.DECIDE_ACTOR
1477
- ];
1478
- /**
1479
- * The whole `agent.` actor-source namespace is reserved for the library, not
1480
- * just the shipped builtins: a key starting with this prefix is rejected at
1481
- * setup time so a future builtin can never collide with (or be shadowed by) a
1482
- * user source. Name your own sources without it.
1483
- */
1484
- const RESERVED_AGENT_KEY_PREFIX = "agent.";
1485
- /**
1486
- * Runtime guards over the user-supplied `actors`/`requests` keys, in one walk
1487
- * of both groups:
1488
- *
1489
- * 1. A key in the reserved `agent.` namespace is rejected — every key with
1490
- * that prefix, not only today's builtins. Without this, the builtins-first
1491
- * spread in {@link createAgentActors} lets such a key overwrite the builtin
1492
- * (`agent.decide`, …) silently, and a builtin added later would start
1493
- * colliding with user code. Deliberate override of a builtin is still
1494
- * possible after the machine is created, via
1495
- * `machine.provide({ actors: { 'agent.decide': ... } })`.
1496
- * 2. A key appearing in BOTH groups is almost certainly a mistake (whichever
1497
- * spread applies last would silently win) — fail fast with a clear message
1498
- * rather than let one implementation shadow another.
1499
- */
1500
- function assertActorKeys(actors, requests) {
1501
- const seenIn = /* @__PURE__ */ new Map();
1502
- const groups = [["actors", actors], ["requests", requests]];
1503
- for (const [groupName, group] of groups) for (const key of Object.keys(group ?? {})) {
1504
- 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}': ... } }).`);
1505
- 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.`);
1506
- const existingGroup = seenIn.get(key);
1507
- 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'.`);
1508
- seenIn.set(key, groupName);
1509
- }
1510
- }
1511
- function createAgentActors(actors, requestActors) {
1512
- assertActorKeys(actors, requestActors);
1513
- return {
1514
- ...require_decision.builtinTextActors,
1515
- [require_decision.USER_INPUT_ACTOR]: require_decision.userInputActor,
1516
- [require_decision.DECIDE_ACTOR]: require_decision.createDecideActor(),
1517
- ...actors,
1518
- ...requestActors
1519
- };
1520
- }
1521
- //#endregion
1522
- Object.defineProperty(exports, "AGENT_INIT_EVENT_TYPE", {
1523
- enumerable: true,
1524
- get: function() {
1525
- return AGENT_INIT_EVENT_TYPE;
1526
- }
1527
- });
1528
- Object.defineProperty(exports, "AGENT_USAGE_EVENT_TYPE", {
1529
- enumerable: true,
1530
- get: function() {
1531
- return AGENT_USAGE_EVENT_TYPE;
1532
- }
1533
- });
1534
- Object.defineProperty(exports, "AgentReplayDivergenceError", {
1535
- enumerable: true,
1536
- get: function() {
1537
- return AgentReplayDivergenceError;
1538
- }
1539
- });
1540
- Object.defineProperty(exports, "AgentReplayMachineMismatchError", {
1541
- enumerable: true,
1542
- get: function() {
1543
- return AgentReplayMachineMismatchError;
1544
- }
1545
- });
1546
- Object.defineProperty(exports, "appendMessages", {
1547
- enumerable: true,
1548
- get: function() {
1549
- return appendMessages;
1550
- }
1551
- });
1552
- Object.defineProperty(exports, "createAgentSchemas", {
1553
- enumerable: true,
1554
- get: function() {
1555
- return createAgentSchemas;
1556
- }
1557
- });
1558
- Object.defineProperty(exports, "createReplayEntry", {
1559
- enumerable: true,
1560
- get: function() {
1561
- return createReplayEntry;
1562
- }
1563
- });
1564
- Object.defineProperty(exports, "diffEventLogs", {
1565
- enumerable: true,
1566
- get: function() {
1567
- return diffEventLogs;
1568
- }
1569
- });
1570
- Object.defineProperty(exports, "executeAgentRequest", {
1571
- enumerable: true,
1572
- get: function() {
1573
- return executeAgentRequest;
1574
- }
1575
- });
1576
- Object.defineProperty(exports, "getAgentEffects", {
1577
- enumerable: true,
1578
- get: function() {
1579
- return getAgentEffects;
1580
- }
1581
- });
1582
- Object.defineProperty(exports, "getAgentSchemas", {
1583
- enumerable: true,
1584
- get: function() {
1585
- return getAgentSchemas;
1586
- }
1587
- });
1588
- Object.defineProperty(exports, "getInvokeEffectMetadata", {
1589
- enumerable: true,
1590
- get: function() {
1591
- return getInvokeEffectMetadata;
1592
- }
1593
- });
1594
- Object.defineProperty(exports, "initEntry", {
1595
- enumerable: true,
1596
- get: function() {
1597
- return initEntry;
1598
- }
1599
- });
1600
- Object.defineProperty(exports, "initialAgentStep", {
1601
- enumerable: true,
1602
- get: function() {
1603
- return initialAgentStep;
1604
- }
1605
- });
1606
- Object.defineProperty(exports, "messagesSchema", {
1607
- enumerable: true,
1608
- get: function() {
1609
- return messagesSchema;
1610
- }
1611
- });
1612
- Object.defineProperty(exports, "replay", {
1613
- enumerable: true,
1614
- get: function() {
1615
- return replay;
1616
- }
1617
- });
1618
- Object.defineProperty(exports, "resolveAgentStep", {
1619
- enumerable: true,
1620
- get: function() {
1621
- return resolveAgentStep;
1622
- }
1623
- });
1624
- Object.defineProperty(exports, "setupAgent", {
1625
- enumerable: true,
1626
- get: function() {
1627
- return setupAgent;
1628
- }
1629
- });
1630
- Object.defineProperty(exports, "transitionAgentStep", {
1631
- enumerable: true,
1632
- get: function() {
1633
- return transitionAgentStep;
1634
- }
1635
- });
1636
- Object.defineProperty(exports, "validateReplayEntries", {
1637
- enumerable: true,
1638
- get: function() {
1639
- return validateReplayEntries;
1640
- }
1641
- });