@statelyai/agent 2.0.0-alpha.12 → 2.0.0-alpha.14

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 (32) hide show
  1. package/dist/ai-sdk.cjs +1 -1
  2. package/dist/ai-sdk.d.cts +2 -2
  3. package/dist/ai-sdk.d.mts +2 -2
  4. package/dist/ai-sdk.mjs +1 -1
  5. package/dist/{decision-dWGhBh0P.cjs → decision-C0cUKvNt.cjs} +0 -105
  6. package/dist/{decision-BezSD_YC.mjs → decision-D9Zi7Xi5.mjs} +2 -65
  7. package/dist/index.cjs +31 -155
  8. package/dist/index.d.cts +8 -12
  9. package/dist/index.d.mts +8 -12
  10. package/dist/index.mjs +33 -156
  11. package/dist/machines.cjs +1 -1
  12. package/dist/machines.d.cts +1 -1
  13. package/dist/machines.d.mts +1 -1
  14. package/dist/machines.mjs +1 -1
  15. package/dist/otel.cjs +5 -15
  16. package/dist/otel.d.cts +1 -1
  17. package/dist/otel.d.mts +1 -1
  18. package/dist/otel.mjs +5 -15
  19. package/dist/{run-agent-B1nBa7aV.d.mts → run-agent-2MnlQTkB.d.mts} +60 -107
  20. package/dist/{run-agent-qkg0evvW.d.cts → run-agent-BlqKwHIF.d.cts} +60 -107
  21. package/dist/{setup-agent-DP95MFrI.cjs → setup-agent-CpK0ZRWV.cjs} +10 -210
  22. package/dist/{setup-agent-DAZZSjDS.mjs → setup-agent-DeHRW-qX.mjs} +11 -205
  23. package/dist/sqlite.d.cts +2 -2
  24. package/dist/sqlite.d.mts +2 -2
  25. package/dist/{text-logic-DjR5PUVz.d.mts → text-logic-C5kbjaDz.d.mts} +57 -106
  26. package/dist/{text-logic-CorGzucG.d.cts → text-logic-Jkilp1Ie.d.cts} +57 -106
  27. package/dist/{types-QbEfCVny.d.cts → types-9Bqg5rZB.d.mts} +2 -2
  28. package/dist/{types-_FXoFBGO.d.mts → types-rMe7x6NR.d.cts} +2 -2
  29. package/package.json +5 -2
  30. package/readme.md +24 -8
  31. /package/dist/{event-log-store-CriMgX1D.d.mts → event-log-store-BkUNtyOF.d.mts} +0 -0
  32. /package/dist/{event-log-store-Ruq18mGp.d.cts → event-log-store-CVd2eyRy.d.cts} +0 -0
@@ -1,6 +1,6 @@
1
- import { _ as StandardSchemaV1, a as AgentToolChoice, c as AgentTools, d as ChosenEvent, h as InferOutput, l as AllowedEvents, n as AgentMessage } from "./types-_FXoFBGO.mjs";
1
+ import { _ as StandardSchemaV1, a as AgentToolChoice, c as AgentTools, d as ChosenEvent, h as InferOutput, l as AllowedEvents, n as AgentMessage } from "./types-9Bqg5rZB.mjs";
2
2
  import { t as AgentError } from "./errors-C9rxnWbX.mjs";
3
- import { AnyMachineSnapshot, AsyncActorLogic, EventObject, LogicActorLogic, MachineSnapshot } from "xstate";
3
+ import { AnyMachineSnapshot, AsyncActorLogic, EventObject, MachineSnapshot } from "xstate";
4
4
 
5
5
  //#region src/events.d.ts
6
6
  /** The invoke `src` of an {@link AgentRequest}/{@link AgentDecisionRequest} — a plain string, widened so literal `src` values still narrow in editor hints. */
@@ -97,92 +97,6 @@ interface AgentDecisionInput<TEvent extends string = string, TMetadata = Record<
97
97
  stopSequences?: string[];
98
98
  metadata?: TMetadata;
99
99
  }
