@statelyai/agent 2.0.0-alpha.30 → 2.0.0-alpha.31

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 (68) hide show
  1. package/CHANGELOG.md +1733 -0
  2. package/dist/ai-sdk.cjs +8 -8
  3. package/dist/ai-sdk.d.cts +1 -1
  4. package/dist/ai-sdk.d.mts +1 -1
  5. package/dist/ai-sdk.mjs +3 -3
  6. package/dist/{decision-BHkvuImD.mjs → decision-DqO018Tp.mjs} +22 -9
  7. package/dist/{decision-CIb7ddIv.cjs → decision-Iys2hzg3.cjs} +30 -17
  8. package/dist/{event-log-BZRfBRd7.cjs → event-log-Bdww2l1D.cjs} +103 -24
  9. package/dist/{event-log-DJCMHek_.mjs → event-log-DE430ZCa.mjs} +86 -25
  10. package/dist/{event-log-store-DZR4IIWe.cjs → event-log-store-BWMLi6oh.cjs} +1 -1
  11. package/dist/{event-log-store-DsP6GCRh.mjs → event-log-store-CCWdTPEP.mjs} +1 -1
  12. package/dist/{event-log-store-CIIJohjj.d.mts → event-log-store-DTf_OzB-.d.cts} +1 -1
  13. package/dist/{event-log-store-CLAC9q2Y.d.cts → event-log-store-RziIobdW.d.mts} +1 -1
  14. package/dist/index.cjs +129 -21
  15. package/dist/index.d.cts +58 -11
  16. package/dist/index.d.mts +58 -11
  17. package/dist/index.mjs +126 -19
  18. package/dist/log.cjs +2 -2
  19. package/dist/log.d.cts +1 -1
  20. package/dist/log.d.mts +1 -1
  21. package/dist/log.mjs +2 -2
  22. package/dist/machines.cjs +1 -1
  23. package/dist/machines.mjs +1 -1
  24. package/dist/{model-source-BaHwJ1wK.mjs → model-source-CXsSZPq0.mjs} +1 -2
  25. package/dist/{model-source-BCKg4qJ1.cjs → model-source-DQ7KgJaT.cjs} +4 -5
  26. package/dist/openai.cjs +2 -2
  27. package/dist/openai.d.cts +1 -1
  28. package/dist/openai.d.mts +1 -1
  29. package/dist/openai.mjs +2 -2
  30. package/dist/otel.d.cts +1 -1
  31. package/dist/otel.d.mts +1 -1
  32. package/dist/{run-agent-CTlMc3Jb.d.cts → run-agent-B5opVUxx.d.cts} +17 -6
  33. package/dist/{run-agent-CAVt5R-r.d.mts → run-agent-D4MwS5GY.d.mts} +17 -6
  34. package/dist/{run-agent-BpHqkaZw.mjs → run-agent-DWZ1uyBJ.mjs} +89 -35
  35. package/dist/{run-agent-ctLCvNgL.cjs → run-agent-tmk58M0x.cjs} +89 -35
  36. package/dist/{setup-agent-7rV_cujV.mjs → setup-agent-BaffhCcM.mjs} +38 -3
  37. package/dist/{setup-agent-CGELn1qZ.d.mts → setup-agent-CPyg2ic7.d.mts} +11 -3
  38. package/dist/{setup-agent-DoUk7EdC.cjs → setup-agent-D0L8Anl_.cjs} +38 -3
  39. package/dist/{setup-agent-CLPCkXsu.d.cts → setup-agent-yFFVXf5s.d.cts} +11 -3
  40. package/dist/tanstack-ai.cjs +3 -3
  41. package/dist/tanstack-ai.d.cts +1 -1
  42. package/dist/tanstack-ai.d.mts +1 -1
  43. package/dist/tanstack-ai.mjs +3 -3
  44. package/dist/testing.cjs +73 -29
  45. package/dist/testing.d.cts +47 -10
  46. package/dist/testing.d.mts +47 -10
  47. package/dist/testing.mjs +65 -22
  48. package/dist/{text-logic-BRYOPWvY.d.mts → text-logic-BwdrDpO9.d.mts} +4 -0
  49. package/dist/{text-logic-DmciuVUQ.d.cts → text-logic-j9hShB7d.d.cts} +4 -0
  50. package/dist/{usage-BkM3z02Y.d.mts → usage-BYqv7VBw.d.cts} +1 -1
  51. package/dist/{usage-Cm_ovz9V.d.cts → usage-Bl4nK8D-.d.mts} +1 -1
  52. package/dist/validate.cjs +3 -3
  53. package/dist/validate.d.cts +2 -2
  54. package/dist/validate.d.mts +2 -2
  55. package/dist/validate.mjs +3 -3
  56. package/dist/{verify-COFWyprJ.mjs → verify-BH5e0XLK.mjs} +55 -5
  57. package/dist/{verify-Dzwd4Mvk.d.cts → verify-CPKDPMwY.d.cts} +14 -6
  58. package/dist/{verify-CVlsTZ-V.cjs → verify-CS_xxvVU.cjs} +57 -7
  59. package/dist/{verify-Cn86rT8l.d.mts → verify-tkymWz6X.d.mts} +14 -6
  60. package/package.json +34 -4
  61. package/readme.md +70 -40
  62. package/skills/add-evals/SKILL.md +23 -8
  63. package/skills/add-traces/SKILL.md +23 -11
  64. package/skills/generate-machine/SKILL.md +2 -2
  65. package/skills/graph-engineering/SKILL.md +1 -1
  66. package/skills/improve-machine/SKILL.md +7 -6
  67. package/skills/loop-to-machine/SKILL.md +34 -7
  68. package/skills/loop-to-machine/policy.md +14 -18
@@ -1,4 +1,4 @@
1
- import { t as AgentCallUsage } from "./text-logic-BRYOPWvY.mjs";
1
+ import { t as AgentCallUsage } from "./text-logic-j9hShB7d.cjs";
2
2
  import { EventObject } from "xstate";
3
3
  //#region src/usage.d.ts
4
4
  /** Reserved event delivered after a model call reports token usage. */
@@ -1,4 +1,4 @@
1
- import { t as AgentCallUsage } from "./text-logic-DmciuVUQ.cjs";
1
+ import { t as AgentCallUsage } from "./text-logic-BwdrDpO9.mjs";
2
2
  import { EventObject } from "xstate";
3
3
  //#region src/usage.d.ts
