@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
package/dist/ai-sdk.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { J as isStandardSchema, L as getRegisteredAgentModels, T as getAgentOutputMode, l as renderDecisionAttempts, x as buildEnvelopeSchema } from "./decision-CQdrKc8k.mjs";
|
|
1
|
+
import { J as isStandardSchema, T as getAgentOutputMode, b as buildEnvelopeSchema, l as renderDecisionAttempts } from "./decision-BezSD_YC.mjs";
|
|
3
2
|
import { NoObjectGeneratedError, Output, generateText, stepCountIs, streamText, tool } from "ai";
|
|
4
|
-
//#region src/ai-sdk/
|
|
3
|
+
//#region src/ai-sdk/mappers.ts
|
|
5
4
|
/**
|
|
6
5
|
* Maps an {@link AgentTools} map onto AI SDK `tool()` definitions. A tool that
|
|
7
6
|
* already carries its own Standard Schema `inputSchema` — an AI SDK
|
|
@@ -10,8 +9,7 @@ import { NoObjectGeneratedError, Output, generateText, stepCountIs, streamText,
|
|
|
10
9
|
* every extra property (`providerOptions`, `toModelOutput`, …) survives. A bare
|
|
11
10
|
* `AgentToolExecute` function becomes a tool with an unconstrained input schema;
|
|
12
11
|
* a minimal descriptor with no readable schema is converted with a permissive
|
|
13
|
-
* fallback. Used
|
|
14
|
-
* building AI SDK calls by hand outside `createAiSdkExecutors`.
|
|
12
|
+
* fallback. Used by {@link toAiSdkCallSettings}.
|
|
15
13
|
*/
|
|
16
14
|
function toAiSdkTools(tools) {
|
|
17
15
|
const entries = [];
|
|
@@ -44,9 +42,6 @@ function toAiSdkTools(tools) {
|
|
|
44
42
|
}
|
|
45
43
|
return Object.fromEntries(entries);
|
|
46
44
|
}
|
|
47
|
-
function maxStepsSetting(request) {
|
|
48
|
-
return typeof request.metadata?.maxSteps === "number" ? { stopWhen: stepCountIs(request.metadata.maxSteps) } : {};
|
|
49
|
-
}
|
|
50
45
|
const unknownSchema = { "~standard": {
|
|
51
46
|
version: 1,
|
|
52
47
|
vendor: "statelyai-agent",
|
|
@@ -54,35 +49,6 @@ const unknownSchema = { "~standard": {
|
|
|
54
49
|
jsonSchema: { input: () => ({}) }
|
|
55
50
|
} };
|
|
56
51
|
/**
|
|
57
|
-
* Identity helper for a `models` map whose value is exported. Returns the map
|
|
58
|
-
* unchanged, but types it as {@link AiSdkModelMap}`<keyof T & string>` — a
|
|
59
|
-
* portable, nameable type — so an exported `const models = defineModels({...})`
|
|
60
|
-
* needs no `Record<'a' | 'b', LanguageModel>` annotation and never triggers
|
|
61
|
-
* TS2742 ("inferred type cannot be named without a reference to …"). The exact
|
|
62
|
-
* ref keys survive, so `createAiSdkExecutors({ models })` and
|
|
63
|
-
* `setupAgent({ models })` still infer/autocomplete them.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```ts
|
|
67
|
-
* export const models = defineModels({
|
|
68
|
-
* quick: openai('gpt-5.4-mini'),
|
|
69
|
-
* deep: openai('gpt-5.4'),
|
|
70
|
-
* });
|
|
71
|
-
* // typeof models === AiSdkModelMap<'quick' | 'deep'>
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
function defineModels(models) {
|
|
75
|
-
return models;
|
|
76
|
-
}
|
|
77
|
-
function resolveAiSdkModel(options, modelRef) {
|
|
78
|
-
if (options.resolveModel) return options.resolveModel(modelRef);
|
|
79
|
-
const models = options.models;
|
|
80
|
-
if (!models) throw new Error(`createAiSdkExecutors: no model resolver configured for '${modelRef}'.`);
|
|
81
|
-
const model = models[modelRef];
|
|
82
|
-
if (!model) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
|
|
83
|
-
return model;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
52
|
* AI SDK request-mapping settings shared by `generateText`/`streamText`.
|
|
87
53
|
* `AgentTextRequest.messages` (`AgentMessage[]`) and AI SDK's `ModelMessage[]`
|
|
88
54
|
* are structurally compatible by design (§1 of .scratch/p0-design.md) — the cast
|
|
@@ -147,6 +113,65 @@ function extractFirstJsonValue(text) {
|
|
|
147
113
|
}
|
|
148
114
|
}
|
|
149
115
|
}
|
|
116
|
+
/** One AI SDK `tool()` per candidate event — the "tool-per-event +
|
|
117
|
+
* toolChoice: 'required'" recipe from .scratch/p0-design.md §2.6. */
|
|
118
|
+
function toAiSdkEventTools(events) {
|
|
119
|
+
return Object.fromEntries(events.map((event) => [event.toolName, tool({
|
|
120
|
+
description: `Choose the '${event.type}' move.`,
|
|
121
|
+
inputSchema: event.inputSchema ? event.inputSchema : unknownSchema
|
|
122
|
+
})]));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Messages for a decision request, with prior failed `attempts` (§2.6)
|
|
126
|
+
* rendered as appended user messages (via core's {@link renderDecisionAttempts})
|
|
127
|
+
* so retries converge. Core never rewrites prompts — this is adapter business.
|
|
128
|
+
*/
|
|
129
|
+
function toDecisionMessages(request) {
|
|
130
|
+
if (!request.messages && request.attempts.length === 0) return;
|
|
131
|
+
const messages = [...request.messages ?? (request.prompt !== void 0 ? [{
|
|
132
|
+
role: "user",
|
|
133
|
+
content: request.prompt
|
|
134
|
+
}] : [])];
|
|
135
|
+
for (const attempt of renderDecisionAttempts(request)) messages.push({
|
|
136
|
+
role: "user",
|
|
137
|
+
content: attempt.content
|
|
138
|
+
});
|
|
139
|
+
return messages;
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/ai-sdk/index.ts
|
|
143
|
+
function maxStepsSetting(request) {
|
|
144
|
+
return typeof request.metadata?.maxSteps === "number" ? { stopWhen: stepCountIs(request.metadata.maxSteps) } : {};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Identity helper for a `models` map whose value is exported. Returns the map
|
|
148
|
+
* unchanged, but types it as {@link AiSdkModelMap}`<keyof T & string>` — a
|
|
149
|
+
* portable, nameable type — so an exported `const models = defineModels({...})`
|
|
150
|
+
* needs no `Record<'a' | 'b', LanguageModel>` annotation and never triggers
|
|
151
|
+
* TS2742 ("inferred type cannot be named without a reference to …"). The exact
|
|
152
|
+
* ref keys survive, so `createAiSdkExecutors({ models })` and
|
|
153
|
+
* `setupAgent({ models })` still infer/autocomplete them.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* export const models = defineModels({
|
|
158
|
+
* quick: openai('gpt-5.4-mini'),
|
|
159
|
+
* deep: openai('gpt-5.4'),
|
|
160
|
+
* });
|
|
161
|
+
* // typeof models === AiSdkModelMap<'quick' | 'deep'>
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function defineModels(models) {
|
|
165
|
+
return models;
|
|
166
|
+
}
|
|
167
|
+
function resolveAiSdkModel(options, modelRef) {
|
|
168
|
+
if (options.resolveModel) return options.resolveModel(modelRef);
|
|
169
|
+
const models = options.models;
|
|
170
|
+
if (!models) throw new Error(`createAiSdkExecutors: no model resolver configured for '${modelRef}'.`);
|
|
171
|
+
const model = models[modelRef];
|
|
172
|
+
if (!model) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
|
|
173
|
+
return model;
|
|
174
|
+
}
|
|
150
175
|
function withJsonRepair(output) {
|
|
151
176
|
return {
|
|
152
177
|
...output,
|
|
@@ -274,58 +299,5 @@ function createAiSdkExecutors(options) {
|
|
|
274
299
|
decide
|
|
275
300
|
};
|
|
276
301
|
}
|
|
277
|
-
/** AI SDK host for a machine authored with `setupAgent({ models })`. */
|
|
278
|
-
function runAgent(machine, options) {
|
|
279
|
-
const models = getRegisteredAgentModels(machine);
|
|
280
|
-
if (!models || Object.keys(models).length === 0) throw new Error("AI SDK runAgent: machine has no models. Pass `models` to setupAgent, or use core runAgent with explicit executors.");
|
|
281
|
-
return runAgent$1(machine, {
|
|
282
|
-
...options,
|
|
283
|
-
executors: createAiSdkExecutors({ models })
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
function createAgent(config) {
|
|
287
|
-
const { model, models: configuredModels, schemas, ...machineConfig } = config;
|
|
288
|
-
const models = configuredModels ?? { default: model };
|
|
289
|
-
const executors = createAiSdkExecutors({ models });
|
|
290
|
-
const machine = setupAgent({
|
|
291
|
-
...schemas,
|
|
292
|
-
models
|
|
293
|
-
}).createMachine(machineConfig);
|
|
294
|
-
return {
|
|
295
|
-
machine,
|
|
296
|
-
run(runInput, options = {}) {
|
|
297
|
-
return runAgent$1(machine, {
|
|
298
|
-
...options,
|
|
299
|
-
input: runInput,
|
|
300
|
-
executors
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
/** One AI SDK `tool()` per candidate event — the "tool-per-event +
|
|
306
|
-
* toolChoice: 'required'" recipe from .scratch/p0-design.md §2.6. */
|
|
307
|
-
function toAiSdkEventTools(events) {
|
|
308
|
-
return Object.fromEntries(events.map((event) => [event.toolName, tool({
|
|
309
|
-
description: `Choose the '${event.type}' move.`,
|
|
310
|
-
inputSchema: event.inputSchema ? event.inputSchema : unknownSchema
|
|
311
|
-
})]));
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Messages for a decision request, with prior failed `attempts` (§2.6)
|
|
315
|
-
* rendered as appended user messages (via core's {@link renderDecisionAttempts})
|
|
316
|
-
* so retries converge. Core never rewrites prompts — this is adapter business.
|
|
317
|
-
*/
|
|
318
|
-
function toDecisionMessages(request) {
|
|
319
|
-
if (!request.messages && request.attempts.length === 0) return;
|
|
320
|
-
const messages = [...request.messages ?? (request.prompt !== void 0 ? [{
|
|
321
|
-
role: "user",
|
|
322
|
-
content: request.prompt
|
|
323
|
-
}] : [])];
|
|
324
|
-
for (const attempt of renderDecisionAttempts(request)) messages.push({
|
|
325
|
-
role: "user",
|
|
326
|
-
content: attempt.content
|
|
327
|
-
});
|
|
328
|
-
return messages;
|
|
329
|
-
}
|
|
330
302
|
//#endregion
|
|
331
|
-
export {
|
|
303
|
+
export { createAiSdkExecutors, defineModels };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as AgentError } from "./errors-CeSXQx0v.mjs";
|
|
1
2
|
import { createAsyncLogic, createLogic, getNextTransitions } from "xstate";
|
|
2
3
|
//#region src/utils.ts
|
|
3
4
|
/**
|
|
@@ -174,8 +175,7 @@ function getAgentMessages(snapshot) {
|
|
|
174
175
|
* Structural guard for a {@link StandardSchemaV1}: `true` when `value` carries
|
|
175
176
|
* the `~standard` marker. Used to tell an already-schema'd tool `inputSchema`
|
|
176
177
|
* (a Zod/Valibot/… schema) apart from an SDK-specific schema wrapper that core
|
|
177
|
-
* can't read directly — see the `ai-sdk` tool pass-through
|
|
178
|
-
* tool serialization.
|
|
178
|
+
* can't read directly — see the `ai-sdk` tool pass-through.
|
|
179
179
|
*/
|
|
180
180
|
function isStandardSchema(value) {
|
|
181
181
|
return typeof value === "object" && value !== null && "~standard" in value;
|
|
@@ -221,9 +221,6 @@ function validateSchemaSync(schema, value) {
|
|
|
221
221
|
//#endregion
|
|
222
222
|
//#region src/internal/registry.ts
|
|
223
223
|
const agentExecutionOptions = /* @__PURE__ */ new WeakMap();
|
|
224
|
-
function getRegisteredAgentModels(machine) {
|
|
225
|
-
return agentExecutionOptions.get(machine)?.models;
|
|
226
|
-
}
|
|
227
224
|
/**
|
|
228
225
|
* Machine-carried wait-state predicates, keyed on the machine's root `config`
|
|
229
226
|
* object. `config` is shared by reference across `machine.provide(...)` (unlike
|
|
@@ -239,6 +236,24 @@ function getMachineSuspensionPredicate(machine) {
|
|
|
239
236
|
const config = machine.config;
|
|
240
237
|
return config ? machineSuspensionPredicates.get(config) : void 0;
|
|
241
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Lint-reachability sidecar for `fromConfig` machines.
|
|
241
|
+
*
|
|
242
|
+
* Static transition targets declared by the source config of a
|
|
243
|
+
* `setupAgent.fromConfig` machine, as `dotted state path → declared target
|
|
244
|
+
* strings` (every `on`/`always`/`after`/`onDone`/`choice` target plus each
|
|
245
|
+
* invoke's `onDone`/`onError`). The JSON layer folds a transition that carries a
|
|
246
|
+
* context patch into an opaque resolver function, erasing its target from
|
|
247
|
+
* `machine.config` — so `lintAgentMachine`'s reachability walk reads the
|
|
248
|
+
* targets from here instead. Keyed on the machine's root `config` object (like
|
|
249
|
+
* {@link machineSuspensionPredicates}) so it survives `machine.provide(...)`.
|
|
250
|
+
*/
|
|
251
|
+
const machineStaticTransitionTargets = /* @__PURE__ */ new WeakMap();
|
|
252
|
+
/** Reads the {@link machineStaticTransitionTargets} map carried by `machine` (via its root `config`), if any. */
|
|
253
|
+
function getMachineStaticTransitionTargets(machine) {
|
|
254
|
+
const config = machine.config;
|
|
255
|
+
return config ? machineStaticTransitionTargets.get(config) : void 0;
|
|
256
|
+
}
|
|
242
257
|
const unboundPlaceholderLogics = /* @__PURE__ */ new WeakSet();
|
|
243
258
|
/** Text/decision logics created WITH their own executor (withExecutor or the
|
|
244
259
|
* factory's second arg) — these are runnable as-is, so runAgent's bind check
|
|
@@ -246,7 +261,7 @@ const unboundPlaceholderLogics = /* @__PURE__ */ new WeakSet();
|
|
|
246
261
|
const executorBoundLogics = /* @__PURE__ */ new WeakSet();
|
|
247
262
|
function missingActor(src) {
|
|
248
263
|
const logic = createAsyncLogic({ run: async () => {
|
|
249
|
-
throw new Error(`'${src}' has no host execution. Provide an implementation with machine.provide({
|
|
264
|
+
throw new Error(`'${src}' has no host execution. Provide an implementation with machine.provide({ actors: { '${src}': ... } }).`);
|
|
250
265
|
} });
|
|
251
266
|
unboundPlaceholderLogics.add(logic);
|
|
252
267
|
return logic;
|
|
@@ -290,11 +305,44 @@ function parseModelRef(modelRef) {
|
|
|
290
305
|
modelId: modelRef.slice(slash + 1)
|
|
291
306
|
};
|
|
292
307
|
}
|
|
308
|
+
/** The token fields {@link AgentUsage} aggregates. @internal */
|
|
309
|
+
const AGENT_USAGE_TOKEN_FIELDS = [
|
|
310
|
+
"inputTokens",
|
|
311
|
+
"outputTokens",
|
|
312
|
+
"totalTokens",
|
|
313
|
+
"reasoningTokens",
|
|
314
|
+
"cachedInputTokens"
|
|
315
|
+
];
|
|
316
|
+
/**
|
|
317
|
+
* Reads a per-call {@link AgentCallUsage} off a raw executor result's `usage`
|
|
318
|
+
* field, keeping only finite numbers. Returns `undefined` when the result
|
|
319
|
+
* reports no usage at all. Works for our `{ output, usage }` envelope, for a
|
|
320
|
+
* raw Vercel AI SDK result (its `LanguageModelUsage` carries the same flat
|
|
321
|
+
* field names), and for any custom executor that follows the shape.
|
|
322
|
+
*
|
|
323
|
+
* @internal
|
|
324
|
+
*/
|
|
325
|
+
function extractCallUsage(raw) {
|
|
326
|
+
const usage = raw?.usage;
|
|
327
|
+
if (!usage || typeof usage !== "object") return;
|
|
328
|
+
let out;
|
|
329
|
+
for (const field of AGENT_USAGE_TOKEN_FIELDS) {
|
|
330
|
+
const value = usage[field];
|
|
331
|
+
if (typeof value === "number" && Number.isFinite(value)) (out ??= {})[field] = value;
|
|
332
|
+
}
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
293
335
|
const agentTextInputSchema = { "~standard": {
|
|
294
336
|
version: 1,
|
|
295
337
|
vendor: "statelyai-agent",
|
|
296
338
|
validate(value) {
|
|
297
|
-
|
|
339
|
+
if (!value || typeof value !== "object") return { issues: [{ message: "Expected agent text input object" }] };
|
|
340
|
+
const request = value;
|
|
341
|
+
if (typeof request.model !== "string") return { issues: [{ message: "Expected agent text input with a string `model`" }] };
|
|
342
|
+
const hasPrompt = typeof request.prompt === "string" && request.prompt.length > 0;
|
|
343
|
+
const hasMessages = Array.isArray(request.messages) && request.messages.length > 0;
|
|
344
|
+
if (!hasPrompt && !hasMessages) return { issues: [{ message: `Agent text request${request.name ? ` '${request.name}'` : ""} has neither a non-empty \`prompt\` nor \`messages\` — provide at least one so the model has something to respond to.` }] };
|
|
345
|
+
return { value: request };
|
|
298
346
|
}
|
|
299
347
|
} };
|
|
300
348
|
const unknownOutputSchema = { "~standard": {
|
|
@@ -311,9 +359,16 @@ const stringOutputSchema = { "~standard": {
|
|
|
311
359
|
return typeof value === "string" ? { value } : { issues: [{ message: "Expected string output" }] };
|
|
312
360
|
}
|
|
313
361
|
} };
|
|
362
|
+
const noInputSchema = { "~standard": {
|
|
363
|
+
version: 1,
|
|
364
|
+
vendor: "statelyai-agent",
|
|
365
|
+
validate(value) {
|
|
366
|
+
return { value };
|
|
367
|
+
}
|
|
368
|
+
} };
|
|
314
369
|
function createBuiltinTextActor(src, mode, outputSchema) {
|
|
315
370
|
const logic = createAsyncLogic({ run: async () => {
|
|
316
|
-
throw new Error(`'${src}' has no host execution. Provide an implementation with machine.provide({
|
|
371
|
+
throw new Error(`'${src}' has no host execution. Provide an implementation with machine.provide({ actors: { '${src}': ... } }) or execute the returned agent request with executeAgentRequest(...).`);
|
|
317
372
|
} });
|
|
318
373
|
return Object.assign(logic, {
|
|
319
374
|
kind: "statelyai.textLogic",
|
|
@@ -362,7 +417,7 @@ const builtinTextActors = {
|
|
|
362
417
|
};
|
|
363
418
|
/** The unbound `agent.userInput` builtin registered by setupAgent (an unbound-placeholder logic — see internal/registry.ts). Output is `string` — what the human typed. @internal */
|
|
364
419
|
const userInputActor = createAsyncLogic({ run: async () => {
|
|
365
|
-
throw new Error(`'${USER_INPUT_ACTOR}' has no host execution. Provide an implementation with machine.provide({
|
|
420
|
+
throw new Error(`'${USER_INPUT_ACTOR}' has no host execution. Provide an implementation with machine.provide({ actors: { '${USER_INPUT_ACTOR}': ... } }).`);
|
|
366
421
|
} });
|
|
367
422
|
unboundPlaceholderLogics.add(userInputActor);
|
|
368
423
|
/**
|
|
@@ -381,7 +436,7 @@ function resolveTextLogicValue(value, args) {
|
|
|
381
436
|
/**
|
|
382
437
|
* Creates reusable, standalone {@link TextLogic}: an actor that, when run,
|
|
383
438
|
* resolves typed input to typed output via a model call. Register the
|
|
384
|
-
* result under `
|
|
439
|
+
* result under `actors:` and invoke it by name (equivalent to what
|
|
385
440
|
* `setupAgent({ requests })` builds internally for each request entry). Pass
|
|
386
441
|
* `execute` here, or bind it later with `.withExecutor(...)`, a runtime
|
|
387
442
|
* adapter's `machine.provide(...)`, or `runAgent`'s `generateText`/
|
|
@@ -399,8 +454,12 @@ function resolveTextLogicValue(value, args) {
|
|
|
399
454
|
* ```
|
|
400
455
|
*/
|
|
401
456
|
function createTextLogic(config, execute) {
|
|
457
|
+
const schemas = {
|
|
458
|
+
input: config.schemas?.input ?? noInputSchema,
|
|
459
|
+
output: config.schemas?.output ?? stringOutputSchema
|
|
460
|
+
};
|
|
402
461
|
const request = (input) => {
|
|
403
|
-
const args = { input: validateSchemaSync(
|
|
462
|
+
const args = { input: validateSchemaSync(schemas.input, input) };
|
|
404
463
|
return {
|
|
405
464
|
name: resolveTextLogicValue(config.name, args),
|
|
406
465
|
model: resolveTextLogicValue(config.model, args),
|
|
@@ -409,7 +468,7 @@ function createTextLogic(config, execute) {
|
|
|
409
468
|
messages: resolveTextLogicValue(config.messages, args),
|
|
410
469
|
tools: resolveTextLogicValue(config.tools, args),
|
|
411
470
|
toolChoice: resolveTextLogicValue(config.toolChoice, args),
|
|
412
|
-
outputSchema:
|
|
471
|
+
outputSchema: schemas.output,
|
|
413
472
|
reasoning: resolveTextLogicValue(config.reasoning, args),
|
|
414
473
|
temperature: resolveTextLogicValue(config.temperature, args),
|
|
415
474
|
maxOutputTokens: resolveTextLogicValue(config.maxOutputTokens, args),
|
|
@@ -422,7 +481,7 @@ function createTextLogic(config, execute) {
|
|
|
422
481
|
};
|
|
423
482
|
const logic = createAsyncLogic({ run: async ({ input, signal, system, self }, enq) => {
|
|
424
483
|
const resolvedRequest = request(input);
|
|
425
|
-
if (!execute) throw new Error("Text logic has no host execution. Pass an executor as the second argument to createTextLogic(...), provide a runtime adapter, or extract it with
|
|
484
|
+
if (!execute) throw new Error("Text logic has no host execution. Pass an executor as the second argument to createTextLogic(...), provide a runtime adapter, or extract it with getAgentEffects(..., { actors }).");
|
|
426
485
|
const result = await execute({
|
|
427
486
|
input,
|
|
428
487
|
request: resolvedRequest,
|
|
@@ -433,16 +492,16 @@ function createTextLogic(config, execute) {
|
|
|
433
492
|
});
|
|
434
493
|
const selfId = self?.id;
|
|
435
494
|
const output = await normalizeGeneratorResult(result, typeof selfId === "string" ? selfId : "text logic", { request: resolvedRequest });
|
|
436
|
-
return validateSchemaSync(
|
|
495
|
+
return validateSchemaSync(schemas.output, output);
|
|
437
496
|
} });
|
|
438
497
|
const textLogic = Object.assign(logic, {
|
|
439
498
|
kind: "statelyai.textLogic",
|
|
440
499
|
mode: config.mode ?? "generate",
|
|
441
|
-
schemas
|
|
500
|
+
schemas,
|
|
442
501
|
request,
|
|
443
502
|
async execute(input, executors) {
|
|
444
503
|
const { output } = await executeAgentTextRequest(config.mode ?? "generate", "textLogic", request(input), executors);
|
|
445
|
-
return validateSchemaSync(
|
|
504
|
+
return validateSchemaSync(schemas.output, output);
|
|
446
505
|
},
|
|
447
506
|
withExecutor(nextExecute) {
|
|
448
507
|
return createTextLogic(config, nextExecute);
|
|
@@ -462,7 +521,7 @@ function createTextLogic(config, execute) {
|
|
|
462
521
|
* @example
|
|
463
522
|
* ```ts
|
|
464
523
|
* childMachine.provide({
|
|
465
|
-
*
|
|
524
|
+
* actors: {
|
|
466
525
|
* researchTopic: bindRequestExecutor(setup.requests.researchTopic, generateText),
|
|
467
526
|
* },
|
|
468
527
|
* });
|
|
@@ -500,10 +559,6 @@ function getAgentOutputMode(schema) {
|
|
|
500
559
|
if (jsonSchema.type === void 0 && ("anyOf" in jsonSchema || "oneOf" in jsonSchema || "allOf" in jsonSchema)) return "structured";
|
|
501
560
|
return "text";
|
|
502
561
|
}
|
|
503
|
-
/** True when {@link getAgentOutputMode} classifies `schema` as `'structured'`. */
|
|
504
|
-
function isStructuredOutputSchema(schema) {
|
|
505
|
-
return getAgentOutputMode(schema) === "structured";
|
|
506
|
-
}
|
|
507
562
|
/**
|
|
508
563
|
* Builds the uniform structured-output envelope schema every structured request
|
|
509
564
|
* is sent to the provider as: a root object `{ result: <inner> }`, plus — when
|
|
@@ -654,7 +709,7 @@ function invalidGeneratorResult(id) {
|
|
|
654
709
|
}
|
|
655
710
|
//#endregion
|
|
656
711
|
//#region src/events.ts
|
|
657
|
-
/** Default prefix for the synthetic tool name generated per candidate event (e.g. `send_event_ASK`). Override per-request with {@link AgentEventToolNameResolver}. */
|
|
712
|
+
/** Default prefix for the synthetic tool name generated per candidate event (e.g. `send_event_ASK`). Override per-request with {@link AgentEventToolNameResolver}. @internal */
|
|
658
713
|
const EVENT_TOOL_PREFIX = "send_event_";
|
|
659
714
|
function hashString(value) {
|
|
660
715
|
let hash = 5381;
|
|
@@ -689,6 +744,18 @@ function matchesEventPattern(eventType, pattern) {
|
|
|
689
744
|
if (pattern.endsWith(".*")) return eventType.startsWith(`${pattern.slice(0, -1)}`);
|
|
690
745
|
return eventType === pattern;
|
|
691
746
|
}
|
|
747
|
+
/**
|
|
748
|
+
* The namespace reserved for events the library itself delivers to a machine
|
|
749
|
+
* (`@agent.init`, `@agent.usage`). A machine may declare transitions on them,
|
|
750
|
+
* but they are never model-facing: {@link getAcceptedEvents} drops them before
|
|
751
|
+
* any `allowedEvents` matching, so they cannot be offered as a decision
|
|
752
|
+
* candidate (not even under a `'*'` wildcard) and {@link parseAgentEvent}
|
|
753
|
+
* rejects them — a model or a wire message must not be able to forge one.
|
|
754
|
+
* Matched as a prefix rather than a list so this module stays free of an import
|
|
755
|
+
* cycle back to `effects.ts`, where the constants live.
|
|
756
|
+
* @internal
|
|
757
|
+
*/
|
|
758
|
+
const RESERVED_AGENT_EVENT_PREFIX = "@agent.";
|
|
692
759
|
/** True when an `allowedEvents` entry is a wildcard pattern rather than a concrete event type. @internal */
|
|
693
760
|
function isEventPattern(entry) {
|
|
694
761
|
return entry === "*" || entry.endsWith(".*");
|
|
@@ -731,13 +798,29 @@ function parseAgentEvent(snapshot, event, options = {}) {
|
|
|
731
798
|
}
|
|
732
799
|
return event;
|
|
733
800
|
}
|
|
801
|
+
/**
|
|
802
|
+
* Lists the events a snapshot can currently accept, as {@link AgentEventDescriptor}s
|
|
803
|
+
* a model can be offered (via `resolveDecision`/an adapter's tool-per-event
|
|
804
|
+
* mapping). **Filters by event TYPE only** — it does not evaluate guards, so
|
|
805
|
+
* a type-legal-but-guard-rejected event can still appear here. Guard
|
|
806
|
+
* legality is checked separately, at decision-resolution time, via
|
|
807
|
+
* `snapshot.can(event)` (the `canTake` option of {@link resolveDecision} /
|
|
808
|
+
* {@link ResolveDecisionOptions}). Pass `eventTypes` to further narrow to a
|
|
809
|
+
* declared `allowedEvents` set — entries may be exact types or wildcard
|
|
810
|
+
* patterns (`'*'`, `'todo.*'`; see {@link matchesEventPattern}).
|
|
811
|
+
*
|
|
812
|
+
* XState-internal (`xstate.*`) and library-reserved
|
|
813
|
+
* ({@link RESERVED_AGENT_EVENT_PREFIX}) event types are always excluded, before
|
|
814
|
+
* any `allowedEvents` matching — a machine that handles `'@agent.usage'` still
|
|
815
|
+
* never offers it to a model.
|
|
816
|
+
*/
|
|
734
817
|
function getAcceptedEvents(snapshot, options = {}) {
|
|
735
818
|
const eventTypes = options.eventTypes;
|
|
736
819
|
const seen = /* @__PURE__ */ new Set();
|
|
737
820
|
const usedToolNames = /* @__PURE__ */ new Set();
|
|
738
821
|
return getNextTransitions(snapshot).flatMap((transitionDefinition) => {
|
|
739
822
|
const eventType = transitionDefinition.eventType;
|
|
740
|
-
if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
|
|
823
|
+
if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || eventType.startsWith(RESERVED_AGENT_EVENT_PREFIX) || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
|
|
741
824
|
seen.add(eventType);
|
|
742
825
|
const defaultToolName = sanitizeEventToolName(eventType);
|
|
743
826
|
const toolName = options.eventToolName ? options.eventToolName({
|
|
@@ -779,7 +862,7 @@ function decideRequestFromInput(input) {
|
|
|
779
862
|
}
|
|
780
863
|
function decideActorWithExecutor(execute) {
|
|
781
864
|
const logic = createAsyncLogic({ run: async ({ input, signal }) => {
|
|
782
|
-
if (!execute) throw new Error(`'${DECIDE_ACTOR}' has no host execution. Provide an implementation with machine.provide({
|
|
865
|
+
if (!execute) throw new Error(`'${DECIDE_ACTOR}' has no host execution. Provide an implementation with machine.provide({ actors: { '${DECIDE_ACTOR}': ... } }) or resolve the returned agent request with resolveDecision(...).`);
|
|
783
866
|
const resolvedEventTypes = resolveAllowedEventTypes(input.allowedEvents, input);
|
|
784
867
|
if (resolvedEventTypes === void 0) throw new Error(`'${DECIDE_ACTOR}' input has omitted \`allowedEvents\`, which means "all currently-legal events" — but that requires a snapshot-aware host (runAgent or the step path) to resolve. Under a bare createActor(...), declare \`allowedEvents\` explicitly to use this actor here.`);
|
|
785
868
|
if (resolvedEventTypes.some(isEventPattern)) throw new Error(`'${DECIDE_ACTOR}' input uses wildcard \`allowedEvents\` patterns, which expand against the live snapshot — that requires a snapshot-aware host (runAgent or the step path). Under a bare createActor(...), list event types explicitly.`);
|
|
@@ -836,7 +919,10 @@ function createPlanActor() {
|
|
|
836
919
|
allowedEventTypes: (input) => resolveAllowedEventTypes(input.allowedEvents, input)
|
|
837
920
|
});
|
|
838
921
|
}
|
|
839
|
-
const PLAN_LEDGER_SCOPE = {
|
|
922
|
+
const PLAN_LEDGER_SCOPE = {
|
|
923
|
+
emit: () => {},
|
|
924
|
+
self: { id: "agent.plan.ledger" }
|
|
925
|
+
};
|
|
840
926
|
/**
|
|
841
927
|
* Builds a fresh plan ledger snapshot from resolved plan input — the shared
|
|
842
928
|
* starting point for BOTH hosts (the step path reads the invoke child's own
|
|
@@ -874,11 +960,11 @@ function isDecisionLogic(value) {
|
|
|
874
960
|
* diagnostics; a machine typically routes this via the decision invoke's
|
|
875
961
|
* `onError`.
|
|
876
962
|
*/
|
|
877
|
-
var
|
|
963
|
+
var AgentDecisionExhaustedError = class extends AgentError {
|
|
878
964
|
attempts;
|
|
879
965
|
constructor(attempts) {
|
|
880
|
-
super(`Decision exhausted after ${attempts.length} attempt${attempts.length === 1 ? "" : "s"}: ` + attempts.map((attempt) => attempt.reason).join("; "));
|
|
881
|
-
this.name = "
|
|
966
|
+
super("decision-exhausted", `Decision exhausted after ${attempts.length} attempt${attempts.length === 1 ? "" : "s"}: ` + attempts.map((attempt) => attempt.reason).join("; "));
|
|
967
|
+
this.name = "AgentDecisionExhaustedError";
|
|
882
968
|
this.attempts = attempts;
|
|
883
969
|
}
|
|
884
970
|
};
|
|
@@ -916,7 +1002,7 @@ function renderDecisionAttempts(request) {
|
|
|
916
1002
|
* the next attempt via `request.attempts`, so an adapter can render "your
|
|
917
1003
|
* last choice failed because X — try again" into the next model call; core
|
|
918
1004
|
* never rewrites the request itself. Exhausting all attempts throws
|
|
919
|
-
* {@link
|
|
1005
|
+
* {@link AgentDecisionExhaustedError} with the full attempts list.
|
|
920
1006
|
*
|
|
921
1007
|
* @example
|
|
922
1008
|
* ```ts
|
|
@@ -931,11 +1017,13 @@ async function resolveDecision(request, executor, options = {}) {
|
|
|
931
1017
|
const eventsByType = new Map(request.events.map((event) => [event.type, event]));
|
|
932
1018
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
933
1019
|
options.signal?.throwIfAborted();
|
|
934
|
-
const
|
|
1020
|
+
const result = await executor({
|
|
935
1021
|
...request,
|
|
936
1022
|
attempts: [...attempts],
|
|
937
1023
|
signal: options.signal
|
|
938
1024
|
});
|
|
1025
|
+
if (!result || typeof result !== "object" || typeof result.event !== "object" || result.event === null || typeof result.event.type !== "string") throw new Error(`decide executor must return { event: { type: string, ... } }; got ${JSON.stringify(result)}. Wrap the chosen event: return { event: { type: 'SAFE' } }.`);
|
|
1026
|
+
const { event } = result;
|
|
939
1027
|
const descriptor = eventsByType.get(event.type);
|
|
940
1028
|
if (!descriptor) {
|
|
941
1029
|
attempts.push({
|
|
@@ -972,7 +1060,7 @@ async function resolveDecision(request, executor, options = {}) {
|
|
|
972
1060
|
}
|
|
973
1061
|
return validatedEvent;
|
|
974
1062
|
}
|
|
975
|
-
throw new
|
|
1063
|
+
throw new AgentDecisionExhaustedError(attempts);
|
|
976
1064
|
}
|
|
977
1065
|
//#endregion
|
|
978
|
-
export { validateSchemaSync as $,
|
|
1066
|
+
export { validateSchemaSync as $, parseStructuredEnvelope as A, missingActor as B, executeAgentTextRequest as C, normalizeGeneratorResult as D, isTextLogic as E, getMachineSuspensionPredicate as F, getJsonSchemaSync as G, findNonSerializableContextPaths as H, getRegisteredAgentExecutionOptions as I, isStandardSchema as J, getMachineStructuralHash as K, isUnboundPlaceholder as L, agentExecutionOptions as M, executorBoundLogics as N, parseModelRef as O, getMachineStaticTransitionTargets as P, userMessage as Q, machineStaticTransitionTargets as R, createTextLogic as S, getAgentOutputMode as T, getAgentMessages as U, assistantMessage as V, getJsonSchema as W, systemMessage as X, persistSnapshot as Y, toolMessage as Z, PLAN_ACTOR as _, createPlanActor as a, buildEnvelopeSchema as b, isPlanLogic as c, getAcceptedEvents as d, parseAgentEvent as f, INTERPRET_SOURCE as g, DECIDE_ACTOR as h, createDecideActor as i, userInputActor as j, parseOutput as k, renderDecisionAttempts as l, AGENT_USAGE_TOKEN_FIELDS as m, PLAN_DONE_EVENT_TYPE as n, initialPlanLedger as o, sanitizeEventToolName as p, getStateMeta as q, advancePlanLedger as r, isDecisionLogic as s, AgentDecisionExhaustedError as t, resolveDecision as u, USER_INPUT_ACTOR as v, extractCallUsage as w, builtinTextActors as x, bindRequestExecutor as y, machineSuspensionPredicates as z };
|