100
- /**
101
- * Inline input for the `agent.plan` builtin actor — a multi-event decision.
102
- * Where `agent.decide` picks exactly one currently-legal event, `agent.plan`
103
- * applies an ordered sequence of them: each step re-reads the live snapshot,
104
- * asks the `decide` executor for one legal event (same validation and
105
- * `rejected-by-guard` retry loop as a decision), sends it to the machine,
106
- * and repeats until a `stopOn` event is chosen, `maxSteps` is reached, no
107
- * legal candidate remains, or an applied event exits the invoking state
108
- * (which cancels the invoke — the machine simply moves on).
109
- *
110
- * Requires a snapshot-aware host: {@link runAgent}, or the step path (where an
111
- * `agent.plan` invoke re-surfaces as a `kind: 'plan'` request that
112
- * `resolveAgentRequests` drives one step per call).
113
- */
114
- interface AgentPlanInput<TEvent extends string = string, TMetadata = Record<string, unknown>, TModel extends string = string> extends AgentDecisionInput<TEvent, TMetadata, TModel> {
115
- /** Maximum events applied in one plan. Default 8. */
116
- maxSteps?: number;
117
- /**
118
- * Machine events that end the plan once chosen: the event is still
119
- * validated and sent, then the loop stops. Usually unnecessary — every
120
- * plan step already offers the built-in {@link PLAN_DONE_EVENT_TYPE}
121
- * "done" option, which ends the plan without touching the machine.
122
- * Declare `stopOn` only for "send this real event AND stop" semantics.
123
- */
124
- stopOn?: readonly TEvent[];
125
- }
126
- /**
127
- * Reserved event type the `agent.plan` builtin adds to every step's
128
- * candidates as the explicit "no further action needed" move. Choosing it
129
- * ends the plan (`stopped: 'done'`); it is never sent to the machine, so
130
- * machines need no no-op sentinel event of their own.
131
- */
132
- declare const PLAN_DONE_EVENT_TYPE: "agent.plan.done";
133
- /** What an `agent.plan` invoke resolves with (its `onDone` output). */
134
- interface AgentPlanOutput {
135
- /** The events applied, in order (possibly empty). */
136
- steps: ChosenEvent[];
137
- /** Why the loop ended. */
138
- stopped: "done" | "stop-event" | "max-steps" | "no-legal-events";
139
- }
140
- /**
141
- * The in-progress state of a plan, held in the `agent.plan` invoke child's own
142
- * `createLogic` snapshot `context`. Because a `createLogic` snapshot serializes
143
- * (and restores) by identity, this lands at
144
- * `children.<planId>.snapshot.context` in a machine's persisted snapshot for
145
- * free — so a step-path host that persists after every event resumes a plan
146
- * mid-flight without a bespoke carrier.
147
- */
148
- interface PlanLedgerContext {
149
- /** The events applied so far in this plan, in order (the trail). */
150
- applied: ChosenEvent[];
151
- /** How many more events the plan may apply (`maxSteps - applied.length`). */
152
- stepsRemaining: number;
153
- /** Set once the plan terminates; `null` while in flight. */
154
- stopped: AgentPlanOutput["stopped"] | null;
155
- }
156
- /**
157
- * The two ledger events that drive a {@link PlanLedgerContext} forward:
158
- * `plan.applied` appends one event to the trail and decrements the budget;
159
- * `plan.ended` records the stop reason and completes the ledger (its snapshot
160
- * goes `done` with the {@link AgentPlanOutput}).
161
- */
162
- type PlanLedgerEvent = {
163
- type: "plan.applied";
164
- event: ChosenEvent;
165
- } | {
166
- type: "plan.ended";
167
- stopped: AgentPlanOutput["stopped"];
168
- };
169
- /**
170
- * Actor logic for the `agent.plan` builtin: a stateful, transition-based
171
- * ledger. Its snapshot `context` ({@link PlanLedgerContext}) IS the plan's
172
- * in-progress state — the applied trail plus remaining budget — advanced one
173
- * {@link PlanLedgerEvent} at a time. On the step path the invoke child runs this
174
- * logic directly (so its context persists at `children.<id>.snapshot.context`);
175
- * runAgent swaps in an async implementation that drives the SAME ledger via the
176
- * shared {@link initialPlanLedger}/{@link advancePlanLedger} drivers.
177
- */
178
- interface PlanLogic<TInputSchema extends StandardSchemaV1 = StandardSchemaV1<AgentPlanInput>> extends LogicActorLogic<PlanLedgerContext, AgentPlanOutput, PlanLedgerEvent, InferOutput<TInputSchema>> {
179
- readonly kind: "statelyai.planLogic";
180
- readonly maxRetries: number;
181
- /** Builds the per-step base {@link AgentDecisionRequest} (id/events filled in per step). */
182
- request(input: InferOutput<TInputSchema>): AgentDecisionRequest;
183
- /** @internal Resolves declared `allowedEvents` (undefined = all currently legal). */
184
- allowedEventTypes(input: InferOutput<TInputSchema>): readonly string[] | undefined;
185
- }
186
100
  /**
187
101
  * Config for {@link createDecisionLogic}: how to build an
188
102
  * {@link AgentDecisionRequest} from typed input. Each field mirrors
@@ -366,7 +280,6 @@ declare const USER_INPUT_ACTOR: "agent.userInput";
366
280
  declare const GENERATE_TEXT_ACTOR: "agent.generateText";
367
281
  declare const STREAM_TEXT_ACTOR: "agent.streamText";
368
282
  declare const DECIDE_ACTOR: "agent.decide";
369
- declare const PLAN_ACTOR: "agent.plan";
370
283
  /** Whether a text request should be resolved with `generateText` (one-shot) or `streamText` (chunked, via `onChunk`). */
371
284
  type AgentRequestMode = "generate" | "stream";
372
285
  /** A `setupAgent({ models })` model registry, mapping short model refs to provider-specific model values. */
@@ -485,13 +398,12 @@ interface AgentUserInput<TMetadata = Record<string, unknown>> {
485
398
  prompt?: string;
486
399
  metadata?: TMetadata;
487
400
  }
488
- /** The five `agent.*` builtin actor logics every setupAgent-built machine registers. @internal */
401
+ /** The four `agent.*` builtin actor logics every setupAgent-built machine registers. @internal */
489
402
  type BuiltinAgentActors<TEvent extends string = string, TModel extends string = string> = {
490
403
  [GENERATE_TEXT_ACTOR]: AsyncActorLogic<unknown, AgentTextRequest>;
491
404
  [STREAM_TEXT_ACTOR]: AsyncActorLogic<unknown, AgentTextRequest>;
492
405
  [USER_INPUT_ACTOR]: AsyncActorLogic<string, AgentUserInput>;
493
406
  [DECIDE_ACTOR]: AsyncActorLogic<ChosenEvent, AgentDecisionInput<TEvent, Record<string, unknown>, TModel>>;
494
- [PLAN_ACTOR]: PlanLogic<StandardSchemaV1<AgentPlanInput<TEvent, Record<string, unknown>, TModel>>>;
495
407
  };
