@statelyai/agent 2.0.0-alpha.21 → 2.0.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-sdk.cjs +53 -25
- package/dist/ai-sdk.d.cts +20 -12
- package/dist/ai-sdk.d.mts +20 -12
- package/dist/ai-sdk.mjs +53 -25
- package/dist/{decision-JWx6n3xR.mjs → decision-BBZ2jMO1.mjs} +542 -84
- package/dist/{decision-BnTCsuJv.cjs → decision-Cv6SfNWl.cjs} +629 -99
- package/dist/index.cjs +2225 -1032
- package/dist/index.d.cts +415 -276
- package/dist/index.d.mts +415 -276
- package/dist/index.mjs +2163 -983
- package/dist/machines.cjs +30 -2
- package/dist/machines.d.cts +151 -54
- package/dist/machines.d.mts +151 -54
- package/dist/machines.mjs +30 -2
- package/dist/openai.cjs +447 -0
- package/dist/openai.d.cts +177 -0
- package/dist/openai.d.mts +177 -0
- package/dist/openai.mjs +437 -0
- package/dist/otel.cjs +3 -6
- package/dist/otel.d.cts +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/otel.mjs +3 -6
- package/dist/run-agent-Ck7Sa3Tb.d.mts +968 -0
- package/dist/run-agent-DWqA8KiI.d.cts +968 -0
- package/dist/setup-agent-CeO2fARv.mjs +639 -0
- package/dist/setup-agent-Dl2VELLi.cjs +663 -0
- package/dist/{text-logic-Mmbgb2jy.d.cts → text-logic-C7bSnH_B.d.cts} +238 -44
- package/dist/{text-logic-BR5twXCv.d.mts → text-logic-DJBK3LbG.d.mts} +238 -44
- package/dist/{types-DSdj2tGs.d.cts → types-CjHk5OdH.d.cts} +4 -19
- package/dist/{types-CvWRGFxP.d.mts → types-DWA6X9R-.d.mts} +4 -19
- package/package.json +17 -21
- package/readme.md +32 -17
- package/dist/errors-BQRk9eiZ.d.cts +0 -19
- package/dist/errors-C9rxnWbX.d.mts +0 -19
- package/dist/errors-CeSXQx0v.mjs +0 -23
- package/dist/errors-DUBBzRLP.cjs +0 -28
- package/dist/event-log-store-Bz7HDBkE.d.cts +0 -145
- package/dist/event-log-store-DmIDosD6.mjs +0 -427
- package/dist/event-log-store-a_TKy1gk.cjs +0 -468
- package/dist/event-log-store-hrA1vqtN.d.mts +0 -145
- package/dist/run-agent-DBNI8ETM.d.mts +0 -1098
- package/dist/run-agent-Do094mGu.d.cts +0 -1098
- package/dist/setup-agent-91FSuZbB.cjs +0 -1641
- package/dist/setup-agent-DqqdcdNh.mjs +0 -1521
- package/dist/sqlite.cjs +0 -129
- package/dist/sqlite.d.cts +0 -57
- package/dist/sqlite.d.mts +0 -57
- package/dist/sqlite.mjs +0 -127
|
@@ -0,0 +1,968 @@
|
|
|
1
|
+
import { _ as StandardSchemaV1, m as InferInput, s as AgentTools, w as WithAgentInputSchema } from "./types-CjHk5OdH.cjs";
|
|
2
|
+
import { F as AgentDecisionRequest, K as AgentEventDescriptor, X as AgentRequestSource, d as AgentRequestMode, f as AgentTextRequest, m as AgentUserInput, p as AgentUsage, r as AgentFinishReason, t as AgentCallUsage, tt as AgentError, u as AgentRequestExecutors } from "./text-logic-C7bSnH_B.cjs";
|
|
3
|
+
import { AnyActorLogic, AnyActorRef, AnyMachineSnapshot, AnyStateMachine, AsyncActorLogic, EmittedFrom, EventFromLogic, EventObject, InputFrom, InspectionEvent, OutputFrom, Snapshot, SnapshotFrom } from "xstate";
|
|
4
|
+
|
|
5
|
+
//#region src/usage.d.ts
|
|
6
|
+
/** Reserved event delivered after a model call reports token usage. */
|
|
7
|
+
declare const AGENT_USAGE_EVENT_TYPE: "@agent.usage";
|
|
8
|
+
/** Machine-owned usage signal. Handle it with an ordinary XState transition. */
|
|
9
|
+
interface AgentUsageEvent extends EventObject {
|
|
10
|
+
type: typeof AGENT_USAGE_EVENT_TYPE;
|
|
11
|
+
usage: AgentCallUsage;
|
|
12
|
+
kind?: "text" | "decision";
|
|
13
|
+
id?: string;
|
|
14
|
+
src?: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/steps.d.ts
|
|
20
|
+
/**
|
|
21
|
+
* A pending text request surfaced by step discovery ({@link getAgentRequests}
|
|
22
|
+
* / {@link AgentStep.requests}): the machine has spawned a
|
|
23
|
+
* `TextLogic`-backed invoke and is waiting on its result. Resolve it with
|
|
24
|
+
* {@link executeAgentRequest} (or by hand, then feed the output into
|
|
25
|
+
* {@link resolveAgentStep} via `xstate.done.actor` + `actorId`).
|
|
26
|
+
*/
|
|
27
|
+
interface AgentRequest<TInput extends AgentTextRequest = AgentTextRequest> {
|
|
28
|
+
kind: "text";
|
|
29
|
+
id: string;
|
|
30
|
+
src: AgentRequestSource;
|
|
31
|
+
mode?: AgentRequestMode;
|
|
32
|
+
input: TInput;
|
|
33
|
+
tools: AgentTools;
|
|
34
|
+
events: AgentEventDescriptor[];
|
|
35
|
+
}
|
|
36
|
+
/** `AgentStep.requests` element: a text or decision request. */
|
|
37
|
+
type AgentStepRequest = AgentRequest | AgentDecisionRequest;
|
|
38
|
+
/**
|
|
39
|
+
* Resolves one **text** request against a host's {@link AgentRequestExecutors}
|
|
40
|
+
* — merges the request's tools, dispatches to `generateText`/`streamText` per
|
|
41
|
+
* `mode`, and validates the result against the request's `outputSchema` if
|
|
42
|
+
* present. Accepts either a `kind: 'text'` `AgentEffect` (the step-path shape
|
|
43
|
+
* from a custom XState host) or an {@link AgentRequest} envelope.
|
|
44
|
+
* **Text-only**: passing a `kind: 'decision'` request throws, directing the
|
|
45
|
+
* caller to `resolveDecision(request, executors, ...)` instead. Always
|
|
46
|
+
* returns both the normalized `output` and the `raw` executor result (tool
|
|
47
|
+
* calls, usage, finish reason — needed for observability and event-sourced
|
|
48
|
+
* replay).
|
|
49
|
+
*/
|
|
50
|
+
/** A `kind: 'text'` `AgentEffect` (structural, to avoid an import cycle with effects.ts). */
|
|
51
|
+
interface TextEffectLike {
|
|
52
|
+
kind: "text";
|
|
53
|
+
requestId: string;
|
|
54
|
+
request: AgentTextRequest;
|
|
55
|
+
mode?: AgentRequestMode;
|
|
56
|
+
}
|
|
57
|
+
declare function executeAgentRequest(requestOrEffect: AgentRequest | TextEffectLike, executors: Partial<AgentRequestExecutors>): Promise<{
|
|
58
|
+
output: unknown;
|
|
59
|
+
raw: unknown;
|
|
60
|
+
}>;
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/event-log.d.ts
|
|
63
|
+
/** The durable entry envelope version. */
|
|
64
|
+
declare const AGENT_EVENT_SCHEMA_VERSION: 1;
|
|
65
|
+
/**
|
|
66
|
+
* The reserved event type of the first entry of every log. It carries the
|
|
67
|
+
* machine `input` (fresh start) or a persisted `snapshot` (continuation), so a
|
|
68
|
+
* log replays with no side channel. Lives in the reserved `@agent.*` namespace
|
|
69
|
+
* so it can never collide with a machine's own vocabulary; it is consumed by
|
|
70
|
+
* {@link replay} and never fed to `transition`.
|
|
71
|
+
*/
|
|
72
|
+
declare const AGENT_INIT_EVENT_TYPE: "@agent.init";
|
|
73
|
+
/** Values that round-trip through JSON without adapters or silent coercion. */
|
|
74
|
+
type JsonValue$1 = null | boolean | number | string | JsonValue$1[] | {
|
|
75
|
+
[key: string]: JsonValue$1;
|
|
76
|
+
};
|
|
77
|
+
/** A persisted (JSON-safe) machine snapshot, as `machine.getPersistedSnapshot()` returns. */
|
|
78
|
+
type AgentPersistedSnapshot = Snapshot<unknown>;
|
|
79
|
+
/** Recorded projection hash used by {@link replay} verification. */
|
|
80
|
+
interface AgentLogVerification {
|
|
81
|
+
/** {@link getSnapshotStateHash} of the persisted snapshot after this entry is applied. */
|
|
82
|
+
stateHash: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* One journaled external input, JSON-safe and stored verbatim.
|
|
86
|
+
*/
|
|
87
|
+
interface AgentLogEntry {
|
|
88
|
+
/** Version of this outer envelope, independent of the machine event type. */
|
|
89
|
+
schemaVersion: typeof AGENT_EVENT_SCHEMA_VERSION;
|
|
90
|
+
/** Stable identity within the log. Forked prefixes retain their ids. */
|
|
91
|
+
id: string;
|
|
92
|
+
/** 0-based position in the log. */
|
|
93
|
+
index: number;
|
|
94
|
+
/** RFC 3339 wall-clock time when the host accepted the entry. Metadata only. */
|
|
95
|
+
recordedAt: string;
|
|
96
|
+
/** The authored XState machine id. */
|
|
97
|
+
machineId: string;
|
|
98
|
+
/** Explicit version or structural hash of the machine that accepted the event. */
|
|
99
|
+
machineVersion: string;
|
|
100
|
+
event: EventObject;
|
|
101
|
+
/** Optional causal parent entry id, scoped to the same log. */
|
|
102
|
+
causationId?: string;
|
|
103
|
+
/** Host-owned, JSON-safe; stored verbatim, never interpreted. */
|
|
104
|
+
metadata?: Record<string, JsonValue$1>;
|
|
105
|
+
/** Recorded projection hash used by replay verification. */
|
|
106
|
+
verification?: AgentLogVerification;
|
|
107
|
+
}
|
|
108
|
+
/** The payload of the reserved {@link AGENT_INIT_EVENT_TYPE} first entry. */
|
|
109
|
+
interface AgentInitEvent extends EventObject {
|
|
110
|
+
type: typeof AGENT_INIT_EVENT_TYPE;
|
|
111
|
+
/** Machine input for a fresh start. Mutually exclusive with `snapshot`. */
|
|
112
|
+
input?: unknown;
|
|
113
|
+
/** Persisted snapshot to continue from. Mutually exclusive with `input`. */
|
|
114
|
+
snapshot?: AgentPersistedSnapshot;
|
|
115
|
+
}
|
|
116
|
+
/** A malformed or internally inconsistent log. */
|
|
117
|
+
declare class AgentEventLogError extends AgentError {
|
|
118
|
+
constructor(message: string);
|
|
119
|
+
}
|
|
120
|
+
/** A precise failure when an entry would not survive a JSON round-trip. */
|
|
121
|
+
declare class NonSerializableAgentEventError extends AgentError {
|
|
122
|
+
readonly path: string;
|
|
123
|
+
readonly valueType: string;
|
|
124
|
+
constructor(path: string, valueType: string);
|
|
125
|
+
}
|
|
126
|
+
/** Replay reached a state that does not match the entry's recorded hash. */
|
|
127
|
+
declare class AgentReplayDivergenceError extends AgentError {
|
|
128
|
+
readonly eventId: string;
|
|
129
|
+
readonly index: number;
|
|
130
|
+
readonly kind: "state" | "missing-verification";
|
|
131
|
+
readonly expected?: string | undefined;
|
|
132
|
+
readonly actual?: string | undefined;
|
|
133
|
+
constructor(eventId: string, index: number, kind: "state" | "missing-verification", expected?: string | undefined, actual?: string | undefined);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* An entry was recorded against a different machine (id) or a different
|
|
137
|
+
* machine version than the one replaying it. An init-with-snapshot entry is
|
|
138
|
+
* exempt: that entry IS the bridge from the old version to the new one.
|
|
139
|
+
*/
|
|
140
|
+
declare class AgentMachineVersionMismatchError extends AgentError {
|
|
141
|
+
readonly eventId: string;
|
|
142
|
+
readonly index: number;
|
|
143
|
+
readonly expected: {
|
|
144
|
+
machineId: string;
|
|
145
|
+
machineVersion: string;
|
|
146
|
+
};
|
|
147
|
+
readonly actual: {
|
|
148
|
+
machineId: string;
|
|
149
|
+
machineVersion: string;
|
|
150
|
+
};
|
|
151
|
+
constructor(eventId: string, index: number, expected: {
|
|
152
|
+
machineId: string;
|
|
153
|
+
machineVersion: string;
|
|
154
|
+
}, actual: {
|
|
155
|
+
machineId: string;
|
|
156
|
+
machineVersion: string;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Rejects values JSON would drop or coerce. Unlike `JSON.stringify`, this does
|
|
161
|
+
* not silently erase `undefined`/functions or turn non-finite numbers into
|
|
162
|
+
* `null`; durable entries contain only plain JSON values.
|
|
163
|
+
*/
|
|
164
|
+
declare function assertJsonSerializable(value: unknown, path?: string, ancestors?: WeakSet<object>): asserts value is JsonValue$1;
|
|
165
|
+
/** Validates the complete durable envelope before append/export/replay. */
|
|
166
|
+
declare function assertAgentLogEntry(entry: unknown): asserts entry is AgentLogEntry;
|
|
167
|
+
/**
|
|
168
|
+
* The canonical hash of a PERSISTED snapshot (`machine.getPersistedSnapshot()`,
|
|
169
|
+
* or {@link replay}'s `persistedSnapshot`) — the value recorded in an entry's
|
|
170
|
+
* `verification.stateHash`.
|
|
171
|
+
*
|
|
172
|
+
* Stripped before hashing, because they are re-minted on every fold and would
|
|
173
|
+
* otherwise make two identical runs hash differently: `sessionId`,
|
|
174
|
+
* `_nextTimerId` and `_nextActorIds` at the snapshot root, `sessionId` on each
|
|
175
|
+
* `children[*]` entry (recursively, through nested child snapshots), and
|
|
176
|
+
* `undefined`-valued properties (so a snapshot hashes the same before and
|
|
177
|
+
* after a JSON round-trip). Stripping is confined to those structural
|
|
178
|
+
* positions: a `sessionId` inside `context`, `output`, `error` or an event
|
|
179
|
+
* payload is application data and is hashed. Object keys are sorted, so key
|
|
180
|
+
* order is irrelevant.
|
|
181
|
+
*
|
|
182
|
+
* A change detector, not a cryptographic digest.
|
|
183
|
+
*/
|
|
184
|
+
declare function getSnapshotStateHash(snapshot: AgentPersistedSnapshot | unknown): string;
|
|
185
|
+
/** Options controlling the durable envelope created by {@link createReplayEntry}. */
|
|
186
|
+
interface CreateReplayEntryOptions {
|
|
187
|
+
/** Explicit machine version; defaults to the machine's resolved version. */
|
|
188
|
+
machineVersion?: string;
|
|
189
|
+
/** Stable entry id; defaults to `evt_` plus the zero-padded index. */
|
|
190
|
+
id?: string;
|
|
191
|
+
/** RFC 3339 acceptance time; defaults to the current wall clock. */
|
|
192
|
+
recordedAt?: string;
|
|
193
|
+
causationId?: string;
|
|
194
|
+
metadata?: Record<string, JsonValue$1>;
|
|
195
|
+
/** Record `verification.stateHash` (default `true`). */
|
|
196
|
+
verification?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* The snapshot this entry folds to, when the caller already has it — avoids
|
|
199
|
+
* re-folding the whole prefix just to compute the hash. Accepts a live or a
|
|
200
|
+
* persisted snapshot.
|
|
201
|
+
*/
|
|
202
|
+
snapshot?: AnyMachineSnapshot | AgentPersistedSnapshot;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Creates a JSON-safe, self-describing entry for `event` appended after
|
|
206
|
+
* `entries` (which must be the complete prefix, so `index` and the recorded
|
|
207
|
+
* state hash line up).
|
|
208
|
+
*/
|
|
209
|
+
declare function createReplayEntry(machine: AnyStateMachine, entries: readonly AgentLogEntry[], event: EventObject, options?: CreateReplayEntryOptions): AgentLogEntry;
|
|
210
|
+
/** How a log begins: from machine input, or from a persisted snapshot. */
|
|
211
|
+
type AgentLogInit = {
|
|
212
|
+
input?: unknown;
|
|
213
|
+
snapshot?: never;
|
|
214
|
+
} | {
|
|
215
|
+
snapshot: AgentPersistedSnapshot;
|
|
216
|
+
input?: never;
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* The reserved first entry of a log. Pass EXACTLY one of:
|
|
220
|
+
*
|
|
221
|
+
* - `{ input }` — a fresh start; replay folds from `initialTransition`.
|
|
222
|
+
* - `{ snapshot }` — a continuation from a persisted snapshot: a version
|
|
223
|
+
* bridge, or a legacy snapshot that predates the log. Replay restores it
|
|
224
|
+
* purely (no actors started) and folds the rest of the log onto it.
|
|
225
|
+
*
|
|
226
|
+
* `options.metadata.executionId` names the lineage; this library always sets
|
|
227
|
+
* one, and readers must tolerate its absence in logs written elsewhere.
|
|
228
|
+
*/
|
|
229
|
+
declare function initEntry(machine: AnyStateMachine, init?: AgentLogInit, options?: CreateReplayEntryOptions): AgentLogEntry;
|
|
230
|
+
/**
|
|
231
|
+
* The log's execution id: the lineage identity pinned in the init entry's
|
|
232
|
+
* `metadata.executionId`.
|
|
233
|
+
*
|
|
234
|
+
* Minted once per run and inherited verbatim by every resume of that log, so
|
|
235
|
+
* it names one lineage rather than one process. Entry ids cannot serve this
|
|
236
|
+
* role — the built-in ids are index-derived, so every log's init entry is
|
|
237
|
+
* `evt_00000000`. A fork copies the init entry, so it shares its parent's
|
|
238
|
+
* execution id by construction.
|
|
239
|
+
*
|
|
240
|
+
* Returns `undefined` for a log with no init entry and for one written without
|
|
241
|
+
* the field — callers must treat the id as optional.
|
|
242
|
+
*/
|
|
243
|
+
declare function getLogExecutionId(entries: readonly AgentLogEntry[]): string | undefined;
|
|
244
|
+
/**
|
|
245
|
+
* Validates a log before replay or append: every envelope well-formed, indices
|
|
246
|
+
* contiguous from 0, ids unique, the first entry the reserved init entry, and
|
|
247
|
+
* one consistent machine identity throughout.
|
|
248
|
+
*
|
|
249
|
+
* With `machine`, entries are also checked against that machine's id and
|
|
250
|
+
* resolved version — a mismatch throws {@link AgentMachineVersionMismatchError}.
|
|
251
|
+
* An init-with-snapshot entry is exempt from the version check: that entry is
|
|
252
|
+
* itself the bridge from whatever version produced the snapshot.
|
|
253
|
+
*/
|
|
254
|
+
declare function validateReplayEntries(entries: readonly AgentLogEntry[], options?: {
|
|
255
|
+
machine?: AnyStateMachine;
|
|
256
|
+
machineVersion?: string;
|
|
257
|
+
}): void;
|
|
258
|
+
/**
|
|
259
|
+
* The prefix `[0, upToIndex)` of a log, as a new log. `upToIndex` is exclusive
|
|
260
|
+
* and must leave the init entry in place, so the fork is still self-contained.
|
|
261
|
+
*/
|
|
262
|
+
declare function forkEventLog(entries: readonly AgentLogEntry[], upToIndex: number): AgentLogEntry[];
|
|
263
|
+
/**
|
|
264
|
+
* The 1-based occurrence `n` for the NEXT call at invoke site `siteId`:
|
|
265
|
+
* `1 + completions`, where a completion is a journaled `xstate.done.actor` OR
|
|
266
|
+
* `xstate.error.actor` for that `actorId` (an error is a semantic completion).
|
|
267
|
+
* The one counting rule behind every `${siteId}#${n}` call key, so a live run
|
|
268
|
+
* and a replay derive the same `n` by construction.
|
|
269
|
+
*/
|
|
270
|
+
declare function agentCallOccurrence(history: readonly (EventObject | AgentLogEntry)[] | undefined, siteId: string): number;
|
|
271
|
+
/**
|
|
272
|
+
* Folds the reserved `@agent.usage` entries of a log into one cumulative usage
|
|
273
|
+
* total. The log is the source of truth, so the totals are a pure projection of
|
|
274
|
+
* it: replay a log, fold it, and you get the numbers the run reported with no
|
|
275
|
+
* host-side accumulator in between.
|
|
276
|
+
*
|
|
277
|
+
* Accepts entries or bare events. Token fields are partial sums: a field stays
|
|
278
|
+
* `undefined` until some entry reports it, and non-finite values are ignored.
|
|
279
|
+
*/
|
|
280
|
+
declare function getUsageFromEvents(entries: readonly (EventObject | AgentLogEntry)[]): AgentCallUsage;
|
|
281
|
+
/**
|
|
282
|
+
* Rewrites a journaled `xstate.done.actor`/`xstate.error.actor` event's
|
|
283
|
+
* `sessionId` to the session the CURRENT fold minted for that `actorId`.
|
|
284
|
+
*
|
|
285
|
+
* Session ids are re-minted on every fold, and XState drops a completion event
|
|
286
|
+
* whose `sessionId` does not match the live child — silently, as a no-op
|
|
287
|
+
* transition. Rebinding is what makes a journaled completion replayable at all.
|
|
288
|
+
* `sessions` caches the mapping per fold, so a later event referring to the
|
|
289
|
+
* recorded session of an already-stopped child still resolves.
|
|
290
|
+
*/
|
|
291
|
+
declare function rebindActorSession(event: EventObject, snapshot: AnyMachineSnapshot, sessions: Map<string, string>): EventObject;
|
|
292
|
+
/** Options for {@link replay}. */
|
|
293
|
+
interface ReplayOptions {
|
|
294
|
+
/** Explicit expected machine version; defaults to the machine's resolved version. */
|
|
295
|
+
machineVersion?: string;
|
|
296
|
+
/**
|
|
297
|
+
* `true` (default) checks the entries that carry a `verification.stateHash`;
|
|
298
|
+
* `'strict'` additionally requires every entry to carry one; `false` skips
|
|
299
|
+
* verification entirely.
|
|
300
|
+
*/
|
|
301
|
+
verify?: boolean | "strict";
|
|
302
|
+
}
|
|
303
|
+
/** The result of a {@link replay}. */
|
|
304
|
+
interface ReplayResult<TMachine extends AnyStateMachine> {
|
|
305
|
+
/** The folded live snapshot (no actors started, no effects run). */
|
|
306
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
307
|
+
/** Its persisted projection — what a host stores, and what hashes. */
|
|
308
|
+
persistedSnapshot: AgentPersistedSnapshot;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Folds a log through XState's pure `initialTransition`/`transition` WITHOUT
|
|
312
|
+
* executing anything: no actor is started, no action runs, no model is called.
|
|
313
|
+
* A journaled `xstate.done.actor` entry carries the completed actor's output
|
|
314
|
+
* inline, so the invoke it belongs to is never re-run. Crash recovery, fork
|
|
315
|
+
* resume, and time travel in one call.
|
|
316
|
+
*
|
|
317
|
+
* The first entry is the reserved {@link initEntry}: `input` folds from
|
|
318
|
+
* `initialTransition`, `snapshot` restores the persisted snapshot purely
|
|
319
|
+
* (`machine.restoreSnapshot`) and folds the rest of the log onto it.
|
|
320
|
+
*/
|
|
321
|
+
declare function replay<TMachine extends AnyStateMachine>(machine: TMachine, entries: readonly AgentLogEntry[], options?: ReplayOptions): ReplayResult<TMachine>;
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/event-log-store.d.ts
|
|
324
|
+
/**
|
|
325
|
+
* An append-only event log: the authoritative durability artifact of a thread.
|
|
326
|
+
* The journal of external inputs IS the source of truth — deterministic
|
|
327
|
+
* `replay` derives every snapshot from it, and a fork is a copied log prefix.
|
|
328
|
+
*
|
|
329
|
+
* Userland stores (a Postgres table with a `(thread_id, index)` primary key, an
|
|
330
|
+
* append-only object in blob storage, …) implement this one shape so they
|
|
331
|
+
* interoperate; {@link createInMemoryEventLogStore} is the reference, and
|
|
332
|
+
* `assertEventLogStoreConformance` checks an implementation against it.
|
|
333
|
+
*/
|
|
334
|
+
interface AgentEventLogStore {
|
|
335
|
+
/**
|
|
336
|
+
* Append `entries` starting at `expectedIndex` (the current length of the
|
|
337
|
+
* thread's log; 0 for a new thread). Atomic — all entries land or none do.
|
|
338
|
+
* Rejects with {@link AgentEventLogConflictError} when the thread's length
|
|
339
|
+
* differs from `expectedIndex`: a concurrent writer appended first. Each
|
|
340
|
+
* entry's `index` must be contiguous from `expectedIndex` (a plain `Error`
|
|
341
|
+
* otherwise: that is caller misuse, not a race).
|
|
342
|
+
*/
|
|
343
|
+
append(input: {
|
|
344
|
+
threadId: string;
|
|
345
|
+
expectedIndex: number;
|
|
346
|
+
entries: AgentLogEntry[];
|
|
347
|
+
}): Promise<void>;
|
|
348
|
+
/**
|
|
349
|
+
* Read a thread's entries in log order. `from` (default 0) skips entries
|
|
350
|
+
* below that index for incremental catch-up. An unknown thread reads as an
|
|
351
|
+
* empty array.
|
|
352
|
+
*/
|
|
353
|
+
read(threadId: string, options?: {
|
|
354
|
+
from?: number;
|
|
355
|
+
}): Promise<AgentLogEntry[]>;
|
|
356
|
+
/** The thread's current log length (0 for an unknown thread) — the next `expectedIndex`. */
|
|
357
|
+
length(threadId: string): Promise<number>;
|
|
358
|
+
/**
|
|
359
|
+
* Copy the prefix `[0, upToIndex)` onto a fresh, empty `newThreadId`.
|
|
360
|
+
* Without `upToIndex` the full source is copied. `upToIndex` is exclusive
|
|
361
|
+
* and must be an integer in `[1, length]`, so the fork keeps the reserved
|
|
362
|
+
* init entry and stays a self-contained log. The fork then appends
|
|
363
|
+
* independently. Rejects (plain `Error`) if `newThreadId` already has
|
|
364
|
+
* entries, the source is unknown, or `upToIndex` is out of range.
|
|
365
|
+
* Implementations may copy-on-write or physically copy; observable behavior
|
|
366
|
+
* must match a full copy.
|
|
367
|
+
*/
|
|
368
|
+
fork(input: {
|
|
369
|
+
threadId: string;
|
|
370
|
+
newThreadId: string; /** Exclusive index cutoff. */
|
|
371
|
+
upToIndex?: number;
|
|
372
|
+
}): Promise<void>;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Rejection from {@link AgentEventLogStore.append} when the thread's stored
|
|
376
|
+
* length is not the `expectedIndex` the writer held — a concurrent writer
|
|
377
|
+
* appended first. `actualIndex` is the next index the store would accept.
|
|
378
|
+
*/
|
|
379
|
+
declare class AgentEventLogConflictError extends AgentError {
|
|
380
|
+
readonly threadId: string;
|
|
381
|
+
readonly expectedIndex: number;
|
|
382
|
+
readonly actualIndex: number;
|
|
383
|
+
constructor(threadId: string, expectedIndex: number, actualIndex: number);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* In-memory reference store, and the baseline the conformance suite runs
|
|
387
|
+
* against. Per-thread entries are held in a contiguous, index-ordered list;
|
|
388
|
+
* append's check-and-push runs synchronously (no `await` between reading the
|
|
389
|
+
* length and writing), so two appends racing on the same `expectedIndex`
|
|
390
|
+
* resolve to exactly one winner. Every stored and returned entry is
|
|
391
|
+
* `structuredClone`d, so a caller can neither mutate stored state through a
|
|
392
|
+
* value it appended nor through a value it read.
|
|
393
|
+
*/
|
|
394
|
+
declare function createInMemoryEventLogStore(): AgentEventLogStore;
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/run-agent.d.ts
|
|
397
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
398
|
+
[key: string]: JsonValue;
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Thrown by {@link runAgent} when a resume is given BOTH an `events` log and a
|
|
402
|
+
* `snapshot` that claims a position in that log (`agentMeta.logIndex`), and the
|
|
403
|
+
* two disagree about the state at that position. The log is the source of
|
|
404
|
+
* truth, so this is a host bug (a snapshot cached from a different lineage, or
|
|
405
|
+
* a snapshot mutated out of band), not a recoverable resume: pass the log
|
|
406
|
+
* alone, or the matching snapshot.
|
|
407
|
+
*/
|
|
408
|
+
declare class AgentSnapshotDivergedError extends AgentError {
|
|
409
|
+
readonly expected: string;
|
|
410
|
+
readonly actual: string;
|
|
411
|
+
readonly logIndex: number;
|
|
412
|
+
constructor(expected: string, actual: string, logIndex: number);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* The stamp {@link RunAgentResult.persist} writes onto the persisted snapshot:
|
|
416
|
+
* the machine identity that produced it plus the position in the event log it
|
|
417
|
+
* caches. Read back by the next resume to decide whether the snapshot can be
|
|
418
|
+
* trusted without replaying the log (see {@link RunAgentOptions.events}).
|
|
419
|
+
*/
|
|
420
|
+
interface AgentRunMeta {
|
|
421
|
+
machineId: string;
|
|
422
|
+
version: string;
|
|
423
|
+
/** The log's `executionId` lineage, when the log carries one. */
|
|
424
|
+
logId?: string;
|
|
425
|
+
/** The log's length at the moment this snapshot was taken. */
|
|
426
|
+
logIndex: number;
|
|
427
|
+
}
|
|
428
|
+
/** Handler for `agent.userInput` invokes passed as {@link RunAgentOptions.userInput}. Resolves to what the human typed. */
|
|
429
|
+
interface AgentUserInputExecutor {
|
|
430
|
+
(input: AgentUserInput): PromiseLike<string>;
|
|
431
|
+
}
|
|
432
|
+
/** Typed root-machine transition observer accepted by {@link runAgent}. */
|
|
433
|
+
type AgentTransitionHandler<TMachine extends AnyStateMachine> = (snapshot: SnapshotFrom<TMachine>, event: EventFromLogic<TMachine>) => void;
|
|
434
|
+
/**
|
|
435
|
+
* The version of the {@link AgentTraceEvent} envelope every trace event carries
|
|
436
|
+
* as `schemaVersion`. Bumped only on a breaking change to the envelope or any
|
|
437
|
+
* payload shape, so a consumer can gate on it. Emitted identically by
|
|
438
|
+
* {@link runAgent}, {@link provideExecutors}' `onTrace`, and
|
|
439
|
+
* {@link traceTransitions}.
|
|
440
|
+
*/
|
|
441
|
+
declare const AGENT_TRACE_SCHEMA_VERSION = 1;
|
|
442
|
+
type AgentTraceEvent<TMachine extends AnyStateMachine = AnyStateMachine> = {
|
|
443
|
+
/** The {@link AGENT_TRACE_SCHEMA_VERSION} the event was produced with. */schemaVersion: typeof AGENT_TRACE_SCHEMA_VERSION;
|
|
444
|
+
runId: string;
|
|
445
|
+
seq: number;
|
|
446
|
+
timestamp: string;
|
|
447
|
+
machineId: string; /** The machine's own `version`, else its structural hash. */
|
|
448
|
+
machineVersion: string;
|
|
449
|
+
} & ({
|
|
450
|
+
type: "run.start";
|
|
451
|
+
input?: InputFrom<TMachine>;
|
|
452
|
+
snapshot?: Snapshot<unknown>;
|
|
453
|
+
event?: EventFromLogic<TMachine>;
|
|
454
|
+
} | {
|
|
455
|
+
type: "request.start";
|
|
456
|
+
request: AgentStepRequest;
|
|
457
|
+
} | {
|
|
458
|
+
type: "request.end";
|
|
459
|
+
request: AgentStepRequest;
|
|
460
|
+
output: unknown;
|
|
461
|
+
raw: unknown;
|
|
462
|
+
/** The model's reasoning, lifted off the raw executor result when the
|
|
463
|
+
* request opted into the structured-output envelope's `reasoning` field.
|
|
464
|
+
* Present only when the executor surfaced a string `reasoning`. */
|
|
465
|
+
reasoning?: string;
|
|
466
|
+
/** This call's token usage, lifted off the raw executor result's `usage`.
|
|
467
|
+
* Present only when the executor reported it. The run-level total is
|
|
468
|
+
* {@link RunAgentResult.usage}. */
|
|
469
|
+
usage?: AgentCallUsage;
|
|
470
|
+
/** Why the call stopped, lifted off the raw executor result's
|
|
471
|
+
* `finishReason` and normalized. Present only when the executor reported
|
|
472
|
+
* one the {@link AgentFinishReason} union names. */
|
|
473
|
+
finishReason?: AgentFinishReason;
|
|
474
|
+
} | {
|
|
475
|
+
type: "request.error";
|
|
476
|
+
request: AgentStepRequest;
|
|
477
|
+
error: unknown;
|
|
478
|
+
} | {
|
|
479
|
+
type: "stream.chunk";
|
|
480
|
+
request: AgentRequest;
|
|
481
|
+
chunk: string;
|
|
482
|
+
} | {
|
|
483
|
+
type: "machine.transition";
|
|
484
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
485
|
+
event: EventFromLogic<TMachine>;
|
|
486
|
+
} | {
|
|
487
|
+
type: "emit";
|
|
488
|
+
event: EmittedFrom<TMachine>;
|
|
489
|
+
} | {
|
|
490
|
+
/** A reserved `@agent.usage` event the run declined to deliver. The
|
|
491
|
+
* tokens still fold into {@link RunAgentResult.usage}; only the machine
|
|
492
|
+
* event is dropped. */
|
|
493
|
+
type: "usage.dropped";
|
|
494
|
+
event: AgentUsageEvent; /** `'settled'`: the call settled after the run's cycle had resolved. */
|
|
495
|
+
reason: "settled";
|
|
496
|
+
} | ({
|
|
497
|
+
type: "run.end";
|
|
498
|
+
status: "done";
|
|
499
|
+
output: OutputFrom<TMachine>;
|
|
500
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
501
|
+
} | {
|
|
502
|
+
type: "run.end";
|
|
503
|
+
status: "idle";
|
|
504
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
505
|
+
pendingUserInputs?: PendingUserInput[];
|
|
506
|
+
} | {
|
|
507
|
+
type: "run.end";
|
|
508
|
+
status: "error";
|
|
509
|
+
cause: RunAgentErrorCause;
|
|
510
|
+
error: unknown;
|
|
511
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
512
|
+
}));
|
|
513
|
+
/**
|
|
514
|
+
* Fields a JSON projection keeps VERBATIM: {@link TRACE_ENVELOPE_KEYS} (the
|
|
515
|
+
* envelope, the `type`/`status`/`cause` discriminants, and the payload fields
|
|
516
|
+
* that are already plain strings) plus `usage.dropped`'s `reason`, which is a
|
|
517
|
+
* string literal — sanitizing it is the identity, so it keeps its literal type.
|
|
518
|
+
* Every other payload field narrows to {@link JsonValue}. @internal
|
|
519
|
+
*/
|
|
520
|
+
type TraceVerbatimKey = (typeof TRACE_ENVELOPE_KEYS)[number] | "reason";
|
|
521
|
+
/** One trace variant's JSON projection. Homomorphic, so `?` modifiers survive. @internal */
|
|
522
|
+
type JsonProjectedTraceVariant<TEvent> = { [K in keyof TEvent]: K extends TraceVerbatimKey ? TEvent[K] : JsonValue };
|
|
523
|
+
/**
|
|
524
|
+
* `raw` is written only when `includeRaw` was set, so it is optional on the
|
|
525
|
+
* JSON side even though the live trace always carries it. @internal
|
|
526
|
+
*/
|
|
527
|
+
type WithOptionalRaw<T> = "raw" extends keyof T ? Omit<T, "raw"> & {
|
|
528
|
+
raw?: JsonValue;
|
|
529
|
+
} : T;
|
|
530
|
+
/**
|
|
531
|
+
* The JSON-safe projection of an {@link AgentTraceEvent} produced by
|
|
532
|
+
* {@link serializeTraceEvent}: the envelope fields are unchanged, and every
|
|
533
|
+
* payload field that can hold a live object (snapshots, machine events, request
|
|
534
|
+
* objects, raw SDK results, errors) is narrowed to a {@link JsonValue}. Safe to
|
|
535
|
+
* hand straight to `JSON.stringify` for a JSONL trace file.
|
|
536
|
+
*
|
|
537
|
+
* DERIVED from {@link AgentTraceEvent}, so a new trace variant cannot silently
|
|
538
|
+
* miss the JSON side. `src/serialize-trace-event.test.ts` pins the result to
|
|
539
|
+
* the shape this type had when it was hand-maintained.
|
|
540
|
+
*/
|
|
541
|
+
type JsonSerializableTraceEvent = AgentTraceEvent extends infer TEvent ? TEvent extends unknown ? WithOptionalRaw<JsonProjectedTraceVariant<TEvent>> : never : never;
|
|
542
|
+
declare const TRACE_ENVELOPE_KEYS: readonly ["schemaVersion", "runId", "seq", "timestamp", "machineId", "machineVersion", "type", "status", "cause", "reasoning", "finishReason", "chunk"];
|
|
543
|
+
/**
|
|
544
|
+
* Projects an {@link AgentTraceEvent} into a guaranteed JSON-safe envelope —
|
|
545
|
+
* the form the trace stream is actually sold for (one `JSON.stringify` per line
|
|
546
|
+
* in a JSONL file). Live values are sanitized rather than trusted:
|
|
547
|
+
*
|
|
548
|
+
* - Snapshots (`run.start`, `machine.transition`, `run.end`) go through the
|
|
549
|
+
* same JSON round-trip as `machine.getPersistedSnapshot(...)`, so what lands on disk is
|
|
550
|
+
* what a resume would see.
|
|
551
|
+
* - `request.end`'s `raw` (a provider SDK object, frequently cyclic) is DROPPED
|
|
552
|
+
* unless `includeRaw` is set, in which case it is sanitized like everything
|
|
553
|
+
* else.
|
|
554
|
+
* - Non-serializable values anywhere (functions, symbols, `undefined`, cyclic
|
|
555
|
+
* back-references) are dropped; `Error`s become `{ name, message, stack?,
|
|
556
|
+
* code? }` instead of `{}`. Nothing throws.
|
|
557
|
+
*
|
|
558
|
+
* @example
|
|
559
|
+
* ```ts
|
|
560
|
+
* await appendFile('trace.jsonl', JSON.stringify(serializeTraceEvent(event)) + '\n');
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
declare function serializeTraceEvent(event: AgentTraceEvent, options?: {
|
|
564
|
+
includeRaw?: boolean;
|
|
565
|
+
}): JsonSerializableTraceEvent;
|
|
566
|
+
/**
|
|
567
|
+
* Options for {@link runAgent}.
|
|
568
|
+
*
|
|
569
|
+
* Host executors are passed as a single {@link AgentRequestExecutors}-shaped
|
|
570
|
+
* set under `executors` (the same shape the step path takes). Each executor
|
|
571
|
+
* kind is required only if the machine actually reaches a request of that kind
|
|
572
|
+
* — checked at bind time, before any actor runs. The whole `executors` field is
|
|
573
|
+
* optional: a machine whose agent sources all carry their own executor
|
|
574
|
+
* (`.withExecutor(...)`) needs none.
|
|
575
|
+
*/
|
|
576
|
+
interface RunAgentOptions<TMachine extends AnyStateMachine> {
|
|
577
|
+
/**
|
|
578
|
+
* The host executor set backing the machine's agent actors — build it with
|
|
579
|
+
* `createAiSdkExecutors({ models })` from '@statelyai/agent/ai-sdk', or supply
|
|
580
|
+
* `{ generateText?, streamText?, decide? }` by hand. Every slot is optional
|
|
581
|
+
* here (unlike the step path's {@link AgentRequestExecutors}): each kind is
|
|
582
|
+
* bind-time-checked only when the machine actually reaches a request of that
|
|
583
|
+
* kind, so e.g. a stream-only machine may pass `{ streamText }` alone.
|
|
584
|
+
*/
|
|
585
|
+
executors?: Partial<AgentRequestExecutors>;
|
|
586
|
+
/**
|
|
587
|
+
* Machine input. Validated against the machine's declared input schema —
|
|
588
|
+
* defaults filled, transforms applied — before it reaches
|
|
589
|
+
* `createActor(machine, { input })`; invalid
|
|
590
|
+
* input throws an {@link AgentError} with code `invalid-machine-input`.
|
|
591
|
+
* Typed as {@link AgentInputFrom}, so fields the schema defaults are optional
|
|
592
|
+
* here. Omit when resuming via `snapshot`.
|
|
593
|
+
*/
|
|
594
|
+
input?: AgentInputFrom<TMachine>;
|
|
595
|
+
/** A previously-settled run's `result.persist()`, to resume from instead of starting fresh. Pair with `event` to deliver the event that unblocks the resumed idle state. */
|
|
596
|
+
snapshot?: Snapshot<unknown>;
|
|
597
|
+
/**
|
|
598
|
+
* An event to send immediately after starting/resuming the actor (e.g. the
|
|
599
|
+
* human's answer to an idle-state prompt), typed as the machine's event
|
|
600
|
+
* union. If the resumed state has no transition for it, the machine ignores
|
|
601
|
+
* it — the run settles normally and the result carries
|
|
602
|
+
* {@link RunAgentResult.ignored}. For a payload off the wire, parse it first
|
|
603
|
+
* with `parseAgentEvent(machine, payload)`.
|
|
604
|
+
*/
|
|
605
|
+
event?: EventFromLogic<TMachine>;
|
|
606
|
+
/**
|
|
607
|
+
* A prior run's `result.events` — the replayable log to resume from and keep
|
|
608
|
+
* appending to. THE LOG IS THE SOURCE OF TRUTH: journaled model/tool results
|
|
609
|
+
* are folded back in rather than re-executed, so a crashed run resumes from
|
|
610
|
+
* its log alone.
|
|
611
|
+
*
|
|
612
|
+
* A `snapshot` passed alongside is a CACHE of that log: it is trusted only
|
|
613
|
+
* when it is stamped (see {@link AgentRunMeta}) at the log's current tail and
|
|
614
|
+
* hashes to what the tail entry recorded; otherwise the log is replayed and
|
|
615
|
+
* the cache is verified against the position it claims (a genuine
|
|
616
|
+
* disagreement throws {@link AgentSnapshotDivergedError}).
|
|
617
|
+
*
|
|
618
|
+
* When the log was written by a DIFFERENT machine version, a `snapshot` is
|
|
619
|
+
* required (XState's own `migrate` applies on restore) and the run starts a
|
|
620
|
+
* NEW log segment whose init entry records where it bridged from; without one
|
|
621
|
+
* it throws `AgentMachineVersionMismatchError`.
|
|
622
|
+
*/
|
|
623
|
+
events?: readonly AgentLogEntry[];
|
|
624
|
+
/**
|
|
625
|
+
* Durable log storage, write-ahead. With a `store` the run reads the thread's
|
|
626
|
+
* log to resume from (unless `events` is given, which wins) and writes every
|
|
627
|
+
* appended entry back through {@link AgentEventLogStore.append}, in log
|
|
628
|
+
* order. Writes are awaited before every model call, so a paid call is never
|
|
629
|
+
* made against an unpersisted log; pure transitions never wait. A rejected
|
|
630
|
+
* write (an {@link AgentEventLogConflictError} from a concurrent writer, or
|
|
631
|
+
* any other failure) stops the run: `{ status: 'error', cause: 'journal' }`.
|
|
632
|
+
*
|
|
633
|
+
* Requires {@link RunAgentOptions.threadId}.
|
|
634
|
+
*/
|
|
635
|
+
store?: AgentEventLogStore;
|
|
636
|
+
/** The {@link RunAgentOptions.store} thread this run reads and appends to. Required whenever `store` is given. */
|
|
637
|
+
threadId?: string;
|
|
638
|
+
/**
|
|
639
|
+
* Called synchronously as each log entry is appended, init entry first. An
|
|
640
|
+
* observer, never awaited: persisting here is at-least-once and the run does
|
|
641
|
+
* not wait for it. Use {@link RunAgentOptions.store} for write-ahead
|
|
642
|
+
* durability.
|
|
643
|
+
*/
|
|
644
|
+
onEvent?: (entry: AgentLogEntry) => void;
|
|
645
|
+
/**
|
|
646
|
+
* Record a `verification.stateHash` on every appended entry (default `true`).
|
|
647
|
+
* The hash is taken O(1) from the live actor's persisted snapshot right after
|
|
648
|
+
* that entry's transition, so `replay(machine, events)` can prove it lands on
|
|
649
|
+
* the same state. Set `false` for a smaller, unverifiable log.
|
|
650
|
+
*/
|
|
651
|
+
verification?: boolean;
|
|
652
|
+
/** Actor source implementations, merged onto the machine before binding — sugar for `machine.provide({ actors })` ahead of the run. */
|
|
653
|
+
actors?: Record<string, AnyActorLogic>;
|
|
654
|
+
/**
|
|
655
|
+
* Optional human-input handler for `agent.userInput` invokes (CLI prompt,
|
|
656
|
+
* web form, Slack, …). With a handler, input is gathered inline without
|
|
657
|
+
* settling. Without one, an `agent.userInput` invoke becomes a *pending
|
|
658
|
+
* placeholder*: it waits indefinitely, does not block idle detection, and
|
|
659
|
+
* the run settles `{ status: 'idle', pendingUserInputs }` once no other work
|
|
660
|
+
* is in flight — persist with `result.persist()` and resume that snapshot
|
|
661
|
+
* with a `userInput` handler that answers it.
|
|
662
|
+
*/
|
|
663
|
+
userInput?: AgentUserInputExecutor;
|
|
664
|
+
/**
|
|
665
|
+
* Sugar over {@link onTrace}'s `stream.chunk` events: fires for each streamed
|
|
666
|
+
* chunk of a `mode: 'stream'` text request, alongside the {@link AgentRequest}
|
|
667
|
+
* that produced it (parallel states can interleave multiple streams). Purely
|
|
668
|
+
* observational.
|
|
669
|
+
*/
|
|
670
|
+
onChunk?: (chunk: string, info: {
|
|
671
|
+
request: AgentRequest;
|
|
672
|
+
}) => void;
|
|
673
|
+
/**
|
|
674
|
+
* Sugar over {@link onTrace}'s `request.end` events: fires once per resolved
|
|
675
|
+
* text/decision request with its normalized output and the raw executor
|
|
676
|
+
* result (tool calls, usage, …) — the seam for tracing/observability and
|
|
677
|
+
* event-sourced replay logging.
|
|
678
|
+
*/
|
|
679
|
+
onResult?: (request: AgentStepRequest, result: {
|
|
680
|
+
output: unknown;
|
|
681
|
+
raw: unknown;
|
|
682
|
+
}) => void;
|
|
683
|
+
/** Fires a single ordered stream of run/request/chunk/transition/emit/end events. Intended for eval traces, JSONL logs, and adapter-owned telemetry/exporters. */
|
|
684
|
+
onTrace?: (event: AgentTraceEvent<TMachine>) => void;
|
|
685
|
+
/**
|
|
686
|
+
* Sugar over {@link onTrace}'s `machine.transition` events: fires on every
|
|
687
|
+
* root-machine transition (snapshot + causing event). Pure observation —
|
|
688
|
+
* progress UIs, logging, tracing. Cannot send events.
|
|
689
|
+
*/
|
|
690
|
+
onTransition?: AgentTransitionHandler<TMachine>;
|
|
691
|
+
/**
|
|
692
|
+
* Handlers for events the machine emits (`enq.emit(...)`), keyed by emitted
|
|
693
|
+
* event type — `'*'` catches all. Typed from the machine's `emitted`
|
|
694
|
+
* schemas (`setupAgent({ emitted: { ... } })`). Purely observational, like
|
|
695
|
+
* {@link onTransition}: the machine narrates progress on its own vocabulary
|
|
696
|
+
* (not xstate internals) and the host renders it — a progress UI, an SSE
|
|
697
|
+
* stream, a log line.
|
|
698
|
+
*/
|
|
699
|
+
on?: { [TType in EmittedFrom<TMachine>["type"] | "*"]?: (emitted: EmittedFrom<TMachine> & (TType extends "*" ? unknown : {
|
|
700
|
+
type: TType;
|
|
701
|
+
})) => void };
|
|
702
|
+
/**
|
|
703
|
+
* Raw xstate inspection passthrough: fires for every inspection event in
|
|
704
|
+
* the whole actor system — root machine, invoked child machines, spawned
|
|
705
|
+
* actors — each carrying its `actorRef` (`event.actorRef.id`/`.src`). This
|
|
706
|
+
* is the system-wide seam {@link onTransition} (root transitions only)
|
|
707
|
+
* cannot give you: filter `event.type === '@xstate.transition'` and read
|
|
708
|
+
* `event.actorRef` to attribute a child machine's states to the child.
|
|
709
|
+
* Purely observational, like the other callbacks. Unlike them it also
|
|
710
|
+
* fires during the final settle (a child's last transition and stop events
|
|
711
|
+
* arrive while the run is tearing down).
|
|
712
|
+
*
|
|
713
|
+
* Accepts a function or an observer (`{ next }`), matching `createActor`'s
|
|
714
|
+
* `inspect` option, so `@statelyai/sdk`'s `inspector.inspect` plugs in
|
|
715
|
+
* directly.
|
|
716
|
+
*/
|
|
717
|
+
inspect?: ((inspectionEvent: InspectionEvent) => void) | {
|
|
718
|
+
next?: (inspectionEvent: InspectionEvent) => void;
|
|
719
|
+
};
|
|
720
|
+
/**
|
|
721
|
+
* Caps the number of model/decision calls this run may make (each retry of a
|
|
722
|
+
* decision counts separately). Default 100. The overrun is thrown into the
|
|
723
|
+
* invoke that would have made the call, as an
|
|
724
|
+
* {@link AgentMaxModelCallsExceededError} with `code: 'max-model-calls'` — so
|
|
725
|
+
* an `onError` can branch on it and route to a degraded state. Unhandled, it
|
|
726
|
+
* settles `{ status: 'error', cause: 'max-model-calls' }`.
|
|
727
|
+
*/
|
|
728
|
+
maxModelCalls?: number;
|
|
729
|
+
/** Aborts the run; settles `{ status: 'error', cause: 'aborted' }` with `signal.reason` as the error. */
|
|
730
|
+
signal?: AbortSignal;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* The outcome of a {@link runAgent} call — always exactly one of three
|
|
734
|
+
* variants, never a throw for a waiting or failed machine (programmer
|
|
735
|
+
* errors like a missing executor still throw, at bind time before any actor
|
|
736
|
+
* runs). `done`: a final state was reached (`output` is the machine's
|
|
737
|
+
* `OutputFrom`). `idle`: the run settled with no in-flight work — resume by
|
|
738
|
+
* calling `runAgent` again with `{ snapshot, event }`. `error`: a run-level
|
|
739
|
+
* failure, discriminated by `cause` (`'aborted'`, `'max-model-calls'`,
|
|
740
|
+
* `'decision-exhausted'`, `'machine'` for any other machine error state, or
|
|
741
|
+
* `'stopped'` for an external stop — see {@link RunAgentErrorCause}). Every
|
|
742
|
+
* variant carries the final `snapshot` and a native XState persistence
|
|
743
|
+
* function. The
|
|
744
|
+
* underlying actor is stopped on every settle path — there is no live actor to
|
|
745
|
+
* resume; resume is always by snapshot.
|
|
746
|
+
*/
|
|
747
|
+
/** A pending unhandled `agent.userInput` invoke surfaced on an idle settle — `id` is the invoke's id, `input` its resolved invoke input (prompt, metadata). Answer it by resuming with a `userInput` handler. */
|
|
748
|
+
interface PendingUserInput {
|
|
749
|
+
id: string;
|
|
750
|
+
input: AgentUserInput | undefined;
|
|
751
|
+
}
|
|
752
|
+
type RunAgentOutcome<TMachine extends AnyStateMachine> = {
|
|
753
|
+
status: "done";
|
|
754
|
+
output: OutputFrom<TMachine>;
|
|
755
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
756
|
+
} | {
|
|
757
|
+
status: "idle";
|
|
758
|
+
snapshot: SnapshotFrom<TMachine>; /** Present when the machine is waiting on unhandled `agent.userInput` invokes: one entry per pending invoke. */
|
|
759
|
+
pendingUserInputs?: PendingUserInput[];
|
|
760
|
+
} | {
|
|
761
|
+
status: "error";
|
|
762
|
+
cause: RunAgentErrorCause;
|
|
763
|
+
error: unknown;
|
|
764
|
+
snapshot: SnapshotFrom<TMachine>;
|
|
765
|
+
};
|
|
766
|
+
type RunAgentResult<TMachine extends AnyStateMachine> = RunAgentOutcome<TMachine> & {
|
|
767
|
+
/**
|
|
768
|
+
* The complete, self-contained replayable log for this run — the resumed
|
|
769
|
+
* prefix (if any) plus every entry this run appended, starting with the
|
|
770
|
+
* reserved `@agent.init` entry. Pass it back as
|
|
771
|
+
* {@link RunAgentOptions.events} to resume; fold it with
|
|
772
|
+
* `getUsageFromEvents` for cumulative spend; hand it to `replay` for
|
|
773
|
+
* crash recovery or time travel.
|
|
774
|
+
*/
|
|
775
|
+
events: AgentLogEntry[];
|
|
776
|
+
/**
|
|
777
|
+
* Returns XState's persisted snapshot while the run-owned actor is still
|
|
778
|
+
* available, including active child state. Store this value and pass it back
|
|
779
|
+
* as `snapshot` to resume. Persistence, migration, and retries remain XState
|
|
780
|
+
* and host responsibilities.
|
|
781
|
+
*
|
|
782
|
+
* The returned object carries an {@link AgentRunMeta} stamp under
|
|
783
|
+
* `agentMeta`, naming the log position it caches — that is what lets a resume
|
|
784
|
+
* skip replaying the log. Only the persisted object is stamped; the live
|
|
785
|
+
* `snapshot` on the result is untouched.
|
|
786
|
+
*/
|
|
787
|
+
persist(): Snapshot<unknown>;
|
|
788
|
+
/**
|
|
789
|
+
* Resolves once every {@link RunAgentOptions.store} write issued so far has
|
|
790
|
+
* landed — including a straggler `@agent.usage` entry appended by a call
|
|
791
|
+
* that settled after the run returned, which the result itself does not wait
|
|
792
|
+
* for. Await it before terminating the process if those entries matter.
|
|
793
|
+
* Resolves immediately when the run has no store, and never rejects: a
|
|
794
|
+
* failed write settles the run with `cause: 'journal'` instead.
|
|
795
|
+
*/
|
|
796
|
+
drain(): Promise<void>;
|
|
797
|
+
/**
|
|
798
|
+
* Aggregated model-call usage for THIS run — `modelCalls` plus the token
|
|
799
|
+
* fields every executor reported (see {@link AgentUsage} for the
|
|
800
|
+
* partial-sum rule). Present on all three variants: an `idle` or `error`
|
|
801
|
+
* result accounts for the calls made before the run settled.
|
|
802
|
+
*
|
|
803
|
+
* A resumed run counts only its own calls, not the history behind
|
|
804
|
+
* `snapshot`.
|
|
805
|
+
*/
|
|
806
|
+
usage: AgentUsage;
|
|
807
|
+
/**
|
|
808
|
+
* The {@link RunAgentOptions.event} the machine did not handle: present only
|
|
809
|
+
* when the resumed state had no transition for it, so sending it was a
|
|
810
|
+
* no-op (no state change, no actions). The run settles normally — usually
|
|
811
|
+
* back to `idle` at the same state — and the event is still journaled, so a
|
|
812
|
+
* replay ignores it again.
|
|
813
|
+
*
|
|
814
|
+
* A host that wants to tell the client nothing happened checks this instead
|
|
815
|
+
* of an error:
|
|
816
|
+
*
|
|
817
|
+
* ```ts
|
|
818
|
+
* if (result.ignored) {
|
|
819
|
+
* return Response.json({ error: `'${result.ignored.type}' does not apply here` }, { status: 409 });
|
|
820
|
+
* }
|
|
821
|
+
* ```
|
|
822
|
+
*/
|
|
823
|
+
ignored?: EventObject;
|
|
824
|
+
};
|
|
825
|
+
/**
|
|
826
|
+
* Discriminates a {@link RunAgentResult} `error`:
|
|
827
|
+
* - `'aborted'` — the run's `signal` fired.
|
|
828
|
+
* - `'max-model-calls'` — the `maxModelCalls` budget was exceeded.
|
|
829
|
+
* - `'decision-exhausted'` — the machine reached an error state whose error is
|
|
830
|
+
* (or wraps) a {@link AgentDecisionExhaustedError} that no `onError` handled.
|
|
831
|
+
* - `'machine'` — any other machine error state.
|
|
832
|
+
* - `'stopped'` — the actor was stopped externally (`status === 'stopped'`).
|
|
833
|
+
* - `'journal'` — a {@link RunAgentOptions.store} write rejected (a concurrent
|
|
834
|
+
* writer's {@link AgentEventLogConflictError}, or any other storage failure).
|
|
835
|
+
*/
|
|
836
|
+
type RunAgentErrorCause = "aborted" | "max-model-calls" | "decision-exhausted" | "machine" | "stopped" | "journal";
|
|
837
|
+
/**
|
|
838
|
+
* Thrown into the invoke that would have made the call once
|
|
839
|
+
* {@link RunAgentOptions.maxModelCalls} is spent. It reaches the machine
|
|
840
|
+
* through the normal error channel, so an invoke's `onError` can branch on it
|
|
841
|
+
* (`error.code === 'max-model-calls'`, the same string the settled result's
|
|
842
|
+
* `cause` uses) and route to a degraded/finish state instead of failing the
|
|
843
|
+
* run. Unhandled, it settles `{ status: 'error', cause: 'max-model-calls' }`.
|
|
844
|
+
*
|
|
845
|
+
* ```ts
|
|
846
|
+
* onError: [
|
|
847
|
+
* { guard: ({ event }) => event.error?.code === 'max-model-calls', target: 'budgetSpent' },
|
|
848
|
+
* { target: 'failed' },
|
|
849
|
+
* ]
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
declare class AgentMaxModelCallsExceededError extends AgentError {
|
|
853
|
+
/** The budget that was exceeded (`options.maxModelCalls`). */
|
|
854
|
+
readonly maxModelCalls: number;
|
|
855
|
+
constructor(maxModelCalls: number);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* The machine input a run accepts, which is the schema's *pre*-validation side.
|
|
859
|
+
*
|
|
860
|
+
* XState's `schemas` are types only — it never validates, and it resolves
|
|
861
|
+
* `schemas.input` to one type shared by `createActor`'s `input` option and the
|
|
862
|
+
* `context: ({ input })` factory. A schema field declared with a default
|
|
863
|
+
* therefore reads as required at the call site even though the caller is meant
|
|
864
|
+
* to omit it. `setupAgent` brands the machine's input type with its own schema
|
|
865
|
+
* ({@link WithAgentInputSchema}), so this recovers the looser caller-facing
|
|
866
|
+
* side while the factory keeps seeing the validated one. Machines with no
|
|
867
|
+
* declared input schema — and machines reached through `.provide(...)`, which
|
|
868
|
+
* drops the brand — fall back to xstate's `InputFrom`.
|
|
869
|
+
*/
|
|
870
|
+
type AgentInputFrom<TMachine extends AnyStateMachine> = [NonNullable<InputFrom<TMachine>>] extends [WithAgentInputSchema<infer TInputSchema>] ? [TInputSchema] extends [StandardSchemaV1] ? InferInput<TInputSchema> : InputFrom<TMachine> : InputFrom<TMachine>;
|
|
871
|
+
/**
|
|
872
|
+
* Runs an agent machine to completion or idle: a `createActor` host that
|
|
873
|
+
* binds `options`' host executors onto the machine's `agent.*`/`TextLogic`/
|
|
874
|
+
* `DecisionLogic` actor sources, starts (or resumes) the actor, and drives
|
|
875
|
+
* it until it settles — {@link RunAgentResult} `done | idle | error`. Unlike
|
|
876
|
+
* the step helpers ({@link initialAgentStep} etc — a pure
|
|
877
|
+
* transition-at-a-time path for durable hosts), `runAgent` owns a live actor
|
|
878
|
+
* internally; there is no continuation callback, so **idle always settles**
|
|
879
|
+
* and the caller resumes explicitly by passing the settled `{ snapshot,
|
|
880
|
+
* event }` back in. The actor is stopped on every settle path (`done`,
|
|
881
|
+
* `idle`, and `error` alike) — resume is always by snapshot, never by
|
|
882
|
+
* holding a reference to a live actor.
|
|
883
|
+
*
|
|
884
|
+
* Binding happens **before** the actor starts: every invoke the machine
|
|
885
|
+
* could reach is walked and checked against the effective actor sources
|
|
886
|
+
* (`options.actors` merged onto the machine), so a missing
|
|
887
|
+
* `streamText`/`decide` executor or any other unbound actor source throws
|
|
888
|
+
* immediately — a bind-time error, not a mid-run failure. The one exception
|
|
889
|
+
* is `agent.userInput`: unhandled, it binds as a pending placeholder that
|
|
890
|
+
* settles the run idle (with `pendingUserInputs`) instead of erroring.
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```ts
|
|
894
|
+
* const executors = createAiSdkExecutors({ models });
|
|
895
|
+
* let r = await runAgent(machine, { input, executors });
|
|
896
|
+
* while (r.status === 'idle') {
|
|
897
|
+
* const event = await promptUser(getAcceptedEvents(r.snapshot));
|
|
898
|
+
* r = await runAgent(machine, { snapshot: r.snapshot, event, executors });
|
|
899
|
+
* }
|
|
900
|
+
* if (r.status !== 'done') throw new Error(`Run did not complete: ${r.status}`);
|
|
901
|
+
* console.log(r.output);
|
|
902
|
+
* ```
|
|
903
|
+
*
|
|
904
|
+
* The `executors`' `generateText`/`streamText` accept the raw Vercel AI SDK
|
|
905
|
+
* functions directly (`executors: { generateText, streamText }` with them
|
|
906
|
+
* imported from `ai`) — their `{ text }`/`{ textStream }` results are unwrapped
|
|
907
|
+
* natively. `decide` cannot be a raw AI SDK function: the tool-per-event mapping
|
|
908
|
+
* lives in an adapter — use `createAiSdkExecutors` from '@statelyai/agent/ai-sdk'.
|
|
909
|
+
*/
|
|
910
|
+
declare function runAgent<TMachine extends AnyStateMachine>(machine: TMachine, options: RunAgentOptions<TMachine>): Promise<RunAgentResult<TMachine>>;
|
|
911
|
+
/**
|
|
912
|
+
* The actor handed to an {@link inspectTransitions} handler: an
|
|
913
|
+
* {@link AnyActorRef} widened with the runtime `id`/`src` used to attribute a
|
|
914
|
+
* transition to the root machine or a specific invoked child (xstate's static
|
|
915
|
+
* `ActorRef` type omits them, but they are always present at runtime).
|
|
916
|
+
*/
|
|
917
|
+
type InspectedActorRef = AnyActorRef & {
|
|
918
|
+
id: string;
|
|
919
|
+
src?: string | AnyActorLogic;
|
|
920
|
+
};
|
|
921
|
+
/**
|
|
922
|
+
* Wraps a `(snapshot, actorRef) => void` handler into a function usable as
|
|
923
|
+
* {@link RunAgentOptions.inspect}: it filters the raw inspection stream to
|
|
924
|
+
* `@xstate.transition` events and hands the handler the typed
|
|
925
|
+
* {@link AnyMachineSnapshot} and the {@link InspectedActorRef} that
|
|
926
|
+
* transitioned. Attribute a child actor via `actorRef.id`/`actorRef.src`. Saves
|
|
927
|
+
* the manual `event.type === '@xstate.transition'` filtering and the snapshot/
|
|
928
|
+
* actorRef casts.
|
|
929
|
+
*/
|
|
930
|
+
declare function inspectTransitions(handler: (snapshot: AnyMachineSnapshot, actorRef: InspectedActorRef) => void): (inspectionEvent: InspectionEvent) => void;
|
|
931
|
+
/**
|
|
932
|
+
* An xstate `inspect` handler that emits `machine.transition` trace events onto
|
|
933
|
+
* `onTrace`, sharing the SAME versioned envelope and per-root-actor `seq`
|
|
934
|
+
* registry as {@link provideExecutors}' `onTrace`. Pair the two on one actor to
|
|
935
|
+
* get a single ordered trace stream (request + transition events) for the
|
|
936
|
+
* uncontrolled path:
|
|
937
|
+
*
|
|
938
|
+
* ```ts
|
|
939
|
+
* const bound = provideExecutors(machine, executors, { onTrace });
|
|
940
|
+
* const actor = createActor(bound, { inspect: traceTransitions(onTrace) });
|
|
941
|
+
* ```
|
|
942
|
+
*
|
|
943
|
+
* Only ROOT-actor transitions are traced (matching `runAgent`'s
|
|
944
|
+
* `machine.transition`); child-actor transitions are ignored. Attribute the
|
|
945
|
+
* event via its envelope `runId`.
|
|
946
|
+
*
|
|
947
|
+
* By design this path has NO `run.start`/`run.end` events: `createActor` has no
|
|
948
|
+
* run boundary the way `runAgent` does, so the stream starts at the actor's
|
|
949
|
+
* first transition. It also does NOT emit `emit` trace events: in this xstate
|
|
950
|
+
* build emitted events are delivered through `actor.on(...)`, not the inspection
|
|
951
|
+
* protocol, so they are not observable from an `inspect` handler — subscribe
|
|
952
|
+
* with `actor.on('*', ...)` if you need them.
|
|
953
|
+
*/
|
|
954
|
+
declare function traceTransitions<TMachine extends AnyStateMachine = AnyStateMachine>(onTrace: (event: AgentTraceEvent<TMachine>) => void): (inspectionEvent: InspectionEvent) => void;
|
|
955
|
+
/**
|
|
956
|
+
* Default machine-owned idle signal used by {@link runAgent}: an active
|
|
957
|
+
* snapshot that accepts an external event anywhere in its active hierarchy,
|
|
958
|
+
* or declares interaction metadata on an active state.
|
|
959
|
+
*
|
|
960
|
+
* Compose this in `setupAgent({ isIdle })` when the application has additional
|
|
961
|
+
* wait states: `isIdle: (snapshot) => isAgentIdle(snapshot) || snapshot.hasTag('waiting')`.
|
|
962
|
+
* Pending work and active invoked children are checked separately by the
|
|
963
|
+
* runner, so this function only answers whether the state is an intentional
|
|
964
|
+
* external wait.
|
|
965
|
+
*/
|
|
966
|
+
declare function isAgentIdle(snapshot: AnyMachineSnapshot): boolean;
|
|
967
|
+
//#endregion
|
|
968
|
+
export { AGENT_USAGE_EVENT_TYPE as $, AgentMachineVersionMismatchError as A, assertJsonSerializable as B, AGENT_EVENT_SCHEMA_VERSION as C, AgentLogEntry as D, AgentInitEvent as E, NonSerializableAgentEventError as F, getUsageFromEvents as G, forkEventLog as H, ReplayOptions as I, replay as J, initEntry as K, ReplayResult as L, AgentReplayDivergenceError as M, CreateReplayEntryOptions as N, AgentLogInit as O, JsonValue$1 as P, executeAgentRequest as Q, agentCallOccurrence as R, createInMemoryEventLogStore as S, AgentEventLogError as T, getLogExecutionId as U, createReplayEntry as V, getSnapshotStateHash as W, AgentRequest as X, validateReplayEntries as Y, AgentStepRequest as Z, runAgent as _, AgentSnapshotDivergedError as a, AgentEventLogConflictError as b, AgentUserInputExecutor as c, PendingUserInput as d, AgentUsageEvent as et, RunAgentErrorCause as f, isAgentIdle as g, inspectTransitions as h, AgentRunMeta as i, AgentPersistedSnapshot as j, AgentLogVerification as k, InspectedActorRef as l, RunAgentResult as m, AgentInputFrom as n, AgentTraceEvent as o, RunAgentOptions as p, rebindActorSession as q, AgentMaxModelCallsExceededError as r, AgentTransitionHandler as s, AGENT_TRACE_SCHEMA_VERSION as t, JsonSerializableTraceEvent as u, serializeTraceEvent as v, AGENT_INIT_EVENT_TYPE as w, AgentEventLogStore as x, traceTransitions as y, assertAgentLogEntry as z };
|