@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.
- package/dist/ai-sdk.cjs +1 -1
- package/dist/ai-sdk.d.cts +2 -2
- package/dist/ai-sdk.d.mts +2 -2
- package/dist/ai-sdk.mjs +1 -1
- package/dist/{decision-dWGhBh0P.cjs → decision-C0cUKvNt.cjs} +0 -105
- package/dist/{decision-BezSD_YC.mjs → decision-D9Zi7Xi5.mjs} +2 -65
- package/dist/index.cjs +31 -155
- package/dist/index.d.cts +8 -12
- package/dist/index.d.mts +8 -12
- package/dist/index.mjs +33 -156
- package/dist/machines.cjs +1 -1
- package/dist/machines.d.cts +1 -1
- package/dist/machines.d.mts +1 -1
- package/dist/machines.mjs +1 -1
- package/dist/otel.cjs +5 -15
- package/dist/otel.d.cts +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/otel.mjs +5 -15
- package/dist/{run-agent-B1nBa7aV.d.mts → run-agent-2MnlQTkB.d.mts} +60 -107
- package/dist/{run-agent-qkg0evvW.d.cts → run-agent-BlqKwHIF.d.cts} +60 -107
- package/dist/{setup-agent-DP95MFrI.cjs → setup-agent-CpK0ZRWV.cjs} +10 -210
- package/dist/{setup-agent-DAZZSjDS.mjs → setup-agent-DeHRW-qX.mjs} +11 -205
- package/dist/sqlite.d.cts +2 -2
- package/dist/sqlite.d.mts +2 -2
- package/dist/{text-logic-DjR5PUVz.d.mts → text-logic-C5kbjaDz.d.mts} +57 -106
- package/dist/{text-logic-CorGzucG.d.cts → text-logic-Jkilp1Ie.d.cts} +57 -106
- package/dist/{types-QbEfCVny.d.cts → types-9Bqg5rZB.d.mts} +2 -2
- package/dist/{types-_FXoFBGO.d.mts → types-rMe7x6NR.d.cts} +2 -2
- package/package.json +5 -2
- package/readme.md +24 -8
- /package/dist/{event-log-store-CriMgX1D.d.mts → event-log-store-BkUNtyOF.d.mts} +0 -0
- /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-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
682
|
-
* {@link AgentRequestExecutorResult}), unwrapped by
|
|
683
|
-
* {@link normalizeGeneratorResult}.
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
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
|
|
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 {
|
|
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-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
682
|
-
* {@link AgentRequestExecutorResult}), unwrapped by
|
|
683
|
-
* {@link normalizeGeneratorResult}.
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
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
|
|
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 {
|
|
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
|
|
205
|
-
*
|
|
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
|
|
205
|
-
*
|
|
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.
|
|
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.
|
|
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
|
|
7
|
+
Stately Agent adds model requests and decisions to XState:
|
|
8
8
|
|
|
9
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
|
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
|
|
|
File without changes
|
|
File without changes
|