496
408
  /**
497
409
  * Validates a raw model/executor output against `schema`, returning the
@@ -660,7 +572,12 @@ interface AgentRequestExecutorInfo {
660
572
  */
661
573
  type AiSdkShapedTextResult = {
662
574
  text: string | PromiseLike<string>;
663
- [key: string]: unknown;
575
+ output?: unknown;
576
+ usage?: unknown;
577
+ reasoning?: unknown;
578
+ finishReason?: unknown;
579
+ toolCalls?: unknown;
580
+ toolResults?: unknown;
664
581
  };
665
582
  /**
666
583
  * A raw Vercel AI SDK `streamText` result shape: exposes a `textStream` async
@@ -674,27 +591,61 @@ type AiSdkShapedTextResult = {
674
591
  type AiSdkShapedStreamResult = {
675
592
  textStream: AsyncIterable<string>;
676
593
  text?: PromiseLike<string>;
677
- [key: string]: unknown;
594
+ output?: unknown;
595
+ usage?: unknown;
596
+ reasoning?: unknown;
597
+ finishReason?: unknown;
598
+ toolCalls?: unknown;
599
+ toolResults?: unknown;
678
600
  };
601
+ /**
602
+ * The lowered request as an {@link AgentRequestExecutor} receives it. At
603
+ * runtime this is exactly the {@link AgentTextRequest} core built (plus the
604
+ * merged `tools` map); the TYPE is deliberately shaped so the Vercel AI SDK's
605
+ * own `generateText`/`streamText` are directly assignable as executors
606
+ * (function parameters are contravariant, so this type must be assignable to
607
+ * `ai`'s options type):
608
+ *
609
+ * - `prompt`/`messages` are mutually exclusive, matching `ai`'s `Prompt`
610
+ * union (core always sets exactly one).
611
+ * - `tools`, `toolChoice`, and `messages` are widened to `any` — their
612
+ * portable shapes ({@link AgentTools}, {@link AgentToolChoice},
613
+ * {@link AgentMessage}) are structural supersets of `ai`'s branded types
614
+ * and would otherwise fail the contravariant check.
615
+ *
616
+ * Hand-written executors that want the precise shapes can annotate their
617
+ * parameter as `AgentTextRequest & { tools: AgentTools }` — that wider
618
+ * parameter type keeps the executor assignable.
619
+ */
620
+ type AgentExecutorTextRequest<TMetadata = Record<string, unknown>> = Omit<AgentTextRequest<TMetadata>, "prompt" | "messages" | "tools" | "toolChoice"> & {
621
+ tools: any;
622
+ toolChoice?: any;
623
+ } & ({
624
+ prompt: string;
625
+ messages?: undefined;
626
+ } | {
627
+ prompt?: undefined;
628
+ messages: any[];
629
+ });
679
630
  /**
680
631
  * Host implementation of one text call (`generateText` or `streamText`) —
681
- * resolves a lowered {@link AgentTextRequest} to an `{ output }` envelope (see
682
- * {@link AgentRequestExecutorResult}), unwrapped by
683
- * {@link normalizeGeneratorResult}. The return type is widened to also admit the
684
- * raw Vercel AI SDK shapes ({@link AiSdkShapedTextResult} /
685
- * {@link AiSdkShapedStreamResult}) so `ai`'s own `generateText`/`streamText`
686
- * pass through without a cast; `normalizeGeneratorResult` checks for `{ output }`
687
- * first, then falls back to those shapes at runtime.
688
- */
689
- type AgentRequestExecutor<TResult extends AgentRequestExecutorResult = AgentRequestExecutorResult> = (request: AgentTextRequest & {
690
- tools: AgentTools;
691
- }, info?: AgentRequestExecutorInfo) => PromiseLike<TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult> | TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult;
632
+ * resolves a lowered {@link AgentExecutorTextRequest} to an `{ output }`
633
+ * envelope (see {@link AgentRequestExecutorResult}), unwrapped by
634
+ * {@link normalizeGeneratorResult}. Both sides are shaped so `ai`'s own
635
+ * `generateText`/`streamText` pass through without a cast: the request
636
+ * parameter is assignable to `ai`'s options (see
637
+ * {@link AgentExecutorTextRequest}), and the return type is widened to also
638
+ * admit the raw Vercel AI SDK shapes ({@link AiSdkShapedTextResult} /
639
+ * {@link AiSdkShapedStreamResult}) — `normalizeGeneratorResult` checks for
640
+ * `{ output }` first, then falls back to those shapes at runtime.
641
+ */
642
+ type AgentRequestExecutor<TResult extends AgentRequestExecutorResult = AgentRequestExecutorResult> = (request: AgentExecutorTextRequest, info?: AgentRequestExecutorInfo) => PromiseLike<TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult> | TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult;
692
643
  /**
693
644
  * The full set of host executors a machine's agent actors are resolved
694
645
  * with — passed to `runAgent`, `executeAgentRequest`, and
695
646
  * `TextLogic.execute`. Every slot is optional: `generateText` is needed only
696
647
  * if the machine has a `mode: 'generate'` text request, `streamText` only for
697
- * a `mode: 'stream'` request, and `decide` only for a decision/plan — omitting
648
+ * a `mode: 'stream'` request, and `decide` only for a decision — omitting
698
649
  * a slot the machine actually needs is a clear bind-time error (see `runAgent`
699
650
  * and `provideExecutors`). Adapter result sets (`AiSdkExecutors`,
700
651
  * `OpenAiCompatExecutors`) re-require all three.
@@ -751,4 +702,4 @@ declare function buildEnvelopeSchema(inner: StandardSchemaV1, options?: {
751
702
  */
