@statelyai/agent 2.0.0-alpha.10 → 2.0.0-alpha.12
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 +62 -99
- package/dist/ai-sdk.d.cts +10 -117
- package/dist/ai-sdk.d.mts +10 -117
- package/dist/ai-sdk.mjs +63 -91
- package/dist/{decision-CQdrKc8k.mjs → decision-BezSD_YC.mjs} +120 -32
- package/dist/{decision-b-lkcs4L.cjs → decision-dWGhBh0P.cjs} +141 -53
- package/dist/errors-BQRk9eiZ.d.cts +19 -0
- package/dist/errors-C9rxnWbX.d.mts +19 -0
- package/dist/errors-CeSXQx0v.mjs +23 -0
- package/dist/errors-DUBBzRLP.cjs +28 -0
- package/dist/event-log-store-CNT_7F0V.cjs +452 -0
- package/dist/event-log-store-CriMgX1D.d.mts +144 -0
- package/dist/event-log-store-D7pWtIhb.mjs +411 -0
- package/dist/event-log-store-Ruq18mGp.d.cts +144 -0
- package/dist/index.cjs +2844 -30
- package/dist/index.d.cts +1005 -12
- package/dist/index.d.mts +1005 -12
- package/dist/index.mjs +2799 -4
- package/dist/machines.cjs +752 -0
- package/dist/machines.d.cts +372 -0
- package/dist/machines.d.mts +372 -0
- package/dist/machines.mjs +741 -0
- package/dist/otel.cjs +268 -0
- package/dist/otel.d.cts +67 -0
- package/dist/otel.d.mts +67 -0
- package/dist/otel.mjs +267 -0
- package/dist/run-agent-B1nBa7aV.d.mts +1111 -0
- package/dist/run-agent-qkg0evvW.d.cts +1111 -0
- package/dist/setup-agent-DAZZSjDS.mjs +1711 -0
- package/dist/setup-agent-DP95MFrI.cjs +1836 -0
- package/dist/sqlite.cjs +135 -0
- package/dist/sqlite.d.cts +57 -0
- package/dist/sqlite.d.mts +57 -0
- package/dist/sqlite.mjs +133 -0
- package/dist/{text-logic-C7WJpCIc.d.mts → text-logic-CorGzucG.d.cts} +110 -66
- package/dist/{text-logic-CZjyACzQ.d.cts → text-logic-DjR5PUVz.d.mts} +110 -66
- package/dist/{types-C9QiMjre.d.cts → types-QbEfCVny.d.cts} +1 -1
- package/dist/{types-qm00QF91.d.mts → types-_FXoFBGO.d.mts} +1 -1
- package/package.json +55 -27
- package/readme.md +40 -9
- package/schemas/agent-workflow.json +44 -26
- package/skills/generate-machine/SKILL.md +267 -0
- package/dist/cli.cjs +0 -64
- package/dist/cli.d.cts +0 -1
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs +0 -65
- package/dist/openai-compat.cjs +0 -319
- package/dist/openai-compat.d.cts +0 -98
- package/dist/openai-compat.d.mts +0 -98
- package/dist/openai-compat.mjs +0 -312
- package/dist/run-agent-BFMkuI1F.cjs +0 -1599
- package/dist/run-agent-BVMd--1l.d.cts +0 -1103
- package/dist/run-agent-BoAOq_0Z.mjs +0 -1540
- package/dist/run-agent-DzYJb3CK.d.mts +0 -1103
- package/dist/src-D-77Ha5p.cjs +0 -1087
- package/dist/src-DUeIFjv-.mjs +0 -1016
- package/dist/utils-Dri7aeEG.d.cts +0 -108
- package/dist/utils-Y6GDRGGE.d.mts +0 -108
- package/dist/zod.cjs +0 -31
- package/dist/zod.d.cts +0 -30
- package/dist/zod.d.mts +0 -30
- package/dist/zod.mjs +0 -30
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as StandardSchemaV1, a as AgentToolChoice, c as AgentTools, d as ChosenEvent, h as InferOutput, l as AllowedEvents, n as AgentMessage } from "./types-_FXoFBGO.mjs";
|
|
2
|
+
import { t as AgentError } from "./errors-C9rxnWbX.mjs";
|
|
2
3
|
import { AnyMachineSnapshot, AsyncActorLogic, EventObject, LogicActorLogic, MachineSnapshot } from "xstate";
|
|
3
4
|
|
|
4
5
|
//#region src/events.d.ts
|
|
5
6
|
/** The invoke `src` of an {@link AgentRequest}/{@link AgentDecisionRequest} — a plain string, widened so literal `src` values still narrow in editor hints. */
|
|
6
7
|
type AgentRequestSource = string & {};
|
|
7
|
-
/** Default prefix for the synthetic tool name generated per candidate event (e.g. `send_event_ASK`). Override per-request with {@link AgentEventToolNameResolver}. */
|
|
8
|
-
declare const EVENT_TOOL_PREFIX: "send_event_";
|
|
9
8
|
/** Customizes the tool name generated for a candidate event; see {@link AgentRequestOptions.eventToolName}. */
|
|
10
9
|
type AgentEventToolNameResolver = (args: {
|
|
11
10
|
eventType: string;
|
|
12
11
|
defaultToolName: string;
|
|
13
12
|
}) => string;
|
|
14
|
-
/**
|
|
15
|
-
* True when an event type matches an `allowedEvents` entry: an exact type,
|
|
16
|
-
* `'*'` (every event), or a `'prefix.*'` wildcard matching any deeper
|
|
17
|
-
* segment (`'todo.*'` matches `'todo.add'` and `'todo.list.clear'`, not
|
|
18
|
-
* `'todo'` itself — mirroring xstate's partial wildcard events).
|
|
19
|
-
*/
|
|
20
|
-
declare function matchesEventPattern(eventType: string, pattern: string): boolean;
|
|
21
13
|
/** One candidate event a decision (or {@link getAcceptedEvents} caller) may choose: its type, the synthetic tool name a model can call to pick it, and its payload schema if one is registered. */
|
|
22
14
|
interface AgentEventDescriptor {
|
|
23
15
|
type: string;
|
|
@@ -33,21 +25,10 @@ interface AgentRequestOptions {
|
|
|
33
25
|
snapshot?: AnyMachineSnapshot;
|
|
34
26
|
events?: Record<string, StandardSchemaV1>;
|
|
35
27
|
schemas?: AgentSchemas;
|
|
36
|
-
|
|
28
|
+
actors?: Record<string, unknown>;
|
|
37
29
|
/** Customize machine-event tool names. Defaults to send_event_<TYPE>. */
|
|
38
30
|
eventToolName?: AgentEventToolNameResolver;
|
|
39
31
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Lists the events a snapshot can currently accept, as {@link AgentEventDescriptor}s
|
|
42
|
-
* a model can be offered (via `resolveDecision`/an adapter's tool-per-event
|
|
43
|
-
* mapping). **Filters by event TYPE only** — it does not evaluate guards, so
|
|
44
|
-
* a type-legal-but-guard-rejected event can still appear here. Guard
|
|
45
|
-
* legality is checked separately, at decision-resolution time, via
|
|
46
|
-
* `snapshot.can(event)` (the `canTake` option of {@link resolveDecision} /
|
|
47
|
-
* {@link ResolveDecisionOptions}). Pass `eventTypes` to further narrow to a
|
|
48
|
-
* declared `allowedEvents` set — entries may be exact types or wildcard
|
|
49
|
-
* patterns (`'*'`, `'todo.*'`; see {@link matchesEventPattern}).
|
|
50
|
-
*/
|
|
51
32
|
/** Recovers a machine's event union from its snapshot type, so {@link parseAgentEvent} returns the machine-typed event without a downstream cast. @internal */
|
|
52
33
|
type EventFromSnapshot<TSnapshot> = TSnapshot extends MachineSnapshot<any, infer TEvent, any, any, any, any, any, any> ? TEvent : EventObject;
|
|
53
34
|
/**
|
|
@@ -74,6 +55,22 @@ type EventFromSnapshot<TSnapshot> = TSnapshot extends MachineSnapshot<any, infer
|
|
|
74
55
|
declare function parseAgentEvent<TSnapshot extends AnyMachineSnapshot>(snapshot: TSnapshot, event: {
|
|
75
56
|
type: string;
|
|
76
57
|
} & Record<string, unknown>, options?: Pick<AgentRequestOptions, "events" | "schemas" | "eventToolName">): EventFromSnapshot<TSnapshot>;
|
|
58
|
+
/**
|
|
59
|
+
* Lists the events a snapshot can currently accept, as {@link AgentEventDescriptor}s
|
|
60
|
+
* a model can be offered (via `resolveDecision`/an adapter's tool-per-event
|
|
61
|
+
* mapping). **Filters by event TYPE only** — it does not evaluate guards, so
|
|
62
|
+
* a type-legal-but-guard-rejected event can still appear here. Guard
|
|
63
|
+
* legality is checked separately, at decision-resolution time, via
|
|
64
|
+
* `snapshot.can(event)` (the `canTake` option of {@link resolveDecision} /
|
|
65
|
+
* {@link ResolveDecisionOptions}). Pass `eventTypes` to further narrow to a
|
|
66
|
+
* declared `allowedEvents` set — entries may be exact types or wildcard
|
|
67
|
+
* patterns (`'*'`, `'todo.*'`; see {@link matchesEventPattern}).
|
|
68
|
+
*
|
|
69
|
+
* XState-internal (`xstate.*`) and library-reserved
|
|
70
|
+
* ({@link RESERVED_AGENT_EVENT_PREFIX}) event types are always excluded, before
|
|
71
|
+
* any `allowedEvents` matching — a machine that handles `'@agent.usage'` still
|
|
72
|
+
* never offers it to a model.
|
|
73
|
+
*/
|
|
77
74
|
declare function getAcceptedEvents(snapshot: AnyMachineSnapshot, options?: Pick<AgentRequestOptions, "events" | "schemas" | "eventToolName"> & {
|
|
78
75
|
eventTypes?: readonly string[];
|
|
79
76
|
}): AgentEventDescriptor[];
|
|
@@ -211,21 +208,6 @@ interface DecisionLogicConfig<TInputSchema extends StandardSchemaV1 = StandardSc
|
|
|
211
208
|
stopSequences?: ResolveTextLogicValue<string[] | undefined, InferOutput<TInputSchema>>;
|
|
212
209
|
metadata?: ResolveTextLogicValue<TMetadata | undefined, InferOutput<TInputSchema>>;
|
|
213
210
|
}
|
|
214
|
-
/**
|
|
215
|
-
* Actor logic for a decision: an async effect that resolves to exactly one
|
|
216
|
-
* currently-legal {@link ChosenEvent} (never a plain value). Under `runAgent`
|
|
217
|
-
* the chosen event is delivered to the invoking actor automatically — the
|
|
218
|
-
* transition it triggers usually exits the invoking state and ends the invoke.
|
|
219
|
-
* Built by {@link createDecisionLogic}. Register it under `actorSources:` to reuse/export/
|
|
220
|
-
* test it standalone; for a state-local, zero-config decision, use the
|
|
221
|
-
* `agent.decide` builtin invoke instead.
|
|
222
|
-
*/
|
|
223
|
-
interface DecisionLogic<TInputSchema extends StandardSchemaV1 = StandardSchemaV1, TMetadata extends Record<string, unknown> = Record<string, unknown>> extends AsyncActorLogic<ChosenEvent, InferOutput<TInputSchema>> {
|
|
224
|
-
readonly kind: "statelyai.decisionLogic";
|
|
225
|
-
readonly maxRetries: number;
|
|
226
|
-
request(input: InferOutput<TInputSchema>): AgentDecisionRequest;
|
|
227
|
-
withExecutor(execute: AgentDecisionExecutor): DecisionLogic<TInputSchema, TMetadata>;
|
|
228
|
-
}
|
|
229
211
|
/**
|
|
230
212
|
* A decision request: resolves to exactly one currently-legal event. See
|
|
231
213
|
* `resolveDecision`.
|
|
@@ -260,6 +242,15 @@ interface AgentDecisionRequest {
|
|
|
260
242
|
* `info.signal`). Runtime-only — never serialized into a provider request.
|
|
261
243
|
*/
|
|
262
244
|
signal?: AbortSignal;
|
|
245
|
+
/**
|
|
246
|
+
* The `runAgent` run this decision belongs to (`run_<n>`, matching trace
|
|
247
|
+
* events), injected by runAgent like `signal` (symmetric with the text
|
|
248
|
+
* executors' `info.runId`). Runtime-only correlation for executor
|
|
249
|
+
* middleware; unset off the runAgent path. Per-attempt context is already
|
|
250
|
+
* on the request: `id` is the durable invoke id and `attempts.length` is
|
|
251
|
+
* the current attempt index.
|
|
252
|
+
*/
|
|
253
|
+
runId?: string;
|
|
263
254
|
}
|
|
264
255
|
/**
|
|
265
256
|
* A single failed decision attempt, recorded by {@link resolveDecision} and
|
|
@@ -282,8 +273,8 @@ interface DecisionAttempt {
|
|
|
282
273
|
* diagnostics; a machine typically routes this via the decision invoke's
|
|
283
274
|
* `onError`.
|
|
284
275
|
*/
|
|
285
|
-
declare class
|
|
286
|
-
attempts: DecisionAttempt[];
|
|
276
|
+
declare class AgentDecisionExhaustedError extends AgentError {
|
|
277
|
+
readonly attempts: DecisionAttempt[];
|
|
287
278
|
constructor(attempts: DecisionAttempt[]);
|
|
288
279
|
}
|
|
289
280
|
/**
|
|
@@ -309,12 +300,15 @@ declare function renderDecisionAttempts(request: Pick<AgentDecisionRequest, "eve
|
|
|
309
300
|
* adapter business; core only validates and retries the returned choice (see
|
|
310
301
|
* {@link resolveDecision}). The optional `reason` is carried through to
|
|
311
302
|
* `onResult`/event-sourcing but never affects validation. Like text
|
|
312
|
-
* executors' `{ output, ...extras }` envelope, any extra keys (
|
|
313
|
-
*
|
|
303
|
+
* executors' `{ output, ...extras }` envelope, any extra keys (finish reason,
|
|
304
|
+
* …) flow untouched to `onResult`'s `raw`; `usage` is the one core reads —
|
|
305
|
+
* report this attempt's tokens there and `runAgent` folds them into the run's
|
|
306
|
+
* aggregated {@link AgentUsage}.
|
|
314
307
|
*/
|
|
315
308
|
type AgentDecisionExecutor = (request: AgentDecisionRequest) => PromiseLike<{
|
|
316
309
|
event: ChosenEvent;
|
|
317
|
-
reason?: string;
|
|
310
|
+
reason?: string; /** This attempt's token usage, aggregated into the run result's {@link AgentUsage}. */
|
|
311
|
+
usage?: AgentCallUsage;
|
|
318
312
|
[key: string]: unknown;
|
|
319
313
|
}>;
|
|
320
314
|
/**
|
|
@@ -356,7 +350,7 @@ interface ResolveDecisionOptions<TEvent extends ChosenEvent = ChosenEvent> {
|
|
|
356
350
|
* the next attempt via `request.attempts`, so an adapter can render "your
|
|
357
351
|
* last choice failed because X — try again" into the next model call; core
|
|
358
352
|
* never rewrites the request itself. Exhausting all attempts throws
|
|
359
|
-
* {@link
|
|
353
|
+
* {@link AgentDecisionExhaustedError} with the full attempts list.
|
|
360
354
|
*
|
|
361
355
|
* @example
|
|
362
356
|
* ```ts
|
|
@@ -452,6 +446,34 @@ interface AgentTextRequest<TMetadata = Record<string, unknown>> {
|
|
|
452
446
|
*/
|
|
453
447
|
metadata?: TMetadata;
|
|
454
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Aggregated model-call usage for ONE `runAgent` call — the run-level total
|
|
451
|
+
* attached to every settled {@link RunAgentResult} (and therefore to
|
|
452
|
+
* `generateResult`'s `{ output, snapshot, events, usage }`).
|
|
453
|
+
*
|
|
454
|
+
* - `modelCalls` counts every model/decision call this run made (each decision
|
|
455
|
+
* retry counts separately) — the same seam `maxModelCalls` budgets. Always a
|
|
456
|
+
* number, even when no executor reported tokens.
|
|
457
|
+
* - Token fields are OPTIONAL and are PARTIAL SUMS: each one sums only the
|
|
458
|
+
* calls that reported it, and stays `undefined` when NO call reported it.
|
|
459
|
+
* Executors that report nothing (custom hosts, test mocks) simply do not
|
|
460
|
+
* contribute — a run mixing reporting and non-reporting calls yields a sum
|
|
461
|
+
* over the reporting subset, not `undefined`.
|
|
462
|
+
* - Aggregation is per-run: a resumed run counts only ITS OWN calls, never the
|
|
463
|
+
* history behind `snapshot`/`events`. Add prior runs' totals yourself if you
|
|
464
|
+
* want a conversation-wide figure.
|
|
465
|
+
*/
|
|
466
|
+
interface AgentUsage {
|
|
467
|
+
inputTokens?: number;
|
|
468
|
+
outputTokens?: number;
|
|
469
|
+
totalTokens?: number;
|
|
470
|
+
reasoningTokens?: number;
|
|
471
|
+
cachedInputTokens?: number;
|
|
472
|
+
/** Model/decision calls made by this run (decision retries count separately). */
|
|
473
|
+
modelCalls: number;
|
|
474
|
+
}
|
|
475
|
+
/** One model call's reported usage — {@link AgentUsage} without the run-level `modelCalls` count. What an executor puts on its result's `usage` field. */
|
|
476
|
+
type AgentCallUsage = Omit<AgentUsage, "modelCalls">;
|
|
455
477
|
/**
|
|
456
478
|
* Inline input for the `agent.userInput` builtin actor — a human-input request
|
|
457
479
|
* (CLI prompt, chat reply, …) that resolves to the `string` the human typed.
|
|
@@ -488,13 +510,19 @@ type ResolveTextLogicValue<TValue, TInput> = TValue | ((args: {
|
|
|
488
510
|
* that validate it. Each request-shaping field (`model`, `system`, `prompt`,
|
|
489
511
|
* …) is either a static value or a `({ input }) => value` resolver.
|
|
490
512
|
*/
|
|
491
|
-
interface TextLogicConfig<TInputSchema extends StandardSchemaV1
|
|
513
|
+
interface TextLogicConfig<TInputSchema extends StandardSchemaV1 = StandardSchemaV1<undefined>, TOutputSchema extends StandardSchemaV1 = StandardSchemaV1<string>, TMetadata = Record<string, unknown>, TModel extends string = string> {
|
|
492
514
|
mode?: AgentRequestMode;
|
|
493
515
|
/** Stamped onto every lowered request as {@link AgentTextRequest.name}. `setupAgent({ requests })` sets this to the request's key. */
|
|
494
516
|
name?: ResolveTextLogicValue<string | undefined, InferOutput<TInputSchema>>;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
517
|
+
/**
|
|
518
|
+
* The request's input/output schemas. Both are optional:
|
|
519
|
+
* - `output` defaults to a string schema (a plain text request).
|
|
520
|
+
* - `input` defaults to a schema that accepts (and types) `undefined`, so
|
|
521
|
+
* the request takes no `input` at the invoke site.
|
|
522
|
+
*/
|
|
523
|
+
schemas?: {
|
|
524
|
+
input?: TInputSchema;
|
|
525
|
+
output?: TOutputSchema;
|
|
498
526
|
};
|
|
499
527
|
model: ResolveTextLogicValue<TModel, InferOutput<TInputSchema>>;
|
|
500
528
|
system?: ResolveTextLogicValue<string | undefined, InferOutput<TInputSchema>>;
|
|
@@ -526,7 +554,7 @@ type TextLogicExecutor<TInputSchema extends StandardSchemaV1, TOutputSchema exte
|
|
|
526
554
|
/**
|
|
527
555
|
* Actor logic for a text request: an async effect that resolves typed input
|
|
528
556
|
* to typed, schema-validated output via a model call. Built by
|
|
529
|
-
* {@link createTextLogic}; register under `
|
|
557
|
+
* {@link createTextLogic}; register under `actors:` and invoke by name, or
|
|
530
558
|
* bind an executor later with `withExecutor`. The `agent.generateText`/
|
|
531
559
|
* `agent.streamText` builtins and `setupAgent({ requests })` entries are
|
|
532
560
|
* both `TextLogic` under the hood.
|
|
@@ -542,14 +570,10 @@ interface TextLogic<TInputSchema extends StandardSchemaV1 = StandardSchemaV1, TO
|
|
|
542
570
|
execute(input: InferOutput<TInputSchema>, executors: AgentRequestExecutors): Promise<InferOutput<TOutputSchema>>;
|
|
543
571
|
withExecutor(execute: TextLogicExecutor<TInputSchema, TOutputSchema, TMetadata>): TextLogic<TInputSchema, TOutputSchema, TMetadata>;
|
|
544
572
|
}
|
|
545
|
-
/** Extracts a {@link TextLogic}'s validated input type. */
|
|
546
|
-
type TextLogicInput<TLogic extends TextLogic> = TLogic extends TextLogic<infer TInputSchema, StandardSchemaV1, infer _TMetadata> ? InferOutput<TInputSchema> : never;
|
|
547
|
-
/** Extracts a {@link TextLogic}'s validated output type. */
|
|
548
|
-
type TextLogicOutput<TLogic extends TextLogic> = TLogic extends TextLogic<StandardSchemaV1, infer TOutputSchema, infer _TMetadata> ? InferOutput<TOutputSchema> : never;
|
|
549
573
|
/**
|
|
550
574
|
* Creates reusable, standalone {@link TextLogic}: an actor that, when run,
|
|
551
575
|
* resolves typed input to typed output via a model call. Register the
|
|
552
|
-
* result under `
|
|
576
|
+
* result under `actors:` and invoke it by name (equivalent to what
|
|
553
577
|
* `setupAgent({ requests })` builds internally for each request entry). Pass
|
|
554
578
|
* `execute` here, or bind it later with `.withExecutor(...)`, a runtime
|
|
555
579
|
* adapter's `machine.provide(...)`, or `runAgent`'s `generateText`/
|
|
@@ -566,7 +590,7 @@ type TextLogicOutput<TLogic extends TextLogic> = TLogic extends TextLogic<Standa
|
|
|
566
590
|
* });
|
|
567
591
|
* ```
|
|
568
592
|
*/
|
|
569
|
-
declare function createTextLogic<TInputSchema extends StandardSchemaV1
|
|
593
|
+
declare function createTextLogic<TInputSchema extends StandardSchemaV1 = StandardSchemaV1<undefined>, TOutputSchema extends StandardSchemaV1 = StandardSchemaV1<string>, TMetadata = Record<string, unknown>, TModel extends string = string>(config: TextLogicConfig<TInputSchema, TOutputSchema, TMetadata, TModel>, execute?: TextLogicExecutor<TInputSchema, TOutputSchema, TMetadata>): TextLogic<TInputSchema, TOutputSchema, TMetadata>;
|
|
570
594
|
/**
|
|
571
595
|
* Binds a child machine's {@link TextLogic} to a raw
|
|
572
596
|
* {@link AgentRequestExecutor} (the `generateText`/`streamText` shape hosts
|
|
@@ -578,7 +602,7 @@ declare function createTextLogic<TInputSchema extends StandardSchemaV1, TOutputS
|
|
|
578
602
|
* @example
|
|
579
603
|
* ```ts
|
|
580
604
|
* childMachine.provide({
|
|
581
|
-
*
|
|
605
|
+
* actors: {
|
|
582
606
|
* researchTopic: bindRequestExecutor(setup.requests.researchTopic, generateText),
|
|
583
607
|
* },
|
|
584
608
|
* });
|
|
@@ -588,12 +612,18 @@ declare function bindRequestExecutor<TInputSchema extends StandardSchemaV1, TOut
|
|
|
588
612
|
/**
|
|
589
613
|
* The envelope an {@link AgentRequestExecutor} must return: `{ output }` where
|
|
590
614
|
* `output` is the request's value (a text string or a structured object).
|
|
591
|
-
* Passthrough fields (
|
|
592
|
-
*
|
|
615
|
+
* Passthrough fields (toolCalls, finishReason, raw, …) are allowed alongside
|
|
616
|
+
* `output` and preserved on the raw result. {@link normalizeGeneratorResult}
|
|
593
617
|
* unwraps `output`; a non-envelope return is a runtime error.
|
|
618
|
+
*
|
|
619
|
+
* `usage` is the one passthrough field core reads: report this call's tokens
|
|
620
|
+
* there and `runAgent` folds them into the run's aggregated
|
|
621
|
+
* {@link AgentUsage}. Optional — an executor that reports nothing still counts
|
|
622
|
+
* toward `modelCalls`.
|
|
594
623
|
*/
|
|
595
624
|
type AgentRequestExecutorResult<TOutput = unknown> = {
|
|
596
|
-
output: TOutput;
|
|
625
|
+
output: TOutput; /** This call's token usage, aggregated into the run result's {@link AgentUsage}. */
|
|
626
|
+
usage?: AgentCallUsage;
|
|
597
627
|
[key: string]: unknown;
|
|
598
628
|
};
|
|
599
629
|
/**
|
|
@@ -604,6 +634,20 @@ type AgentRequestExecutorResult<TOutput = unknown> = {
|
|
|
604
634
|
interface AgentRequestExecutorInfo {
|
|
605
635
|
onChunk?: (chunk: string) => void;
|
|
606
636
|
signal?: AbortSignal;
|
|
637
|
+
/**
|
|
638
|
+
* The `runAgent` run this call belongs to (`run_<n>`, matching trace
|
|
639
|
+
* events). Undefined off the runAgent path (bare `provideExecutors` /
|
|
640
|
+
* direct `TextLogic.execute`). Lets executor middleware (caching, rate
|
|
641
|
+
* limits, span parenting) correlate calls without side channels.
|
|
642
|
+
*/
|
|
643
|
+
runId?: string;
|
|
644
|
+
/**
|
|
645
|
+
* The durable invoke id of the request making this call (e.g.
|
|
646
|
+
* `'0.(machine).asking'`) — stable across resume/replay, and it encodes the
|
|
647
|
+
* invoking state, so per-state middleware can key on it. Undefined when the
|
|
648
|
+
* call has no invoking actor.
|
|
649
|
+
*/
|
|
650
|
+
requestId?: string;
|
|
607
651
|
}
|
|
608
652
|
/**
|
|
609
653
|
* A raw Vercel AI SDK `generateText` result shape: resolves `{ text }` (a
|
|
@@ -648,13 +692,15 @@ type AgentRequestExecutor<TResult extends AgentRequestExecutorResult = AgentRequ
|
|
|
648
692
|
/**
|
|
649
693
|
* The full set of host executors a machine's agent actors are resolved
|
|
650
694
|
* with — passed to `runAgent`, `executeAgentRequest`, and
|
|
651
|
-
* `TextLogic.execute`.
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
* machine actually needs
|
|
695
|
+
* `TextLogic.execute`. Every slot is optional: `generateText` is needed only
|
|
696
|
+
* if the machine has a `mode: 'generate'` text request, `streamText` only for
|
|
697
|
+
* a `mode: 'stream'` request, and `decide` only for a decision/plan — omitting
|
|
698
|
+
* a slot the machine actually needs is a clear bind-time error (see `runAgent`
|
|
699
|
+
* and `provideExecutors`). Adapter result sets (`AiSdkExecutors`,
|
|
700
|
+
* `OpenAiCompatExecutors`) re-require all three.
|
|
655
701
|
*/
|
|
656
702
|
interface AgentRequestExecutors<TGenerateResult extends AgentRequestExecutorResult = AgentRequestExecutorResult, TStreamResult extends AgentRequestExecutorResult = AgentRequestExecutorResult> {
|
|
657
|
-
generateText
|
|
703
|
+
generateText?: AgentRequestExecutor<TGenerateResult>;
|
|
658
704
|
streamText?: AgentRequestExecutor<TStreamResult>;
|
|
659
705
|
decide?: AgentDecisionExecutor;
|
|
660
706
|
}
|
|
@@ -670,8 +716,6 @@ type AgentOutputMode = "structured" | "text";
|
|
|
670
716
|
* as `'text'`.
|
|
671
717
|
*/
|
|
672
718
|
declare function getAgentOutputMode(schema?: StandardSchemaV1): AgentOutputMode;
|
|
673
|
-
/** True when {@link getAgentOutputMode} classifies `schema` as `'structured'`. */
|
|
674
|
-
declare function isStructuredOutputSchema(schema?: StandardSchemaV1): boolean;
|
|
675
719
|
/** The unwrapped shape a {@link buildEnvelopeSchema} validate returns: the inner
|
|
676
720
|
* `result` value plus, when opted in and present, the model's `reasoning`. */
|
|
677
721
|
interface StructuredOutputEnvelope {
|
|
@@ -707,4 +751,4 @@ declare function buildEnvelopeSchema(inner: StandardSchemaV1, options?: {
|
|
|
707
751
|
*/
|
|
708
752
|
declare function parseStructuredEnvelope(request: Pick<AgentTextRequest, "outputSchema" | "reasoning">, value: unknown): StructuredOutputEnvelope;
|
|
709
753
|
//#endregion
|
|
710
|
-
export { AgentDecisionInput as A,
|
|
754
|
+
export { AgentDecisionInput as A, resolveDecision as B, createTextLogic as C, parseStructuredEnvelope as D, parseOutput as E, DecisionLogicConfig as F, getAcceptedEvents as G, AgentEventToolNameResolver as H, PLAN_DONE_EVENT_TYPE as I, parseAgentEvent as K, PlanLogic as L, AgentPlanInput as M, AgentPlanOutput as N, AgentDecisionExecutor as O, DecisionAttempt as P, ResolveDecisionOptions as R, buildEnvelopeSchema as S, parseModelRef as T, AgentRequestOptions as U, AgentEventDescriptor as V, AgentRequestSource as W, TextLogic as _, AgentRequestExecutor as a, TextLogicExecutor as b, AgentRequestExecutors as c, AgentUsage as d, AgentUserInput as f, StructuredOutputEnvelope as g, BuiltinAgentActors as h, AgentOutputMode as i, AgentDecisionRequest as j, AgentDecisionExhaustedError as k, AgentRequestMode as l, AiSdkShapedTextResult as m, AgentModelMap as n, AgentRequestExecutorInfo as o, AiSdkShapedStreamResult as p, AgentModelRef as r, AgentRequestExecutorResult as s, AgentCallUsage as t, AgentTextRequest as u, TextLogicConfig as v, getAgentOutputMode as w, bindRequestExecutor as x, TextLogicExecuteArgs as y, renderDecisionAttempts as z };
|
|
@@ -216,4 +216,4 @@ type AllowedEvents<TEvent extends string = string, TInput = unknown> = AllowedEv
|
|
|
216
216
|
input: TInput;
|
|
217
217
|
}) => AllowedEventPattern<TEvent> | readonly AllowedEventPattern<TEvent>[]);
|
|
218
218
|
//#endregion
|
|
219
|
-
export { UserMessage as
|
|
219
|
+
export { UserMessage as C, ToolResultPart as S, StandardSchemaV1 as _, AgentToolChoice as a, ToolCallPart as b, AgentTools as c, ChosenEvent as d, EventUnion as f, NormalizedEventSchemas as g, InferOutput as h, AgentTool as i, AllowedEvents as l, ImagePart as m, AgentMessage as n, AgentToolDescriptor as o, FilePart as p, AgentSnapshotStore as r, AgentToolExecute as s, AgentEventSchemaInputMap as t, AssistantMessage as u, SystemMessage as v, ToolMessage as x, TextPart as y };
|
|
@@ -216,4 +216,4 @@ type AllowedEvents<TEvent extends string = string, TInput = unknown> = AllowedEv
|
|
|
216
216
|
input: TInput;
|
|
217
217
|
}) => AllowedEventPattern<TEvent> | readonly AllowedEventPattern<TEvent>[]);
|
|
218
218
|
//#endregion
|
|
219
|
-
export { UserMessage as
|
|
219
|
+
export { UserMessage as C, ToolResultPart as S, StandardSchemaV1 as _, AgentToolChoice as a, ToolCallPart as b, AgentTools as c, ChosenEvent as d, EventUnion as f, NormalizedEventSchemas as g, InferOutput as h, AgentTool as i, AllowedEvents as l, ImagePart as m, AgentMessage as n, AgentToolDescriptor as o, FilePart as p, AgentSnapshotStore as r, AgentToolExecute as s, AgentEventSchemaInputMap as t, AssistantMessage as u, SystemMessage as v, ToolMessage as x, TextPart as y };
|
package/package.json
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/agent",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0-alpha.12",
|
|
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",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
8
8
|
"types": "dist/index.d.mts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"statelyai-agent": "dist/cli.mjs"
|
|
11
|
-
},
|
|
12
9
|
"exports": {
|
|
13
10
|
".": {
|
|
14
11
|
"import": {
|
|
@@ -30,31 +27,42 @@
|
|
|
30
27
|
"default": "./dist/ai-sdk.cjs"
|
|
31
28
|
}
|
|
32
29
|
},
|
|
33
|
-
"./
|
|
30
|
+
"./machines": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/machines.d.mts",
|
|
33
|
+
"default": "./dist/machines.mjs"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/machines.d.cts",
|
|
37
|
+
"default": "./dist/machines.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./otel": {
|
|
34
41
|
"import": {
|
|
35
|
-
"types": "./dist/
|
|
36
|
-
"default": "./dist/
|
|
42
|
+
"types": "./dist/otel.d.mts",
|
|
43
|
+
"default": "./dist/otel.mjs"
|
|
37
44
|
},
|
|
38
45
|
"require": {
|
|
39
|
-
"types": "./dist/
|
|
40
|
-
"default": "./dist/
|
|
46
|
+
"types": "./dist/otel.d.cts",
|
|
47
|
+
"default": "./dist/otel.cjs"
|
|
41
48
|
}
|
|
42
49
|
},
|
|
43
|
-
"./
|
|
50
|
+
"./sqlite": {
|
|
44
51
|
"import": {
|
|
45
|
-
"types": "./dist/
|
|
46
|
-
"default": "./dist/
|
|
52
|
+
"types": "./dist/sqlite.d.mts",
|
|
53
|
+
"default": "./dist/sqlite.mjs"
|
|
47
54
|
},
|
|
48
55
|
"require": {
|
|
49
|
-
"types": "./dist/
|
|
50
|
-
"default": "./dist/
|
|
56
|
+
"types": "./dist/sqlite.d.cts",
|
|
57
|
+
"default": "./dist/sqlite.cjs"
|
|
51
58
|
}
|
|
52
59
|
},
|
|
53
60
|
"./agent-workflow.json": "./schemas/agent-workflow.json"
|
|
54
61
|
},
|
|
55
62
|
"files": [
|
|
56
63
|
"dist",
|
|
57
|
-
"schemas"
|
|
64
|
+
"schemas",
|
|
65
|
+
"skills"
|
|
58
66
|
],
|
|
59
67
|
"keywords": [
|
|
60
68
|
"ai",
|
|
@@ -80,54 +88,74 @@
|
|
|
80
88
|
"@anthropic-ai/sdk": "^0.109.1",
|
|
81
89
|
"@changesets/changelog-github": "^0.5.0",
|
|
82
90
|
"@changesets/cli": "^2.27.9",
|
|
83
|
-
"@
|
|
91
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
92
|
+
"@flue/runtime": "2.0.0",
|
|
84
93
|
"@inquirer/prompts": "^8.5.2",
|
|
85
|
-
"@
|
|
94
|
+
"@langchain/core": "^1.2.4",
|
|
95
|
+
"@langchain/openai": "^1.5.5",
|
|
96
|
+
"@mastra/core": "^1.54.0",
|
|
97
|
+
"@opentelemetry/api": "^1.9.1",
|
|
98
|
+
"@opentelemetry/context-async-hooks": "^2.10.0",
|
|
99
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
|
|
100
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
101
|
+
"@opentelemetry/sdk-trace-node": "^2.10.0",
|
|
102
|
+
"@statelyai/sdk": "^0.15.0",
|
|
103
|
+
"@types/express": "^5.0.6",
|
|
86
104
|
"@types/node": "^20.16.10",
|
|
87
|
-
"
|
|
105
|
+
"@types/react": "^19.2.17",
|
|
88
106
|
"ai": "^6.0.67",
|
|
89
107
|
"ajv": "^8.20.0",
|
|
108
|
+
"braintrust": "^3.25.0",
|
|
90
109
|
"dotenv": "^16.4.5",
|
|
110
|
+
"express": "^5.2.1",
|
|
111
|
+
"hono": "^4.12.30",
|
|
91
112
|
"knip": "6.24.0",
|
|
113
|
+
"langchain": "^1.5.4",
|
|
92
114
|
"openai": "^6.45.0",
|
|
93
115
|
"oxfmt": "0.57.0",
|
|
94
116
|
"oxlint": "1.72.0",
|
|
117
|
+
"react": "^19.2.7",
|
|
95
118
|
"tsdown": "^0.21.7",
|
|
96
119
|
"tsx": "^4.21.0",
|
|
97
120
|
"typescript": "^5.6.2",
|
|
98
|
-
"
|
|
99
|
-
"
|
|
121
|
+
"valibot": "^1.4.2",
|
|
122
|
+
"vitest": "^3.2.6",
|
|
123
|
+
"xstate": "6.0.0-alpha.25",
|
|
100
124
|
"zod": "^4.3.6"
|
|
101
125
|
},
|
|
102
126
|
"publishConfig": {
|
|
103
127
|
"access": "public"
|
|
104
128
|
},
|
|
105
129
|
"peerDependencies": {
|
|
130
|
+
"@opentelemetry/api": "^1",
|
|
106
131
|
"ai": "^6.0.67",
|
|
107
|
-
"xstate": ">=6.0.0-alpha.
|
|
108
|
-
"zod": "^3.25.0 || ^4.0.0"
|
|
132
|
+
"xstate": ">=6.0.0-alpha.25 <6.0.0"
|
|
109
133
|
},
|
|
110
134
|
"peerDependenciesMeta": {
|
|
111
|
-
"
|
|
135
|
+
"@opentelemetry/api": {
|
|
112
136
|
"optional": true
|
|
113
137
|
},
|
|
114
|
-
"
|
|
138
|
+
"ai": {
|
|
115
139
|
"optional": true
|
|
116
140
|
}
|
|
117
141
|
},
|
|
118
142
|
"scripts": {
|
|
119
143
|
"build": "tsdown",
|
|
120
144
|
"proto:prefabs": "tsx .scratch/prefabs/demo.ts",
|
|
121
|
-
"typecheck": "pnpm run typecheck:src && pnpm run typecheck:examples",
|
|
145
|
+
"typecheck": "pnpm run typecheck:src && pnpm run typecheck:examples && pnpm run typecheck:example-packages",
|
|
122
146
|
"typecheck:src": "tsc --noEmit",
|
|
123
147
|
"typecheck:examples": "tsc -p examples/tsconfig.json --noEmit",
|
|
148
|
+
"typecheck:example-packages": "tsc -p examples/next-host --noEmit && tsc -p examples/tanstack-start-host --noEmit && tsc -p examples/tanstack-ai-stream --noEmit && tsc -p examples/cloudflare-agent-host --noEmit && tsc -p examples/cloudflare-workers-ai-host --noEmit",
|
|
149
|
+
"test:cloudflare": "pnpm --filter @statelyai/example-cloudflare-agent-host test && pnpm --filter @statelyai/example-cloudflare-workers-ai-host test",
|
|
124
150
|
"lint": "oxlint",
|
|
125
151
|
"format": "oxfmt src examples",
|
|
126
152
|
"format:check": "oxfmt --check src examples",
|
|
127
153
|
"knip": "knip",
|
|
128
154
|
"check": "pnpm run typecheck && pnpm run lint && pnpm run format:check && pnpm run knip",
|
|
155
|
+
"check:dts": "tsc -p fixtures/dts-consumer/tsconfig.json",
|
|
129
156
|
"test": "vitest",
|
|
130
|
-
"test:
|
|
157
|
+
"test:live": "LIVE_TESTS=1 vitest --run",
|
|
158
|
+
"test:ci": "vitest --run && pnpm run test:cloudflare",
|
|
131
159
|
"changeset": "changeset",
|
|
132
160
|
"release": "changeset publish",
|
|
133
161
|
"version": "changeset version"
|
package/readme.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Stately Agent
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Make invalid agent actions impossible.**
|
|
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
7
|
Stately Agent adds model requests and decisions to XState. The state machine defines what the agent can do. Your application chooses the model, runs the requests, and stores the state.
|
|
8
8
|
|
|
@@ -12,15 +12,21 @@ Stately Agent 2 is in alpha. APIs may change before the stable release.
|
|
|
12
12
|
|
|
13
13
|
[Documentation](https://stately.ai/docs/agents) · [Examples](examples/README.md) · [XState](https://github.com/statelyai/xstate)
|
|
14
14
|
|
|
15
|
+
## Three ways to start
|
|
16
|
+
|
|
17
|
+
- **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
|
+
- **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).
|
|
19
|
+
- **Copy a known pattern.** ReAct, reflection, plan-and-execute, RAG, supervisor, and more, each a single runnable file you lift in 60 seconds. See [Agent patterns](docs/patterns.md).
|
|
20
|
+
|
|
15
21
|
## Install
|
|
16
22
|
|
|
17
23
|
<!-- install command matching the package prerelease channel and package.json peers -->
|
|
18
24
|
|
|
19
25
|
```sh
|
|
20
|
-
pnpm add @statelyai/agent@alpha xstate@alpha zod ai @ai-sdk/openai
|
|
26
|
+
pnpm add @statelyai/agent@alpha xstate@alpha zod ai@^6 @ai-sdk/openai@^3
|
|
21
27
|
```
|
|
22
28
|
|
|
23
|
-
Node 22.18 or newer is required.
|
|
29
|
+
Node 22.18 or newer is required. The package is ESM-first (CommonJS builds are published too, so `require()` works) and requires XState v6 alpha.25 or newer. Provider packages must match your `ai` major: `@ai-sdk/openai@^3` pairs with `ai@^6` (a bare `@ai-sdk/openai` resolves to `@latest`, which can mismatch the `ai` peer).
|
|
24
30
|
|
|
25
31
|
## Quick start
|
|
26
32
|
|
|
@@ -30,15 +36,15 @@ This agent reviews refund requests. The model may propose an automatic refund, b
|
|
|
30
36
|
|
|
31
37
|
```ts
|
|
32
38
|
import { openai } from "@ai-sdk/openai";
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
39
|
+
import { runAgent, setupAgent } from "@statelyai/agent";
|
|
40
|
+
import { createAiSdkExecutors, defineModels } from "@statelyai/agent/ai-sdk";
|
|
35
41
|
import { z } from "zod";
|
|
36
42
|
|
|
37
43
|
const models = defineModels({
|
|
38
44
|
fast: openai("gpt-5.4-mini"),
|
|
39
45
|
});
|
|
40
46
|
|
|
41
|
-
const
|
|
47
|
+
const agentSetup = setupAgent({
|
|
42
48
|
models,
|
|
43
49
|
context: z.object({
|
|
44
50
|
request: z.string(),
|
|
@@ -57,7 +63,7 @@ const agent = setupAgent({
|
|
|
57
63
|
},
|
|
58
64
|
});
|
|
59
65
|
|
|
60
|
-
const refundMachine =
|
|
66
|
+
const refundMachine = agentSetup.createMachine({
|
|
61
67
|
context: ({ input }) => input,
|
|
62
68
|
initial: "deciding",
|
|
63
69
|
states: {
|
|
@@ -92,6 +98,7 @@ const result = await runAgent(refundMachine, {
|
|
|
92
98
|
request: "I was charged twice for the same order.",
|
|
93
99
|
amount: 75,
|
|
94
100
|
},
|
|
101
|
+
executors: createAiSdkExecutors({ models }),
|
|
95
102
|
});
|
|
96
103
|
|
|
97
104
|
if (result.status === "done") {
|
|
@@ -107,6 +114,19 @@ When the machine reaches `refunded`, the result is:
|
|
|
107
114
|
|
|
108
115
|
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.
|
|
109
116
|
|
|
117
|
+
**Run it with no API key.** `createScriptedExecutors` plays back canned answers through the same executor contract, so the machine above runs end to end before a model is involved:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { createScriptedExecutors } from "@statelyai/agent";
|
|
121
|
+
|
|
122
|
+
const result = await runAgent(refundMachine, {
|
|
123
|
+
input: { request: "I was charged twice for the same order.", amount: 75 },
|
|
124
|
+
executors: createScriptedExecutors({ decisions: [{ type: "AUTO_REFUND" }] }),
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Swap in `createAiSdkExecutors({ models })` when you want a real model. The scripted set is what your tests keep using.
|
|
129
|
+
|
|
110
130
|
## The state machine
|
|
111
131
|
|
|
112
132
|
<!-- Add the state machine illustration here. -->
|
|
@@ -122,6 +142,7 @@ The example has one model decision and two final outcomes. Real machines can add
|
|
|
122
142
|
- **Requests are typed.** Inputs, outputs, context, and events use Standard Schema. Zod works out of the box.
|
|
123
143
|
- **Your code runs the model.** `runAgent` accepts executor functions. The example uses the Vercel AI SDK adapter, but the machine does not depend on a provider.
|
|
124
144
|
- **Snapshots can be stored.** An agent can stop for human input, save its XState snapshot, and resume later in another process.
|
|
145
|
+
- **Runs export verified replay entries.** Every `runAgent` result carries a JSON-safe `AgentLogEntry[]` with event identity, timestamp, machine version, and state/effect hashes; pass it to `replay` or `verifyReplay` without repeating model or tool calls.
|
|
125
146
|
- **Machines can be checked without model calls.** Lint their structure, simulate scripted decisions, and explore paths without an API key.
|
|
126
147
|
- **Agents are XState machines.** Guards, actors, parallel states, inspection, testing, and visualization work as usual.
|
|
127
148
|
|
|
@@ -144,4 +165,14 @@ See [all examples](examples/README.md).
|
|
|
144
165
|
- [Decisions](docs/decisions.md)
|
|
145
166
|
- [Human in the loop](docs/human-in-the-loop.md)
|
|
146
167
|
- [Testing and verification](docs/verify.md)
|
|
147
|
-
- [
|
|
168
|
+
- [Evals](docs/evals.md)
|
|
169
|
+
- [Generating machines with an LLM](docs/generate-machines.md)
|
|
170
|
+
- [Hosts and executors](docs/hosts.md)
|
|
171
|
+
- [Models and providers](docs/models-and-providers.md)
|
|
172
|
+
- [Use in any stack](docs/any-stack.md)
|
|
173
|
+
- [The event log](docs/event-log.md)
|
|
174
|
+
- [Observability](docs/observability.md)
|
|
175
|
+
- [Usage and budgets](docs/usage-and-budgets.md)
|
|
176
|
+
- [Agent patterns](docs/patterns.md)
|
|
177
|
+
- [Migrating from a loop](docs/from-a-loop.md)
|
|
178
|
+
- [LangGraph vs agent machines](docs/langgraph-comparison.md)
|