@statelyai/agent 2.0.0-alpha.20 → 2.0.0-alpha.21

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_decision = require("./decision-DhsKLYAI.cjs");
2
+ const require_decision = require("./decision-BnTCsuJv.cjs");
3
3
  require("./validate.cjs");
4
4
  let ai = require("ai");
5
5
  //#region src/ai-sdk/mappers.ts
@@ -51,6 +51,27 @@ const unknownSchema = { "~standard": {
51
51
  jsonSchema: { input: () => ({}) }
52
52
  } };
53
53
  /**
54
+ * Folds AI SDK v7's nested token details onto the flat field names core
55
+ * aggregates. v7 moved `reasoningTokens` under `outputTokenDetails` and the
56
+ * cached-input count under `inputTokenDetails.cacheReadTokens`, while
57
+ * {@link AgentCallUsage} stays flat and provider-agnostic. The SDK's own shape
58
+ * is spread through unchanged, so `onResult` consumers still see every field
59
+ * the provider reported, including v7's `raw`.
60
+ */
61
+ function toAgentCallUsage(usage) {
62
+ const reasoningTokens = usage.outputTokenDetails?.reasoningTokens;
63
+ const cachedInputTokens = usage.inputTokenDetails?.cacheReadTokens;
64
+ return {
65
+ ...usage,
66
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : {},
67
+ ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {}
68
+ };
69
+ }
70
+ /** Drops keys whose value is `undefined`, so a spread cannot erase what it lands on. */
71
+ function defined(settings) {
72
+ return Object.fromEntries(Object.entries(settings).filter(([, value]) => value !== void 0));
73
+ }
74
+ /**
54
75
  * AI SDK request-mapping settings shared by `generateText`/`streamText`.
55
76
  * `AgentTextRequest.messages` (`AgentMessage[]`) and AI SDK's `ModelMessage[]`
56
77
  * are structurally compatible by design (§1 of .scratch/p0-design.md) — the cast
@@ -60,16 +81,36 @@ function toAiSdkCallSettings(request) {
60
81
  const messages = request.messages;
61
82
  return {
62
83
  system: request.system,
63
- ...messages ? { messages } : { prompt: request.prompt ?? "" },
84
+ ...messages ? {
85
+ messages,
86
+ allowSystemInMessages: true
87
+ } : { prompt: request.prompt ?? "" },
88
+ ...toAiSdkGenerationSettings(request),
89
+ ...defined({
90
+ tools: request.tools ? toAiSdkTools(request.tools) : void 0,
91
+ toolChoice: toAiSdkToolChoice(request.toolChoice)
92
+ })
93
+ };
94
+ }
95
+ /**
96
+ * The generation settings a text request and a decision request share, with
97
+ * unset keys omitted.
98
+ *
99
+ * Omitting matters: these settings are one layer of a stack — the host's
100
+ * `createAiSdkExecutors({ settings })`, then the model ref's own, then the
101
+ * request's — and an `undefined` spread over a layer below erases it. Both the
102
+ * text path and `decide` map their settings through here so neither can drift
103
+ * back into writing the keys unconditionally.
104
+ */
105
+ function toAiSdkGenerationSettings(request) {
106
+ return defined({
64
107
  temperature: request.temperature,
65
108
  maxOutputTokens: request.maxOutputTokens,
66
109
  topP: request.topP,
67
110
  topK: request.topK,
68
111
  seed: request.seed,
69
- stopSequences: request.stopSequences,
70
- tools: request.tools ? toAiSdkTools(request.tools) : void 0,
71
- toolChoice: toAiSdkToolChoice(request.toolChoice)
72
- };
112
+ stopSequences: request.stopSequences
113
+ });
73
114
  }
74
115
  /** Maps an {@link AgentToolChoice} to AI SDK's tool-choice shape — `{ type: 'tool'; name }` becomes `{ type: 'tool'; toolName }`; `'auto'`/`'none'`/`'required'`/`undefined` pass through unchanged. */