4
4
  /** Reserved event delivered after a model call reports token usage. */
package/dist/validate.cjs CHANGED
@@ -21,9 +21,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_event_log = require("./event-log-BZRfBRd7.cjs");
25
- const require_setup_agent = require("./setup-agent-DoUk7EdC.cjs");
26
- const require_verify = require("./verify-CVlsTZ-V.cjs");
24
+ const require_event_log = require("./event-log-Bdww2l1D.cjs");
25
+ const require_setup_agent = require("./setup-agent-D0L8Anl_.cjs");
26
+ const require_verify = require("./verify-CS_xxvVU.cjs");
27
27
  let ajv_dist_2020_js = require("ajv/dist/2020.js");
28
28
  ajv_dist_2020_js = __toESM(ajv_dist_2020_js, 1);
29
29
  //#region schemas/agent-workflow.json
@@ -1,5 +1,5 @@
1
- import { d as AgentWorkflowConfig, g as FromConfigOptions, v as SchemaCompiler } from "./setup-agent-CLPCkXsu.cjs";
2
- import { l as ExplorePathsOptions } from "./verify-Dzwd4Mvk.cjs";
1
+ import { d as AgentWorkflowConfig, g as FromConfigOptions, v as SchemaCompiler } from "./setup-agent-yFFVXf5s.cjs";
2
+ import { u as ExplorePathsOptions } from "./verify-CPKDPMwY.cjs";
3
3
  import { AnyActorLogic, AnyStateMachine } from "xstate";
4
4
  //#region src/validate/validate-config.d.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { d as AgentWorkflowConfig, g as FromConfigOptions, v as SchemaCompiler } from "./setup-agent-CGELn1qZ.mjs";
2
- import { l as ExplorePathsOptions } from "./verify-Cn86rT8l.mjs";
1
+ import { d as AgentWorkflowConfig, g as FromConfigOptions, v as SchemaCompiler } from "./setup-agent-CPyg2ic7.mjs";
2
+ import { u as ExplorePathsOptions } from "./verify-tkymWz6X.mjs";
3
3
  import { AnyActorLogic, AnyStateMachine } from "xstate";
4
4
  //#region src/validate/validate-config.d.ts
5
5
  /**
package/dist/validate.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { D as STREAM_TEXT_ACTOR, E as GENERATE_TEXT_ACTOR, T as DECIDE_ACTOR } from "./event-log-DJCMHek_.mjs";
2
- import { i as setupAgentFromConfig } from "./setup-agent-7rV_cujV.mjs";
3
- import { a as explorePaths, o as lintAgentMachine } from "./verify-COFWyprJ.mjs";
1
+ import { D as STREAM_TEXT_ACTOR, E as GENERATE_TEXT_ACTOR, T as DECIDE_ACTOR } from "./event-log-DE430ZCa.mjs";
2
+ import { i as setupAgentFromConfig } from "./setup-agent-BaffhCcM.mjs";
3
+ import { a as explorePaths, o as lintAgentMachine } from "./verify-BH5e0XLK.mjs";
4
4
  import Ajv2020 from "ajv/dist/2020.js";
5
5
  //#region schemas/agent-workflow.json
6
6
  var agent_workflow_default = {
@@ -1,6 +1,6 @@
1
- import { P as isTextLogic, U as getRegisteredAgentExecutionOptions, V as executorBoundLogics, X as getJsonSchemaSync, st as AgentError } from "./event-log-DJCMHek_.mjs";
2
- import { d as getAcceptedEvents, l as resolveDecision, m as isRecord, n as acceptedDecisionOptions, s as isDecisionLogic, t as AgentDecisionExhaustedError } from "./decision-BHkvuImD.mjs";
3
- import { getNextTransitions, initialTransition, transition } from "xstate";
1
+ import { P as isTextLogic, U as getRegisteredAgentExecutionOptions, V as executorBoundLogics, X as getJsonSchemaSync, lt as isRecord, ut as AgentError } from "./event-log-DE430ZCa.mjs";
2
+ import { d as getAcceptedEvents, f as getHumanEventTypes, l as resolveDecision, n as acceptedDecisionOptions, p as isEventPattern, s as isDecisionLogic, t as AgentDecisionExhaustedError } from "./decision-DqO018Tp.mjs";
3
+ import { getNextTransitions, initialTransition, machineToJSON, transition } from "xstate";
4
4
  //#region src/steps.ts
5
5
  /**
6
6
  * Internal: the pure `(state, event) => (nextState, requests)` view of an
@@ -79,12 +79,15 @@ function getAgentRequests(actions, { machine, ...options } = {}) {
79
79
  const events = options.snapshot ? getAcceptedEvents(options.snapshot, {
80
80
  events: options.events,
81
81
  schemas: options.schemas,
82
- eventTypes: allowedEventTypes
82
+ eventTypes: allowedEventTypes,
83
+ actor: "agent"
83
84
  }) : [];
85
+ const humanEventTypes = options.snapshot ? getHumanEventTypes(options.snapshot) : /* @__PURE__ */ new Set();
84
86
  return [{
85
87
  ...decisionRequest,
86
88
  id: params.id,
87
- events
89
+ events,
90
+ ...decisionRequest.options ? { options: decisionRequest.options.filter((option) => !humanEventTypes.has(option.event.type)) } : {}
88
91
  }];
89
92
  }
90
93
  const textLogic = isTextLogic(registeredLogic) ? registeredLogic : void 0;
@@ -335,6 +338,45 @@ function checkDecideWithoutEvents(ctx) {
335
338
  }
336
339
  return out;
337
340
  }
