@statelyai/agent 2.0.0-alpha.11 → 2.0.0-alpha.13

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 (66) hide show
  1. package/dist/ai-sdk.cjs +4 -5
  2. package/dist/ai-sdk.d.cts +7 -4
  3. package/dist/ai-sdk.d.mts +7 -4
  4. package/dist/ai-sdk.mjs +1 -2
  5. package/dist/{events-JiVPYrct.mjs → decision-BezSD_YC.mjs} +327 -20
  6. package/dist/{events-CRQj3VtP.cjs → decision-dWGhBh0P.cjs} +401 -28
  7. package/dist/errors-BQRk9eiZ.d.cts +19 -0
  8. package/dist/errors-C9rxnWbX.d.mts +19 -0
  9. package/dist/errors-CeSXQx0v.mjs +23 -0
  10. package/dist/errors-DUBBzRLP.cjs +28 -0
  11. package/dist/event-log-store-CNT_7F0V.cjs +452 -0
  12. package/dist/event-log-store-CriMgX1D.d.mts +144 -0
  13. package/dist/event-log-store-D7pWtIhb.mjs +411 -0
  14. package/dist/event-log-store-Ruq18mGp.d.cts +144 -0
  15. package/dist/index.cjs +1050 -705
  16. package/dist/index.d.cts +538 -565
  17. package/dist/index.d.mts +538 -565
  18. package/dist/index.mjs +950 -644
  19. package/dist/machines.cjs +752 -0
  20. package/dist/machines.d.cts +372 -0
  21. package/dist/machines.d.mts +372 -0
  22. package/dist/machines.mjs +741 -0
  23. package/dist/otel.cjs +268 -0
  24. package/dist/otel.d.cts +67 -0
  25. package/dist/otel.d.mts +67 -0
  26. package/dist/otel.mjs +267 -0
  27. package/dist/run-agent-C3mFDGTf.d.mts +1111 -0
  28. package/dist/run-agent-DnvtcnTZ.d.cts +1111 -0
  29. package/dist/setup-agent-DAZZSjDS.mjs +1711 -0
  30. package/dist/setup-agent-DP95MFrI.cjs +1836 -0
  31. package/dist/sqlite.cjs +135 -0
  32. package/dist/sqlite.d.cts +57 -0
  33. package/dist/sqlite.d.mts +57 -0
  34. package/dist/sqlite.mjs +133 -0
  35. package/dist/{text-logic-CaKqgX4Y.d.mts → text-logic-BDxwQNsD.d.cts} +155 -72
  36. package/dist/{text-logic-Ckhr2kKC.d.cts → text-logic-TkKPw8Aq.d.mts} +155 -72
  37. package/dist/{types-qm00QF91.d.mts → types-QbEfCVny.d.cts} +1 -1
  38. package/dist/{types-C9QiMjre.d.cts → types-_FXoFBGO.d.mts} +1 -1
  39. package/package.json +47 -39
  40. package/readme.md +49 -12
  41. package/schemas/agent-workflow.json +40 -21
  42. package/skills/generate-machine/SKILL.md +267 -0
  43. package/dist/adapter.cjs +0 -15
  44. package/dist/adapter.d.cts +0 -4
  45. package/dist/adapter.d.mts +0 -4
  46. package/dist/adapter.mjs +0 -2
  47. package/dist/decision-C3k4ve51.mjs +0 -227
  48. package/dist/decision-D8wJrM8W.cjs +0 -286
  49. package/dist/openai-compat.cjs +0 -309
  50. package/dist/openai-compat.d.cts +0 -59
  51. package/dist/openai-compat.d.mts +0 -59
  52. package/dist/openai-compat.mjs +0 -308
  53. package/dist/steps-BALp1eZo.d.mts +0 -198
  54. package/dist/steps-CVe54GPP.cjs +0 -420
  55. package/dist/steps-CkyyyuHd.mjs +0 -379
  56. package/dist/steps-MjnQI4aB.d.cts +0 -198
  57. package/dist/steps.cjs +0 -12
  58. package/dist/steps.d.cts +0 -3
  59. package/dist/steps.d.mts +0 -3
  60. package/dist/steps.mjs +0 -3
  61. package/dist/utils-BYqT_Dyv.d.cts +0 -108
  62. package/dist/utils-Do5wIJrh.d.mts +0 -108
  63. package/dist/zod.cjs +0 -31
  64. package/dist/zod.d.cts +0 -30
  65. package/dist/zod.d.mts +0 -30
  66. package/dist/zod.mjs +0 -30