752
703
  declare function parseStructuredEnvelope(request: Pick<AgentTextRequest, "outputSchema" | "reasoning">, value: unknown): StructuredOutputEnvelope;
753
704
  //#endregion
754
- export { AgentDecisionInput as A, resolveDecision as B, createTextLogic as C, parseStructuredEnvelope as D, parseOutput as E, DecisionLogicConfig as F, getAcceptedEvents as G, AgentEventToolNameResolver as H, PLAN_DONE_EVENT_TYPE as I, parseAgentEvent as K, PlanLogic as L, AgentPlanInput as M, AgentPlanOutput as N, AgentDecisionExecutor as O, DecisionAttempt as P, ResolveDecisionOptions as R, buildEnvelopeSchema as S, parseModelRef as T, AgentRequestOptions as U, AgentEventDescriptor as V, AgentRequestSource as W, TextLogic as _, AgentRequestExecutor as a, TextLogicExecutor as b, AgentRequestExecutors as c, AgentUsage as d, AgentUserInput as f, StructuredOutputEnvelope as g, BuiltinAgentActors as h, AgentOutputMode as i, AgentDecisionRequest as j, AgentDecisionExhaustedError as k, AgentRequestMode as l, AiSdkShapedTextResult as m, AgentModelMap as n, AgentRequestExecutorInfo as o, AiSdkShapedStreamResult as p, AgentModelRef as r, AgentRequestExecutorResult as s, AgentCallUsage as t, AgentTextRequest as u, TextLogicConfig as v, getAgentOutputMode as w, bindRequestExecutor as x, TextLogicExecuteArgs as y, renderDecisionAttempts as z };
705
+ export { AgentDecisionExhaustedError as A, AgentRequestOptions as B, buildEnvelopeSchema as C, parseOutput as D, parseModelRef as E, ResolveDecisionOptions as F, getAcceptedEvents as H, renderDecisionAttempts as I, resolveDecision as L, AgentDecisionRequest as M, DecisionAttempt as N, parseStructuredEnvelope as O, DecisionLogicConfig as P, AgentEventDescriptor as R, bindRequestExecutor as S, getAgentOutputMode as T, parseAgentEvent as U, AgentRequestSource as V, StructuredOutputEnvelope as _, AgentOutputMode as a, TextLogicExecuteArgs as b, AgentRequestExecutorResult as c, AgentTextRequest as d, AgentUsage as f, BuiltinAgentActors as g, AiSdkShapedTextResult as h, AgentModelRef as i, AgentDecisionInput as j, AgentDecisionExecutor as k, AgentRequestExecutors as l, AiSdkShapedStreamResult as m, AgentExecutorTextRequest as n, AgentRequestExecutor as o, AgentUserInput as p, AgentModelMap as r, AgentRequestExecutorInfo as s, AgentCallUsage as t, AgentRequestMode as u, TextLogic as v, createTextLogic as w, TextLogicExecutor as x, TextLogicConfig as y, AgentEventToolNameResolver as z };
@@ -1,6 +1,6 @@
1
- import { _ as StandardSchemaV1, a as AgentToolChoice, c as AgentTools, d as ChosenEvent, h as InferOutput, l as AllowedEvents, n as AgentMessage } from "./types-QbEfCVny.cjs";
1
+ import { _ as StandardSchemaV1, a as AgentToolChoice, c as AgentTools, d as ChosenEvent, h as InferOutput, l as AllowedEvents, n as AgentMessage } from "./types-rMe7x6NR.cjs";
2
2
  import { t as AgentError } from "./errors-BQRk9eiZ.cjs";
3
- import { AnyMachineSnapshot, AsyncActorLogic, EventObject, LogicActorLogic, MachineSnapshot } from "xstate";
3
+ import { AnyMachineSnapshot, AsyncActorLogic, EventObject, MachineSnapshot } from "xstate";
4
4
 
5
5
  //#region src/events.d.ts
6
6
  /** The invoke `src` of an {@link AgentRequest}/{@link AgentDecisionRequest} — a plain string, widened so literal `src` values still narrow in editor hints. */
@@ -97,92 +97,6 @@ interface AgentDecisionInput<TEvent extends string = string, TMetadata = Record<
97
97
  stopSequences?: string[];
98
98
  metadata?: TMetadata;
99
99
  }