341
+ function literalAllowedEvents(json, path, index) {
342
+ let node = json;
343
+ for (const key of path.split(".")) node = node?.states?.[key];
344
+ let input = normalizeInvokes(node?.invoke)[index]?.input;
345
+ if (isRecord(input) && typeof input["@expr"] === "string") try {
346
+ input = JSON.parse(input["@expr"]);
347
+ } catch {
348
+ return;
349
+ }
350
+ const allowedEvents = isRecord(input) ? input.allowedEvents : void 0;
351
+ return typeof allowedEvents === "string" ? [allowedEvents] : Array.isArray(allowedEvents) ? allowedEvents : void 0;
352
+ }
353
+ function handlesAsHuman(config, eventType) {
354
+ const transitions = config.on?.[eventType];
355
+ return (Array.isArray(transitions) ? transitions : [transitions]).some((transition) => !!transition && typeof transition === "object" && transition.meta?.actor === "human");
356
+ }
357
+ function checkDecideAllowsHumanEvent(ctx) {
358
+ const out = [];
359
+ for (const node of ctx.index.values()) for (const [index, invoke] of node.invokes.entries()) {
360
+ if (!isDecisionInvoke(invoke.src, ctx.actors)) continue;
361
+ const allowedEvents = literalAllowedEvents(ctx.json, node.path, index);
362
+ if (!allowedEvents) continue;
363
+ const configs = [
364
+ node.config,
365
+ ...ancestorChain(node, ctx.index).map((ancestor) => ancestor.config),
366
+ ctx.config
367
+ ];
368
+ for (const type of allowedEvents) {
369
+ if (typeof type !== "string" || isEventPattern(type) || !configs.some((config) => handlesAsHuman(config, type))) continue;
370
+ out.push({
371
+ code: "decide-allows-human-event",
372
+ severity: "error",
373
+ path: node.path,
374
+ message: `State '${node.path}' lets a decision choose '${type}', but a transition tagged 'meta: { actor: "human" }' handles it, so the model is never offered it. Remove '${type}' from 'allowedEvents', or drop the tag if a model may send it.`
375
+ });
376
+ }
377
+ }
378
+ return out;
379
+ }
338
380
  function checkDirectObjectSrc(ctx) {
339
381
  const out = [];
340
382
  for (const node of ctx.index.values()) for (const invoke of node.invokes) {
@@ -371,6 +413,7 @@ function checkInvokeWithoutOnError(ctx) {
371
413
  }
372
414
  const LINT_CHECKS = [
373
415
  checkDecideWithoutEvents,
416
+ checkDecideAllowsHumanEvent,
374
417
  checkDirectObjectSrc,
375
418
  checkInvokeWithoutOnError
376
419
  ];
@@ -408,8 +451,15 @@ function lintAgentMachine(machine, options = {}) {
408
451
  const config = machine.config ?? {};
409
452
  const index = buildStateIndex(config);
410
453
  const registered = getRegisteredAgentExecutionOptions(machine);
454
+ let json;
455
+ try {
456
+ json = machineToJSON(machine);
457
+ } catch {
458
+ json = void 0;
459
+ }
411
460
  const ctx = {
412
461
  config,
462
+ json,
413
463
  index,
414
464
  schemas: registered.schemas,
415
465
  actors: registered.actors ?? machine.sources?.actors ?? {}
@@ -1,5 +1,5 @@
1
1
  import { u as ChosenEvent } from "./types-Dp5_Ru4R.cjs";
2
- import { Q as AgentError } from "./text-logic-DmciuVUQ.cjs";
2
+ import { Q as AgentError } from "./text-logic-j9hShB7d.cjs";
3
3
  import { AnyMachineSnapshot, AnyStateMachine } from "xstate";
4
4
  //#region src/verify.d.ts
5
5
  /** Severity of an {@link AgentLintDiagnostic}. `error` findings fail CI/the CLI; `warning`s are advisory. */
@@ -10,7 +10,7 @@ type AgentLintSeverity = "error" | "warning";
10
10
  * or config location, and `message` explains the problem and its remedy.
11
11
  */
12
12
  interface AgentLintDiagnostic {
13
- code: "decide-without-events" | "direct-object-src" | "invoke-without-on-error";
13
+ code: "decide-without-events" | "decide-allows-human-event" | "direct-object-src" | "invoke-without-on-error";
14
14
  severity: AgentLintSeverity;
15
15
  /** State path (`parent.child`) or config pointer (e.g. `(root)`, `context`) the finding is about. */
16
16
  path: string;
@@ -212,6 +212,14 @@ interface SimulateAgentResult {
212
212
  */
213
213
  declare function simulateAgent(machine: AnyStateMachine, options: SimulateAgentOptions): Promise<SimulateAgentResult>;
214
214
  /** Options for {@link explorePaths}. */
215
+ /**
216
+ * The snapshot type the exploration callbacks (`payloads`, `dedupeBy`, a
217
+ * `canReach` predicate) receive. Import it from here rather than from your
218
+ * own `xstate`, which can be another version than the one this package uses.
219
+ */
220
+ type ExploreSnapshot = AnyMachineSnapshot;
221
+ /** What {@link canReach} looks for: a state id or path, or a snapshot predicate. */
222
+ type CanReachTarget = string | ((snapshot: ExploreSnapshot) => boolean);
215
223
  interface ExplorePathsOptions {
216
224
  input?: unknown;
217
225
  /** Max branch points (decisions + external-event forks) along any path. Default 8. */
@@ -274,7 +282,7 @@ interface ExplorePathsOptions {
274
282
  * were not all tried, so it is listed in `unexpandedEvents`. A type with no
275
283
  * schema at all is applied as `{ type }`.
276
284
  */
277
- payloads?: (snapshot: AnyMachineSnapshot) => Partial<Record<string, Record<string, unknown>[]>>;
285
+ payloads?: (snapshot: ExploreSnapshot) => Partial<Record<string, Record<string, unknown>[]>>;
278
286
  /**
279
287
  * A projection of the snapshot that determines its future. Settled
280
288
  * snapshots with an equal key are explored once (again only when reached
@@ -283,7 +291,7 @@ interface ExplorePathsOptions {
283
291
  * a key that drops a field the machine reads makes the search unsound.
284
292
  * Without it, every path is explored in full.
285
293
  */
286
- dedupeBy?: (snapshot: AnyMachineSnapshot) => string;
294
+ dedupeBy?: (snapshot: ExploreSnapshot) => string;
287
295
  }
288
296
  /** A single explored path's terminal outcome. */
289
297
  interface AgentPathTerminal {
@@ -409,6 +417,6 @@ declare class AgentUnknownStateError extends AgentError {
409
417
  * // violation.reachable → false is the safety proof
410
418
  * ```
411
419
  */
412
- declare function canReach(machine: AnyStateMachine, target: string | ((snapshot: AnyMachineSnapshot) => boolean), options?: ExplorePathsOptions): Promise<CanReachResult>;
420
+ declare function canReach(machine: AnyStateMachine, target: CanReachTarget, options?: ExplorePathsOptions): Promise<CanReachResult>;
413
421
  //#endregion
414
- export { explorePaths as _, AgentPathTerminal as a, CanReachResult as c, SimulateAgentOptions as d, SimulateAgentResult as f, canReach as g, assertAgentMachine as h, AgentPathReport as i, ExplorePathsOptions as l, SimulationTrailEntry as m, AgentLintError as n, AgentUnknownStateError as o, SimulationScript as p, AgentLintSeverity as r, AssertAgentMachineOptions as s, AgentLintDiagnostic as t, LintAgentMachineOptions as u, lintAgentMachine as v, simulateAgent as y };
422
+ export { assertAgentMachine as _, AgentPathTerminal as a, lintAgentMachine as b, CanReachResult as c, ExploreSnapshot as d, LintAgentMachineOptions as f, SimulationTrailEntry as g, SimulationScript as h, AgentPathReport as i, CanReachTarget as l, SimulateAgentResult as m, AgentLintError as n, AgentUnknownStateError as o, SimulateAgentOptions as p, AgentLintSeverity as r, AssertAgentMachineOptions as s, AgentLintDiagnostic as t, ExplorePathsOptions as u, canReach as v, simulateAgent as x, explorePaths as y };
@@ -1,5 +1,5 @@
1
- const require_event_log = require("./event-log-BZRfBRd7.cjs");
2
- const require_decision = require("./decision-CIb7ddIv.cjs");
1
+ const require_event_log = require("./event-log-Bdww2l1D.cjs");
2
+ const require_decision = require("./decision-Iys2hzg3.cjs");
3
3
  let xstate = require("xstate");
4
4
  //#region src/steps.ts
5
5
  /**
@@ -79,12 +79,15 @@ function getAgentRequests(actions, { machine, ...options } = {}) {
79
79
  const events = options.snapshot ? require_decision.getAcceptedEvents(options.snapshot, {
80
80
  events: options.events,
81
81
  schemas: options.schemas,
82
- eventTypes: allowedEventTypes
82
+ eventTypes: allowedEventTypes,
83
+ actor: "agent"
83
84
  }) : [];
85
+ const humanEventTypes = options.snapshot ? require_decision.getHumanEventTypes(options.snapshot) : /* @__PURE__ */ new Set();
84
86
  return [{
85
87
  ...decisionRequest,
86
88
  id: params.id,
87
- events
89
+ events,
90
+ ...decisionRequest.options ? { options: decisionRequest.options.filter((option) => !humanEventTypes.has(option.event.type)) } : {}
88
91
  }];
89
92
  }
90
93
  const textLogic = require_event_log.isTextLogic(registeredLogic) ? registeredLogic : void 0;
@@ -335,6 +338,45 @@ function checkDecideWithoutEvents(ctx) {
335
338
  }
336
339
  return out;
337
340
  }
341
+ function literalAllowedEvents(json, path, index) {
342
+ let node = json;
343
+ for (const key of path.split(".")) node = node?.states?.[key];
344
+ let input = normalizeInvokes(node?.invoke)[index]?.input;
345
+ if (require_event_log.isRecord(input) && typeof input["@expr"] === "string") try {
346
+ input = JSON.parse(input["@expr"]);
347
+ } catch {
348
+ return;
349
+ }
350
+ const allowedEvents = require_event_log.isRecord(input) ? input.allowedEvents : void 0;
351
+ return typeof allowedEvents === "string" ? [allowedEvents] : Array.isArray(allowedEvents) ? allowedEvents : void 0;
352
+ }
353
+ function handlesAsHuman(config, eventType) {
354
+ const transitions = config.on?.[eventType];
355
+ return (Array.isArray(transitions) ? transitions : [transitions]).some((transition) => !!transition && typeof transition === "object" && transition.meta?.actor === "human");
356
+ }
357
+ function checkDecideAllowsHumanEvent(ctx) {
358
+ const out = [];
359
+ for (const node of ctx.index.values()) for (const [index, invoke] of node.invokes.entries()) {
360
+ if (!isDecisionInvoke(invoke.src, ctx.actors)) continue;
361
+ const allowedEvents = literalAllowedEvents(ctx.json, node.path, index);
362
+ if (!allowedEvents) continue;
363
+ const configs = [
364
+ node.config,
365
+ ...ancestorChain(node, ctx.index).map((ancestor) => ancestor.config),
366
+ ctx.config
367
+ ];
368
+ for (const type of allowedEvents) {
369
+ if (typeof type !== "string" || require_decision.isEventPattern(type) || !configs.some((config) => handlesAsHuman(config, type))) continue;
370
+ out.push({
371
+ code: "decide-allows-human-event",
372
+ severity: "error",
373
+ path: node.path,
374
+ message: `State '${node.path}' lets a decision choose '${type}', but a transition tagged 'meta: { actor: "human" }' handles it, so the model is never offered it. Remove '${type}' from 'allowedEvents', or drop the tag if a model may send it.`
375
+ });
376
+ }
377
+ }
378
+ return out;
379
+ }
338
380
  function checkDirectObjectSrc(ctx) {
339
381
  const out = [];
340
382
  for (const node of ctx.index.values()) for (const invoke of node.invokes) {
@@ -371,6 +413,7 @@ function checkInvokeWithoutOnError(ctx) {
371
413
  }
372
414
  const LINT_CHECKS = [
373
415
  checkDecideWithoutEvents,
416
+ checkDecideAllowsHumanEvent,
374
417
  checkDirectObjectSrc,
375
418
  checkInvokeWithoutOnError
376
419
  ];
@@ -408,8 +451,15 @@ function lintAgentMachine(machine, options = {}) {
408
451
  const config = machine.config ?? {};
409
452
  const index = buildStateIndex(config);
410
453
  const registered = require_event_log.getRegisteredAgentExecutionOptions(machine);
454
+ let json;
455
+ try {
456
+ json = (0, xstate.machineToJSON)(machine);
457
+ } catch {
458
+ json = void 0;
459
+ }
411
460
  const ctx = {
412
461
  config,
462
+ json,
413
463
  index,
414
464
  schemas: registered.schemas,
415
465
  actors: registered.actors ?? machine.sources?.actors ?? {}
@@ -716,7 +766,7 @@ const MAX_ADVANCE_STEPS = 1e3;
716
766
  const FINITE_PAYLOAD_CAP = 64;
717
767
  const DEFAULT_MAX_NODES = 1e5;
718
768
  function finiteDomain(schema) {
719
- if (!require_decision.isRecord(schema)) return;
769
+ if (!require_event_log.isRecord(schema)) return;
720
770
  if ("const" in schema) return [schema["const"]];
721
771
  if (Array.isArray(schema["enum"])) return schema["enum"];
722
772
  const union = schema["anyOf"] ?? schema["oneOf"];
@@ -733,8 +783,8 @@ function finitePayloads(jsonSchema) {
733
783
  payloads: [{}],
734
784
  complete: false
735
785
  };
736
- if (!require_decision.isRecord(jsonSchema) || jsonSchema["type"] !== "object" && !require_decision.isRecord(jsonSchema["properties"])) return bare;
737
- const properties = require_decision.isRecord(jsonSchema["properties"]) ? jsonSchema["properties"] : {};
786
+ if (!require_event_log.isRecord(jsonSchema) || jsonSchema["type"] !== "object" && !require_event_log.isRecord(jsonSchema["properties"])) return bare;
787
+ const properties = require_event_log.isRecord(jsonSchema["properties"]) ? jsonSchema["properties"] : {};
738
788
  const required = new Set(Array.isArray(jsonSchema["required"]) ? jsonSchema["required"] : []);
739
789
  if ([...required].some((key) => key !== "type" && !(key in properties))) return bare;
740
790
  let product = [{}];
@@ -1,5 +1,5 @@
1
1
  import { u as ChosenEvent } from "./types-Dp5_Ru4R.mjs";
2
- import { Q as AgentError } from "./text-logic-BRYOPWvY.mjs";
2
+ import { Q as AgentError } from "./text-logic-BwdrDpO9.mjs";
3
3
  import { AnyMachineSnapshot, AnyStateMachine } from "xstate";
4
4
  //#region src/verify.d.ts
5
5
  /** Severity of an {@link AgentLintDiagnostic}. `error` findings fail CI/the CLI; `warning`s are advisory. */
@@ -10,7 +10,7 @@ type AgentLintSeverity = "error" | "warning";
10
10
  * or config location, and `message` explains the problem and its remedy.
11
11
  */
12
12
  interface AgentLintDiagnostic {
13
- code: "decide-without-events" | "direct-object-src" | "invoke-without-on-error";
13
+ code: "decide-without-events" | "decide-allows-human-event" | "direct-object-src" | "invoke-without-on-error";
14
14
  severity: AgentLintSeverity;
15
15
  /** State path (`parent.child`) or config pointer (e.g. `(root)`, `context`) the finding is about. */
16
16
  path: string;
@@ -212,6 +212,14 @@ interface SimulateAgentResult {
212
212
  */
213
213
  declare function simulateAgent(machine: AnyStateMachine, options: SimulateAgentOptions): Promise<SimulateAgentResult>;
214
214
  /** Options for {@link explorePaths}. */
215
+ /**
216
+ * The snapshot type the exploration callbacks (`payloads`, `dedupeBy`, a
217
+ * `canReach` predicate) receive. Import it from here rather than from your
218
+ * own `xstate`, which can be another version than the one this package uses.
219
+ */
220
+ type ExploreSnapshot = AnyMachineSnapshot;
221
+ /** What {@link canReach} looks for: a state id or path, or a snapshot predicate. */
222
+ type CanReachTarget = string | ((snapshot: ExploreSnapshot) => boolean);
215
223
  interface ExplorePathsOptions {
216
224
  input?: unknown;
217
225
  /** Max branch points (decisions + external-event forks) along any path. Default 8. */
@@ -274,7 +282,7 @@ interface ExplorePathsOptions {
274
282
  * were not all tried, so it is listed in `unexpandedEvents`. A type with no
275
283
  * schema at all is applied as `{ type }`.
276
284
  */
277
- payloads?: (snapshot: AnyMachineSnapshot) => Partial<Record<string, Record<string, unknown>[]>>;
285
+ payloads?: (snapshot: ExploreSnapshot) => Partial<Record<string, Record<string, unknown>[]>>;
278
286
  /**
279
287
  * A projection of the snapshot that determines its future. Settled
280
288
  * snapshots with an equal key are explored once (again only when reached
@@ -283,7 +291,7 @@ interface ExplorePathsOptions {
283
291
  * a key that drops a field the machine reads makes the search unsound.
284
292
  * Without it, every path is explored in full.
285
293
  */
286
- dedupeBy?: (snapshot: AnyMachineSnapshot) => string;
294
+ dedupeBy?: (snapshot: ExploreSnapshot) => string;
287
295
  }
288
296
  /** A single explored path's terminal outcome. */
289
297
  interface AgentPathTerminal {
@@ -409,6 +417,6 @@ declare class AgentUnknownStateError extends AgentError {
409
417
  * // violation.reachable → false is the safety proof
410
418
  * ```
411
419
  */
412
- declare function canReach(machine: AnyStateMachine, target: string | ((snapshot: AnyMachineSnapshot) => boolean), options?: ExplorePathsOptions): Promise<CanReachResult>;
420
+ declare function canReach(machine: AnyStateMachine, target: CanReachTarget, options?: ExplorePathsOptions): Promise<CanReachResult>;
413
421
  //#endregion
414
- export { explorePaths as _, AgentPathTerminal as a, CanReachResult as c, SimulateAgentOptions as d, SimulateAgentResult as f, canReach as g, assertAgentMachine as h, AgentPathReport as i, ExplorePathsOptions as l, SimulationTrailEntry as m, AgentLintError as n, AgentUnknownStateError as o, SimulationScript as p, AgentLintSeverity as r, AssertAgentMachineOptions as s, AgentLintDiagnostic as t, LintAgentMachineOptions as u, lintAgentMachine as v, simulateAgent as y };
422
+ export { assertAgentMachine as _, AgentPathTerminal as a, lintAgentMachine as b, CanReachResult as c, ExploreSnapshot as d, LintAgentMachineOptions as f, SimulationTrailEntry as g, SimulationScript as h, AgentPathReport as i, CanReachTarget as l, SimulateAgentResult as m, AgentLintError as n, AgentUnknownStateError as o, SimulateAgentOptions as p, AgentLintSeverity as r, AssertAgentMachineOptions as s, AgentLintDiagnostic as t, ExplorePathsOptions as u, canReach as v, simulateAgent as x, explorePaths as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/agent",
3
- "version": "2.0.0-alpha.30",
3
+ "version": "2.0.0-alpha.31",
4
4
  "description": "Make invalid agent actions impossible. Agent logic as state machines: deterministic, inspectable, resumable, runs anywhere.",
5
5
  "keywords": [
6
6
  "agent",
@@ -21,12 +21,41 @@
21
21
  "files": [
22
22
  "dist",
23
23
  "schemas",
24
- "skills"
24
+ "skills",
25
+ "CHANGELOG.md"
25
26
  ],
26
27
  "type": "module",
27
28
  "main": "dist/index.cjs",
28
29
  "module": "dist/index.mjs",
29
30
  "types": "dist/index.d.mts",
31
+ "typesVersions": {
32
+ "*": {
33
+ "ai-sdk": [
34
+ "./dist/ai-sdk.d.mts"
35
+ ],
36
+ "log": [
37
+ "./dist/log.d.mts"
38
+ ],
39
+ "machines": [
40
+ "./dist/machines.d.mts"
41
+ ],
42
+ "openai": [
43
+ "./dist/openai.d.mts"
44
+ ],
45
+ "otel": [
46
+ "./dist/otel.d.mts"
47
+ ],
48
+ "tanstack-ai": [
49
+ "./dist/tanstack-ai.d.mts"
50
+ ],
51
+ "testing": [
52
+ "./dist/testing.d.mts"
53
+ ],
54
+ "validate": [
55
+ "./dist/validate.d.mts"
56
+ ]
57
+ }
58
+ },
30
59
  "exports": {
31
60
  ".": {
32
61
  "import": {
@@ -132,6 +161,7 @@
132
161
  "@langchain/core": "^1.2.17",
133
162
  "@langchain/openai": "^1.6.2",
134
163
  "@mastra/core": "^1.75.0",
164
+ "@modelcontextprotocol/sdk": "^1.29.0",
135
165
  "@opentelemetry/api": "^1.9.1",
136
166
  "@opentelemetry/context-async-hooks": "^2.12.0",
137
167
  "@opentelemetry/sdk-trace-base": "^2.12.0",
@@ -159,7 +189,7 @@
159
189
  "peerDependencies": {
160
190
  "@opentelemetry/api": "^1",
161
191
  "@tanstack/ai": ">=0.66.0 <1",
162
- "ai": "^7.0.0",
192
+ "ai": "^7.0.128",
163
193
  "ajv": "^8.20.0",
164
194
  "openai": ">=5.0.0 <8",
165
195
  "xstate": "6.0.0-alpha.69"
@@ -182,7 +212,7 @@
182
212
  }
183
213
  },
184
214
  "engines": {
185
- "node": ">=22.18.0"
215
+ "node": ">=22"
186
216
  },
187
217
  "scripts": {
188
218
  "build": "tsdown",
package/readme.md CHANGED
@@ -14,18 +14,18 @@ Environment and policy:
14
14
 
15
15
  - The environment is code you own and can verify; the policy is something a model can write inside it.
16
16
  - The environment holds the rules and invariants as TypeScript states and guards, fixed and checked with `canReach`.
17
- - The policy is a JSON machine a model can author and improve from traces, gated before it runs and promoted only on a measured gain. See [Environment and policy](docs/environment-and-policy.md).
17
+ - The policy is a JSON machine a model can author and improve from traces, gated before it runs and promoted only on a measured gain. See [Environment and policy](https://github.com/statelyai/agent/blob/next/docs/environment-and-policy.md).
18
18
 
19
19
  Stately Agent 2 is in alpha. APIs may change before the stable release.
20
20
 
21
- [Documentation](https://stately.ai/docs/packages/agent) · [Examples](examples/README.md) · [XState](https://github.com/statelyai/xstate)
21
+ [Documentation](https://stately.ai/docs/packages/agent) · [Examples](https://github.com/statelyai/agent/blob/next/examples/README.md) · [XState](https://github.com/statelyai/xstate)
22
22
 
23
23
  ## Four starting points
24
24
 
25
- - **Author a new agent.** Build a machine from states, decisions, and typed requests; run it locally with `runAgent`, test it with no API key, then use it in any framework or runtime with zero machine changes. See the [Quickstart](docs/quickstart.md) and [Use in any stack](docs/any-stack.md).
26
- - **Retrofit an existing agent.** Turn a `while` loop into a machine: your SDK calls, tools, and retry code become the executors; the machine replaces only the control flow. See [Migrating from a hand-rolled loop](docs/from-a-loop.md).
27
- - **Copy a known pattern.** ReAct, reflection, plan-and-execute, RAG, supervisor, and more, each a single runnable file you lift in 60 seconds. See [Agent patterns](docs/patterns.md).
28
- - **Let an agent improve its own logic.** Keep the rules in a fixed TypeScript environment and let a model rewrite the JSON policy inside it, gated by `verifyAgentConfig` and promoted only when held-out scenarios improve. See [Environment and policy](docs/environment-and-policy.md) and the [`improve-machine` skill](skills/improve-machine/SKILL.md).
25
+ - **Author a new agent.** Build a machine from states, decisions, and typed requests; run it locally with `runAgent`, test it with no API key, then use it in any framework or runtime with zero machine changes. See the [Quickstart](https://github.com/statelyai/agent/blob/next/docs/quickstart.md) and [Use in any stack](https://github.com/statelyai/agent/blob/next/docs/any-stack.md).
26
+ - **Retrofit an existing agent.** Turn a `while` loop into a machine: your SDK calls, tools, and retry code become the executors; the machine replaces only the control flow. See [Migrating from a hand-rolled loop](https://github.com/statelyai/agent/blob/next/docs/from-a-loop.md).
27
+ - **Copy a known pattern.** ReAct, reflection, plan-and-execute, RAG, supervisor, and more, each a single runnable file you lift in 60 seconds. See [Agent patterns](https://github.com/statelyai/agent/blob/next/docs/patterns.md).
28
+ - **Let an agent improve its own logic.** Keep the rules in a fixed TypeScript environment and let a model rewrite the JSON policy inside it, gated by `verifyAgentConfig` and promoted only when held-out scenarios improve. See [Environment and policy](https://github.com/statelyai/agent/blob/next/docs/environment-and-policy.md) and the [`improve-machine` skill](https://github.com/statelyai/agent/blob/next/skills/improve-machine/SKILL.md).
29
29
 
30
30
  ## Install
31
31
 
@@ -40,7 +40,7 @@ XState is pinned while its experimental durable restoration API evolves.
40
40
  For the optional Vercel AI SDK executor:
41
41
 
42
42
  ```sh
43
- pnpm add ai@^7 @ai-sdk/openai@^4
43
+ pnpm add ai@^7.0.128 @ai-sdk/openai@^4
44
44
  ```
45
45
 
46
46
  For the optional raw OpenAI SDK executor (`@statelyai/agent/openai`):
@@ -55,13 +55,43 @@ For the optional TanStack AI executor (`@statelyai/agent/tanstack-ai`):
55
55
  pnpm add @tanstack/ai @tanstack/ai-openai
56
56
  ```
57
57
 
58
- Classification, grading, relevance, and yes/no checks are judgments: call the AI SDK's `experimental_decide` with `@ai-sdk/typesafe-ai` (`pnpm add ai @ai-sdk/typesafe-ai`) from an ordinary actor; see [Judgments with the AI SDK](docs/judgments.md).
58
+ Classification, grading, relevance, and yes/no checks are judgments: call the AI SDK's `experimental_decide` with `@ai-sdk/typesafe-ai` (`pnpm add ai @ai-sdk/typesafe-ai`) from an ordinary actor; see [Judgments with the AI SDK](https://github.com/statelyai/agent/blob/next/docs/judgments.md).
59
+
60
+ Upgrading from an earlier alpha: see [Upgrading between alphas](https://github.com/statelyai/agent/blob/next/docs/upgrading.md). Every release's notes are in `CHANGELOG.md`, which ships in the package.
59
61
 
60
62
  Requirements:
61
63
 
62
- - Node 22.18 or newer, and XState `6.0.0-alpha.69`.
63
- - The package is ESM-first. CommonJS builds are published too, so `require()` works.
64
- - Provider packages must match your `ai` major: `@ai-sdk/openai@^4` pairs with `ai@^7`. A bare `@ai-sdk/openai` resolves to `@latest`, which can mismatch the `ai` peer.
64
+ - Node 22 or newer, and XState exactly `6.0.0-alpha.69`.
65
+ - TypeScript 5.4 or newer. Older versions accept the code, but callback parameters in `createMachine` silently become `any`.
66
+ - A [Standard Schema](https://standardschema.dev) library: zod 4, zod 3.24 or newer, Valibot, or ArkType. `setupAgent` throws `invalid-schema` for zod 3.23 and earlier.
67
+ - The package is ESM-first. CommonJS builds are published too, so `require()` works. Subpath imports (`@statelyai/agent/testing`) resolve under every `moduleResolution`, including `node`.
68
+ - `@statelyai/agent/ai-sdk` needs `ai` 7.0.128 or newer. Provider packages must match your `ai` major: `@ai-sdk/openai@^4` pairs with `ai@^7`. A bare `@ai-sdk/openai` resolves to `@latest`, which can mismatch the `ai` peer. `@statelyai/agent/openai` needs `openai` 5 or newer.
69
+
70
+ An app that already uses XState 4 or 5 keeps it: put the agent in its own workspace package. See [Use in an XState 4 or 5 app](https://github.com/statelyai/agent/blob/next/docs/xstate-4-and-5-apps.md). If both versions land in one `node_modules`, the package fails with errors that do not mention a version:
71
+
72
+ | Error | Cause |
73
+ | --- | --- |
74
+ | `createAsyncLogic is not a function` | `xstate` resolved to 4 or 5 from CommonJS |
75
+ | `Cannot find module '…/node_modules/xstate/durable'` | `xstate` resolved to 4 or 5 from ESM |
76
+ | `unmet peer dependency "xstate@6.0.0-alpha.69"` (pnpm, npm) or `has incorrect peer dependency "xstate@6.0.0-alpha.69"` (yarn 1) | The install's only warning of the two above |
77
+
78
+ ## Agent skills
79
+
80
+ The package ships agent skills in `node_modules/@statelyai/agent/skills/`. Copy them into your coding agent's skills directory (for Claude Code, `.claude/skills/`):
81
+
82
+ ```sh
83
+ mkdir -p .claude/skills
84
+ cp -R node_modules/@statelyai/agent/skills/* .claude/skills/
85
+ ```
86
+
87
+ | Skill | What it does |
88
+ | --- | --- |
89
+ | [`graph-engineering`](https://github.com/statelyai/agent/blob/next/skills/graph-engineering/SKILL.md) | Finds which step a project is at and routes to the next skill |
90
+ | [`loop-to-machine`](https://github.com/statelyai/agent/blob/next/skills/loop-to-machine/SKILL.md) | Converts existing agent code into a machine and checks parity with `compareRuns` |
91
+ | [`generate-machine`](https://github.com/statelyai/agent/blob/next/skills/generate-machine/SKILL.md) | Authors a JSON policy machine from scratch and runs `verifyAgentConfig` |
92
+ | [`add-traces`](https://github.com/statelyai/agent/blob/next/skills/add-traces/SKILL.md) | Stamps and persists every run so it replays |
93
+ | [`add-evals`](https://github.com/statelyai/agent/blob/next/skills/add-evals/SKILL.md) | Writes evals per state, at the cheapest level that catches the failure |
94
+ | [`improve-machine`](https://github.com/statelyai/agent/blob/next/skills/improve-machine/SKILL.md) | Improves a policy from traces and hands the change to a person as a pull request |
65
95
 
66
96
  ## Quick start
67
97
 
@@ -159,11 +189,11 @@ const liveResult = await runAgent(refundMachine, {
159
189
  });
160
190
  ```
161
191
 
162
- `createAiSdkExecutors(refundMachine)` reads the `models` declared in `setupAgent({ models })`, which also type the machine's model refs. `createAiSdkExecutors({ models })` still works when the host owns the map. Executors are always explicit, and core does not import the AI SDK. See [Models and providers](docs/models-and-providers.md) and [Hosts and executors](docs/hosts.md).
192
+ `createAiSdkExecutors(refundMachine)` reads the `models` declared in `setupAgent({ models })`, which also type the machine's model refs. `createAiSdkExecutors({ models })` still works when the host owns the map. Executors are always explicit, and core does not import the AI SDK. See [Models and providers](https://github.com/statelyai/agent/blob/next/docs/models-and-providers.md) and [Hosts and executors](https://github.com/statelyai/agent/blob/next/docs/hosts.md).
163
193
 
164
- For a machine with several requests, the executor routes on `request.name`, or `MockLanguageModelV3` from `ai/test` stands in for the provider behind `createAiSdkExecutors`. See [Evals](docs/evals.md#testing-without-a-provider).
194
+ For a machine with several requests, the executor routes on `request.name`, or `MockLanguageModelV3` from `ai/test` stands in for the provider behind `createAiSdkExecutors`. See [Evals](https://github.com/statelyai/agent/blob/next/docs/evals.md#testing-without-a-provider).
165
195
 
166
- A host that needs the transition loop itself (a durable object, events pushed mid-run, a custom checkpoint policy) uses `createAgentRuntime` directly. See [Write your own host loop](docs/hosts.md#write-your-own-host-loop).
196
+ A host that needs the transition loop itself (a durable object, events pushed mid-run, a custom checkpoint policy) uses `createAgentRuntime` directly. See [Write your own host loop](https://github.com/statelyai/agent/blob/next/docs/hosts.md#write-your-own-host-loop).
167
197
 
168
198
  ## Architecture
169
199
 
@@ -181,38 +211,38 @@ The machine never talks to a model directly, so swapping `createAiSdkExecutors`
181
211
 
182
212
  The example above has one model decision and two final outcomes. Real machines add approval states, retries, parallel work, child agents, and long-running waits without changing how control flow is represented.
183
213
 
184
- The core concepts (machines owning control flow, bounded model decisions, typed requests, host-run executors, and native XState snapshots) are in the [documentation overview](docs/index.md).
214
+ The core concepts (machines owning control flow, bounded model decisions, typed requests, host-run executors, and native XState snapshots) are in the [documentation overview](https://github.com/statelyai/agent/blob/next/docs/index.md).
185
215
 
186
216
  ## Examples
187
217
 
188
218
  <!-- starter examples derived from examples/*/metadata.json and examples/index.ts -->
189
219
 
190
- - [Twenty Questions](examples/twenty-questions) shows a model choosing legal events in a loop.
191
- - [Chameleon](examples/chameleon) combines hidden information, sequential turns, and a human vote.
192
- - [Snapshot migration](examples/snapshot-migration) uses XState's native `version` and `migrate` contract.
193
- - [Portable XState loop](examples/portable-xstate-loop) runs the artifact through native transitions and effects.
194
- - [Application-owned storage](examples/file-snapshot-store) persists native XState snapshots in application code.
195
- - [Tool calling](examples/review-tool-calls) keeps tools and message history in the AI SDK's native format.
196
- - [Ticket triage](examples/triage) returns structured data from a model request.
197
- - [JSON agent](examples/json-agent) runs a machine defined as data.
220
+ - [Twenty Questions](https://github.com/statelyai/agent/tree/next/examples/twenty-questions) shows a model choosing legal events in a loop.
221
+ - [Chameleon](https://github.com/statelyai/agent/tree/next/examples/chameleon) combines hidden information, sequential turns, and a human vote.
222
+ - [Snapshot migration](https://github.com/statelyai/agent/tree/next/examples/snapshot-migration) uses XState's native `version` and `migrate` contract.
223
+ - [Portable XState loop](https://github.com/statelyai/agent/tree/next/examples/portable-xstate-loop) runs the artifact through native transitions and effects.
224
+ - [Application-owned storage](https://github.com/statelyai/agent/tree/next/examples/file-snapshot-store) persists native XState snapshots in application code.
225
+ - [Tool calling](https://github.com/statelyai/agent/tree/next/examples/review-tool-calls) keeps tools and message history in the AI SDK's native format.
226
+ - [Ticket triage](https://github.com/statelyai/agent/tree/next/examples/triage) returns structured data from a model request.
227
+ - [JSON agent](https://github.com/statelyai/agent/tree/next/examples/json-agent) runs a machine defined as data.
198
228
 
199
- See [all examples](examples/README.md).
229
+ See [all examples](https://github.com/statelyai/agent/blob/next/examples/README.md).
200
230
 
201
231
  ## Related
202
232
 
203
- - [Machines](docs/machines.md)
204
- - [Text requests](docs/text-requests.md)
205
- - [Decisions](docs/decisions.md)
206
- - [Human in the loop](docs/human-in-the-loop.md)
207
- - [Testing and verification](docs/verify.md)
208
- - [Evals](docs/evals.md)
209
- - [Generating machines with an LLM](docs/generate-machines.md)
210
- - [Hosts and executors](docs/hosts.md)
211
- - [Models and providers](docs/models-and-providers.md)
212
- - [Use in any stack](docs/any-stack.md)
213
- - [Persistence](docs/persistence.md)
214
- - [Observability](docs/observability.md)
215
- - [Usage and budgets](docs/usage-and-budgets.md)
216
- - [Agent patterns](docs/patterns.md)
217
- - [Migrating from a hand-rolled loop](docs/from-a-loop.md)
218
- - [Coming from LangGraph](docs/langgraph-comparison.md)
233
+ - [Machines](https://github.com/statelyai/agent/blob/next/docs/machines.md)
234
+ - [Text requests](https://github.com/statelyai/agent/blob/next/docs/text-requests.md)
235
+ - [Decisions](https://github.com/statelyai/agent/blob/next/docs/decisions.md)
236
+ - [Human in the loop](https://github.com/statelyai/agent/blob/next/docs/human-in-the-loop.md)
237
+ - [Testing and verification](https://github.com/statelyai/agent/blob/next/docs/verify.md)
238
+ - [Evals](https://github.com/statelyai/agent/blob/next/docs/evals.md)
239
+ - [Generating machines with an LLM](https://github.com/statelyai/agent/blob/next/docs/generate-machines.md)
240
+ - [Hosts and executors](https://github.com/statelyai/agent/blob/next/docs/hosts.md)
241
+ - [Models and providers](https://github.com/statelyai/agent/blob/next/docs/models-and-providers.md)
242
+ - [Use in any stack](https://github.com/statelyai/agent/blob/next/docs/any-stack.md)
243
+ - [Persistence](https://github.com/statelyai/agent/blob/next/docs/persistence.md)
244
+ - [Observability](https://github.com/statelyai/agent/blob/next/docs/observability.md)
245
+ - [Usage and budgets](https://github.com/statelyai/agent/blob/next/docs/usage-and-budgets.md)
246
+ - [Agent patterns](https://github.com/statelyai/agent/blob/next/docs/patterns.md)
247
+ - [Migrating from a hand-rolled loop](https://github.com/statelyai/agent/blob/next/docs/from-a-loop.md)
248
+ - [Coming from LangGraph](https://github.com/statelyai/agent/blob/next/docs/langgraph-comparison.md)