@statelyai/agent 1.1.6 → 2.0.0-alpha.10

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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ai-sdk.cjs +342 -0
  3. package/dist/ai-sdk.d.cts +206 -0
  4. package/dist/ai-sdk.d.mts +206 -0
  5. package/dist/ai-sdk.mjs +331 -0
  6. package/dist/cli.cjs +64 -0
  7. package/dist/cli.d.cts +1 -0
  8. package/dist/cli.d.mts +1 -0
  9. package/dist/cli.mjs +65 -0
  10. package/dist/decision-CQdrKc8k.mjs +978 -0
  11. package/dist/decision-b-lkcs4L.cjs +1295 -0
  12. package/dist/index.cjs +59 -0
  13. package/dist/index.d.cts +212 -0
  14. package/dist/index.d.mts +201 -417
  15. package/dist/index.mjs +4 -588
  16. package/dist/openai-compat.cjs +319 -0
  17. package/dist/openai-compat.d.cts +98 -0
  18. package/dist/openai-compat.d.mts +98 -0
  19. package/dist/openai-compat.mjs +312 -0
  20. package/dist/run-agent-BFMkuI1F.cjs +1599 -0
  21. package/dist/run-agent-BVMd--1l.d.cts +1103 -0
  22. package/dist/run-agent-BoAOq_0Z.mjs +1540 -0
  23. package/dist/run-agent-DzYJb3CK.d.mts +1103 -0
  24. package/dist/src-D-77Ha5p.cjs +1087 -0
  25. package/dist/src-DUeIFjv-.mjs +1016 -0
  26. package/dist/text-logic-C7WJpCIc.d.mts +710 -0
  27. package/dist/text-logic-CZjyACzQ.d.cts +710 -0
  28. package/dist/types-C9QiMjre.d.cts +219 -0
  29. package/dist/types-qm00QF91.d.mts +219 -0
  30. package/dist/utils-Dri7aeEG.d.cts +108 -0
  31. package/dist/utils-Y6GDRGGE.d.mts +108 -0
  32. package/dist/zod.cjs +31 -0
  33. package/dist/zod.d.cts +30 -0
  34. package/dist/zod.d.mts +30 -0
  35. package/dist/zod.mjs +30 -0
  36. package/package.json +109 -28
  37. package/readme.md +143 -6
  38. package/schemas/agent-workflow.json +527 -0
  39. package/.changeset/README.md +0 -8
  40. package/.changeset/config.json +0 -11
  41. package/.env.template +0 -3
  42. package/.github/actions/ci-setup/action.yml +0 -24
  43. package/.github/workflows/release.yml +0 -46
  44. package/.vscode/launch.json +0 -28
  45. package/CHANGELOG.md +0 -222
  46. package/dist/index.d.ts +0 -428
  47. package/dist/index.js +0 -621
  48. package/examples/chatbot.ts +0 -71
  49. package/examples/cot.ts +0 -89
  50. package/examples/email.ts +0 -118
  51. package/examples/example.ts +0 -81
  52. package/examples/goal.ts +0 -94
  53. package/examples/helpers/helpers.ts +0 -17
  54. package/examples/helpers/loader.ts +0 -32
  55. package/examples/helpers/runner.ts +0 -27
  56. package/examples/joke.ts +0 -225
  57. package/examples/multi.ts +0 -103
  58. package/examples/newspaper.ts +0 -324
  59. package/examples/number.ts +0 -102
  60. package/examples/raffle.ts +0 -105
  61. package/examples/sandbox.ts +0 -28
  62. package/examples/simple.ts +0 -39
  63. package/examples/support.ts +0 -147
  64. package/examples/ticTacToe.ts +0 -224
  65. package/examples/todo.ts +0 -137
  66. package/examples/tutor.ts +0 -100
  67. package/examples/verify.ts +0 -120
  68. package/examples/weather.ts +0 -178
  69. package/examples/wiki.ts +0 -30
  70. package/examples/word.ts +0 -171
  71. package/src/adapters/vercel.ts +0 -7
  72. package/src/agent-experimental.ts +0 -221
  73. package/src/agent.test.ts +0 -506
  74. package/src/agent.ts +0 -300
  75. package/src/decision.test.ts +0 -179
  76. package/src/decision.ts +0 -84
  77. package/src/index.ts +0 -4
  78. package/src/memory.ts +0 -25
  79. package/src/planners/shortestPathPlanner.ts +0 -22
  80. package/src/planners/simplePlanner.ts +0 -139
  81. package/src/schemas.ts +0 -11
  82. package/src/strategies/chain-of-note.ts +0 -155
  83. package/src/templates/defaultText.ts +0 -18
  84. package/src/text.ts +0 -241
  85. package/src/types.ts +0 -499
  86. package/src/utils.ts +0 -72
  87. package/tsconfig.json +0 -109
  88. package/vitest.config.ts +0 -9