100
- /**
101
- * Inline input for the `agent.plan` builtin actor — a multi-event decision.
102
- * Where `agent.decide` picks exactly one currently-legal event, `agent.plan`
103
- * applies an ordered sequence of them: each step re-reads the live snapshot,
104
- * asks the `decide` executor for one legal event (same validation and
105
- * `rejected-by-guard` retry loop as a decision), sends it to the machine,
106
- * and repeats until a `stopOn` event is chosen, `maxSteps` is reached, no
107
- * legal candidate remains, or an applied event exits the invoking state
108
- * (which cancels the invoke — the machine simply moves on).
109
- *
110
- * Requires a snapshot-aware host: {@link runAgent}, or the step path (where an
111
- * `agent.plan` invoke re-surfaces as a `kind: 'plan'` request that
112
- * `resolveAgentRequests` drives one step per call).
113
- */
114
- interface AgentPlanInput<TEvent extends string = string, TMetadata = Record<string, unknown>, TModel extends string = string> extends AgentDecisionInput<TEvent, TMetadata, TModel> {
115
- /** Maximum events applied in one plan. Default 8. */
116
- maxSteps?: number;
117
- /**
118
- * Machine events that end the plan once chosen: the event is still
119
- * validated and sent, then the loop stops. Usually unnecessary — every
120
- * plan step already offers the built-in {@link PLAN_DONE_EVENT_TYPE}
121
- * "done" option, which ends the plan without touching the machine.
122
- * Declare `stopOn` only for "send this real event AND stop" semantics.
123
- */
124
- stopOn?: readonly TEvent[];
125
- }
126
- /**
127
- * Reserved event type the `agent.plan` builtin adds to every step's
128
- * candidates as the explicit "no further action needed" move. Choosing it
129
- * ends the plan (`stopped: 'done'`); it is never sent to the machine, so
130
- * machines need no no-op sentinel event of their own.
131
- */
132
- declare const PLAN_DONE_EVENT_TYPE: "agent.plan.done";
133
- /** What an `agent.plan` invoke resolves with (its `onDone` output). */
134
- interface AgentPlanOutput {
135
- /** The events applied, in order (possibly empty). */
136
- steps: ChosenEvent[];
137
- /** Why the loop ended. */
138
- stopped: "done" | "stop-event" | "max-steps" | "no-legal-events";
139
- }
140
- /**
141
- * The in-progress state of a plan, held in the `agent.plan` invoke child's own
142
- * `createLogic` snapshot `context`. Because a `createLogic` snapshot serializes
143
- * (and restores) by identity, this lands at
144
- * `children.<planId>.snapshot.context` in a machine's persisted snapshot for
145
- * free — so a step-path host that persists after every event resumes a plan
146
- * mid-flight without a bespoke carrier.
147
- */
148
- interface PlanLedgerContext {
149
- /** The events applied so far in this plan, in order (the trail). */
150
- applied: ChosenEvent[];
151
- /** How many more events the plan may apply (`maxSteps - applied.length`). */
152
- stepsRemaining: number;
153
- /** Set once the plan terminates; `null` while in flight. */
154
- stopped: AgentPlanOutput["stopped"] | null;
155
- }
156
- /**
157
- * The two ledger events that drive a {@link PlanLedgerContext} forward:
158
- * `plan.applied` appends one event to the trail and decrements the budget;
159
- * `plan.ended` records the stop reason and completes the ledger (its snapshot
160
- * goes `done` with the {@link AgentPlanOutput}).
161
- */
162
- type PlanLedgerEvent = {
163
- type: "plan.applied";
164
- event: ChosenEvent;
165
- } | {
166
- type: "plan.ended";
167
- stopped: AgentPlanOutput["stopped"];
168
- };
169
- /**
170
- * Actor logic for the `agent.plan` builtin: a stateful, transition-based
171
- * ledger. Its snapshot `context` ({@link PlanLedgerContext}) IS the plan's
172
- * in-progress state — the applied trail plus remaining budget — advanced one
173
- * {@link PlanLedgerEvent} at a time. On the step path the invoke child runs this
174
- * logic directly (so its context persists at `children.<id>.snapshot.context`);
175
- * runAgent swaps in an async implementation that drives the SAME ledger via the
176
- * shared {@link initialPlanLedger}/{@link advancePlanLedger} drivers.
177
- */
178
- interface PlanLogic<TInputSchema extends StandardSchemaV1 = StandardSchemaV1<AgentPlanInput>> extends LogicActorLogic<PlanLedgerContext, AgentPlanOutput, PlanLedgerEvent, InferOutput<TInputSchema>> {
179
- readonly kind: "statelyai.planLogic";
180
- readonly maxRetries: number;
181
- /** Builds the per-step base {@link AgentDecisionRequest} (id/events filled in per step). */
182
- request(input: InferOutput<TInputSchema>): AgentDecisionRequest;
183
- /** @internal Resolves declared `allowedEvents` (undefined = all currently legal). */
184
- allowedEventTypes(input: InferOutput<TInputSchema>): readonly string[] | undefined;
185
- }
186
100
  /**
187
101
  * Config for {@link createDecisionLogic}: how to build an
188
102
  * {@link AgentDecisionRequest} from typed input. Each field mirrors
@@ -366,7 +280,6 @@ declare const USER_INPUT_ACTOR: "agent.userInput";
366
280
  declare const GENERATE_TEXT_ACTOR: "agent.generateText";
367
281
  declare const STREAM_TEXT_ACTOR: "agent.streamText";
368
282
  declare const DECIDE_ACTOR: "agent.decide";
369
- declare const PLAN_ACTOR: "agent.plan";
370
283
  /** Whether a text request should be resolved with `generateText` (one-shot) or `streamText` (chunked, via `onChunk`). */
371
284
  type AgentRequestMode = "generate" | "stream";
372
285
  /** A `setupAgent({ models })` model registry, mapping short model refs to provider-specific model values. */
@@ -485,13 +398,12 @@ interface AgentUserInput<TMetadata = Record<string, unknown>> {
485
398
  prompt?: string;
486
399
  metadata?: TMetadata;
487
400
  }
488
- /** The five `agent.*` builtin actor logics every setupAgent-built machine registers. @internal */
401
+ /** The four `agent.*` builtin actor logics every setupAgent-built machine registers. @internal */
489
402
  type BuiltinAgentActors<TEvent extends string = string, TModel extends string = string> = {
490
403
  [GENERATE_TEXT_ACTOR]: AsyncActorLogic<unknown, AgentTextRequest>;
491
404
  [STREAM_TEXT_ACTOR]: AsyncActorLogic<unknown, AgentTextRequest>;
492
405
  [USER_INPUT_ACTOR]: AsyncActorLogic<string, AgentUserInput>;
493
406
  [DECIDE_ACTOR]: AsyncActorLogic<ChosenEvent, AgentDecisionInput<TEvent, Record<string, unknown>, TModel>>;
494
- [PLAN_ACTOR]: PlanLogic<StandardSchemaV1<AgentPlanInput<TEvent, Record<string, unknown>, TModel>>>;
495
407
  };
