@statelyai/agent 2.0.0-alpha.24 → 2.0.0-alpha.26
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 +1088 -0
- package/dist/testing.d.cts +617 -0
- package/dist/testing.d.mts +617 -0
- package/dist/testing.mjs +1079 -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-C2DPqomn.d.mts +109 -0
- package/dist/utils-ceStNCOh.d.cts +109 -0
- package/package.json +26 -5
- package/readme.md +5 -3
- 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,109 @@
|
|
|
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, v as SystemMessage, x as ToolMessage, y as TextPart } from "./types-B1Qs2q3q.cjs";
|
|
2
|
+
import { AnyMachineSnapshot, AnyStateMachine, StateValue } from "xstate";
|
|
3
|
+
|
|
4
|
+
//#region src/utils.d.ts
|
|
5
|
+
/** Returns the human-readable text carried by a message, ignoring non-text parts. */
|
|
6
|
+
declare function getMessageText(message: AgentMessage): string;
|
|
7
|
+
/**
|
|
8
|
+
* A stable, dependency-free structural fingerprint of a machine — a short hex
|
|
9
|
+
* `djb2` hash over its **structural** config only: state ids/nesting, transition
|
|
10
|
+
* event types and targets, invoke `src`s, `initial`, and any other serializable
|
|
11
|
+
* config fields. Function values (context/output builders, prompts, inline
|
|
12
|
+
* guards/actions) are excluded entirely, so two machines that differ only in
|
|
13
|
+
* their prompts or executors hash identically; adding/removing/retargeting a
|
|
14
|
+
* state or transition changes the hash.
|
|
15
|
+
*
|
|
16
|
+
* Used by {@link runAgent} to stamp settled snapshots with a `version` and to
|
|
17
|
+
* detect a structurally-edited machine on resume. It is a change detector, not
|
|
18
|
+
* a cryptographic digest — collisions are possible but unlikely for real
|
|
19
|
+
* configs. Declare `createMachine({ version })` to pin an explicit version instead.
|
|
20
|
+
*/
|
|
21
|
+
declare function getMachineStructuralHash(machine: AnyStateMachine): string;
|
|
22
|
+
/** Builds a {@link UserMessage} from a string or multimodal content parts. */
|
|
23
|
+
declare function userMessage(content: string | Array<TextPart | ImagePart | FilePart>): UserMessage;
|
|
24
|
+
/** Builds an {@link AssistantMessage} from a string or content parts (text, files, tool calls/results). */
|
|
25
|
+
declare function assistantMessage(content: string | Array<TextPart | FilePart | ToolCallPart | ToolResultPart>): AssistantMessage;
|
|
26
|
+
/** Builds a {@link SystemMessage}. */
|
|
27
|
+
declare function systemMessage(content: string): SystemMessage;
|
|
28
|
+
/** Builds a {@link ToolMessage} from one or more tool-result parts. */
|
|
29
|
+
declare function toolMessage(content: Array<ToolResultPart>): ToolMessage;
|
|
30
|
+
type MetaOfSnapshot<TSnapshot extends {
|
|
31
|
+
getMeta(): Record<string, unknown>;
|
|
32
|
+
}> = NonNullable<ReturnType<TSnapshot["getMeta"]>[keyof ReturnType<TSnapshot["getMeta"]>]>;
|
|
33
|
+
/**
|
|
34
|
+
* Returns the merged `meta` of a snapshot's active state(s) — the typed
|
|
35
|
+
* replacement for the `Object.values(snapshot.getMeta())[0]` dance.
|
|
36
|
+
*
|
|
37
|
+
* `snapshot.getMeta()` is keyed by state id; a leaf machine has one active
|
|
38
|
+
* state, but parallel/nested machines can have several. This shallow-merges
|
|
39
|
+
* every active state's meta into one object and returns `{}` when no active
|
|
40
|
+
* state declares meta.
|
|
41
|
+
*
|
|
42
|
+
* Merge order is fixed and does not depend on XState's internal node order:
|
|
43
|
+
* entries are sorted by structural depth (the state node's distance from the
|
|
44
|
+
* root, regardless of custom `id` strings), then by state id lexicographically,
|
|
45
|
+
* and merged in that order. So a deeper state's key wins over an ancestor's,
|
|
46
|
+
* and between equal-depth parallel siblings the later state id alphabetically
|
|
47
|
+
* wins.
|
|
48
|
+
*
|
|
49
|
+
* The return type is recovered from the snapshot's own `getMeta()` type, so a
|
|
50
|
+
* schema-typed machine (`setupAgent({ meta })`) yields the meta schema's
|
|
51
|
+
* output type. Pass an explicit `TMeta` to override when the snapshot is
|
|
52
|
+
* untyped (e.g. `AnyMachineSnapshot`).
|
|
53
|
+
*
|
|
54
|
+
* @example HITL: read the current state's interaction protocol off an idle
|
|
55
|
+
* snapshot to render for a human.
|
|
56
|
+
* ```ts
|
|
57
|
+
* const { interaction } = getStateMeta(result.snapshot);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
declare function getStateMeta<TSnapshot extends {
|
|
61
|
+
getMeta(): Record<string, unknown>;
|
|
62
|
+
} = AnyMachineSnapshot, TMeta = MetaOfSnapshot<TSnapshot>>(snapshot: TSnapshot): Partial<TMeta>;
|
|
63
|
+
/**
|
|
64
|
+
* Renders a snapshot's state value as one deterministic string, so a log line,
|
|
65
|
+
* a progress field, or a test assertion reads the same on every run.
|
|
66
|
+
*
|
|
67
|
+
* - An atomic state is its own name: `'writing'`.
|
|
68
|
+
* - A nested state joins with dots: `{ review: { editing: 'draft' } }` →
|
|
69
|
+
* `'review.editing.draft'`.
|
|
70
|
+
* - A parallel state brackets its regions, sorted by region name, so key order
|
|
71
|
+
* never leaks into the string: `{ p: { left: 'x', right: { a: 'b' } } }` →
|
|
72
|
+
* `'p:{left.x,right.a.b}'`.
|
|
73
|
+
*
|
|
74
|
+
* Prefer this over `String(snapshot.value)`, which renders every non-atomic
|
|
75
|
+
* value as `[object Object]`.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* onTransition: (snapshot) => console.log(getStatePath(snapshot));
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function getStatePath(snapshot: {
|
|
83
|
+
value: StateValue;
|
|
84
|
+
status?: string;
|
|
85
|
+
} | StateValue): string;
|
|
86
|
+
/**
|
|
87
|
+
* Structural guard for a {@link StandardSchemaV1}: `true` when `value` carries
|
|
88
|
+
* the `~standard` marker. Used to tell an already-schema'd tool `inputSchema`
|
|
89
|
+
* (a Zod/Valibot/… schema) apart from an SDK-specific schema wrapper that core
|
|
90
|
+
* can't read directly — see the `ai-sdk` tool pass-through.
|
|
91
|
+
*/
|
|
92
|
+
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
93
|
+
/**
|
|
94
|
+
* Pulls the JSON Schema off a {@link StandardSchemaV1} via its optional
|
|
95
|
+
* `~standard.jsonSchema.input()` extension (implemented by e.g. Zod v4's
|
|
96
|
+
* `z.toJSONSchema`), awaiting it when the producer is async. Returns
|
|
97
|
+
* `undefined` when the schema doesn't expose the extension. Use this to build
|
|
98
|
+
* a provider request's `response_format`/tool `parameters` from a schema.
|
|
99
|
+
*/
|
|
100
|
+
declare function getJsonSchema(schema?: StandardSchemaV1): Promise<Record<string, unknown> | undefined>;
|
|
101
|
+
/**
|
|
102
|
+
* Synchronous variant of {@link getJsonSchema}, for call sites that can't
|
|
103
|
+
* await (building tool/event descriptors inline). An async JSON Schema
|
|
104
|
+
* producer is treated as absent (returns `undefined`) — in practice Zod's
|
|
105
|
+
* `z.toJSONSchema` resolves synchronously.
|
|
106
|
+
*/
|
|
107
|
+
declare function getJsonSchemaSync(schema?: StandardSchemaV1): Record<string, unknown> | undefined;
|
|
108
|
+
//#endregion
|
|
109
|
+
export { getMachineStructuralHash as a, getStatePath as c, toolMessage as d, userMessage as f, getJsonSchemaSync as i, isStandardSchema as l, assistantMessage as n, getMessageText as o, getJsonSchema as r, getStateMeta as s, MetaOfSnapshot as t, systemMessage as u };
|
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.26",
|
|
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",
|
|
@@ -95,6 +115,7 @@
|
|
|
95
115
|
},
|
|
96
116
|
"devDependencies": {
|
|
97
117
|
"@ai-sdk/openai": "^4.0.0",
|
|
118
|
+
"@ai-sdk/typesafe-ai": "3.0.6",
|
|
98
119
|
"@anthropic-ai/sdk": "^0.120.0",
|
|
99
120
|
"@changesets/changelog-github": "^0.5.2",
|
|
100
121
|
"@changesets/cli": "^2.31.1",
|
|
@@ -108,7 +129,7 @@
|
|
|
108
129
|
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
109
130
|
"@types/node": "^20.19.43",
|
|
110
131
|
"@types/react": "^19.2.18",
|
|
111
|
-
"ai": "^7.0.
|
|
132
|
+
"ai": "^7.0.113",
|
|
112
133
|
"ajv": "^8.20.0",
|
|
113
134
|
"braintrust": "^3.28.0",
|
|
114
135
|
"dotenv": "^16.6.1",
|
|
@@ -123,7 +144,7 @@
|
|
|
123
144
|
"typescript": "^5.9.3",
|
|
124
145
|
"valibot": "^1.4.2",
|
|
125
146
|
"vitest": "^4.1.11",
|
|
126
|
-
"xstate": "6.0.0-alpha.
|
|
147
|
+
"xstate": "6.0.0-alpha.57",
|
|
127
148
|
"zod": "^4.4.3"
|
|
128
149
|
},
|
|
129
150
|
"peerDependencies": {
|
|
@@ -131,7 +152,7 @@
|
|
|
131
152
|
"ai": "^7.0.0",
|
|
132
153
|
"ajv": "^8.20.0",
|
|
133
154
|
"openai": ">=5.0.0 <8",
|
|
134
|
-
"xstate": ">=6.0.0-alpha.
|
|
155
|
+
"xstate": ">=6.0.0-alpha.57 <6.0.0"
|
|
135
156
|
},
|
|
136
157
|
"peerDependenciesMeta": {
|
|
137
158
|
"@opentelemetry/api": {
|
|
@@ -168,7 +189,7 @@
|
|
|
168
189
|
"check:dts": "tsc -p fixtures/dts-consumer/tsconfig.json",
|
|
169
190
|
"test": "vitest",
|
|
170
191
|
"test:live": "LIVE_TESTS=1 vitest --run",
|
|
171
|
-
"test:ci": "vitest --run && pnpm run
|
|
192
|
+
"test:ci": "vitest --run && pnpm run build && pnpm run test:cloudflare && pnpm --filter @statelyai/agent-demo test",
|
|
172
193
|
"changeset": "changeset",
|
|
173
194
|
"release": "changeset publish",
|
|
174
195
|
"version": "changeset version"
|
package/readme.md
CHANGED
|
@@ -40,6 +40,8 @@ For the optional raw OpenAI SDK executor (`@statelyai/agent/openai`):
|
|
|
40
40
|
pnpm add openai
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
Classification, grading, relevance, and yes/no checks are judgments: call the AI SDK's `experimental_evaluate` with `@ai-sdk/typesafe-ai` (`pnpm add ai @ai-sdk/typesafe-ai`) from an ordinary actor; see [Judgments with the AI SDK](docs/judgments.md).
|
|
44
|
+
|
|
43
45
|
Requirements:
|
|
44
46
|
|
|
45
47
|
- Node 22.18 or newer, and XState v6 alpha.46 or newer.
|
|
@@ -139,9 +141,9 @@ const liveResult = await runAgent(refundMachine, {
|
|
|
139
141
|
});
|
|
140
142
|
```
|
|
141
143
|
|
|
142
|
-
For a machine with several requests, `
|
|
144
|
+
For a machine with several requests, the executor routes on `request.name`, or `MockLanguageModelV3` from `ai/test` stands in for the provider behind `createAiSdkExecutors`. See [Evals](docs/evals.md#testing-without-a-provider).
|
|
143
145
|
|
|
144
|
-
Passing
|
|
146
|
+
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
147
|
|
|
146
148
|
## Architecture
|
|
147
149
|
|
|
@@ -155,7 +157,7 @@ flowchart LR
|
|
|
155
157
|
R -->|event or output| M
|
|
156
158
|
```
|
|
157
159
|
|
|
158
|
-
The machine never talks to a model directly, so swapping `createAiSdkExecutors` for
|
|
160
|
+
The machine never talks to a model directly, so swapping `createAiSdkExecutors` for your own functions changes nothing about the agent.
|
|
159
161
|
|
|
160
162
|
The example above has one model decision and two final outcomes. Real machines add approval states, retries, parallel work, child agents, and long-running waits without changing how control flow is represented.
|
|
161
163
|
|
|
@@ -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: {
|