@@ -0,0 +1,312 @@
1
+ import { G as getJsonSchemaSync, J as isStandardSchema, T as getAgentOutputMode, W as getJsonSchema, l as renderDecisionAttempts, x as buildEnvelopeSchema } from "./decision-CQdrKc8k.mjs";
2
+ //#region src/openai-compat/index.ts
3
+ /**
4
+ * OpenAI-compatible Chat Completions adapter — a COMPLETE `{ generateText,
5
+ * streamText, decide }` executor set built on raw `fetch`, with zero runtime
6
+ * dependencies (no `openai` package, no Vercel AI SDK).
7
+ *
8
+ * The OpenAI Chat Completions wire format is the lingua franca of hosted and
9
+ * local inference: Groq, Together, Fireworks, OpenRouter, vLLM, Ollama, LM
10
+ * Studio, and OpenAI itself all speak it. Point `baseUrl` at any of them.
11
+ *
12
+ * Compare `createAiSdkExecutors` in `../ai-sdk/index.ts` (the AI-SDK-backed
13
+ * adapter) — same three-function contract, different transport. The request
14
+ * mapping is ported from `examples/openai-sdk-host/index.ts`, but wired
15
+ * against `POST {baseUrl}/chat/completions` instead of the `openai` package.
16
+ */
17
+ /**
18
+ * Reads a Standard Schema's optional `~standard.jsonSchema.input()` extension
19
+ * (implemented by e.g. Zod v4's `z.toJSONSchema`), awaiting it when it returns
20
+ * a Promise. Returns `undefined` when the schema doesn't expose the extension.
21
+ * Thin re-export of core's {@link getJsonSchema}.
22
+ */
23
+ const extractJsonSchema = getJsonSchema;
24
+ /** Maps `AgentTextRequest.messages`/`system`/`prompt` to Chat Completions messages. */
25
+ function toOpenAiMessages(request) {
26
+ if (request.messages) return request.messages.flatMap((message) => {
27
+ const content = typeof message.content === "string" ? message.content : "";
28
+ switch (message.role) {
29
+ case "system": return [{
30
+ role: "system",
31
+ content
32
+ }];
33
+ case "user": return [{
34
+ role: "user",
35
+ content
36
+ }];
37
+ case "assistant": return [{
38
+ role: "assistant",
39
+ content
40
+ }];
41
+ case "tool": return message.content.map((part) => ({
42
+ role: "tool",
43
+ content: part.output.type === "text" || part.output.type === "error-text" ? part.output.value : JSON.stringify(part.output.value),
44
+ tool_call_id: part.toolCallId
45
+ }));
46
+ }
47
+ });
48
+ const messages = [];
49
+ if (request.system) messages.push({
50
+ role: "system",
51
+ content: request.system
52
+ });
53
+ messages.push({
54
+ role: "user",
55
+ content: request.prompt ?? ""
56
+ });
57
+ return messages;
58
+ }
59
+ /**
60
+ * Maps sampling/stop settings. Targets `max_tokens` (not
61
+ * `max_completion_tokens`) — it's the field every OpenAI-compatible backend
62
+ * accepts (Ollama, vLLM, Groq, …), where `max_completion_tokens` is
63
+ * OpenAI-only. Undefined fields are pruned so they never hit the wire.
64
+ */
65
+ function toOpenAiCallSettings(request) {
66
+ return pruneUndefined({
67
+ temperature: request.temperature,
68
+ max_tokens: request.maxOutputTokens,
69
+ top_p: request.topP,
70
+ seed: request.seed,
71
+ stop: request.stopSequences
72
+ });
73
+ }
74
+ /** One wire function tool per `AgentTools` entry. */
75
+ function toOpenAiTools(tools) {
76
+ return Object.entries(tools).flatMap(([name, descriptor]) => {
77
+ if (!descriptor) return [];
78
+ const inputSchema = typeof descriptor === "function" ? void 0 : descriptor.inputSchema;
79
+ return [{
80
+ type: "function",
81
+ function: {
82
+ name,
83
+ description: typeof descriptor === "function" ? void 0 : descriptor.description,
84
+ parameters: (isStandardSchema(inputSchema) ? getJsonSchemaSync(inputSchema) : void 0) ?? {}
85
+ }
86
+ }];
87
+ });
88
+ }
89
+ /** One wire function tool per candidate decision event — the
90
+ * "tool-per-event + tool_choice: 'required'" recipe. */
91
+ function toOpenAiEventTools(events) {
92
+ return events.map((event) => ({
93
+ type: "function",
94
+ function: {
95
+ name: event.toolName,
96
+ description: `Choose the '${event.type}' move.`,
97
+ parameters: getJsonSchemaSync(event.inputSchema) ?? {}
98
+ }
99
+ }));
100
+ }
101
+ /** Messages for a decision request, with prior failed `attempts` rendered as
102
+ * appended user messages (via core's {@link renderDecisionAttempts}) so
103
+ * retries converge. */
104
+ function toDecisionMessages(request) {
105
+ const messages = toOpenAiMessages(request);
106
+ for (const attempt of renderDecisionAttempts(request)) messages.push({
107
+ role: "user",
108
+ content: attempt.content
109
+ });
110
+ return messages;
111
+ }
112
+ function pruneUndefined(record) {
113
+ return Object.fromEntries(Object.entries(record).filter(([, value]) => value !== void 0));
114
+ }
115
+ /**
116
+ * Builds a complete `{ generateText, streamText, decide }` executor set over
117
+ * the OpenAI Chat Completions wire format via raw `fetch`.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * const executors = createOpenAiCompatExecutors({
122
+ * baseUrl: 'https://api.groq.com/openai/v1',
123
+ * apiKey: process.env.GROQ_API_KEY,
124
+ * models: { quick: 'llama-3.3-70b-versatile' },
125
+ * });
126
+ * const result = await runAgent(machine, { input, executors });
127
+ * ```
128
+ */
129
+ function createOpenAiCompatExecutors(options) {
130
+ const doFetch = options.fetch ?? globalThis.fetch;
131
+ if (!doFetch) throw new Error("createOpenAiCompatExecutors: no `fetch` available — pass options.fetch for this runtime.");
132
+ const url = `${options.baseUrl.replace(/\/+$/, "")}/chat/completions`;
133
+ function resolveModel(modelRef) {
134
+ const resolved = options.models?.[modelRef] ?? modelRef ?? options.model;
135
+ if (!resolved) throw new Error("createOpenAiCompatExecutors: no model to send — set request.model, options.model, or options.models.");
136
+ return resolved;
137
+ }
138
+ function buildHeaders() {
139
+ return {
140
+ "content-type": "application/json",
141
+ ...options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {},
142
+ ...options.headers
143
+ };
144
+ }
145
+ async function post(body, signal) {
146
+ const response = await doFetch(url, {
147
+ method: "POST",
148
+ headers: buildHeaders(),
149
+ body: JSON.stringify(body),
150
+ signal
151
+ });
152
+ if (!response.ok) {
153
+ const snippet = await response.text().catch(() => "");
154
+ throw new Error(`createOpenAiCompatExecutors: ${url} responded ${response.status} ${response.statusText}: ` + snippet.slice(0, 500));
155
+ }
156
+ return response;
157
+ }
158
+ const generateText = async (request, info) => {
159
+ const tools = toOpenAiTools(request.tools);
160
+ const body = {
161
+ model: resolveModel(request.model),
162
+ messages: toOpenAiMessages(request),
163
+ ...toOpenAiCallSettings(request),
164
+ ...tools.length > 0 ? { tools } : {},
165
+ ...request.toolChoice ? { tool_choice: toWireToolChoice(request.toolChoice) } : {}
166
+ };
167
+ const structured = getAgentOutputMode(request.outputSchema) === "structured";
168
+ if (structured) {
169
+ const jsonSchema = await getJsonSchema(buildEnvelopeSchema(request.outputSchema, { reasoning: request.reasoning }));
170
+ body.response_format = jsonSchema ? {
171
+ type: "json_schema",
172
+ json_schema: {
173
+ name: "output",
174
+ schema: jsonSchema,
175
+ strict: false
176
+ }
177
+ } : { type: "json_object" };
178
+ }
179
+ const json = await (await post(body, info?.signal)).json();
180
+ const choice = json.choices?.[0];
181
+ const content = choice?.message?.content ?? "";
182
+ if (structured) {
183
+ let parsed;
184
+ try {
185
+ parsed = content ? JSON.parse(content) : void 0;
186
+ } catch (error) {
187
+ throw new Error(`createOpenAiCompatExecutors: generateText${nameSuffix(request)} — structured request returned non-JSON content: ${errorMessage(error)}`);
188
+ }
189
+ let output = parsed;
190
+ let reasoning;
191
+ if (parsed && typeof parsed === "object" && "result" in parsed) {
192
+ output = parsed.result;
193
+ const rawReasoning = parsed.reasoning;
194
+ if (typeof rawReasoning === "string") reasoning = rawReasoning;
195
+ }
196
+ return {
197
+ output,
198
+ ...reasoning !== void 0 ? { reasoning } : {},
199
+ usage: json.usage,
200
+ finishReason: choice?.finish_reason ?? void 0
201
+ };
202
+ }
203
+ return {
204
+ output: content,
205
+ usage: json.usage,
206
+ finishReason: choice?.finish_reason ?? void 0
207
+ };
208
+ };
209
+ const streamText = async (request, info) => {
210
+ const response = await post({
211
+ model: resolveModel(request.model),
212
+ messages: toOpenAiMessages(request),
213
+ ...toOpenAiCallSettings(request),
214
+ stream: true
215
+ }, info?.signal);
216
+ let text = "";
217
+ for await (const data of iterateSse(response, request)) {
218
+ let chunk;
219
+ try {
220
+ chunk = JSON.parse(data);
221
+ } catch (error) {
222
+ throw new Error(`createOpenAiCompatExecutors: streamText${nameSuffix(request)} — malformed SSE JSON chunk: ${errorMessage(error)}`);
223
+ }
224
+ const delta = chunk.choices?.[0]?.delta?.content;
225
+ if (delta) {
226
+ text += delta;
227
+ info?.onChunk?.(delta);
228
+ }
229
+ }
230
+ return { output: text };
231
+ };
232
+ const decide = async (request) => {
233
+ const tools = toOpenAiEventTools(request.events);
234
+ const json = await (await post({
235
+ model: resolveModel(request.model),
236
+ messages: toDecisionMessages(request),
237
+ tools,
238
+ tool_choice: "required",
239
+ ...pruneUndefined({
240
+ temperature: request.temperature,
241
+ max_tokens: request.maxOutputTokens,
242
+ top_p: request.topP,
243
+ seed: request.seed,
244
+ stop: request.stopSequences
245
+ })
246
+ }, request.signal)).json();
247
+ const choice = json.choices?.[0];
248
+ const toolCall = choice?.message?.tool_calls?.[0];
249
+ if (!toolCall || toolCall.type && toolCall.type !== "function" || !toolCall.function?.name) throw new Error("createOpenAiCompatExecutors: decide — model did not call an event tool.");
250
+ const chosenEvent = request.events.find((event) => event.toolName === toolCall.function.name);
251
+ if (!chosenEvent) throw new Error(`createOpenAiCompatExecutors: decide — model called unknown tool '${toolCall.function.name}'.`);
252
+ let args = {};
253
+ if (toolCall.function.arguments) try {
254
+ args = JSON.parse(toolCall.function.arguments);
255
+ } catch (error) {
256
+ throw new Error(`createOpenAiCompatExecutors: decide — could not parse tool arguments for '${chosenEvent.type}': ${errorMessage(error)}`);
257
+ }
258
+ return {
259
+ event: {
260
+ ...args && typeof args === "object" ? args : {},
261
+ type: chosenEvent.type
262
+ },
263
+ usage: json.usage,
264
+ finishReason: choice?.finish_reason ?? void 0
265
+ };
266
+ };
267
+ return {
268
+ generateText,
269
+ streamText,
270
+ decide
271
+ };
272
+ }
273
+ /** Maps an `AgentToolChoice` to the wire `tool_choice` shape. */
274
+ function toWireToolChoice(toolChoice) {
275
+ return typeof toolChoice === "object" ? {
276
+ type: "function",
277
+ function: { name: toolChoice.name }
278
+ } : toolChoice;
279
+ }
280
+ async function* iterateSse(response, request) {
281
+ const body = response.body;
282
+ if (!body) throw new Error(`createOpenAiCompatExecutors: streamText${nameSuffix(request)} — response has no body to read SSE from.`);
283
+ const reader = body.getReader();
284
+ const decoder = new TextDecoder();
285
+ let buffer = "";
286
+ const flushLine = function* (line) {
287
+ const trimmed = line.trim();
288
+ if (!trimmed || !trimmed.startsWith("data:")) return;
289
+ const data = trimmed.slice(5).trim();
290
+ if (data && data !== "[DONE]") yield data;
291
+ };
292
+ while (true) {
293
+ const { done, value } = await reader.read();
294
+ if (done) break;
295
+ buffer += decoder.decode(value, { stream: true });
296
+ let newlineIndex;
297
+ while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
298
+ const line = buffer.slice(0, newlineIndex);
299
+ buffer = buffer.slice(newlineIndex + 1);
300
+ yield* flushLine(line);
301
+ }
302
+ }
303
+ yield* flushLine(buffer);
304
+ }
305
+ function nameSuffix(request) {
306
+ return request.name ? ` '${request.name}'` : "";
307
+ }
308
+ function errorMessage(error) {
309
+ return error instanceof Error ? error.message : String(error);
310
+ }
311
+ //#endregion
312
+ export { createOpenAiCompatExecutors, extractJsonSchema, toDecisionMessages, toOpenAiCallSettings, toOpenAiEventTools, toOpenAiMessages, toOpenAiTools };