496
408
  /**
497
409
  * Validates a raw model/executor output against `schema`, returning the
@@ -660,7 +572,12 @@ interface AgentRequestExecutorInfo {
660
572
  */
661
573
  type AiSdkShapedTextResult = {
662
574
  text: string | PromiseLike<string>;
663
- [key: string]: unknown;
575
+ output?: unknown;
576
+ usage?: unknown;
577
+ reasoning?: unknown;
578
+ finishReason?: unknown;
579
+ toolCalls?: unknown;
580
+ toolResults?: unknown;
664
581
  };
665
582
  /**
666
583
  * A raw Vercel AI SDK `streamText` result shape: exposes a `textStream` async
@@ -674,27 +591,61 @@ type AiSdkShapedTextResult = {
674
591
  type AiSdkShapedStreamResult = {
675
592
  textStream: AsyncIterable<string>;
676
593
  text?: PromiseLike<string>;
677
- [key: string]: unknown;
594
+ output?: unknown;
595
+ usage?: unknown;
596
+ reasoning?: unknown;
597
+ finishReason?: unknown;
598
+ toolCalls?: unknown;
599
+ toolResults?: unknown;
678
600
  };
601
+ /**
602
+ * The lowered request as an {@link AgentRequestExecutor} receives it. At
603
+ * runtime this is exactly the {@link AgentTextRequest} core built (plus the
604
+ * merged `tools` map); the TYPE is deliberately shaped so the Vercel AI SDK's
605
+ * own `generateText`/`streamText` are directly assignable as executors
606
+ * (function parameters are contravariant, so this type must be assignable to
607
+ * `ai`'s options type):
608
+ *
609
+ * - `prompt`/`messages` are mutually exclusive, matching `ai`'s `Prompt`
610
+ * union (core always sets exactly one).
611
+ * - `tools`, `toolChoice`, and `messages` are widened to `any` — their
612
+ * portable shapes ({@link AgentTools}, {@link AgentToolChoice},
613
+ * {@link AgentMessage}) are structural supersets of `ai`'s branded types
614
+ * and would otherwise fail the contravariant check.
615
+ *
616
+ * Hand-written executors that want the precise shapes can annotate their
617
+ * parameter as `AgentTextRequest & { tools: AgentTools }` — that wider
618
+ * parameter type keeps the executor assignable.
619
+ */
620
+ type AgentExecutorTextRequest<TMetadata = Record<string, unknown>> = Omit<AgentTextRequest<TMetadata>, "prompt" | "messages" | "tools" | "toolChoice"> & {
621
+ tools: any;
622
+ toolChoice?: any;
623
+ } & ({
624
+ prompt: string;
625
+ messages?: undefined;
626
+ } | {
627
+ prompt?: undefined;
628
+ messages: any[];
629
+ });
679
630
  /**
680
631
  * Host implementation of one text call (`generateText` or `streamText`) —
681
- * resolves a lowered {@link AgentTextRequest} to an `{ output }` envelope (see
682
- * {@link AgentRequestExecutorResult}), unwrapped by
683
- * {@link normalizeGeneratorResult}. The return type is widened to also admit the
684
- * raw Vercel AI SDK shapes ({@link AiSdkShapedTextResult} /
685
- * {@link AiSdkShapedStreamResult}) so `ai`'s own `generateText`/`streamText`
686
- * pass through without a cast; `normalizeGeneratorResult` checks for `{ output }`
687
- * first, then falls back to those shapes at runtime.
688
- */
689
- type AgentRequestExecutor<TResult extends AgentRequestExecutorResult = AgentRequestExecutorResult> = (request: AgentTextRequest & {
690
- tools: AgentTools;
691
- }, info?: AgentRequestExecutorInfo) => PromiseLike<TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult> | TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult;
632
+ * resolves a lowered {@link AgentExecutorTextRequest} to an `{ output }`
633
+ * envelope (see {@link AgentRequestExecutorResult}), unwrapped by
634
+ * {@link normalizeGeneratorResult}. Both sides are shaped so `ai`'s own
635
+ * `generateText`/`streamText` pass through without a cast: the request
636
+ * parameter is assignable to `ai`'s options (see
637
+ * {@link AgentExecutorTextRequest}), and the return type is widened to also
638
+ * admit the raw Vercel AI SDK shapes ({@link AiSdkShapedTextResult} /
639
+ * {@link AiSdkShapedStreamResult}) — `normalizeGeneratorResult` checks for
640
+ * `{ output }` first, then falls back to those shapes at runtime.
641
+ */
642
+ type AgentRequestExecutor<TResult extends AgentRequestExecutorResult = AgentRequestExecutorResult> = (request: AgentExecutorTextRequest, info?: AgentRequestExecutorInfo) => PromiseLike<TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult> | TResult | AiSdkShapedTextResult | AiSdkShapedStreamResult;
692
643
  /**
693
644
  * The full set of host executors a machine's agent actors are resolved
694
645
  * with — passed to `runAgent`, `executeAgentRequest`, and
695
646
  * `TextLogic.execute`. Every slot is optional: `generateText` is needed only
696
647
  * if the machine has a `mode: 'generate'` text request, `streamText` only for
697
- * a `mode: 'stream'` request, and `decide` only for a decision/plan — omitting
648
+ * a `mode: 'stream'` request, and `decide` only for a decision — omitting
698
649
  * a slot the machine actually needs is a clear bind-time error (see `runAgent`
699
650
  * and `provideExecutors`). Adapter result sets (`AiSdkExecutors`,
700
651
  * `OpenAiCompatExecutors`) re-require all three.
@@ -751,4 +702,4 @@ declare function buildEnvelopeSchema(inner: StandardSchemaV1, options?: {
751
702
  */