75
116
  function toAiSdkToolChoice(toolChoice) {
@@ -167,13 +208,29 @@ function maxStepsSetting(request) {
167
208
  function defineModels(models) {
168
209
  return models;
169
210
  }
211
+ /** Resolves the host's `settings` option for one request. */
212
+ function callSettings(options, request) {
213
+ const settings = options.settings;
214
+ return (typeof settings === "function" ? settings(request) : settings) ?? {};
215
+ }
170
216
  function resolveAiSdkModel(options, modelRef) {
171
- if (options.resolveModel) return options.resolveModel(modelRef);
217
+ if (options.resolveModel) return { model: options.resolveModel(modelRef) };
172
218
  const models = options.models;
173
219
  if (!models) throw new Error(`createAiSdkExecutors: no model resolver configured for '${modelRef}'.`);
174
- const model = models[modelRef];
175
- if (!model) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
176
- return model;
220
+ const entry = models[modelRef];
221
+ if (!entry) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
222
+ return isModelWithSettings(entry) ? entry : { model: entry };
223
+ }
224
+ /**
225
+ * The `LanguageModel` inside a map entry, whichever form it takes. `defineModels`
226
+ * widens its return to {@link AiSdkModelMap}, so reading an entry out of the map
227
+ * to hand to a raw AI SDK call needs this to get past the union.
228
+ */
229
+ function toLanguageModel(entry) {
230
+ return isModelWithSettings(entry) ? entry.model : entry;
231
+ }
232
+ function isModelWithSettings(entry) {
233
+ return typeof entry === "object" && entry !== null && "model" in entry;
177
234
  }
178
235
  function withJsonRepair(output) {
179
236
  return {
@@ -208,14 +265,17 @@ function withJsonRepair(output) {
208
265
  */
209
266
  function createAiSdkExecutors(options) {
210
267
  const generateText = async (request, info) => {
268
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
211
269
  const common = {
212
- model: resolveAiSdkModel(options, request.model),
270
+ model,
213
271
  abortSignal: info?.signal,
272
+ ...callSettings(options, request),
273
+ ...defined(modelSettings ?? {}),
214
274
  ...toAiSdkCallSettings(request),
215
275
  ...maxStepsSetting(request)
216
276
  };
217
277
  if (isStructuredOutputRequest(request)) {
218
- const envelope = require_decision.buildEnvelopeSchema(request.outputSchema, { reasoning: request.reasoning });
278
+ const envelope = require_decision.buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning });
219
279
  const structuredOutput = withJsonRepair(ai.Output.object({ schema: envelope }));
220
280
  const canRetry = !request.tools || Object.keys(request.tools).length === 0;
221
281
  let result;
@@ -235,7 +295,7 @@ function createAiSdkExecutors(options) {
235
295
  return {
236
296
  output,
237
297
  ...reasoning !== void 0 ? { reasoning } : {},
238
- usage: result.usage,
298
+ usage: toAgentCallUsage(result.usage),
239
299
  finishReason: result.finishReason,
240
300
  toolCalls: result.toolCalls,
241
301
  toolResults: result.toolResults
@@ -244,44 +304,47 @@ function createAiSdkExecutors(options) {
244
304
  const result = await (0, ai.generateText)(common);
245
305
  return {
246
306
  output: result.text,
247
- usage: result.usage,
307
+ usage: toAgentCallUsage(result.usage),
248
308
  finishReason: result.finishReason,
249
309
  toolCalls: result.toolCalls,
250
310
  toolResults: result.toolResults
251
311
  };
252
312
  };
253
313
  const streamText = async (request, info) => {
314
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
254
315
  const result = (0, ai.streamText)({
255
- model: resolveAiSdkModel(options, request.model),
316
+ model,
256
317
  abortSignal: info?.signal,
318
+ ...callSettings(options, request),
319
+ ...defined(modelSettings ?? {}),
257
320
  ...toAiSdkCallSettings(request),
258
321
  ...maxStepsSetting(request)
259
322
  });
260
323
  for await (const chunk of result.textStream) info?.onChunk?.(chunk);
261
324
  return {
262
325
  output: await result.text,
263
- usage: await result.usage,
326
+ usage: toAgentCallUsage(await result.usage),
264
327
  finishReason: await result.finishReason
265
328
  };
266
329
  };
267
330
  const decide = async (request) => {
268
- const model = resolveAiSdkModel(options, request.model);
331
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
269
332
  const tools = toAiSdkEventTools(request.events);
270
333
  const messages = toDecisionMessages(request);
271
334
  const result = await (0, ai.generateText)({
272
335
  model,
273
336
  abortSignal: request.signal,
337
+ ...callSettings(options, request),
338
+ ...defined(modelSettings ?? {}),
274
339
  system: request.system,
275
- ...messages ? { messages } : { prompt: request.prompt ?? "" },
340
+ ...messages ? {
341
+ messages,
342
+ allowSystemInMessages: true
343
+ } : { prompt: request.prompt ?? "" },
276
344
  tools,
277
345
  toolChoice: "required",
278
346
  stopWhen: (0, ai.stepCountIs)(1),
279
- temperature: request.temperature,
280
- maxOutputTokens: request.maxOutputTokens,
281
- topP: request.topP,
282
- topK: request.topK,
283
- seed: request.seed,
284
- stopSequences: request.stopSequences
347
+ ...toAiSdkGenerationSettings(request)
285
348
  });
286
349
  const toolCall = result.toolCalls[0];
287
350
  if (!toolCall) throw new Error("createAiSdkExecutors: decide — model did not call an event tool.");
@@ -292,7 +355,7 @@ function createAiSdkExecutors(options) {
292
355
  ...toolCall.input && typeof toolCall.input === "object" ? toolCall.input : {},
293
356
  type: chosenEvent.type
294
357
  },
295
- usage: result.usage,
358
+ usage: toAgentCallUsage(result.usage),
296
359
  finishReason: result.finishReason
297
360
  };
298
361
  };
@@ -305,3 +368,4 @@ function createAiSdkExecutors(options) {
305
368
  //#endregion
306
369
  exports.createAiSdkExecutors = createAiSdkExecutors;
307
370
  exports.defineModels = defineModels;
371
+ exports.toLanguageModel = toLanguageModel;
package/dist/ai-sdk.d.cts CHANGED
@@ -1,10 +1,28 @@
1
- import { d as ChosenEvent } from "./types-pJ5Hn8fv.cjs";
2
- import { A as AgentDecisionExecutor, l as AgentRequestExecutors, o as AgentRequestExecutor } from "./text-logic-Cavva1W6.cjs";
3
- import { FinishReason, LanguageModel, LanguageModelUsage, ToolSet, TypedToolCall, TypedToolResult } from "ai";
1
+ import { d as ChosenEvent } from "./types-DSdj2tGs.cjs";
2
+ import { A as AgentDecisionExecutor, N as AgentDecisionRequest, d as AgentTextRequest, l as AgentRequestExecutors, o as AgentRequestExecutor, t as AgentCallUsage } from "./text-logic-Mmbgb2jy.cjs";
3
+ import { FinishReason, LanguageModel, LanguageModelUsage, ToolSet, TypedToolCall, TypedToolResult, generateText } from "ai";
4
4
 
5
+ //#region src/ai-sdk/mappers.d.ts
6
+ /**
7
+ * One call's usage as the adapter reports it: the AI SDK's `LanguageModelUsage`
8
+ * plus the flat {@link AgentCallUsage} token fields core folds into a run's
9
+ * aggregated usage.
10
+ */
11
+ type AiSdkCallUsage = LanguageModelUsage & Pick<AgentCallUsage, "reasoningTokens" | "cachedInputTokens">;
12
+ //#endregion
5
13
  //#region src/ai-sdk/index.d.ts
6
- /** AI SDK model registry: maps model refs (as used in `setupAgent({ models })`/`AgentTextRequest.model`) to AI SDK `LanguageModel` values. The optional `TKey` parameter pins the ref keys (see {@link defineModels}); it defaults to `string`, so bare `AiSdkModelMap` stays `Record<string, LanguageModel>`. */
7
- type AiSdkModelMap<TKey extends string = string> = Record<TKey, LanguageModel>;
14
+ /**
15
+ * One entry in an {@link AiSdkModelMap}: a bare `LanguageModel`, or a model
16
+ * paired with the {@link AiSdkCallSettings} that ref always runs with. The
17
+ * paired form is how a host gives a ref a persona — `deep` thinks harder than
18
+ * `quick` — without the machine naming a provider knob.
19
+ */
20
+ type AiSdkModelEntry = LanguageModel | {
21
+ model: LanguageModel;
22
+ settings?: AiSdkCallSettings;
23
+ };
24
+ /** AI SDK model registry: maps model refs (as used in `setupAgent({ models })`/`AgentTextRequest.model`) to AI SDK `LanguageModel` values, or to `{ model, settings }` pairs. The optional `TKey` parameter pins the ref keys (see {@link defineModels}); it defaults to `string`, so bare `AiSdkModelMap` stays `Record<string, AiSdkModelEntry>`. */
25
+ type AiSdkModelMap<TKey extends string = string> = Record<TKey, AiSdkModelEntry>;
8
26
  /**
9
27
  * Identity helper for a `models` map whose value is exported. Returns the map
10
28
  * unchanged, but types it as {@link AiSdkModelMap}`<keyof T & string>` — a
@@ -23,20 +41,45 @@ type AiSdkModelMap<TKey extends string = string> = Record<TKey, LanguageModel>;
23
41
  * // typeof models === AiSdkModelMap<'quick' | 'deep'>
24
42
  * ```
25
43
  */
26
- declare function defineModels<T extends Record<string, LanguageModel>>(models: T): AiSdkModelMap<keyof T & string>;
44
+ declare function defineModels<T extends Record<string, AiSdkModelEntry>>(models: T): AiSdkModelMap<keyof T & string>;
45
+ /**
46
+ * Per-call AI SDK settings a host can apply on top of what the machine asked
47
+ * for — reasoning effort, `providerOptions`, and anything else the SDK's call
48
+ * options accept. Typed straight off `generateText`, so it tracks the
49
+ * installed `ai` version instead of restating its vocabulary.
50
+ *
51
+ * The request's own fields (`model`, `prompt`/`messages`, `tools`, and the
52
+ * generation settings every provider shares) are excluded: those belong to the
53
+ * machine, and a host override would silently contradict it.
54
+ */
55
+ type AiSdkCallSettings = Omit<Parameters<typeof generateText>[0], "model" | "prompt" | "messages" | "system" | "instructions" | "tools" | "toolChoice" | "output" | "abortSignal" | "stopWhen">;
27
56
  /**
28
57
  * Options for {@link createAiSdkExecutors}: either a static `models` map
29
58
  * (model refs resolved by lookup), a `resolveModel` function (refs resolved
30
59
  * dynamically, e.g. `"openai/gpt-5.4-mini"` → `openai('gpt-5.4-mini')`), or
31
60
  * both — `resolveModel` takes precedence when both are supplied.
61
+ *
62
+ * `settings` carries provider knobs that are the HOST's business rather than
63
+ * the machine's, such as reasoning effort. Pass an object to apply it to every
64
+ * call, or a function to vary it per request (`request.name` is the request's
65
+ * registered key). Core neither declares nor reads these: a machine stays
66
+ * portable, and a host that cannot honor a knob simply does not set it.
32
67
  */
33
68
  type CreateAiSdkExecutorsOptions<TModels extends AiSdkModelMap = AiSdkModelMap> = {
69
+ settings?: AiSdkCallSettings | ((request: AgentTextRequest | AgentDecisionRequest) => AiSdkCallSettings | undefined);
70
+ } & ({
34
71
  models: TModels;
35
72
  resolveModel?: (modelRef: keyof TModels & string) => LanguageModel;
36
73
  } | {
37
74
  models?: TModels;
38
75
  resolveModel: (modelRef: string) => LanguageModel;
39
- };
76
+ });
77
+ /**
78
+ * The `LanguageModel` inside a map entry, whichever form it takes. `defineModels`
79
+ * widens its return to {@link AiSdkModelMap}, so reading an entry out of the map
80
+ * to hand to a raw AI SDK call needs this to get past the union.
81
+ */
82
+ declare function toLanguageModel(entry: AiSdkModelEntry): LanguageModel;
40
83
  /**
41
84
  * Raw result shape from {@link AiSdkExecutors.generateText} — the `{ output }`
42
85
  * envelope (the validated structured object for structured-output requests,
@@ -54,8 +97,9 @@ type AiSdkGenerateResult = {
54
97
  reasoning?: string;
55
98
  /** The call's token usage. Its flat `inputTokens`/`outputTokens`/`totalTokens`/
56
99
  * `reasoningTokens`/`cachedInputTokens` fields are what `runAgent` folds into
57
- * the run result's aggregated `AgentUsage`. */
58
- usage: LanguageModelUsage;
100
+ * the run result's aggregated `AgentUsage`; the AI SDK's own nested
101
+ * `inputTokenDetails`/`outputTokenDetails` and `raw` ride along untouched. */
102
+ usage: AiSdkCallUsage;
59
103
  finishReason: FinishReason;
60
104
  toolCalls: TypedToolCall<ToolSet>[];
61
105
  toolResults: TypedToolResult<ToolSet>[];
@@ -63,13 +107,13 @@ type AiSdkGenerateResult = {
63
107
  /** Raw result shape from {@link AiSdkExecutors.streamText} — the `{ output }` envelope carrying the fully-accumulated text once the stream finishes (chunks are delivered separately via `onChunk`), plus the stream's final usage/finish metadata for `onResult`. */
64
108
  type AiSdkStreamResult = {
65
109
  output: string; /** The stream's final (awaited) usage; aggregated into the run result's `AgentUsage`. */
66
- usage: LanguageModelUsage;
110
+ usage: AiSdkCallUsage;
67
111
  finishReason: FinishReason;
68
112
  };
69
113
  /** Raw result shape from {@link AiSdkExecutors.decide} — the chosen event plus the AI SDK call metadata, delivered per decision attempt to `onResult`. */
70
114
  type AiSdkDecideResult = {
71
115
  event: ChosenEvent; /** This attempt's usage; aggregated into the run result's `AgentUsage`. */
72
- usage: LanguageModelUsage;
116
+ usage: AiSdkCallUsage;
73
117
  finishReason: FinishReason;
74
118
  };
75
119
  /** `createAiSdkExecutors` always populates all three slots (unlike the
@@ -96,4 +140,4 @@ interface AiSdkExecutors extends AgentRequestExecutors<AiSdkGenerateResult, AiSd
96
140
  */
97
141
  declare function createAiSdkExecutors<TModels extends AiSdkModelMap>(options: CreateAiSdkExecutorsOptions<TModels>): AiSdkExecutors;
98
142
  //#endregion
99
- export { AiSdkDecideResult, AiSdkExecutors, AiSdkGenerateResult, AiSdkModelMap, AiSdkStreamResult, CreateAiSdkExecutorsOptions, createAiSdkExecutors, defineModels };
143
+ export { AiSdkCallSettings, AiSdkDecideResult, AiSdkExecutors, AiSdkGenerateResult, AiSdkModelEntry, AiSdkModelMap, AiSdkStreamResult, CreateAiSdkExecutorsOptions, createAiSdkExecutors, defineModels, toLanguageModel };
package/dist/ai-sdk.d.mts CHANGED
@@ -1,10 +1,28 @@
1
- import { d as ChosenEvent } from "./types-DYpK3QF4.mjs";
2
- import { A as AgentDecisionExecutor, l as AgentRequestExecutors, o as AgentRequestExecutor } from "./text-logic-Er5KkTX6.mjs";
3
- import { FinishReason, LanguageModel, LanguageModelUsage, ToolSet, TypedToolCall, TypedToolResult } from "ai";
1
+ import { d as ChosenEvent } from "./types-CvWRGFxP.mjs";
2
+ import { A as AgentDecisionExecutor, N as AgentDecisionRequest, d as AgentTextRequest, l as AgentRequestExecutors, o as AgentRequestExecutor, t as AgentCallUsage } from "./text-logic-BR5twXCv.mjs";
3
+ import { FinishReason, LanguageModel, LanguageModelUsage, ToolSet, TypedToolCall, TypedToolResult, generateText } from "ai";
4
4
 
5
+ //#region src/ai-sdk/mappers.d.ts
6
+ /**
7
+ * One call's usage as the adapter reports it: the AI SDK's `LanguageModelUsage`
8
+ * plus the flat {@link AgentCallUsage} token fields core folds into a run's
9
+ * aggregated usage.
10
+ */
11
+ type AiSdkCallUsage = LanguageModelUsage & Pick<AgentCallUsage, "reasoningTokens" | "cachedInputTokens">;
12
+ //#endregion
5
13
  //#region src/ai-sdk/index.d.ts
6
- /** AI SDK model registry: maps model refs (as used in `setupAgent({ models })`/`AgentTextRequest.model`) to AI SDK `LanguageModel` values. The optional `TKey` parameter pins the ref keys (see {@link defineModels}); it defaults to `string`, so bare `AiSdkModelMap` stays `Record<string, LanguageModel>`. */
7
- type AiSdkModelMap<TKey extends string = string> = Record<TKey, LanguageModel>;
14
+ /**
15
+ * One entry in an {@link AiSdkModelMap}: a bare `LanguageModel`, or a model
16
+ * paired with the {@link AiSdkCallSettings} that ref always runs with. The
17
+ * paired form is how a host gives a ref a persona — `deep` thinks harder than
18
+ * `quick` — without the machine naming a provider knob.
19
+ */
20
+ type AiSdkModelEntry = LanguageModel | {
21
+ model: LanguageModel;
22
+ settings?: AiSdkCallSettings;
23
+ };
24
+ /** AI SDK model registry: maps model refs (as used in `setupAgent({ models })`/`AgentTextRequest.model`) to AI SDK `LanguageModel` values, or to `{ model, settings }` pairs. The optional `TKey` parameter pins the ref keys (see {@link defineModels}); it defaults to `string`, so bare `AiSdkModelMap` stays `Record<string, AiSdkModelEntry>`. */
25
+ type AiSdkModelMap<TKey extends string = string> = Record<TKey, AiSdkModelEntry>;
8
26
  /**
9
27
  * Identity helper for a `models` map whose value is exported. Returns the map
10
28
  * unchanged, but types it as {@link AiSdkModelMap}`<keyof T & string>` — a
@@ -23,20 +41,45 @@ type AiSdkModelMap<TKey extends string = string> = Record<TKey, LanguageModel>;
23
41
  * // typeof models === AiSdkModelMap<'quick' | 'deep'>
24
42
  * ```
25
43
  */
26
- declare function defineModels<T extends Record<string, LanguageModel>>(models: T): AiSdkModelMap<keyof T & string>;
44
+ declare function defineModels<T extends Record<string, AiSdkModelEntry>>(models: T): AiSdkModelMap<keyof T & string>;
45
+ /**
46
+ * Per-call AI SDK settings a host can apply on top of what the machine asked
47
+ * for — reasoning effort, `providerOptions`, and anything else the SDK's call
48
+ * options accept. Typed straight off `generateText`, so it tracks the
49
+ * installed `ai` version instead of restating its vocabulary.
50
+ *
51
+ * The request's own fields (`model`, `prompt`/`messages`, `tools`, and the
52
+ * generation settings every provider shares) are excluded: those belong to the
53
+ * machine, and a host override would silently contradict it.
54
+ */
55
+ type AiSdkCallSettings = Omit<Parameters<typeof generateText>[0], "model" | "prompt" | "messages" | "system" | "instructions" | "tools" | "toolChoice" | "output" | "abortSignal" | "stopWhen">;
27
56
  /**
28
57
  * Options for {@link createAiSdkExecutors}: either a static `models` map
29
58
  * (model refs resolved by lookup), a `resolveModel` function (refs resolved
30
59
  * dynamically, e.g. `"openai/gpt-5.4-mini"` → `openai('gpt-5.4-mini')`), or
31
60
  * both — `resolveModel` takes precedence when both are supplied.
61
+ *
62
+ * `settings` carries provider knobs that are the HOST's business rather than
63
+ * the machine's, such as reasoning effort. Pass an object to apply it to every
64
+ * call, or a function to vary it per request (`request.name` is the request's
65
+ * registered key). Core neither declares nor reads these: a machine stays
66
+ * portable, and a host that cannot honor a knob simply does not set it.
32
67
  */
33
68
  type CreateAiSdkExecutorsOptions<TModels extends AiSdkModelMap = AiSdkModelMap> = {
69
+ settings?: AiSdkCallSettings | ((request: AgentTextRequest | AgentDecisionRequest) => AiSdkCallSettings | undefined);
70
+ } & ({
34
71
  models: TModels;
35
72
  resolveModel?: (modelRef: keyof TModels & string) => LanguageModel;
36
73
  } | {
37
74
  models?: TModels;
38
75
  resolveModel: (modelRef: string) => LanguageModel;
39
- };
76
+ });
77
+ /**
78
+ * The `LanguageModel` inside a map entry, whichever form it takes. `defineModels`
79
+ * widens its return to {@link AiSdkModelMap}, so reading an entry out of the map
80
+ * to hand to a raw AI SDK call needs this to get past the union.
81
+ */
82
+ declare function toLanguageModel(entry: AiSdkModelEntry): LanguageModel;
40
83
  /**
41
84
  * Raw result shape from {@link AiSdkExecutors.generateText} — the `{ output }`
42
85
  * envelope (the validated structured object for structured-output requests,
@@ -54,8 +97,9 @@ type AiSdkGenerateResult = {
54
97
  reasoning?: string;
55
98
  /** The call's token usage. Its flat `inputTokens`/`outputTokens`/`totalTokens`/
56
99
  * `reasoningTokens`/`cachedInputTokens` fields are what `runAgent` folds into
57
- * the run result's aggregated `AgentUsage`. */
58
- usage: LanguageModelUsage;
100
+ * the run result's aggregated `AgentUsage`; the AI SDK's own nested
101
+ * `inputTokenDetails`/`outputTokenDetails` and `raw` ride along untouched. */
102
+ usage: AiSdkCallUsage;
59
103
  finishReason: FinishReason;
60
104
  toolCalls: TypedToolCall<ToolSet>[];
61
105
  toolResults: TypedToolResult<ToolSet>[];
@@ -63,13 +107,13 @@ type AiSdkGenerateResult = {
63
107
  /** Raw result shape from {@link AiSdkExecutors.streamText} — the `{ output }` envelope carrying the fully-accumulated text once the stream finishes (chunks are delivered separately via `onChunk`), plus the stream's final usage/finish metadata for `onResult`. */
64
108
  type AiSdkStreamResult = {
65
109
  output: string; /** The stream's final (awaited) usage; aggregated into the run result's `AgentUsage`. */
66
- usage: LanguageModelUsage;
110
+ usage: AiSdkCallUsage;
67
111
  finishReason: FinishReason;
68
112
  };
69
113
  /** Raw result shape from {@link AiSdkExecutors.decide} — the chosen event plus the AI SDK call metadata, delivered per decision attempt to `onResult`. */
70
114
  type AiSdkDecideResult = {
71
115
  event: ChosenEvent; /** This attempt's usage; aggregated into the run result's `AgentUsage`. */
72
- usage: LanguageModelUsage;
116
+ usage: AiSdkCallUsage;
73
117
  finishReason: FinishReason;
74
118
  };
75
119
  /** `createAiSdkExecutors` always populates all three slots (unlike the
@@ -96,4 +140,4 @@ interface AiSdkExecutors extends AgentRequestExecutors<AiSdkGenerateResult, AiSd
96
140
  */
97
141
  declare function createAiSdkExecutors<TModels extends AiSdkModelMap>(options: CreateAiSdkExecutorsOptions<TModels>): AiSdkExecutors;
98
142
  //#endregion
99
- export { AiSdkDecideResult, AiSdkExecutors, AiSdkGenerateResult, AiSdkModelMap, AiSdkStreamResult, CreateAiSdkExecutorsOptions, createAiSdkExecutors, defineModels };
143
+ export { AiSdkCallSettings, AiSdkDecideResult, AiSdkExecutors, AiSdkGenerateResult, AiSdkModelEntry, AiSdkModelMap, AiSdkStreamResult, CreateAiSdkExecutorsOptions, createAiSdkExecutors, defineModels, toLanguageModel };
package/dist/ai-sdk.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { H as isStandardSchema, _ as getAgentOutputMode, i as renderDecisionAttempts, p as buildEnvelopeSchema } from "./decision-BfhSgCc6.mjs";
1
+ import { W as isStandardSchema, h as buildEnvelopeSchema, i as renderDecisionAttempts, y as getAgentOutputMode } from "./decision-JWx6n3xR.mjs";
2
2
  import { NoObjectGeneratedError, Output, generateText, stepCountIs, streamText, tool } from "ai";
3
3
  //#region src/ai-sdk/mappers.ts
4
4
  /**
@@ -49,6 +49,27 @@ const unknownSchema = { "~standard": {
49
49
  jsonSchema: { input: () => ({}) }
50
50
  } };
51
51
  /**
52
+ * Folds AI SDK v7's nested token details onto the flat field names core
53
+ * aggregates. v7 moved `reasoningTokens` under `outputTokenDetails` and the
54
+ * cached-input count under `inputTokenDetails.cacheReadTokens`, while
55
+ * {@link AgentCallUsage} stays flat and provider-agnostic. The SDK's own shape
56
+ * is spread through unchanged, so `onResult` consumers still see every field
57
+ * the provider reported, including v7's `raw`.
58
+ */
59
+ function toAgentCallUsage(usage) {
60
+ const reasoningTokens = usage.outputTokenDetails?.reasoningTokens;
61
+ const cachedInputTokens = usage.inputTokenDetails?.cacheReadTokens;
62
+ return {
63
+ ...usage,
64
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : {},
65
+ ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {}
66
+ };
67
+ }
68
+ /** Drops keys whose value is `undefined`, so a spread cannot erase what it lands on. */
69
+ function defined(settings) {
70
+ return Object.fromEntries(Object.entries(settings).filter(([, value]) => value !== void 0));
71
+ }
72
+ /**
52
73
  * AI SDK request-mapping settings shared by `generateText`/`streamText`.
53
74
  * `AgentTextRequest.messages` (`AgentMessage[]`) and AI SDK's `ModelMessage[]`
54
75
  * are structurally compatible by design (§1 of .scratch/p0-design.md) — the cast
@@ -58,16 +79,36 @@ function toAiSdkCallSettings(request) {
58
79
  const messages = request.messages;
59
80
  return {
60
81
  system: request.system,
61
- ...messages ? { messages } : { prompt: request.prompt ?? "" },
82
+ ...messages ? {
83
+ messages,
84
+ allowSystemInMessages: true
85
+ } : { prompt: request.prompt ?? "" },
86
+ ...toAiSdkGenerationSettings(request),
87
+ ...defined({
88
+ tools: request.tools ? toAiSdkTools(request.tools) : void 0,
89
+ toolChoice: toAiSdkToolChoice(request.toolChoice)
90
+ })
91
+ };
92
+ }
93
+ /**
94
+ * The generation settings a text request and a decision request share, with
95
+ * unset keys omitted.
96
+ *
97
+ * Omitting matters: these settings are one layer of a stack — the host's
98
+ * `createAiSdkExecutors({ settings })`, then the model ref's own, then the
99
+ * request's — and an `undefined` spread over a layer below erases it. Both the
100
+ * text path and `decide` map their settings through here so neither can drift
101
+ * back into writing the keys unconditionally.
102
+ */
103
+ function toAiSdkGenerationSettings(request) {
104
+ return defined({
62
105
  temperature: request.temperature,
63
106
  maxOutputTokens: request.maxOutputTokens,
64
107
  topP: request.topP,
65
108
  topK: request.topK,
66
109
  seed: request.seed,
67
- stopSequences: request.stopSequences,
68
- tools: request.tools ? toAiSdkTools(request.tools) : void 0,
69
- toolChoice: toAiSdkToolChoice(request.toolChoice)
70
- };
110
+ stopSequences: request.stopSequences
111
+ });
71
112
  }
72
113
  /** Maps an {@link AgentToolChoice} to AI SDK's tool-choice shape — `{ type: 'tool'; name }` becomes `{ type: 'tool'; toolName }`; `'auto'`/`'none'`/`'required'`/`undefined` pass through unchanged. */
73
114
  function toAiSdkToolChoice(toolChoice) {
@@ -165,13 +206,29 @@ function maxStepsSetting(request) {
165
206
  function defineModels(models) {
166
207
  return models;
167
208
  }
209
+ /** Resolves the host's `settings` option for one request. */
210
+ function callSettings(options, request) {
211
+ const settings = options.settings;
212
+ return (typeof settings === "function" ? settings(request) : settings) ?? {};
213
+ }
168
214
  function resolveAiSdkModel(options, modelRef) {
169
- if (options.resolveModel) return options.resolveModel(modelRef);
215
+ if (options.resolveModel) return { model: options.resolveModel(modelRef) };
170
216
  const models = options.models;
171
217
  if (!models) throw new Error(`createAiSdkExecutors: no model resolver configured for '${modelRef}'.`);
172
- const model = models[modelRef];
173
- if (!model) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
174
- return model;
218
+ const entry = models[modelRef];
219
+ if (!entry) throw new Error(`createAiSdkExecutors: unknown model '${modelRef}'.`);
220
+ return isModelWithSettings(entry) ? entry : { model: entry };
221
+ }
222
+ /**
223
+ * The `LanguageModel` inside a map entry, whichever form it takes. `defineModels`
224
+ * widens its return to {@link AiSdkModelMap}, so reading an entry out of the map
225
+ * to hand to a raw AI SDK call needs this to get past the union.
226
+ */
227
+ function toLanguageModel(entry) {
228
+ return isModelWithSettings(entry) ? entry.model : entry;
229
+ }
230
+ function isModelWithSettings(entry) {
231
+ return typeof entry === "object" && entry !== null && "model" in entry;
175
232
  }
176
233
  function withJsonRepair(output) {
177
234
  return {
@@ -206,14 +263,17 @@ function withJsonRepair(output) {
206
263
  */
207
264
  function createAiSdkExecutors(options) {
208
265
  const generateText$1 = async (request, info) => {
266
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
209
267
  const common = {
210
- model: resolveAiSdkModel(options, request.model),
268
+ model,
211
269
  abortSignal: info?.signal,
270
+ ...callSettings(options, request),
271
+ ...defined(modelSettings ?? {}),
212
272
  ...toAiSdkCallSettings(request),
213
273
  ...maxStepsSetting(request)
214
274
  };
215
275
  if (isStructuredOutputRequest(request)) {
216
- const envelope = buildEnvelopeSchema(request.outputSchema, { reasoning: request.reasoning });
276
+ const envelope = buildEnvelopeSchema(request.outputSchema, { reasoning: request.includeReasoning });
217
277
  const structuredOutput = withJsonRepair(Output.object({ schema: envelope }));
218
278
  const canRetry = !request.tools || Object.keys(request.tools).length === 0;
219
279
  let result;
@@ -233,7 +293,7 @@ function createAiSdkExecutors(options) {
233
293
  return {
234
294
  output,
235
295
  ...reasoning !== void 0 ? { reasoning } : {},
236
- usage: result.usage,
296
+ usage: toAgentCallUsage(result.usage),
237
297
  finishReason: result.finishReason,
238
298
  toolCalls: result.toolCalls,
239
299
  toolResults: result.toolResults
@@ -242,44 +302,47 @@ function createAiSdkExecutors(options) {
242
302
  const result = await generateText(common);
243
303
  return {
244
304
  output: result.text,
245
- usage: result.usage,
305
+ usage: toAgentCallUsage(result.usage),
246
306
  finishReason: result.finishReason,
247
307
  toolCalls: result.toolCalls,
248
308
  toolResults: result.toolResults
249
309
  };
250
310
  };
251
311
  const streamText$1 = async (request, info) => {
312
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
252
313
  const result = streamText({
253
- model: resolveAiSdkModel(options, request.model),
314
+ model,
254
315
  abortSignal: info?.signal,
316
+ ...callSettings(options, request),
317
+ ...defined(modelSettings ?? {}),
255
318
  ...toAiSdkCallSettings(request),
256
319
  ...maxStepsSetting(request)
257
320
  });
258
321
  for await (const chunk of result.textStream) info?.onChunk?.(chunk);
259
322
  return {
260
323
  output: await result.text,
261
- usage: await result.usage,
324
+ usage: toAgentCallUsage(await result.usage),
262
325
  finishReason: await result.finishReason
263
326
  };
264
327
  };
265
328
  const decide = async (request) => {
266
- const model = resolveAiSdkModel(options, request.model);
329
+ const { model, settings: modelSettings } = resolveAiSdkModel(options, request.model);
267
330
  const tools = toAiSdkEventTools(request.events);
268
331
  const messages = toDecisionMessages(request);
269
332
  const result = await generateText({
270
333
  model,
271
334
  abortSignal: request.signal,
335
+ ...callSettings(options, request),
336
+ ...defined(modelSettings ?? {}),
272
337
  system: request.system,
273
- ...messages ? { messages } : { prompt: request.prompt ?? "" },
338
+ ...messages ? {
339
+ messages,
340
+ allowSystemInMessages: true
341
+ } : { prompt: request.prompt ?? "" },
274
342
  tools,
275
343
  toolChoice: "required",
276
344
  stopWhen: stepCountIs(1),
277
- temperature: request.temperature,
278
- maxOutputTokens: request.maxOutputTokens,
279
- topP: request.topP,
280
- topK: request.topK,
281
- seed: request.seed,
282
- stopSequences: request.stopSequences
345
+ ...toAiSdkGenerationSettings(request)
283
346
  });
284
347
  const toolCall = result.toolCalls[0];
285
348
  if (!toolCall) throw new Error("createAiSdkExecutors: decide — model did not call an event tool.");
@@ -290,7 +353,7 @@ function createAiSdkExecutors(options) {
290
353
  ...toolCall.input && typeof toolCall.input === "object" ? toolCall.input : {},
291
354
  type: chosenEvent.type
292
355
  },
293
- usage: result.usage,
356
+ usage: toAgentCallUsage(result.usage),
294
357
  finishReason: result.finishReason
295
358
  };
296
359
  };
@@ -301,4 +364,4 @@ function createAiSdkExecutors(options) {
301
364
  };
302
365
  }
303
366
  //#endregion
304
- export { createAiSdkExecutors, defineModels };
367
+ export { createAiSdkExecutors, defineModels, toLanguageModel };