ai 6.0.237 → 6.0.238

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.
@@ -164,7 +164,7 @@ function detectMediaType({
164
164
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
165
165
 
166
166
  // src/version.ts
167
- var VERSION = true ? "6.0.237" : "0.0.0-test";
167
+ var VERSION = true ? "6.0.238" : "0.0.0-test";
168
168
 
169
169
  // src/util/download/download.ts
170
170
  var download = async ({
@@ -144,7 +144,7 @@ import {
144
144
  } from "@ai-sdk/provider-utils";
145
145
 
146
146
  // src/version.ts
147
- var VERSION = true ? "6.0.237" : "0.0.0-test";
147
+ var VERSION = true ? "6.0.238" : "0.0.0-test";
148
148
 
149
149
  // src/util/download/download.ts
150
150
  var download = async ({
@@ -117,6 +117,10 @@ const agent = new ToolLoopAgent({
117
117
 
118
118
  Learn more about [loop control and stop conditions](/docs/agents/loop-control).
119
119
 
120
+ Model call settings returned from `prepareStep`, such as `temperature`, apply
121
+ only to the current step. Later steps use the agent's top-level setting unless
122
+ they return another override.
123
+
120
124
  ### Tool Choice
121
125
 
122
126
  Control how the agent uses tools:
@@ -178,6 +178,46 @@ const result = await agent.generate({
178
178
  });
179
179
  ```
180
180
 
181
+ ### Model Call Settings
182
+
183
+ Override provider-agnostic model call settings for an individual step. This can
184
+ be useful when tool-calling steps need more deterministic sampling than the
185
+ final response:
186
+
187
+ ```ts
188
+ import { ToolLoopAgent } from 'ai';
189
+ __PROVIDER_IMPORT__;
190
+
191
+ const agent = new ToolLoopAgent({
192
+ model: __MODEL__,
193
+ temperature: 0.7,
194
+ tools: {
195
+ // your tools
196
+ },
197
+ prepareStep: async ({ stepNumber }) => {
198
+ if (stepNumber === 0) {
199
+ return {
200
+ temperature: 0,
201
+ maxOutputTokens: 300,
202
+ };
203
+ }
204
+
205
+ return {};
206
+ },
207
+ });
208
+
209
+ const result = await agent.generate({
210
+ prompt: '...',
211
+ });
212
+ ```
213
+
214
+ `prepareStep` can override `maxOutputTokens`, `temperature`, `topP`, `topK`,
215
+ `presencePenalty`, `frequencyPenalty`, `stopSequences`, and `seed`. These
216
+ overrides apply only to the current step. When a setting is omitted or
217
+ `undefined`, the top-level value is used for that step. Defined falsy values
218
+ such as `temperature: 0`, `seed: 0`, and an empty `stopSequences` array are
219
+ preserved.
220
+
181
221
  ### Context Management
182
222
 
183
223
  Manage growing conversation history in long-running loops:
@@ -197,7 +197,7 @@ The event types for each method are the same as the corresponding [event callbac
197
197
 
198
198
  `generateText` records 3 types of spans:
199
199
 
200
- - `ai.generateText` (span): the full length of the generateText call. It contains 1 or more `ai.generateText.doGenerate` spans.
200
+ - `ai.generateText` (span): the full length of the generateText call. It is the direct parent of 1 or more `ai.generateText.doGenerate` spans and any `ai.toolCall` spans recorded for the call.
201
201
  It contains the [basic LLM span information](#basic-llm-span-information) and the following attributes:
202
202
 
203
203
  - `operation.name`: `ai.generateText` and the functionId that was set through `telemetry.functionId`
@@ -208,7 +208,7 @@ The event types for each method are the same as the corresponding [event callbac
208
208
  - `ai.response.finishReason`: the reason why the generation finished
209
209
  - `ai.settings.maxOutputTokens`: the maximum number of output tokens that were set
210
210
 
211
- - `ai.generateText.doGenerate` (span): a provider doGenerate call. It can contain `ai.toolCall` spans.
211
+ - `ai.generateText.doGenerate` (span): a provider doGenerate call.
212
212
  It contains the [call LLM span information](#call-llm-span-information) and the following attributes:
213
213
 
214
214
  - `operation.name`: `ai.generateText.doGenerate` and the functionId that was set through `telemetry.functionId`
@@ -229,7 +229,7 @@ The event types for each method are the same as the corresponding [event callbac
229
229
 
230
230
  `streamText` records 3 types of spans and 2 types of events:
231
231
 
232
- - `ai.streamText` (span): the full length of the streamText call. It contains a `ai.streamText.doStream` span.
232
+ - `ai.streamText` (span): the full length of the streamText call. It is the direct parent of 1 or more `ai.streamText.doStream` spans and any `ai.toolCall` spans recorded for the call.
233
233
  It contains the [basic LLM span information](#basic-llm-span-information) and the following attributes:
234
234
 
235
235
  - `operation.name`: `ai.streamText` and the functionId that was set through `telemetry.functionId`
@@ -241,7 +241,7 @@ The event types for each method are the same as the corresponding [event callbac
241
241
  - `ai.settings.maxOutputTokens`: the maximum number of output tokens that were set
242
242
 
243
243
  - `ai.streamText.doStream` (span): a provider doStream call.
244
- This span contains an `ai.stream.firstChunk` event and `ai.toolCall` spans.
244
+ This span can contain `ai.stream.firstChunk` and `ai.stream.finish` events.
245
245
  It contains the [call LLM span information](#call-llm-span-information) and the following attributes:
246
246
 
247
247
  - `operation.name`: `ai.streamText.doStream` and the functionId that was set through `telemetry.functionId`
@@ -530,7 +530,7 @@ To see `generateText` in action, check out [these examples](#examples).
530
530
  type: '(options: PrepareStepOptions) => PrepareStepResult<TOOLS> | Promise<PrepareStepResult<TOOLS>>',
531
531
  isOptional: true,
532
532
  description:
533
- 'Optional function that you can use to provide different settings for a step. You can modify the model, tool choices, active tools, system prompt, and input messages for each step.',
533
+ 'Optional function that you can use to provide different settings for a step. You can modify the model, model call settings, tool choices, active tools, system prompt, and input messages for each step.',
534
534
  properties: [
535
535
  {
536
536
  type: 'PrepareStepFunction<TOOLS>',
@@ -590,6 +590,62 @@ To see `generateText` in action, check out [these examples](#examples).
590
590
  description:
591
591
  'Optionally override which LanguageModel instance is used for this step.',
592
592
  },
593
+ {
594
+ name: 'maxOutputTokens',
595
+ type: 'number',
596
+ isOptional: true,
597
+ description:
598
+ 'Maximum number of tokens to generate for this step. Uses the top-level value when omitted or undefined.',
599
+ },
600
+ {
601
+ name: 'temperature',
602
+ type: 'number',
603
+ isOptional: true,
604
+ description:
605
+ 'Temperature for this step. Uses the top-level value when omitted or undefined.',
606
+ },
607
+ {
608
+ name: 'topP',
609
+ type: 'number',
610
+ isOptional: true,
611
+ description:
612
+ 'Nucleus sampling value for this step. Uses the top-level value when omitted or undefined.',
613
+ },
614
+ {
615
+ name: 'topK',
616
+ type: 'number',
617
+ isOptional: true,
618
+ description:
619
+ 'Top-K sampling value for this step. Uses the top-level value when omitted or undefined.',
620
+ },
621
+ {
622
+ name: 'presencePenalty',
623
+ type: 'number',
624
+ isOptional: true,
625
+ description:
626
+ 'Presence penalty for this step. Uses the top-level value when omitted or undefined.',
627
+ },
628
+ {
629
+ name: 'frequencyPenalty',
630
+ type: 'number',
631
+ isOptional: true,
632
+ description:
633
+ 'Frequency penalty for this step. Uses the top-level value when omitted or undefined.',
634
+ },
635
+ {
636
+ name: 'stopSequences',
637
+ type: 'string[]',
638
+ isOptional: true,
639
+ description:
640
+ 'Stop sequences for this step. Uses the top-level value when omitted or undefined.',
641
+ },
642
+ {
643
+ name: 'seed',
644
+ type: 'number',
645
+ isOptional: true,
646
+ description:
647
+ 'Random sampling seed for this step. Uses the top-level value when omitted or undefined.',
648
+ },
593
649
  {
594
650
  name: 'toolChoice',
595
651
  type: 'ToolChoice<TOOLS>',
@@ -1977,7 +2033,8 @@ To see `generateText` in action, check out [these examples](#examples).
1977
2033
  {
1978
2034
  name: 'text',
1979
2035
  type: 'string',
1980
- description: 'The generated text by the model.',
2036
+ description:
2037
+ 'The concatenation of all text parts generated in the final step. It is an empty string if the final step contains no text parts. Inspect `content` for a text part to distinguish that case.',
1981
2038
  },
1982
2039
  {
1983
2040
  name: 'reasoning',
@@ -2388,7 +2445,8 @@ To see `generateText` in action, check out [these examples](#examples).
2388
2445
  {
2389
2446
  name: 'text',
2390
2447
  type: 'string',
2391
- description: 'The generated text.',
2448
+ description:
2449
+ 'The concatenation of all text parts generated in this step. It is an empty string if the step contains no text parts.',
2392
2450
  },
2393
2451
  {
2394
2452
  name: 'reasoning',
@@ -574,7 +574,7 @@ To see `streamText` in action, check out [these examples](#examples).
574
574
  type: '(options: PrepareStepOptions) => PrepareStepResult<TOOLS> | Promise<PrepareStepResult<TOOLS>>',
575
575
  isOptional: true,
576
576
  description:
577
- 'Optional function that you can use to provide different settings for a step. You can modify the model, tool choices, active tools, system prompt, and input messages for each step.',
577
+ 'Optional function that you can use to provide different settings for a step. You can modify the model, model call settings, tool choices, active tools, system prompt, and input messages for each step.',
578
578
  properties: [
579
579
  {
580
580
  type: 'PrepareStepFunction<TOOLS>',
@@ -634,6 +634,62 @@ To see `streamText` in action, check out [these examples](#examples).
634
634
  description:
635
635
  'Optionally override which LanguageModel instance is used for this step.',
636
636
  },
637
+ {
638
+ name: 'maxOutputTokens',
639
+ type: 'number',
640
+ isOptional: true,
641
+ description:
642
+ 'Maximum number of tokens to generate for this step. Uses the top-level value when omitted or undefined.',
643
+ },
644
+ {
645
+ name: 'temperature',
646
+ type: 'number',
647
+ isOptional: true,
648
+ description:
649
+ 'Temperature for this step. Uses the top-level value when omitted or undefined.',
650
+ },
651
+ {
652
+ name: 'topP',
653
+ type: 'number',
654
+ isOptional: true,
655
+ description:
656
+ 'Nucleus sampling value for this step. Uses the top-level value when omitted or undefined.',
657
+ },
658
+ {
659
+ name: 'topK',
660
+ type: 'number',
661
+ isOptional: true,
662
+ description:
663
+ 'Top-K sampling value for this step. Uses the top-level value when omitted or undefined.',
664
+ },
665
+ {
666
+ name: 'presencePenalty',
667
+ type: 'number',
668
+ isOptional: true,
669
+ description:
670
+ 'Presence penalty for this step. Uses the top-level value when omitted or undefined.',
671
+ },
672
+ {
673
+ name: 'frequencyPenalty',
674
+ type: 'number',
675
+ isOptional: true,
676
+ description:
677
+ 'Frequency penalty for this step. Uses the top-level value when omitted or undefined.',
678
+ },
679
+ {
680
+ name: 'stopSequences',
681
+ type: 'string[]',
682
+ isOptional: true,
683
+ description:
684
+ 'Stop sequences for this step. Uses the top-level value when omitted or undefined.',
685
+ },
686
+ {
687
+ name: 'seed',
688
+ type: 'number',
689
+ isOptional: true,
690
+ description:
691
+ 'Random sampling seed for this step. Uses the top-level value when omitted or undefined.',
692
+ },
637
693
  {
638
694
  name: 'toolChoice',
639
695
  type: 'ToolChoice<TOOLS>',
@@ -102,7 +102,7 @@ To see `ToolLoopAgent` in action, check out [these examples](#examples).
102
102
  type: 'PrepareStepFunction',
103
103
  isOptional: true,
104
104
  description:
105
- 'Optional function to mutate step settings or inject state for each agent step.',
105
+ 'Optional function to mutate step settings or inject state for each agent step, including per-step model call settings such as temperature, maxOutputTokens, sampling controls, penalties, stop sequences, and seed. Model call setting overrides apply only to the current step.',
106
106
  },
107
107
  {
108
108
  name: 'experimental_repairToolCall',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.237",
3
+ "version": "6.0.238",
4
4
  "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -45,9 +45,9 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
- "@ai-sdk/gateway": "3.0.159",
48
+ "@ai-sdk/gateway": "3.0.160",
49
49
  "@ai-sdk/provider": "3.0.14",
50
- "@ai-sdk/provider-utils": "4.0.40"
50
+ "@ai-sdk/provider-utils": "4.0.41"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@edge-runtime/vm": "^5.0.0",
@@ -36,7 +36,9 @@ export interface GenerateTextResult<
36
36
  readonly content: Array<ContentPart<TOOLS>>;
37
37
 
38
38
  /**
39
- * The text that was generated in the last step.
39
+ * The concatenation of all text parts generated in the final step.
40
+ * It is an empty string if the final step contains no text parts.
41
+ * Inspect `content` for a text part to distinguish that case.
40
42
  */
41
43
  readonly text: string;
42
44
 
@@ -77,6 +77,7 @@ import { text, type Output } from './output';
77
77
  import type { InferCompleteOutput } from './output-utils';
78
78
  import { parseToolCall } from './parse-tool-call';
79
79
  import type { PrepareStepFunction } from './prepare-step';
80
+ import { prepareStepCallSettings } from './prepare-step-call-settings';
80
81
  import type { ResponseMessage } from './response-message';
81
82
  import { DefaultStepResult, type StepResult } from './step-result';
82
83
  import {
@@ -752,6 +753,11 @@ export async function generateText<
752
753
  prepareStepResult?.providerOptions,
753
754
  );
754
755
 
756
+ const stepCallSettings = prepareStepCallSettings({
757
+ callSettings,
758
+ stepSettings: prepareStepResult,
759
+ });
760
+
755
761
  await notify({
756
762
  event: {
757
763
  stepNumber: steps.length,
@@ -816,20 +822,22 @@ export async function generateText<
816
822
  'gen_ai.system': stepModel.provider,
817
823
  'gen_ai.request.model': stepModel.modelId,
818
824
  'gen_ai.request.frequency_penalty':
819
- settings.frequencyPenalty,
820
- 'gen_ai.request.max_tokens': settings.maxOutputTokens,
821
- 'gen_ai.request.presence_penalty': settings.presencePenalty,
822
- 'gen_ai.request.stop_sequences': settings.stopSequences,
823
- 'gen_ai.request.temperature':
824
- settings.temperature ?? undefined,
825
- 'gen_ai.request.top_k': settings.topK,
826
- 'gen_ai.request.top_p': settings.topP,
825
+ stepCallSettings.frequencyPenalty,
826
+ 'gen_ai.request.max_tokens':
827
+ stepCallSettings.maxOutputTokens,
828
+ 'gen_ai.request.presence_penalty':
829
+ stepCallSettings.presencePenalty,
830
+ 'gen_ai.request.stop_sequences':
831
+ stepCallSettings.stopSequences,
832
+ 'gen_ai.request.temperature': stepCallSettings.temperature,
833
+ 'gen_ai.request.top_k': stepCallSettings.topK,
834
+ 'gen_ai.request.top_p': stepCallSettings.topP,
827
835
  },
828
836
  }),
829
837
  tracer,
830
838
  fn: async span => {
831
839
  const result = await stepModel.doGenerate({
832
- ...callSettings,
840
+ ...stepCallSettings,
833
841
  tools: stepTools,
834
842
  toolChoice: stepToolChoice,
835
843
  responseFormat: await output?.responseFormat,
@@ -0,0 +1,30 @@
1
+ import { prepareCallSettings } from '../prompt/prepare-call-settings';
2
+ import type { PrepareStepCallSettings } from './prepare-step';
3
+
4
+ /**
5
+ * Resolves model call settings for a single step.
6
+ *
7
+ * Undefined step settings intentionally fall back to the outer call settings,
8
+ * while defined falsy values such as `temperature: 0` and `seed: 0` are kept.
9
+ */
10
+ export function prepareStepCallSettings({
11
+ callSettings,
12
+ stepSettings,
13
+ }: {
14
+ callSettings: PrepareStepCallSettings;
15
+ stepSettings: PrepareStepCallSettings | undefined;
16
+ }): PrepareStepCallSettings {
17
+ return prepareCallSettings({
18
+ maxOutputTokens:
19
+ stepSettings?.maxOutputTokens ?? callSettings.maxOutputTokens,
20
+ temperature: stepSettings?.temperature ?? callSettings.temperature,
21
+ topP: stepSettings?.topP ?? callSettings.topP,
22
+ topK: stepSettings?.topK ?? callSettings.topK,
23
+ presencePenalty:
24
+ stepSettings?.presencePenalty ?? callSettings.presencePenalty,
25
+ frequencyPenalty:
26
+ stepSettings?.frequencyPenalty ?? callSettings.frequencyPenalty,
27
+ stopSequences: stepSettings?.stopSequences ?? callSettings.stopSequences,
28
+ seed: stepSettings?.seed ?? callSettings.seed,
29
+ });
30
+ }
@@ -4,9 +4,22 @@ import type {
4
4
  SystemModelMessage,
5
5
  Tool,
6
6
  } from '@ai-sdk/provider-utils';
7
+ import type { CallSettings } from '../prompt/call-settings';
7
8
  import type { LanguageModel, ToolChoice } from '../types/language-model';
8
9
  import type { StepResult } from './step-result';
9
10
 
11
+ export type PrepareStepCallSettings = Pick<
12
+ CallSettings,
13
+ | 'maxOutputTokens'
14
+ | 'temperature'
15
+ | 'topP'
16
+ | 'topK'
17
+ | 'presencePenalty'
18
+ | 'frequencyPenalty'
19
+ | 'stopSequences'
20
+ | 'seed'
21
+ >;
22
+
10
23
  /**
11
24
  * Function that you can use to provide different settings for a step.
12
25
  *
@@ -51,12 +64,16 @@ export type PrepareStepFunction<
51
64
 
52
65
  /**
53
66
  * The result type returned by a {@link PrepareStepFunction},
54
- * allowing per-step overrides of model, tools, or messages.
67
+ * allowing per-step overrides of model call settings, model, tools, or
68
+ * messages.
69
+ *
70
+ * Model call setting overrides apply only to the current step. Undefined
71
+ * settings fall back to the outer call settings.
55
72
  */
56
73
  export type PrepareStepResult<
57
74
  TOOLS extends Record<string, Tool> = Record<string, Tool>,
58
75
  > =
59
- | {
76
+ | ({
60
77
  /**
61
78
  * Optionally override which LanguageModel instance is used for this step.
62
79
  */
@@ -99,5 +116,5 @@ export type PrepareStepResult<
99
116
  * container IDs for Anthropic's code execution.
100
117
  */
101
118
  providerOptions?: ProviderOptions;
102
- }
119
+ } & PrepareStepCallSettings)
103
120
  | undefined;
@@ -65,7 +65,8 @@ export type StepResult<TOOLS extends ToolSet> = {
65
65
  readonly content: Array<ContentPart<TOOLS>>;
66
66
 
67
67
  /**
68
- * The generated text.
68
+ * The concatenation of all text parts generated in this step.
69
+ * It is an empty string if the step contains no text parts.
69
70
  */
70
71
  readonly text: string;
71
72
 
@@ -103,6 +103,7 @@ import type {
103
103
  InferPartialOutput,
104
104
  } from './output-utils';
105
105
  import type { PrepareStepFunction } from './prepare-step';
106
+ import { prepareStepCallSettings } from './prepare-step-call-settings';
106
107
  import type { ResponseMessage } from './response-message';
107
108
  import {
108
109
  runToolsTransformation,
@@ -714,6 +715,11 @@ function createOutputTransformStream<
714
715
  textChunk += chunk.text;
715
716
  textProviderMetadata = chunk.providerMetadata ?? textProviderMetadata;
716
717
 
718
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
719
+ controller.enqueue({ part: chunk, partialOutput: undefined });
720
+ return;
721
+ }
722
+
717
723
  // only publish if partial json can be parsed:
718
724
  const result = await output.parsePartialOutput({ text });
719
725
 
@@ -1670,6 +1676,11 @@ class DefaultStreamTextResult<
1670
1676
  prepareStepResult?.providerOptions,
1671
1677
  );
1672
1678
 
1679
+ const stepCallSettings = prepareStepCallSettings({
1680
+ callSettings,
1681
+ stepSettings: prepareStepResult,
1682
+ });
1683
+
1673
1684
  await notify({
1674
1685
  event: {
1675
1686
  stepNumber: recordedSteps.length,
@@ -1735,14 +1746,16 @@ class DefaultStreamTextResult<
1735
1746
  'gen_ai.system': stepModel.provider,
1736
1747
  'gen_ai.request.model': stepModel.modelId,
1737
1748
  'gen_ai.request.frequency_penalty':
1738
- callSettings.frequencyPenalty,
1739
- 'gen_ai.request.max_tokens': callSettings.maxOutputTokens,
1749
+ stepCallSettings.frequencyPenalty,
1750
+ 'gen_ai.request.max_tokens':
1751
+ stepCallSettings.maxOutputTokens,
1740
1752
  'gen_ai.request.presence_penalty':
1741
- callSettings.presencePenalty,
1742
- 'gen_ai.request.stop_sequences': callSettings.stopSequences,
1743
- 'gen_ai.request.temperature': callSettings.temperature,
1744
- 'gen_ai.request.top_k': callSettings.topK,
1745
- 'gen_ai.request.top_p': callSettings.topP,
1753
+ stepCallSettings.presencePenalty,
1754
+ 'gen_ai.request.stop_sequences':
1755
+ stepCallSettings.stopSequences,
1756
+ 'gen_ai.request.temperature': stepCallSettings.temperature,
1757
+ 'gen_ai.request.top_k': stepCallSettings.topK,
1758
+ 'gen_ai.request.top_p': stepCallSettings.topP,
1746
1759
  },
1747
1760
  }),
1748
1761
  tracer,
@@ -1751,7 +1764,7 @@ class DefaultStreamTextResult<
1751
1764
  startTimestampMs: now(), // get before the call
1752
1765
  doStreamSpan,
1753
1766
  result: await stepModel.doStream({
1754
- ...callSettings,
1767
+ ...stepCallSettings,
1755
1768
  tools: stepTools,
1756
1769
  toolChoice: stepToolChoice,
1757
1770
  responseFormat: await output?.responseFormat,
@@ -1878,15 +1891,18 @@ class DefaultStreamTextResult<
1878
1891
  }
1879
1892
 
1880
1893
  case 'text-delta': {
1881
- if (chunk.delta.length > 0) {
1894
+ if (
1895
+ chunk.delta.length > 0 ||
1896
+ chunk.providerMetadata != null
1897
+ ) {
1882
1898
  controller.enqueue({
1883
1899
  type: 'text-delta',
1884
1900
  id: chunk.id,
1885
1901
  text: chunk.delta,
1886
1902
  providerMetadata: chunk.providerMetadata,
1887
1903
  });
1888
- activeText += chunk.delta;
1889
1904
  }
1905
+ activeText += chunk.delta;
1890
1906
  break;
1891
1907
  }
1892
1908