752
703
  declare function parseStructuredEnvelope(request: Pick<AgentTextRequest, "outputSchema" | "reasoning">, value: unknown): StructuredOutputEnvelope;
753
704
  //#endregion
754
- export { AgentDecisionInput as A, resolveDecision as B, createTextLogic as C, parseStructuredEnvelope as D, parseOutput as E, DecisionLogicConfig as F, getAcceptedEvents as G, AgentEventToolNameResolver as H, PLAN_DONE_EVENT_TYPE as I, parseAgentEvent as K, PlanLogic as L, AgentPlanInput as M, AgentPlanOutput as N, AgentDecisionExecutor as O, DecisionAttempt as P, ResolveDecisionOptions as R, buildEnvelopeSchema as S, parseModelRef as T, AgentRequestOptions as U, AgentEventDescriptor as V, AgentRequestSource as W, TextLogic as _, AgentRequestExecutor as a, TextLogicExecutor as b, AgentRequestExecutors as c, AgentUsage as d, AgentUserInput as f, StructuredOutputEnvelope as g, BuiltinAgentActors as h, AgentOutputMode as i, AgentDecisionRequest as j, AgentDecisionExhaustedError as k, AgentRequestMode as l, AiSdkShapedTextResult as m, AgentModelMap as n, AgentRequestExecutorInfo as o, AiSdkShapedStreamResult as p, AgentModelRef as r, AgentRequestExecutorResult as s, AgentCallUsage as t, AgentTextRequest as u, TextLogicConfig as v, getAgentOutputMode as w, bindRequestExecutor as x, TextLogicExecuteArgs as y, renderDecisionAttempts as z };
705
+ export { AgentDecisionExhaustedError as A, AgentRequestOptions as B, buildEnvelopeSchema as C, parseOutput as D, parseModelRef as E, ResolveDecisionOptions as F, getAcceptedEvents as H, renderDecisionAttempts as I, resolveDecision as L, AgentDecisionRequest as M, DecisionAttempt as N, parseStructuredEnvelope as O, DecisionLogicConfig as P, AgentEventDescriptor as R, bindRequestExecutor as S, getAgentOutputMode as T, parseAgentEvent as U, AgentRequestSource as V, StructuredOutputEnvelope as _, AgentOutputMode as a, TextLogicExecuteArgs as b, AgentRequestExecutorResult as c, AgentTextRequest as d, AgentUsage as f, BuiltinAgentActors as g, AiSdkShapedTextResult as h, AgentModelRef as i, AgentDecisionInput as j, AgentDecisionExecutor as k, AgentRequestExecutors as l, AiSdkShapedStreamResult as m, AgentExecutorTextRequest as n, AgentRequestExecutor as o, AgentUserInput as p, AgentModelMap as r, AgentRequestExecutorInfo as s, AgentCallUsage as t, AgentRequestMode as u, TextLogic as v, createTextLogic as w, TextLogicExecutor as x, TextLogicConfig as y, AgentEventToolNameResolver as z };
@@ -201,8 +201,8 @@ type EventWildcardsOf<TEvent extends string> = TEvent extends `${infer Head}.${i
201
201
  /** One `allowedEvents` entry: an exact declared event type, `'*'` (every event), or a `'prefix.*'` wildcard derived from the declared dotted event types. */
202
202
  type AllowedEventPattern<TEvent extends string = string> = TEvent | "*" | EventWildcardsOf<TEvent>;
203
203
  /**
204
- * Candidate event types for a decision or plan (declared on the
205
- * `agent.decide`/`agent.plan` builtins' `allowedEvents` input). A single
204
+ * Candidate event types for a decision (declared on the `agent.decide`
205
+ * builtin's `allowedEvents` input). A single
206
206
  * entry or an array; entries are exact event types or wildcard patterns
207
207
  * (`'*'` for every event, `'todo.*'` for a dotted namespace). The effective
208
208
  * candidate set offered to the model is this declaration **intersected with
@@ -201,8 +201,8 @@ type EventWildcardsOf<TEvent extends string> = TEvent extends `${infer Head}.${i
201
201
  /** One `allowedEvents` entry: an exact declared event type, `'*'` (every event), or a `'prefix.*'` wildcard derived from the declared dotted event types. */
202
202
  type AllowedEventPattern<TEvent extends string = string> = TEvent | "*" | EventWildcardsOf<TEvent>;
203
203
  /**
204
- * Candidate event types for a decision or plan (declared on the
205
- * `agent.decide`/`agent.plan` builtins' `allowedEvents` input). A single
204
+ * Candidate event types for a decision (declared on the `agent.decide`
205
+ * builtin's `allowedEvents` input). A single
206
206
  * entry or an array; entries are exact event types or wildcard patterns
207
207
  * (`'*'` for every event, `'todo.*'` for a dotted namespace). The effective
208
208
  * candidate set offered to the model is this declaration **intersected with
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/agent",
3
- "version": "2.0.0-alpha.12",
3
+ "version": "2.0.0-alpha.14",
4
4
  "description": "Make invalid agent actions impossible. Agent logic as state machines: deterministic, inspectable, resumable, runs anywhere.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -99,7 +99,7 @@
99
99
  "@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
100
100
  "@opentelemetry/sdk-trace-base": "^2.10.0",
101
101
  "@opentelemetry/sdk-trace-node": "^2.10.0",
102
- "@statelyai/sdk": "^0.15.0",
102
+ "@statelyai/sdk": "^0.16.2",
103
103
  "@types/express": "^5.0.6",
104
104
  "@types/node": "^20.16.10",
105
105
  "@types/react": "^19.2.17",
@@ -117,6 +117,7 @@
117
117
  "react": "^19.2.7",
118
118
  "tsdown": "^0.21.7",
119
119
  "tsx": "^4.21.0",
120
+ "twoslash": "^0.3.9",
120
121
  "typescript": "^5.6.2",
121
122
  "valibot": "^1.4.2",
122
123
  "vitest": "^3.2.6",
@@ -141,7 +142,9 @@
141
142
  },
142
143
  "scripts": {
143
144
  "build": "tsdown",
145
+ "demo": "pnpm --filter @statelyai/agent-demo dev",
144
146
  "proto:prefabs": "tsx .scratch/prefabs/demo.ts",
147
+ "docs:check": "tsx scripts/check-docs-snippets.ts",
145
148
  "typecheck": "pnpm run typecheck:src && pnpm run typecheck:examples && pnpm run typecheck:example-packages",
146
149
  "typecheck:src": "tsc --noEmit",
147
150
  "typecheck:examples": "tsc -p examples/tsconfig.json --noEmit",
package/readme.md CHANGED
@@ -4,15 +4,17 @@
4
4
 
5
5
  Agent logic as state machines: deterministic, inspectable, resumable, runs anywhere. The machine owns control flow; the model only ever picks a legal event. Testing, inspection, and visualization fall out for free.
6
6
 
7
- Stately Agent adds model requests and decisions to XState. The state machine defines what the agent can do. Your application chooses the model, runs the requests, and stores the state.
7
+ Stately Agent adds model requests and decisions to XState:
8
8
 
9
- Any agent workflow or loop can be modeled as a state machine. Model calls and tools run as effects inside it. The model proposes an event. The machine decides whether it is allowed and what happens next.
9
+ - The machine defines what the agent can do.
10
+ - Your application chooses the model, runs the requests, and stores the state.
11
+ - The model proposes an event; the machine decides whether it is allowed and what happens next.
10
12
 
11
13
  Stately Agent 2 is in alpha. APIs may change before the stable release.
12
14
 
13
15
  [Documentation](https://stately.ai/docs/agents) · [Examples](examples/README.md) · [XState](https://github.com/statelyai/xstate)
14
16
 
15
- ## Three ways to start
17
+ ## Three starting points
16
18
 
17
19
  - **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).
18
20
  - **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 loop](docs/from-a-loop.md).
@@ -26,7 +28,11 @@ Stately Agent 2 is in alpha. APIs may change before the stable release.
26
28
  pnpm add @statelyai/agent@alpha xstate@alpha zod ai@^6 @ai-sdk/openai@^3
27
29
  ```
28
30
 
29
- Node 22.18 or newer is required. The package is ESM-first (CommonJS builds are published too, so `require()` works) and requires XState v6 alpha.25 or newer. Provider packages must match your `ai` major: `@ai-sdk/openai@^3` pairs with `ai@^6` (a bare `@ai-sdk/openai` resolves to `@latest`, which can mismatch the `ai` peer).
31
+ Requirements:
32
+
33
+ - Node 22.18 or newer, and XState v6 alpha.25 or newer.
34
+ - The package is ESM-first. CommonJS builds are published too, so `require()` works.
35
+ - Provider packages must match your `ai` major: `@ai-sdk/openai@^3` pairs with `ai@^6`. A bare `@ai-sdk/openai` resolves to `@latest`, which can mismatch the `ai` peer.
30
36
 
31
37
  ## Quick start
32
38
 
@@ -114,7 +120,7 @@ When the machine reaches `refunded`, the result is:
114
120
 
115
121
  The model chooses between the events allowed in `deciding`. The `AUTO_REFUND` transition only works when the amount is at most $100. If the model chooses it for a larger amount, the guard rejects the choice and the decision is tried again.
116
122
 
117
- **Run it with no API key.** `createScriptedExecutors` plays back canned answers through the same executor contract, so the machine above runs end to end before a model is involved:
123
+ `createScriptedExecutors` plays back canned answers through the same executor contract, so the machine above runs end to end before a model is involved. **No API key needed:**
118
124
 
119
125
  ```ts
120
126
  import { createScriptedExecutors } from "@statelyai/agent";
@@ -127,11 +133,21 @@ const result = await runAgent(refundMachine, {
127
133
 
128
134
  Swap in `createAiSdkExecutors({ models })` when you want a real model. The scripted set is what your tests keep using.
129
135
 
130
- ## The state machine
136
+ ## Architecture
137
+
138
+ ```mermaid
139
+ flowchart LR
140
+ M["Agent machine<br/>states · guards · requests"] -->|request| R["runAgent"]
141
+ R -->|executor call| E["Host executors<br/>generateText · streamText · decide"]
142
+ E -->|API call| L["Model"]
143
+ L -->|result| E
144
+ E -->|result| R
145
+ R -->|event or output| M
146
+ ```
131
147
 
132
- <!-- Add the state machine illustration here. -->
148
+ The machine never talks to a model directly, so swapping `createAiSdkExecutors` for `createScriptedExecutors` (or your own functions) changes nothing about the agent.
133
149
 
134
- The example has one model decision and two final outcomes. Real machines can add approval states, retries, parallel work, child agents, and long-running waits without changing how the control flow is represented.
150
+ 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.
135
151
 
136
152
  ## Core concepts
137
153