@@ -0,0 +1,752 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_setup_agent = require("./setup-agent-DP95MFrI.cjs");
3
+ //#region src/machines/internal.ts
4
+ /** The builtin inline text request every preset lowers a request entry to. */
5
+ const GENERATE_TEXT_SRC = "agent.generateText";
6
+ /** The builtin decision actor the router and supervisor presets invoke. */
7
+ const DECIDE_SRC = "agent.decide";
8
+ /**
9
+ * A permissive Standard Schema that carries a JSON Schema. Presets build their
10
+ * own context/input/output schemas this way so the module stays dependency-free
11
+ * (no Zod in `src/`) while `lintAgentMachine` and JSON tooling still see a
12
+ * serializable shape.
13
+ *
14
+ * @internal
15
+ */
16
+ function objectSchema(properties, required = []) {
17
+ const json = {
18
+ type: "object",
19
+ properties,
20
+ required: [...required]
21
+ };
22
+ return { "~standard": {
23
+ version: 1,
24
+ vendor: "statelyai-agent-machines",
25
+ validate: (value) => value !== null && typeof value === "object" ? { value } : { issues: [{ message: "Expected an object" }] },
26
+ jsonSchema: { input: () => json }
27
+ } };
28
+ }
29
+ /** A payload-less event schema (`{}` shorthand equivalent) with a JSON Schema. @internal */
30
+ const emptyPayload = objectSchema({});
31
+ /** JSON Schema fragments reused across preset context schemas. @internal */
32
+ const jsonString = { type: "string" };
33
+ /** @internal */
34
+ const jsonNumber = { type: "number" };
35
+ /** @internal */
36
+ const jsonRecord = {
37
+ type: "object",
38
+ additionalProperties: true
39
+ };
40
+ /** @internal */
41
+ const jsonArray = { type: "array" };
42
+ /** @internal */
43
+ const jsonAny = {};
44
+ /** True when `entry` delegates to a child machine rather than an inline request. @internal */
45
+ function isMachineEntry(entry) {
46
+ return "machine" in entry && !!entry.machine;
47
+ }
48
+ /** The actor sources a preset must register: one per child-machine entry. @internal */
49
+ function machineActors(entries) {
50
+ return Object.fromEntries(Object.entries(entries).filter(([, entry]) => isMachineEntry(entry)).map(([name, entry]) => [name, entry.machine]));
51
+ }
52
+ /** The `src` an entry invokes: its own actor key (child machine) or the inline text builtin. @internal */
53
+ function entrySrc(name, entry) {
54
+ return isMachineEntry(entry) ? name : GENERATE_TEXT_SRC;
55
+ }
56
+ /** Builds an entry's invoke `input` from the current prompt. @internal */
57
+ function entryInput(name, entry, defaultModel, prompt) {
58
+ if (isMachineEntry(entry)) return entry.input ? entry.input({ prompt }) : { prompt };
59
+ return requestInput(name, entry, defaultModel, prompt);
60
+ }
61
+ /** Builds the inline `agent.generateText` input for a request entry. @internal */
62
+ function requestInput(name, entry, defaultModel, prompt) {
63
+ const model = entry.model ?? defaultModel;
64
+ if (!model) throw new Error(`Preset request '${name}' has no model. Set 'model' on the entry or on the factory config.`);
65
+ return {
66
+ name,
67
+ model,
68
+ ...entry.instructions ? { system: entry.instructions } : {},
69
+ prompt,
70
+ ...entry.tools ? { tools: entry.tools } : {},
71
+ ...entry.outputSchema ? { outputSchema: entry.outputSchema } : {},
72
+ ...entry.maxTurns !== void 0 ? { metadata: { maxSteps: entry.maxTurns } } : {}
73
+ };
74
+ }
75
+ /**
76
+ * Rejects an entry name that would collide with a preset's own state names or
77
+ * with the reserved `agent.*` actor namespace. A collision is otherwise a
78
+ * confusing machine-build failure far from its cause.
79
+ *
80
+ * @internal
81
+ */
82
+ function assertEntryNames(kind, names, reserved) {
83
+ if (names.length === 0) throw new Error(`Preset requires at least one ${kind}.`);
84
+ for (const name of names) {
85
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) throw new Error(`Invalid ${kind} name '${name}'. Names must be identifier-like (letters, digits, underscore; not starting with a digit) — they become state names and event types.`);
86
+ if (reserved.includes(name)) throw new Error(`Invalid ${kind} name '${name}': it collides with a state this preset already declares (${reserved.join(", ")}). Rename it.`);
87
+ }
88
+ }
89
+ /** Renders the `name: description` list a routing/supervising model chooses from. @internal */
90
+ function renderEntryList(entries) {
91
+ return Object.entries(entries).map(([name, entry]) => `- ${name}: ${entry.description ?? "(no description)"}`).join("\n");
92
+ }
93
+ //#endregion
94
+ //#region src/machines/tool-loop.ts
95
+ const contextSchema$6 = objectSchema({
96
+ prompt: jsonString,
97
+ result: jsonAny
98
+ }, ["prompt"]);
99
+ const inputSchema$6 = objectSchema({ prompt: jsonString }, ["prompt"]);
100
+ const outputSchema$5 = objectSchema({ result: jsonAny }, ["result"]);
101
+ /**
102
+ * The single-state tool loop: one text request carries the `tools`, and the
103
+ * host runs the tool loop inside it (`maxTurns` bounds it). Selecting and
104
+ * executing tools is the model + host's business, not machine states.
105
+ *
106
+ * States: `answering` → `done`.
107
+ *
108
+ * ```ts
109
+ * const machine = createToolLoopMachine({
110
+ * model: "quick",
111
+ * instructions: "Answer using the tools.",
112
+ * tools: { calculate },
113
+ * maxTurns: 5,
114
+ * });
115
+ *
116
+ * const result = await runAgent(machine, {
117
+ * input: { prompt: "What is 42 * 17?" },
118
+ * executors,
119
+ * });
120
+ * // Snapshots and log entries carry machine.version ("1") automatically.
121
+ * ```
122
+ */
123
+ function createToolLoopMachine(config) {
124
+ const { model, instructions, tools, outputSchema: resultSchema, maxTurns, interruptOn } = config;
125
+ const metadata = {
126
+ ...maxTurns !== void 0 ? { maxSteps: maxTurns } : {},
127
+ ...interruptOn && interruptOn.length > 0 ? { interruptOn: [...interruptOn] } : {}
128
+ };
129
+ return require_setup_agent.setupAgent({
130
+ context: contextSchema$6,
131
+ input: inputSchema$6,
132
+ output: outputSchema$5
133
+ }).createMachine({
134
+ id: "tool-loop",
135
+ version: "1",
136
+ context: ({ input }) => ({
137
+ prompt: input.prompt,
138
+ result: null
139
+ }),
140
+ initial: "answering",
141
+ states: {
142
+ answering: { invoke: {
143
+ id: "answer",
144
+ src: GENERATE_TEXT_SRC,
145
+ input: ({ context }) => ({
146
+ name: "answer",
147
+ model,
148
+ ...instructions ? { system: instructions } : {},
149
+ prompt: context.prompt,
150
+ ...tools ? { tools } : {},
151
+ ...resultSchema ? { outputSchema: resultSchema } : {},
152
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
153
+ }),
154
+ onDone: ({ output }) => ({
155
+ target: "done",
156
+ context: { result: output }
157
+ })
158
+ } },
159
+ done: {
160
+ type: "final",
161
+ output: ({ context }) => ({ result: context.result })
162
+ }
163
+ }
164
+ });
165
+ }
166
+ //#endregion
167
+ //#region src/machines/sequential.ts
168
+ const contextSchema$5 = objectSchema({
169
+ prompt: jsonString,
170
+ results: jsonRecord,
171
+ previous: jsonAny
172
+ }, ["prompt", "results"]);
173
+ const inputSchema$5 = objectSchema({ prompt: jsonString }, ["prompt"]);
174
+ const outputSchema$4 = objectSchema({
175
+ results: jsonRecord,
176
+ output: jsonAny
177
+ }, ["results"]);
178
+ /**
179
+ * A prompt chain: each step is one state, and each step's output feeds the
180
+ * next. The default prompt for a step is the previous step's output, so a
181
+ * chain needs no `prompt` functions at all.
182
+ *
183
+ * States: one per step, in order → `done`.
184
+ *
185
+ * ```ts
186
+ * const machine = createSequentialMachine({
187
+ * model: "quick",
188
+ * steps: [
189
+ * { name: "outline", instructions: "Outline the post." },
190
+ * { name: "draft", instructions: "Write the post from the outline." },
191
+ * { name: "polish", instructions: "Tighten the prose." },
192
+ * ],
193
+ * });
194
+ * ```
195
+ */
196
+ function createSequentialMachine(config) {
197
+ const { model, steps } = config;
198
+ assertEntryNames("step", steps.map((step) => step.name), ["done"]);
199
+ const agentSetup = require_setup_agent.setupAgent({
200
+ context: contextSchema$5,
201
+ input: inputSchema$5,
202
+ output: outputSchema$4
203
+ });
204
+ const states = {};
205
+ steps.forEach((step, index) => {
206
+ const next = steps[index + 1]?.name ?? "done";
207
+ states[step.name] = { invoke: {
208
+ id: step.name,
209
+ src: GENERATE_TEXT_SRC,
210
+ input: ({ context }) => requestInput(step.name, {
211
+ instructions: step.instructions,
212
+ model: step.model,
213
+ outputSchema: step.outputSchema,
214
+ tools: step.tools,
215
+ maxTurns: step.maxTurns
216
+ }, model, step.prompt ? step.prompt({
217
+ prompt: context.prompt,
218
+ results: context.results,
219
+ previous: context.previous
220
+ }) : context.previous === null || context.previous === void 0 ? context.prompt : String(context.previous)),
221
+ onDone: ({ context, output }) => ({
222
+ target: next,
223
+ context: {
224
+ results: {
225
+ ...context.results,
226
+ [step.name]: output
227
+ },
228
+ previous: output
229
+ }
230
+ })
231
+ } };
232
+ });
233
+ states.done = {
234
+ type: "final",
235
+ output: ({ context }) => ({
236
+ results: context.results,
237
+ output: context.previous
238
+ })
239
+ };
240
+ const machineConfig = {
241
+ id: "sequential",
242
+ version: "1",
243
+ context: ({ input }) => ({
244
+ prompt: input.prompt,
245
+ results: {},
246
+ previous: null
247
+ }),
248
+ initial: steps[0].name,
249
+ states
250
+ };
251
+ return agentSetup.createMachine(machineConfig);
252
+ }
253
+ //#endregion
254
+ //#region src/machines/router.ts
255
+ const contextSchema$4 = objectSchema({
256
+ prompt: jsonString,
257
+ route: { type: ["string", "null"] },
258
+ result: jsonAny
259
+ }, ["prompt"]);
260
+ const inputSchema$4 = objectSchema({ prompt: jsonString }, ["prompt"]);
261
+ const outputSchema$3 = objectSchema({
262
+ route: { type: ["string", "null"] },
263
+ result: jsonAny
264
+ }, ["route"]);
265
+ /** The event a route decision chooses: `ROUTE_<name>`. */
266
+ function routeEventType(route) {
267
+ return `ROUTE_${route}`;
268
+ }
269
+ /**
270
+ * One `agent.decide` picks exactly one declared route, then the machine runs
271
+ * it. Only the declared routes have events and transitions, so a model naming
272
+ * anything else is rejected before any work happens — illegal routes are
273
+ * impossible, not discouraged.
274
+ *
275
+ * States: `routing` → one state per route → `done`.
276
+ *
277
+ * ```ts
278
+ * const machine = createRouterMachine({
279
+ * model: "quick",
280
+ * routes: {
281
+ * billing: { description: "Payments and invoices", instructions: "Answer the billing question." },
282
+ * technical: { description: "Bugs and outages", machine: technicalMachine },
283
+ * },
284
+ * fallback: "technical",
285
+ * });
286
+ * ```
287
+ */
288
+ function createRouterMachine(config) {
289
+ const { model, instructions, routes, fallback } = config;
290
+ const names = Object.keys(routes);
291
+ assertEntryNames("route", names, ["routing", "done"]);
292
+ if (fallback !== void 0 && !names.includes(fallback)) throw new Error(`createRouterMachine: fallback '${fallback}' is not a declared route (${names.join(", ")}).`);
293
+ const agentSetup = require_setup_agent.setupAgent({
294
+ context: contextSchema$4,
295
+ input: inputSchema$4,
296
+ output: outputSchema$3,
297
+ events: Object.fromEntries(names.map((name) => [routeEventType(name), emptyPayload])),
298
+ actors: machineActors(routes)
299
+ });
300
+ const routeList = renderEntryList(routes);
301
+ const states = {
302
+ routing: {
303
+ invoke: {
304
+ id: "route",
305
+ src: DECIDE_SRC,
306
+ input: ({ context }) => ({
307
+ model,
308
+ system: instructions ?? "Route the request to exactly one destination. Choose the single best fit.",
309
+ prompt: `Request:\n${context.prompt}\n\nDestinations:\n${routeList}`,
310
+ allowedEvents: names.map(routeEventType)
311
+ }),
312
+ ...fallback ? { onError: {
313
+ target: fallback,
314
+ context: { route: fallback }
315
+ } } : {}
316
+ },
317
+ on: Object.fromEntries(names.map((name) => [routeEventType(name), {
318
+ target: name,
319
+ context: { route: name }
320
+ }]))
321
+ },
322
+ done: {
323
+ type: "final",
324
+ output: ({ context }) => ({
325
+ route: context.route,
326
+ result: context.result
327
+ })
328
+ }
329
+ };
330
+ for (const [name, entry] of Object.entries(routes)) states[name] = { invoke: {
331
+ id: name,
332
+ src: entrySrc(name, entry),
333
+ input: ({ context }) => entryInput(name, entry, model, context.prompt),
334
+ onDone: ({ output }) => ({
335
+ target: "done",
336
+ context: { result: output }
337
+ })
338
+ } };
339
+ const machineConfig = {
340
+ id: "router",
341
+ version: "1",
342
+ context: ({ input }) => ({
343
+ prompt: input.prompt,
344
+ route: null,
345
+ result: null
346
+ }),
347
+ initial: "routing",
348
+ states
349
+ };
350
+ return agentSetup.createMachine(machineConfig);
351
+ }
352
+ //#endregion
353
+ //#region src/machines/parallel.ts
354
+ const contextSchema$3 = objectSchema({
355
+ prompt: jsonString,
356
+ results: jsonRecord
357
+ }, ["prompt", "results"]);
358
+ const inputSchema$3 = objectSchema({ prompt: jsonString }, ["prompt"]);
359
+ const outputSchema$2 = objectSchema({ results: jsonRecord }, ["results"]);
360
+ /**
361
+ * Static fan-out: every branch runs concurrently as its own region of one
362
+ * parallel state, and the run joins when all of them finish. Results are keyed
363
+ * by branch name.
364
+ *
365
+ * Branch count is fixed at author time. For an N decided at run time (a planner
366
+ * choosing subtopics), eject to `examples/fan-out`, which spawns branches
367
+ * dynamically.
368
+ *
369
+ * States: `running` (one region per branch) → `done`.
370
+ *
371
+ * ```ts
372
+ * const machine = createParallelMachine({
373
+ * model: "quick",
374
+ * branches: {
375
+ * security: { instructions: "Review for security issues." },
376
+ * performance: { instructions: "Review for performance issues." },
377
+ * },
378
+ * });
379
+ * ```
380
+ */
381
+ function createParallelMachine(config) {
382
+ const { model, branches } = config;
383
+ assertEntryNames("branch", Object.keys(branches), ["running", "done"]);
384
+ const agentSetup = require_setup_agent.setupAgent({
385
+ context: contextSchema$3,
386
+ input: inputSchema$3,
387
+ output: outputSchema$2,
388
+ actors: machineActors(branches)
389
+ });
390
+ const regions = {};
391
+ for (const [name, entry] of Object.entries(branches)) regions[name] = {
392
+ initial: "running",
393
+ states: {
394
+ running: { invoke: {
395
+ id: name,
396
+ src: entrySrc(name, entry),
397
+ input: ({ context }) => entryInput(name, entry, model, context.prompt),
398
+ onDone: ({ context, output }) => ({
399
+ target: "done",
400
+ context: { results: {
401
+ ...context.results,
402
+ [name]: output
403
+ } }
404
+ })
405
+ } },
406
+ done: { type: "final" }
407
+ }
408
+ };
409
+ const machineConfig = {
410
+ id: "parallel",
411
+ version: "1",
412
+ context: ({ input }) => ({
413
+ prompt: input.prompt,
414
+ results: {}
415
+ }),
416
+ initial: "running",
417
+ states: {
418
+ running: {
419
+ type: "parallel",
420
+ states: regions,
421
+ onDone: { target: "done" }
422
+ },
423
+ done: {
424
+ type: "final",
425
+ output: ({ context }) => ({ results: context.results })
426
+ }
427
+ }
428
+ };
429
+ return agentSetup.createMachine(machineConfig);
430
+ }
431
+ //#endregion
432
+ //#region src/machines/loop.ts
433
+ const contextSchema$2 = objectSchema({
434
+ prompt: jsonString,
435
+ iterations: jsonNumber,
436
+ results: jsonArray,
437
+ last: jsonAny
438
+ }, [
439
+ "prompt",
440
+ "iterations",
441
+ "results"
442
+ ]);
443
+ const inputSchema$2 = objectSchema({ prompt: jsonString }, ["prompt"]);
444
+ const outputSchema$1 = objectSchema({
445
+ iterations: jsonNumber,
446
+ results: jsonArray,
447
+ last: jsonAny
448
+ }, ["iterations", "results"]);
449
+ /**
450
+ * A bounded repeat: run the body, check `until` over the accumulated state,
451
+ * and either stop or go again. `maxIterations` is a guard, so the loop cannot
452
+ * run away even if `until` never returns `true`.
453
+ *
454
+ * States: `running` → `checking` → (`running` | `done`).
455
+ *
456
+ * ```ts
457
+ * const machine = createLoopMachine({
458
+ * model: "quick",
459
+ * body: { instructions: "Improve the draft. Return only the draft." },
460
+ * until: ({ last }) => String(last).length > 500,
461
+ * maxIterations: 4,
462
+ * });
463
+ * ```
464
+ */
465
+ function createLoopMachine(config) {
466
+ const { model, body, until, maxIterations } = config;
467
+ if (!Number.isInteger(maxIterations) || maxIterations < 1) throw new Error("createLoopMachine: maxIterations must be an integer >= 1.");
468
+ const agentSetup = require_setup_agent.setupAgent({
469
+ context: contextSchema$2,
470
+ input: inputSchema$2,
471
+ output: outputSchema$1,
472
+ actors: isMachineEntry(body) ? { body: body.machine } : {}
473
+ });
474
+ const loopState = (context) => ({
475
+ prompt: context.prompt,
476
+ iterations: context.iterations,
477
+ results: context.results,
478
+ last: context.last
479
+ });
480
+ const machineConfig = {
481
+ id: "loop",
482
+ version: "1",
483
+ context: ({ input }) => ({
484
+ prompt: input.prompt,
485
+ iterations: 0,
486
+ results: [],
487
+ last: null
488
+ }),
489
+ initial: "running",
490
+ states: {
491
+ running: { invoke: {
492
+ id: "body",
493
+ src: entrySrc("body", body),
494
+ input: ({ context }) => entryInput("body", body, model, body.prompt ? body.prompt(loopState(context)) : context.prompt),
495
+ onDone: ({ context, output }) => ({
496
+ target: "checking",
497
+ context: {
498
+ iterations: context.iterations + 1,
499
+ results: [...context.results, output],
500
+ last: output
501
+ }
502
+ })
503
+ } },
504
+ checking: {
505
+ type: "choice",
506
+ choice: ({ context }) => context.iterations >= maxIterations || until(loopState(context)) ? { target: "done" } : { target: "running" }
507
+ },
508
+ done: {
509
+ type: "final",
510
+ output: ({ context }) => ({
511
+ iterations: context.iterations,
512
+ results: context.results,
513
+ last: context.last
514
+ })
515
+ }
516
+ }
517
+ };
518
+ return agentSetup.createMachine(machineConfig);
519
+ }
520
+ //#endregion
521
+ //#region src/machines/supervisor.ts
522
+ const contextSchema$1 = objectSchema({
523
+ task: jsonString,
524
+ results: jsonRecord,
525
+ turns: jsonNumber,
526
+ worker: { type: ["string", "null"] }
527
+ }, [
528
+ "task",
529
+ "results",
530
+ "turns"
531
+ ]);
532
+ const inputSchema$1 = objectSchema({ task: jsonString }, ["task"]);
533
+ const outputSchema = objectSchema({
534
+ results: jsonRecord,
535
+ turns: jsonNumber
536
+ }, ["results", "turns"]);
537
+ /** The event a supervising decision chooses to delegate to a worker: `DELEGATE_<name>`. */
538
+ function delegateEventType(worker) {
539
+ return `DELEGATE_${worker}`;
540
+ }
541
+ /** The event a supervising decision chooses to stop. */
542
+ const FINISH_EVENT_TYPE = "FINISH";
543
+ /**
544
+ * A supervisor delegating to typed workers: each turn, one `agent.decide`
545
+ * picks a worker or `FINISH`. Worker results accumulate in context and are fed
546
+ * back into the next decision.
547
+ *
548
+ * Control always returns to the supervisor after a worker finishes — that is
549
+ * what separates this from {@link createHandoffMachine}, where control
550
+ * transfers and does not come back.
551
+ *
552
+ * `maxTurns` bounds the delegations twice over: a spent budget removes every
553
+ * `DELEGATE_*` from the decision's candidate events, and a guard on each
554
+ * delegate transition rejects one anyway. `FINISH` is all that is left.
555
+ *
556
+ * States: `supervising` → one state per worker → `supervising` → … → `done`.
557
+ *
558
+ * ```ts
559
+ * const machine = createSupervisorMachine({
560
+ * model: "quick",
561
+ * workers: {
562
+ * researcher: { description: "Facts and background", instructions: "Research it." },
563
+ * writer: { description: "Prose and summaries", instructions: "Write it up." },
564
+ * },
565
+ * maxTurns: 4,
566
+ * });
567
+ * ```
568
+ */
569
+ function createSupervisorMachine(config) {
570
+ const { model, instructions, workers, maxTurns = 6 } = config;
571
+ const names = Object.keys(workers);
572
+ assertEntryNames("worker", names, ["supervising", "done"]);
573
+ if (!Number.isInteger(maxTurns) || maxTurns < 1) throw new Error("createSupervisorMachine: maxTurns must be an integer >= 1.");
574
+ const agentSetup = require_setup_agent.setupAgent({
575
+ context: contextSchema$1,
576
+ input: inputSchema$1,
577
+ output: outputSchema,
578
+ events: {
579
+ ...Object.fromEntries(names.map((name) => [delegateEventType(name), emptyPayload])),
580
+ [FINISH_EVENT_TYPE]: emptyPayload
581
+ },
582
+ actors: machineActors(workers)
583
+ });
584
+ const workerList = renderEntryList(workers);
585
+ const states = {
586
+ supervising: {
587
+ invoke: {
588
+ id: "supervise",
589
+ src: DECIDE_SRC,
590
+ input: ({ context }) => ({
591
+ model,
592
+ system: instructions ?? "You are a supervisor. Delegate the task to one worker at a time, then finish once the accumulated results answer it.",
593
+ prompt: `Task:\n${context.task}\n\nWorkers:\n${workerList}\n\nResults so far:\n${renderResults(context.results)}\n\nTurns used: ${context.turns} of ${maxTurns}.`,
594
+ allowedEvents: context.turns < maxTurns ? [...names.map(delegateEventType), FINISH_EVENT_TYPE] : [FINISH_EVENT_TYPE]
595
+ })
596
+ },
597
+ on: {
598
+ ...Object.fromEntries(names.map((name) => [delegateEventType(name), ({ context }) => context.turns < maxTurns ? {
599
+ target: name,
600
+ context: { worker: name }
601
+ } : void 0])),
602
+ [FINISH_EVENT_TYPE]: { target: "done" }
603
+ }
604
+ },
605
+ done: {
606
+ type: "final",
607
+ output: ({ context }) => ({
608
+ results: context.results,
609
+ turns: context.turns
610
+ })
611
+ }
612
+ };
613
+ for (const [name, entry] of Object.entries(workers)) states[name] = { invoke: {
614
+ id: name,
615
+ src: entrySrc(name, entry),
616
+ input: ({ context }) => entryInput(name, entry, model, context.task),
617
+ onDone: ({ context, output }) => ({
618
+ target: "supervising",
619
+ context: {
620
+ results: {
621
+ ...context.results,
622
+ [name]: output
623
+ },
624
+ turns: context.turns + 1
625
+ }
626
+ })
627
+ } };
628
+ const machineConfig = {
629
+ id: "supervisor",
630
+ version: "1",
631
+ context: ({ input }) => ({
632
+ task: input.task,
633
+ results: {},
634
+ turns: 0,
635
+ worker: null
636
+ }),
637
+ initial: "supervising",
638
+ states
639
+ };
640
+ return agentSetup.createMachine(machineConfig);
641
+ }
642
+ function renderResults(results) {
643
+ const entries = Object.entries(results);
644
+ if (entries.length === 0) return "(none yet)";
645
+ return entries.map(([name, value]) => `- ${name}: ${typeof value === "string" ? value : JSON.stringify(value)}`).join("\n");
646
+ }
647
+ //#endregion
648
+ //#region src/machines/handoff.ts
649
+ const contextSchema = objectSchema({
650
+ message: jsonString,
651
+ activeAgent: jsonString,
652
+ reply: jsonAny
653
+ }, ["message", "activeAgent"]);
654
+ const inputSchema = objectSchema({
655
+ message: jsonString,
656
+ activeAgent: jsonString
657
+ }, ["message"]);
658
+ const transferPayload = objectSchema({ message: jsonString });
659
+ /** The event that hands the mic to a peer: `transfer_to_<name>`. */
660
+ function transferEventType(agent) {
661
+ return `transfer_to_${agent}`;
662
+ }
663
+ /**
664
+ * Peer handoff (the swarm shape): `context.activeAgent` holds the mic, runs one
665
+ * turn, then the machine settles idle in `waiting`. A `transfer_to_<name>`
666
+ * event moves the mic to a peer and re-routes.
667
+ *
668
+ * Control TRANSFERS and does not return — the opposite of
669
+ * {@link createSupervisorMachine}, where every worker hands control back.
670
+ *
671
+ * There is no final state: a conversation ends when the host stops resuming it.
672
+ * Persist the idle snapshot between turns; `activeAgent` round-trips with it.
673
+ *
674
+ * States: `routing` → one turn state per agent → `waiting` → `routing` → …
675
+ *
676
+ * ```ts
677
+ * const machine = createHandoffMachine({
678
+ * model: "quick",
679
+ * defaultActiveAgent: "travel",
680
+ * agents: {
681
+ * travel: { description: "Destinations and itineraries", instructions: "You are a travel concierge." },
682
+ * food: { description: "Restaurants and dishes", instructions: "You are a food concierge." },
683
+ * },
684
+ * });
685
+ *
686
+ * const next = await runAgent(machine, {
687
+ * snapshot,
688
+ * event: { type: "transfer_to_food", message: "What should I eat there?" },
689
+ * executors,
690
+ * });
691
+ * ```
692
+ */
693
+ function createHandoffMachine(config) {
694
+ const { agents, defaultActiveAgent, model } = config;
695
+ const names = Object.keys(agents);
696
+ assertEntryNames("agent", names, ["routing", "waiting"]);
697
+ if (!names.includes(defaultActiveAgent)) throw new Error(`createHandoffMachine: defaultActiveAgent '${defaultActiveAgent}' is not a declared agent (${names.join(", ")}).`);
698
+ const agentSetup = require_setup_agent.setupAgent({
699
+ context: contextSchema,
700
+ input: inputSchema,
701
+ events: Object.fromEntries(names.map((name) => [transferEventType(name), transferPayload])),
702
+ actors: machineActors(agents),
703
+ isSuspended: (snapshot) => snapshot.matches("waiting")
704
+ });
705
+ const turnState = (name) => `${name}Turn`;
706
+ const states = {
707
+ routing: {
708
+ type: "choice",
709
+ choice: ({ context }) => ({ target: names.includes(context.activeAgent) ? turnState(context.activeAgent) : turnState(defaultActiveAgent) })
710
+ },
711
+ waiting: { on: Object.fromEntries(names.map((name) => [transferEventType(name), ({ context, event }) => ({
712
+ target: "routing",
713
+ context: {
714
+ activeAgent: name,
715
+ message: event.message ?? context.message
716
+ }
717
+ })])) }
718
+ };
719
+ for (const [name, entry] of Object.entries(agents)) states[turnState(name)] = { invoke: {
720
+ id: name,
721
+ src: entrySrc(name, entry),
722
+ input: ({ context }) => entryInput(name, entry, model, context.message),
723
+ onDone: ({ output }) => ({
724
+ target: "waiting",
725
+ context: { reply: output }
726
+ })
727
+ } };
728
+ const machineConfig = {
729
+ id: "handoff",
730
+ version: "1",
731
+ context: ({ input }) => ({
732
+ message: input.message,
733
+ activeAgent: input.activeAgent ?? defaultActiveAgent,
734
+ reply: null
735
+ }),
736
+ initial: "routing",
737
+ states
738
+ };
739
+ return agentSetup.createMachine(machineConfig);
740
+ }
741
+ //#endregion
742
+ exports.FINISH_EVENT_TYPE = FINISH_EVENT_TYPE;
743
+ exports.createHandoffMachine = createHandoffMachine;
744
+ exports.createLoopMachine = createLoopMachine;
745
+ exports.createParallelMachine = createParallelMachine;
746
+ exports.createRouterMachine = createRouterMachine;
747
+ exports.createSequentialMachine = createSequentialMachine;
748
+ exports.createSupervisorMachine = createSupervisorMachine;
749
+ exports.createToolLoopMachine = createToolLoopMachine;
750
+ exports.delegateEventType = delegateEventType;
751
+ exports.routeEventType = routeEventType;
752
+ exports.transferEventType = transferEventType;