@statelyai/agent 2.0.0-alpha.23 → 2.0.0-alpha.25
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 +30 -34
- package/dist/ai-sdk.d.cts +27 -31
- package/dist/ai-sdk.d.mts +27 -31
- package/dist/ai-sdk.mjs +27 -31
- package/dist/decision-CM9CYZ6t.cjs +519 -0
- package/dist/decision-DzSv1NpD.mjs +453 -0
- package/dist/event-log-store-Ba2fsc4E.mjs +576 -0
- package/dist/event-log-store-DQmImLYk.cjs +702 -0
- package/dist/event-log-store-DvOcs10J.d.cts +338 -0
- package/dist/event-log-store-DxyVgnas.d.mts +338 -0
- package/dist/index.cjs +429 -4272
- package/dist/index.d.cts +104 -1005
- package/dist/index.d.mts +104 -1005
- package/dist/index.mjs +389 -4202
- package/dist/log.cjs +392 -0
- package/dist/log.d.cts +32 -0
- package/dist/log.d.mts +32 -0
- package/dist/log.mjs +371 -0
- package/dist/machines.cjs +27 -16
- package/dist/machines.d.cts +1 -1
- package/dist/machines.d.mts +1 -1
- package/dist/machines.mjs +27 -16
- package/dist/openai.cjs +16 -15
- package/dist/openai.d.cts +9 -9
- package/dist/openai.d.mts +9 -9
- package/dist/openai.mjs +10 -9
- package/dist/otel.d.cts +1 -1
- package/dist/otel.d.mts +1 -1
- package/dist/{run-agent-Ck7Sa3Tb.d.mts → run-agent-BOfoJg5B.d.cts} +86 -387
- package/dist/{run-agent-DWqA8KiI.d.cts → run-agent-CG343kFs.d.mts} +86 -387
- package/dist/run-agent-Cb1-LS5P.cjs +1783 -0
- package/dist/run-agent-DvDQd4If.mjs +1669 -0
- package/dist/{setup-agent-CeO2fARv.mjs → setup-agent-CFW-jPI8.mjs} +9 -20
- package/dist/{setup-agent-Dl2VELLi.cjs → setup-agent-CPf7MxnG.cjs} +20 -37
- package/dist/testing.cjs +1222 -0
- package/dist/testing.d.cts +602 -0
- package/dist/testing.d.mts +602 -0
- package/dist/testing.mjs +1212 -0
- package/dist/{text-logic-DJBK3LbG.d.mts → text-logic-BFEOxyxv.d.cts} +71 -147
- package/dist/text-logic-Bl_ZRxDi.mjs +833 -0
- package/dist/text-logic-C8xyr6Ag.cjs +1091 -0
- package/dist/{text-logic-C7bSnH_B.d.cts → text-logic-hZSiRUo1.d.mts} +71 -147
- package/dist/{types-CjHk5OdH.d.cts → types-B1Qs2q3q.d.cts} +2 -1
- package/dist/{types-DWA6X9R-.d.mts → types-tA3SdczG.d.mts} +2 -1
- package/dist/usage-BdEjFuIi.mjs +5 -0
- package/dist/usage-efOQPdf_.cjs +10 -0
- package/dist/utils-C1p37X_c.d.mts +209 -0
- package/dist/utils-RalRn9sk.d.cts +209 -0
- package/package.json +24 -4
- package/readme.md +2 -2
- package/skills/generate-machine/SKILL.md +4 -6
- package/dist/decision-BBZ2jMO1.mjs +0 -1490
- package/dist/decision-Cv6SfNWl.cjs +0 -1856
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { C as UserMessage, S as ToolResultPart, _ as StandardSchemaV1, b as ToolCallPart, f as FilePart, l as AssistantMessage, n as AgentMessage, p as ImagePart, u as ChosenEvent, v as SystemMessage, x as ToolMessage, y as TextPart } from "./types-B1Qs2q3q.cjs";
|
|
2
|
+
import { M as AgentDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, t as AgentCallUsage, u as AgentRequestExecutors } from "./text-logic-BFEOxyxv.cjs";
|
|
3
|
+
import { AnyMachineSnapshot, AnyStateMachine, StateValue } from "xstate";
|
|
4
|
+
|
|
5
|
+
//#region src/scripted-executors.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A scripted `decide` answer: either the {@link ChosenEvent} itself (an object
|
|
8
|
+
* with a string `type`), or the executor result `{ event, reason?, usage? }`
|
|
9
|
+
* when the entry also reports a `reason` or token `usage`.
|
|
10
|
+
*/
|
|
11
|
+
type ScriptedDecisionValue = ChosenEvent | {
|
|
12
|
+
event: ChosenEvent;
|
|
13
|
+
reason?: string;
|
|
14
|
+
usage?: AgentCallUsage;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* One scripted `decide` answer, or a function of the
|
|
18
|
+
* {@link AgentDecisionRequest} returning one (for choices that depend on the
|
|
19
|
+
* prompt, the candidate `events`, or the prior failed `attempts`).
|
|
20
|
+
*/
|
|
21
|
+
type ScriptedDecisionEntry = ScriptedDecisionValue | ((request: AgentDecisionRequest) => ScriptedDecisionValue | PromiseLike<ScriptedDecisionValue>);
|
|
22
|
+
/**
|
|
23
|
+
* One scripted text answer: the request's output value (a string, or the
|
|
24
|
+
* object a structured request declares), or a function of the
|
|
25
|
+
* {@link AgentTextRequest} returning one.
|
|
26
|
+
*
|
|
27
|
+
* An entry is taken as the executor result (instead of the value itself)
|
|
28
|
+
* only when its OWN keys are a `result` plus, optionally, `messages`/`usage`/
|
|
29
|
+
* `raw` — that is how an entry reports token `usage`. Anything else, including
|
|
30
|
+
* an object that merely happens to have a `result` key alongside its own data
|
|
31
|
+
* (`{ result: 'draft', confidence: 0.9 }`), is the output value. For a
|
|
32
|
+
* structured request whose declared output is exactly `{ result }` (or
|
|
33
|
+
* `{ result, usage }`), wrap it once more: `{ result: { result: '…' } }`.
|
|
34
|
+
*/
|
|
35
|
+
type ScriptedTextEntry = ((request: AgentTextRequest, info?: AgentRequestExecutorInfo) => unknown) | string | number | boolean | null | object;
|
|
36
|
+
/**
|
|
37
|
+
* A request-name keyed script. The key is the request's resolved `name` — the
|
|
38
|
+
* authored name, else the invoke `id`. `"*"` is the fallback route.
|
|
39
|
+
*/
|
|
40
|
+
type ScriptedByName<TEntry> = Record<string, TEntry | TEntry[]>;
|
|
41
|
+
/** One scripted stream call: chunks, or a function producing chunks. */
|
|
42
|
+
type ScriptedStreamEntry = string | readonly string[] | ((request: AgentTextRequest, info?: AgentRequestExecutorInfo) => string | readonly string[] | PromiseLike<string | readonly string[]>);
|
|
43
|
+
/** A call observed by {@link createScriptedExecutors}. */
|
|
44
|
+
interface ScriptedExecutorCall {
|
|
45
|
+
kind: "generateText" | "streamText" | "decide";
|
|
46
|
+
name: string;
|
|
47
|
+
input: unknown;
|
|
48
|
+
request: AgentTextRequest | AgentDecisionRequest;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The script {@link createScriptedExecutors} plays back. Every channel is
|
|
52
|
+
* keyed by request name and consumed in order; the last entry for a name
|
|
53
|
+
* repeats forever.
|
|
54
|
+
*/
|
|
55
|
+
interface ScriptedExecutorsScript {
|
|
56
|
+
/** Answers for `decide` requests, keyed by request name. */
|
|
57
|
+
decisions?: ScriptedByName<ScriptedDecisionEntry>;
|
|
58
|
+
/** Answers for generate requests, keyed by request name. */
|
|
59
|
+
text?: ScriptedByName<ScriptedTextEntry>;
|
|
60
|
+
/** Stream chunks keyed by request name. */
|
|
61
|
+
stream?: Record<string, ScriptedStreamEntry>;
|
|
62
|
+
/** Default usage attached when an entry does not provide its own. */
|
|
63
|
+
usage?: AgentCallUsage;
|
|
64
|
+
}
|
|
65
|
+
/** What {@link createScriptedExecutors} returns: the full executor set plus the calls it observed. */
|
|
66
|
+
type ScriptedExecutors = Required<AgentRequestExecutors> & {
|
|
67
|
+
calls: ScriptedExecutorCall[];
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Executors that replay a script instead of calling a model. Every slot is
|
|
71
|
+
* provided, so any machine binds.
|
|
72
|
+
*
|
|
73
|
+
* Answers are keyed by the request's resolved name — its authored `name`, else
|
|
74
|
+
* the invoke `id` — and `"*"` serves anything unmatched.
|
|
75
|
+
* Entries for a name are consumed in order and the last one repeats forever, so
|
|
76
|
+
* a looping machine needs no extra option. A request the script has no route
|
|
77
|
+
* for throws an ordinary `Error` from inside the executor, which reaches the
|
|
78
|
+
* machine as an actor error.
|
|
79
|
+
*
|
|
80
|
+
* Queues are copied on creation, so the caller's arrays are never mutated and
|
|
81
|
+
* each call builds a fresh, independent playthrough. Entries may be plain
|
|
82
|
+
* values or functions of the request.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* const result = await runAgent(moderationMachine, {
|
|
87
|
+
* input: { comment: 'honestly this update is terrible', trust: 20 },
|
|
88
|
+
* executors: createScriptedExecutors({
|
|
89
|
+
* decisions: { moderate: [{ type: 'FLAG', reason: 'Borderline tone.' }] },
|
|
90
|
+
* }),
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example Dynamic entries
|
|
95
|
+
* ```ts
|
|
96
|
+
* createScriptedExecutors({
|
|
97
|
+
* text: { draft: (request) => `Draft about ${request.prompt}` },
|
|
98
|
+
* decisions: { route: (request) => ({ type: request.events[0]!.type }) },
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function createScriptedExecutors(script?: ScriptedExecutorsScript): ScriptedExecutors;
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/utils.d.ts
|
|
105
|
+
/** Returns the human-readable text carried by a message, ignoring non-text parts. */
|
|
106
|
+
declare function getMessageText(message: AgentMessage): string;
|
|
107
|
+
/**
|
|
108
|
+
* A stable, dependency-free structural fingerprint of a machine — a short hex
|
|
109
|
+
* `djb2` hash over its **structural** config only: state ids/nesting, transition
|
|
110
|
+
* event types and targets, invoke `src`s, `initial`, and any other serializable
|
|
111
|
+
* config fields. Function values (context/output builders, prompts, inline
|
|
112
|
+
* guards/actions) are excluded entirely, so two machines that differ only in
|
|
113
|
+
* their prompts or executors hash identically; adding/removing/retargeting a
|
|
114
|
+
* state or transition changes the hash.
|
|
115
|
+
*
|
|
116
|
+
* Used by {@link runAgent} to stamp settled snapshots with a `version` and to
|
|
117
|
+
* detect a structurally-edited machine on resume. It is a change detector, not
|
|
118
|
+
* a cryptographic digest — collisions are possible but unlikely for real
|
|
119
|
+
* configs. Declare `createMachine({ version })` to pin an explicit version instead.
|
|
120
|
+
*/
|
|
121
|
+
declare function getMachineStructuralHash(machine: AnyStateMachine): string;
|
|
122
|
+
/** Builds a {@link UserMessage} from a string or multimodal content parts. */
|
|
123
|
+
declare function userMessage(content: string | Array<TextPart | ImagePart | FilePart>): UserMessage;
|
|
124
|
+
/** Builds an {@link AssistantMessage} from a string or content parts (text, files, tool calls/results). */
|
|
125
|
+
declare function assistantMessage(content: string | Array<TextPart | FilePart | ToolCallPart | ToolResultPart>): AssistantMessage;
|
|
126
|
+
/** Builds a {@link SystemMessage}. */
|
|
127
|
+
declare function systemMessage(content: string): SystemMessage;
|
|
128
|
+
/** Builds a {@link ToolMessage} from one or more tool-result parts. */
|
|
129
|
+
declare function toolMessage(content: Array<ToolResultPart>): ToolMessage;
|
|
130
|
+
type MetaOfSnapshot<TSnapshot extends {
|
|
131
|
+
getMeta(): Record<string, unknown>;
|
|
132
|
+
}> = NonNullable<ReturnType<TSnapshot["getMeta"]>[keyof ReturnType<TSnapshot["getMeta"]>]>;
|
|
133
|
+
/**
|
|
134
|
+
* Returns the merged `meta` of a snapshot's active state(s) — the typed
|
|
135
|
+
* replacement for the `Object.values(snapshot.getMeta())[0]` dance.
|
|
136
|
+
*
|
|
137
|
+
* `snapshot.getMeta()` is keyed by state id; a leaf machine has one active
|
|
138
|
+
* state, but parallel/nested machines can have several. This shallow-merges
|
|
139
|
+
* every active state's meta into one object and returns `{}` when no active
|
|
140
|
+
* state declares meta.
|
|
141
|
+
*
|
|
142
|
+
* Merge order is fixed and does not depend on XState's internal node order:
|
|
143
|
+
* entries are sorted by structural depth (the state node's distance from the
|
|
144
|
+
* root, regardless of custom `id` strings), then by state id lexicographically,
|
|
145
|
+
* and merged in that order. So a deeper state's key wins over an ancestor's,
|
|
146
|
+
* and between equal-depth parallel siblings the later state id alphabetically
|
|
147
|
+
* wins.
|
|
148
|
+
*
|
|
149
|
+
* The return type is recovered from the snapshot's own `getMeta()` type, so a
|
|
150
|
+
* schema-typed machine (`setupAgent({ meta })`) yields the meta schema's
|
|
151
|
+
* output type. Pass an explicit `TMeta` to override when the snapshot is
|
|
152
|
+
* untyped (e.g. `AnyMachineSnapshot`).
|
|
153
|
+
*
|
|
154
|
+
* @example HITL: read the current state's interaction protocol off an idle
|
|
155
|
+
* snapshot to render for a human.
|
|
156
|
+
* ```ts
|
|
157
|
+
* const { interaction } = getStateMeta(result.snapshot);
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
declare function getStateMeta<TSnapshot extends {
|
|
161
|
+
getMeta(): Record<string, unknown>;
|
|
162
|
+
} = AnyMachineSnapshot, TMeta = MetaOfSnapshot<TSnapshot>>(snapshot: TSnapshot): Partial<TMeta>;
|
|
163
|
+
/**
|
|
164
|
+
* Renders a snapshot's state value as one deterministic string, so a log line,
|
|
165
|
+
* a progress field, or a test assertion reads the same on every run.
|
|
166
|
+
*
|
|
167
|
+
* - An atomic state is its own name: `'writing'`.
|
|
168
|
+
* - A nested state joins with dots: `{ review: { editing: 'draft' } }` →
|
|
169
|
+
* `'review.editing.draft'`.
|
|
170
|
+
* - A parallel state brackets its regions, sorted by region name, so key order
|
|
171
|
+
* never leaks into the string: `{ p: { left: 'x', right: { a: 'b' } } }` →
|
|
172
|
+
* `'p:{left.x,right.a.b}'`.
|
|
173
|
+
*
|
|
174
|
+
* Prefer this over `String(snapshot.value)`, which renders every non-atomic
|
|
175
|
+
* value as `[object Object]`.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* onTransition: (snapshot) => console.log(getStatePath(snapshot));
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare function getStatePath(snapshot: {
|
|
183
|
+
value: StateValue;
|
|
184
|
+
status?: string;
|
|
185
|
+
} | StateValue): string;
|
|
186
|
+
/**
|
|
187
|
+
* Structural guard for a {@link StandardSchemaV1}: `true` when `value` carries
|
|
188
|
+
* the `~standard` marker. Used to tell an already-schema'd tool `inputSchema`
|
|
189
|
+
* (a Zod/Valibot/… schema) apart from an SDK-specific schema wrapper that core
|
|
190
|
+
* can't read directly — see the `ai-sdk` tool pass-through.
|
|
191
|
+
*/
|
|
192
|
+
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
193
|
+
/**
|
|
194
|
+
* Pulls the JSON Schema off a {@link StandardSchemaV1} via its optional
|
|
195
|
+
* `~standard.jsonSchema.input()` extension (implemented by e.g. Zod v4's
|
|
196
|
+
* `z.toJSONSchema`), awaiting it when the producer is async. Returns
|
|
197
|
+
* `undefined` when the schema doesn't expose the extension. Use this to build
|
|
198
|
+
* a provider request's `response_format`/tool `parameters` from a schema.
|
|
199
|
+
*/
|
|
200
|
+
declare function getJsonSchema(schema?: StandardSchemaV1): Promise<Record<string, unknown> | undefined>;
|
|
201
|
+
/**
|
|
202
|
+
* Synchronous variant of {@link getJsonSchema}, for call sites that can't
|
|
203
|
+
* await (building tool/event descriptors inline). An async JSON Schema
|
|
204
|
+
* producer is treated as absent (returns `undefined`) — in practice Zod's
|
|
205
|
+
* `z.toJSONSchema` resolves synchronously.
|
|
206
|
+
*/
|
|
207
|
+
declare function getJsonSchemaSync(schema?: StandardSchemaV1): Record<string, unknown> | undefined;
|
|
208
|
+
//#endregion
|
|
209
|
+
export { ScriptedExecutorsScript as _, getMachineStructuralHash as a, getStatePath as c, toolMessage as d, userMessage as f, ScriptedExecutors as g, ScriptedDecisionValue as h, getJsonSchemaSync as i, isStandardSchema as l, ScriptedDecisionEntry as m, assistantMessage as n, getMessageText as o, ScriptedByName as p, getJsonSchema as r, getStateMeta as s, MetaOfSnapshot as t, systemMessage as u, ScriptedTextEntry as v, createScriptedExecutors as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statelyai/agent",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.25",
|
|
4
4
|
"description": "Make invalid agent actions impossible. Agent logic as state machines: deterministic, inspectable, resumable, runs anywhere.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -48,6 +48,16 @@
|
|
|
48
48
|
"default": "./dist/ai-sdk.cjs"
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
+
"./log": {
|
|
52
|
+
"import": {
|
|
53
|
+
"types": "./dist/log.d.mts",
|
|
54
|
+
"default": "./dist/log.mjs"
|
|
55
|
+
},
|
|
56
|
+
"require": {
|
|
57
|
+
"types": "./dist/log.d.cts",
|
|
58
|
+
"default": "./dist/log.cjs"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
51
61
|
"./machines": {
|
|
52
62
|
"import": {
|
|
53
63
|
"types": "./dist/machines.d.mts",
|
|
@@ -78,6 +88,16 @@
|
|
|
78
88
|
"default": "./dist/otel.cjs"
|
|
79
89
|
}
|
|
80
90
|
},
|
|
91
|
+
"./testing": {
|
|
92
|
+
"import": {
|
|
93
|
+
"types": "./dist/testing.d.mts",
|
|
94
|
+
"default": "./dist/testing.mjs"
|
|
95
|
+
},
|
|
96
|
+
"require": {
|
|
97
|
+
"types": "./dist/testing.d.cts",
|
|
98
|
+
"default": "./dist/testing.cjs"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
81
101
|
"./validate": {
|
|
82
102
|
"import": {
|
|
83
103
|
"types": "./dist/validate.d.mts",
|
|
@@ -123,7 +143,7 @@
|
|
|
123
143
|
"typescript": "^5.9.3",
|
|
124
144
|
"valibot": "^1.4.2",
|
|
125
145
|
"vitest": "^4.1.11",
|
|
126
|
-
"xstate": "6.0.0-alpha.
|
|
146
|
+
"xstate": "6.0.0-alpha.57",
|
|
127
147
|
"zod": "^4.4.3"
|
|
128
148
|
},
|
|
129
149
|
"peerDependencies": {
|
|
@@ -131,7 +151,7 @@
|
|
|
131
151
|
"ai": "^7.0.0",
|
|
132
152
|
"ajv": "^8.20.0",
|
|
133
153
|
"openai": ">=5.0.0 <8",
|
|
134
|
-
"xstate": ">=6.0.0-alpha.
|
|
154
|
+
"xstate": ">=6.0.0-alpha.57 <6.0.0"
|
|
135
155
|
},
|
|
136
156
|
"peerDependenciesMeta": {
|
|
137
157
|
"@opentelemetry/api": {
|
|
@@ -168,7 +188,7 @@
|
|
|
168
188
|
"check:dts": "tsc -p fixtures/dts-consumer/tsconfig.json",
|
|
169
189
|
"test": "vitest",
|
|
170
190
|
"test:live": "LIVE_TESTS=1 vitest --run",
|
|
171
|
-
"test:ci": "vitest --run && pnpm run
|
|
191
|
+
"test:ci": "vitest --run && pnpm run build && pnpm run test:cloudflare && pnpm --filter @statelyai/agent-demo test",
|
|
172
192
|
"changeset": "changeset",
|
|
173
193
|
"release": "changeset publish",
|
|
174
194
|
"version": "changeset version"
|
package/readme.md
CHANGED
|
@@ -139,9 +139,9 @@ const liveResult = await runAgent(refundMachine, {
|
|
|
139
139
|
});
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
For a machine with several requests, `createScriptedExecutors` holds ordered answers keyed by request name. See [Evals](docs/evals.md#scripted-executors).
|
|
142
|
+
For a machine with several requests, `createScriptedExecutors` from `@statelyai/agent/testing` holds ordered answers keyed by request name. See [Evals](docs/evals.md#scripted-executors).
|
|
143
143
|
|
|
144
|
-
Passing
|
|
144
|
+
Passing the same `models` map to `setupAgent({ models })` types the machine's model refs. Executors are always explicit, and core does not import the AI SDK. See [Hosts and executors](docs/hosts.md).
|
|
145
145
|
|
|
146
146
|
## Architecture
|
|
147
147
|
|
|
@@ -27,7 +27,7 @@ Rules the runtime enforces. Each one maps to a build error or a lint diagnostic:
|
|
|
27
27
|
- A model call is either a named `requests` entry invoked with `src: "<requestName>"`, or an inline invoke with `src: "agent.decide"` plus an `allowedEvents` list.
|
|
28
28
|
- A state invoking `agent.decide` MUST handle every allowed event in its `on`.
|
|
29
29
|
- An `agent.decide` invoke has no `onDone` (a decision produces no output). Use `onError` for the retries-exhausted path.
|
|
30
|
-
- A request invoke
|
|
30
|
+
- A request invoke resolves with `{ result, messages }`, so `onDone.assign` reads its result from `"{{ event.output.result.<field> }}"` (`"{{ event.output.result }}"` for a plain-text request). A non-request `actors` invoke reads `"{{ event.output.<field> }}"` directly.
|
|
31
31
|
- Every path must reach a `"type": "final"` state, and each final state needs an `output` when `schemas.output` is declared.
|
|
32
32
|
- Do not invent guard or action names. Only `"{{ }}"` guards, `assign`, and `emit` exist unless the host tells you which named guards/actions it implements.
|
|
33
33
|
- Model refs are strings (`"openai/gpt-5.4-mini"`); the host resolves them.
|
|
@@ -113,7 +113,7 @@ Reference config — decision, text request, idle human step, one final state:
|
|
|
113
113
|
"input": { "ticket": "{{ context.ticket }}" },
|
|
114
114
|
"onDone": {
|
|
115
115
|
"target": "awaitingApproval",
|
|
116
|
-
"assign": { "reply": "{{ event.output.reply }}" }
|
|
116
|
+
"assign": { "reply": "{{ event.output.result.reply }}" }
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
},
|
|
@@ -191,8 +191,7 @@ Lowering is itself a gate: it throws on an unresolved named guard/action and on
|
|
|
191
191
|
## 5. Lint
|
|
192
192
|
|
|
193
193
|
```ts
|
|
194
|
-
import { lintAgentMachine } from "@statelyai/agent";
|
|
195
|
-
|
|
194
|
+
import { lintAgentMachine } from "@statelyai/agent/testing";
|
|
196
195
|
const diagnostics = lintAgentMachine(machine);
|
|
197
196
|
lintAgentMachine(machine, { throw: true }); // throws AgentLintError on error-severity findings
|
|
198
197
|
```
|
|
@@ -206,8 +205,7 @@ The one that bites most often is `decide-without-events`: an `allowedEvents` lis
|
|
|
206
205
|
Lint is structural. A dry run proves a path actually settles. No API key needed.
|
|
207
206
|
|
|
208
207
|
```ts
|
|
209
|
-
import { simulateAgent } from "@statelyai/agent";
|
|
210
|
-
|
|
208
|
+
import { simulateAgent } from "@statelyai/agent/testing";
|
|
211
209
|
const dryRun = await simulateAgent(machine, {
|
|
212
210
|
input: { ticket: "" },
|
|
213
211
|
script: {
|