ai 7.0.41 → 7.0.42
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/CHANGELOG.md +14 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.js +36 -5
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +2 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.js.map +1 -1
- package/docs/03-agents/02-building-agents.mdx +4 -0
- package/docs/03-agents/04-loop-control.mdx +40 -0
- package/docs/03-ai-sdk-core/36-transcription.mdx +1 -0
- package/docs/03-ai-sdk-core/65-devtools.mdx +47 -1
- package/docs/06-advanced/11-secure-url-fetching.mdx +18 -24
- package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +68 -3
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +64 -1
- package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +1 -1
- package/package.json +3 -3
- package/src/generate-text/generate-text-result.ts +3 -1
- package/src/generate-text/generate-text.ts +8 -2
- package/src/generate-text/prepare-step-call-settings.ts +31 -0
- package/src/generate-text/prepare-step.ts +8 -3
- package/src/generate-text/step-result.ts +2 -1
- package/src/generate-text/stream-text.ts +16 -2
|
@@ -129,6 +129,10 @@ const result = await agent.generate({
|
|
|
129
129
|
});
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
Model call settings returned from `prepareStep`, such as `temperature`, apply
|
|
133
|
+
only to the current step. Later steps use the agent's top-level setting unless
|
|
134
|
+
they return another override.
|
|
135
|
+
|
|
132
136
|
For the full model, including sensitive context filtering and where each context
|
|
133
137
|
value is available, see [Runtime and Tool
|
|
134
138
|
Context](/docs/ai-sdk-core/runtime-and-tool-context).
|
|
@@ -180,6 +180,46 @@ const result = await agent.generate({
|
|
|
180
180
|
});
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
+
### Model Call Settings
|
|
184
|
+
|
|
185
|
+
Override provider-agnostic model call settings for an individual step. This can
|
|
186
|
+
be useful when tool-calling steps need more deterministic sampling than the
|
|
187
|
+
final response:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import { ToolLoopAgent } from 'ai';
|
|
191
|
+
__PROVIDER_IMPORT__;
|
|
192
|
+
|
|
193
|
+
const agent = new ToolLoopAgent({
|
|
194
|
+
model: __MODEL__,
|
|
195
|
+
temperature: 0.7,
|
|
196
|
+
tools: {
|
|
197
|
+
// your tools
|
|
198
|
+
},
|
|
199
|
+
prepareStep: async ({ stepNumber }) => {
|
|
200
|
+
if (stepNumber === 0) {
|
|
201
|
+
return {
|
|
202
|
+
temperature: 0,
|
|
203
|
+
maxOutputTokens: 300,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return {};
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const result = await agent.generate({
|
|
212
|
+
prompt: '...',
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`prepareStep` can override `maxOutputTokens`, `temperature`, `topP`, `topK`,
|
|
217
|
+
`presencePenalty`, `frequencyPenalty`, `stopSequences`, `seed`, and
|
|
218
|
+
`reasoning`. These overrides apply only to the current step. When a setting is
|
|
219
|
+
omitted or `undefined`, the top-level value is used for that step. Defined
|
|
220
|
+
falsy values such as `temperature: 0`, `seed: 0`, and an empty
|
|
221
|
+
`stopSequences` array are preserved.
|
|
222
|
+
|
|
183
223
|
### Context Management
|
|
184
224
|
|
|
185
225
|
Long-running agents can accumulate large tool results, reasoning parts, and assistant messages. Use `prepareStep` to mutate the message state that will be used by later steps. This is useful for compaction, and you decide when compaction should happen.
|
|
@@ -304,6 +304,7 @@ try {
|
|
|
304
304
|
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#streaming-transcription-models) | `scribe_v2_realtime` |
|
|
305
305
|
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3-turbo` |
|
|
306
306
|
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3` |
|
|
307
|
+
| [Mistral](/providers/ai-sdk-providers/mistral#transcription-models) | `voxtral-mini-latest` |
|
|
307
308
|
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `whisper-1` |
|
|
308
309
|
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-transcribe` |
|
|
309
310
|
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-mini-transcribe` |
|
|
@@ -105,10 +105,56 @@ the workspace.
|
|
|
105
105
|
DevTools captures the following information from your AI SDK calls:
|
|
106
106
|
|
|
107
107
|
- **Input parameters and prompts**: View the complete input sent to your LLM
|
|
108
|
-
- **Output content and tool calls**: Inspect generated text and tool
|
|
108
|
+
- **Output content and tool calls**: Inspect generated text, tool invocations, and tool results
|
|
109
|
+
- **Media previews**: View images, audio, and video included in prompts, tool inputs, and tool outputs
|
|
109
110
|
- **Token usage and timing**: Monitor resource consumption and performance
|
|
110
111
|
- **Raw provider data**: Access provider request and response payloads when body retention is enabled
|
|
111
112
|
|
|
113
|
+
### Media previews
|
|
114
|
+
|
|
115
|
+
DevTools recognizes current `file` content parts as well as the deprecated
|
|
116
|
+
`image-*`, `file-*`, and `media` tool-result aliases. Inline image, audio, and
|
|
117
|
+
video data is previewed directly, while the captured JSON shape and metadata
|
|
118
|
+
remain available for inspection. The viewer displays at most 8 previews per
|
|
119
|
+
value, traverses at most 12 nested levels, and embeds inline previews up to 5
|
|
120
|
+
MiB. Longer JSON strings are truncated in the viewer to avoid duplicating large
|
|
121
|
+
base64 payloads. Binary values in recognized media-bearing fields are persisted
|
|
122
|
+
as base64 so they remain previewable; unrelated binary values retain their
|
|
123
|
+
normal JSON representation.
|
|
124
|
+
|
|
125
|
+
For example, a tool can return media through `toModelOutput`:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { tool } from 'ai';
|
|
129
|
+
import { z } from 'zod';
|
|
130
|
+
|
|
131
|
+
const captureScreenshot = tool({
|
|
132
|
+
inputSchema: z.object({}),
|
|
133
|
+
execute: async () => ({
|
|
134
|
+
base64: await captureScreenshotAsBase64(),
|
|
135
|
+
}),
|
|
136
|
+
toModelOutput: ({ output }) => ({
|
|
137
|
+
type: 'content',
|
|
138
|
+
value: [
|
|
139
|
+
{
|
|
140
|
+
type: 'file',
|
|
141
|
+
filename: 'screenshot.png',
|
|
142
|
+
mediaType: 'image/png',
|
|
143
|
+
data: { type: 'data', data: output.base64 },
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
}),
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Remote `http` and `https` media is not loaded automatically. Select **Load
|
|
151
|
+
preview** in the viewer to fetch it with anonymous CORS and no referrer.
|
|
152
|
+
Cross-origin browser credentials are omitted, but same-origin browser
|
|
153
|
+
credentials may still be included by the browser. URLs containing embedded
|
|
154
|
+
usernames or passwords are rejected. Unsupported media, provider references,
|
|
155
|
+
malformed values, unsafe URL schemes, and inline values over the preview limit
|
|
156
|
+
retain their JSON and metadata fallback without an embedded preview.
|
|
157
|
+
|
|
112
158
|
Telemetry is enabled automatically, but AI SDK 7 excludes raw request and response bodies from step results by default. To make them available to DevTools for `generateText`, enable body retention on the call:
|
|
113
159
|
|
|
114
160
|
```ts highlight="4-7"
|
|
@@ -27,6 +27,10 @@ When the SDK fetches a URL taken from a provider response, it:
|
|
|
27
27
|
are rejected too.
|
|
28
28
|
- **Re-validates every redirect hop** — a URL that passes but then redirects to
|
|
29
29
|
an internal address is blocked; the redirect is never followed blindly.
|
|
30
|
+
- **Validates DNS at connection time on Node.js** — every resolved address is
|
|
31
|
+
checked, and the socket is pinned to the validated DNS result so DNS
|
|
32
|
+
rebinding cannot introduce a different address between validation and
|
|
33
|
+
connection.
|
|
30
34
|
- **Strips risky request headers** — proxy-forwarding, cloud-metadata, and
|
|
31
35
|
cookie headers are removed before the request.
|
|
32
36
|
- **Drops credentials across origins** — caller headers (`Authorization`,
|
|
@@ -43,28 +47,17 @@ custom `baseURL` pointing at a self-hosted or `localhost` deployment) are
|
|
|
43
47
|
exempt from these checks — they target exactly the host you told the SDK to
|
|
44
48
|
talk to. Any redirect off that origin is still validated.
|
|
45
49
|
|
|
46
|
-
##
|
|
50
|
+
## DNS validation across runtimes
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
On Node.js, the default validated download fetch uses `node:dns` and an
|
|
53
|
+
`undici` connector hook to validate every resolved address at connection time.
|
|
54
|
+
The connector uses those exact results, closing both hostname-to-private-IP and
|
|
55
|
+
DNS-rebinding bypasses.
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
time-of-check/time-of-use window).
|
|
56
|
-
|
|
57
|
-
### Why this isn't built in
|
|
58
|
-
|
|
59
|
-
Closing these requires resolving DNS and pinning the resolved IP **at connect
|
|
60
|
-
time** — Node-only capabilities (`node:dns`, a custom `undici` dispatcher). The
|
|
61
|
-
SDK's provider utilities are **cross-runtime**: they run on the edge, in the
|
|
62
|
-
browser, and on Bun/Deno, with no Node-only dependencies, so those APIs aren't
|
|
63
|
-
available there. The threat is also specifically a **server-side** one — on the
|
|
64
|
-
edge and in the browser, outbound `fetch` cannot reach a host's internal network
|
|
65
|
-
or metadata endpoint in the first place. So connect-time IP pinning is only
|
|
66
|
-
meaningful, and only available, on a Node server — which is exactly where you
|
|
67
|
-
can add it yourself.
|
|
57
|
+
If you inject or globally replace `fetch`, it is responsible for equivalent DNS
|
|
58
|
+
validation and connection pinning. Other runtimes do not expose Node's
|
|
59
|
+
DNS/socket hooks, so server deployments on those runtimes should restrict
|
|
60
|
+
network egress to private, loopback, link-local, and cloud-metadata ranges.
|
|
68
61
|
|
|
69
62
|
## Hardening your deployment
|
|
70
63
|
|
|
@@ -77,9 +70,10 @@ Deny your server's network egress to `169.254.0.0/16`, RFC-1918 ranges, and
|
|
|
77
70
|
loopback. This is the most robust control and is independent of application
|
|
78
71
|
code.
|
|
79
72
|
|
|
80
|
-
### 2.
|
|
73
|
+
### 2. Harden an injected `fetch`
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
The Node.js default is already pinned. If you inject or globally replace
|
|
76
|
+
`fetch`, back it with an `undici`
|
|
83
77
|
`Agent` whose `connect.lookup` validates the resolved IP and lets the socket
|
|
84
78
|
connect only to a safe address — closing both the hostname-to-private and the
|
|
85
79
|
DNS-rebinding windows:
|
|
@@ -113,5 +107,5 @@ import { createFal } from '@ai-sdk/fal';
|
|
|
113
107
|
const fal = createFal({ fetch: safeFetch });
|
|
114
108
|
```
|
|
115
109
|
|
|
116
|
-
The SDK's
|
|
117
|
-
keep both.
|
|
110
|
+
The SDK's URL validation and your custom fetch's connect-time pinning are
|
|
111
|
+
complementary — keep both.
|
|
@@ -597,7 +597,7 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
597
597
|
type: '(options: PrepareStepOptions) => PrepareStepResult<TOOLS> | Promise<PrepareStepResult<TOOLS>>',
|
|
598
598
|
isOptional: true,
|
|
599
599
|
description:
|
|
600
|
-
'Optional function that you can use to provide different settings for a step. You can modify the model, tool choices, active tools, instructions, input messages, and experimental sandbox for each step.',
|
|
600
|
+
'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, instructions, input messages, and experimental sandbox for each step.',
|
|
601
601
|
properties: [
|
|
602
602
|
{
|
|
603
603
|
type: 'PrepareStepFunction<TOOLS>',
|
|
@@ -682,6 +682,69 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
682
682
|
description:
|
|
683
683
|
'Optionally override which LanguageModel instance is used for this step.',
|
|
684
684
|
},
|
|
685
|
+
{
|
|
686
|
+
name: 'maxOutputTokens',
|
|
687
|
+
type: 'number',
|
|
688
|
+
isOptional: true,
|
|
689
|
+
description:
|
|
690
|
+
'Maximum number of tokens to generate for this step. Uses the top-level value when omitted or undefined.',
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
name: 'temperature',
|
|
694
|
+
type: 'number',
|
|
695
|
+
isOptional: true,
|
|
696
|
+
description:
|
|
697
|
+
'Temperature for this step. Uses the top-level value when omitted or undefined.',
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
name: 'topP',
|
|
701
|
+
type: 'number',
|
|
702
|
+
isOptional: true,
|
|
703
|
+
description:
|
|
704
|
+
'Nucleus sampling value for this step. Uses the top-level value when omitted or undefined.',
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
name: 'topK',
|
|
708
|
+
type: 'number',
|
|
709
|
+
isOptional: true,
|
|
710
|
+
description:
|
|
711
|
+
'Top-K sampling value for this step. Uses the top-level value when omitted or undefined.',
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
name: 'presencePenalty',
|
|
715
|
+
type: 'number',
|
|
716
|
+
isOptional: true,
|
|
717
|
+
description:
|
|
718
|
+
'Presence penalty for this step. Uses the top-level value when omitted or undefined.',
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
name: 'frequencyPenalty',
|
|
722
|
+
type: 'number',
|
|
723
|
+
isOptional: true,
|
|
724
|
+
description:
|
|
725
|
+
'Frequency penalty for this step. Uses the top-level value when omitted or undefined.',
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
name: 'stopSequences',
|
|
729
|
+
type: 'string[]',
|
|
730
|
+
isOptional: true,
|
|
731
|
+
description:
|
|
732
|
+
'Stop sequences for this step. Uses the top-level value when omitted or undefined.',
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
name: 'seed',
|
|
736
|
+
type: 'number',
|
|
737
|
+
isOptional: true,
|
|
738
|
+
description:
|
|
739
|
+
'Random sampling seed for this step. Uses the top-level value when omitted or undefined.',
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
name: 'reasoning',
|
|
743
|
+
type: 'LanguageModelV4CallOptions["reasoning"]',
|
|
744
|
+
isOptional: true,
|
|
745
|
+
description:
|
|
746
|
+
'Reasoning effort for this step. Uses the top-level value when omitted or undefined.',
|
|
747
|
+
},
|
|
685
748
|
{
|
|
686
749
|
name: 'toolChoice',
|
|
687
750
|
type: 'ToolChoice<TOOLS>',
|
|
@@ -2362,7 +2425,8 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
2362
2425
|
{
|
|
2363
2426
|
name: 'text',
|
|
2364
2427
|
type: 'string',
|
|
2365
|
-
description:
|
|
2428
|
+
description:
|
|
2429
|
+
'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 `finalStep.content` to distinguish that case.',
|
|
2366
2430
|
},
|
|
2367
2431
|
{
|
|
2368
2432
|
name: 'reasoning',
|
|
@@ -2795,7 +2859,8 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
2795
2859
|
{
|
|
2796
2860
|
name: 'text',
|
|
2797
2861
|
type: 'string',
|
|
2798
|
-
description:
|
|
2862
|
+
description:
|
|
2863
|
+
'The concatenation of all text parts generated in this step. It is an empty string if the step contains no text parts.',
|
|
2799
2864
|
},
|
|
2800
2865
|
{
|
|
2801
2866
|
name: 'reasoning',
|
|
@@ -641,7 +641,7 @@ To see `streamText` in action, check out [these examples](#examples).
|
|
|
641
641
|
type: '(options: PrepareStepOptions) => PrepareStepResult<TOOLS> | Promise<PrepareStepResult<TOOLS>>',
|
|
642
642
|
isOptional: true,
|
|
643
643
|
description:
|
|
644
|
-
'Optional function that you can use to provide different settings for a step. You can modify the model, tool choices, active tools, instructions, input messages, and experimental sandbox for each step.',
|
|
644
|
+
'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, instructions, input messages, and experimental sandbox for each step.',
|
|
645
645
|
properties: [
|
|
646
646
|
{
|
|
647
647
|
type: 'PrepareStepFunction<TOOLS>',
|
|
@@ -726,6 +726,69 @@ To see `streamText` in action, check out [these examples](#examples).
|
|
|
726
726
|
description:
|
|
727
727
|
'Optionally override which LanguageModel instance is used for this step.',
|
|
728
728
|
},
|
|
729
|
+
{
|
|
730
|
+
name: 'maxOutputTokens',
|
|
731
|
+
type: 'number',
|
|
732
|
+
isOptional: true,
|
|
733
|
+
description:
|
|
734
|
+
'Maximum number of tokens to generate for this step. Uses the top-level value when omitted or undefined.',
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
name: 'temperature',
|
|
738
|
+
type: 'number',
|
|
739
|
+
isOptional: true,
|
|
740
|
+
description:
|
|
741
|
+
'Temperature for this step. Uses the top-level value when omitted or undefined.',
|
|
742
|
+
},
|
|
743
|
+
{
|
|
744
|
+
name: 'topP',
|
|
745
|
+
type: 'number',
|
|
746
|
+
isOptional: true,
|
|
747
|
+
description:
|
|
748
|
+
'Nucleus sampling value for this step. Uses the top-level value when omitted or undefined.',
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
name: 'topK',
|
|
752
|
+
type: 'number',
|
|
753
|
+
isOptional: true,
|
|
754
|
+
description:
|
|
755
|
+
'Top-K sampling value for this step. Uses the top-level value when omitted or undefined.',
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
name: 'presencePenalty',
|
|
759
|
+
type: 'number',
|
|
760
|
+
isOptional: true,
|
|
761
|
+
description:
|
|
762
|
+
'Presence penalty for this step. Uses the top-level value when omitted or undefined.',
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
name: 'frequencyPenalty',
|
|
766
|
+
type: 'number',
|
|
767
|
+
isOptional: true,
|
|
768
|
+
description:
|
|
769
|
+
'Frequency penalty for this step. Uses the top-level value when omitted or undefined.',
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: 'stopSequences',
|
|
773
|
+
type: 'string[]',
|
|
774
|
+
isOptional: true,
|
|
775
|
+
description:
|
|
776
|
+
'Stop sequences for this step. Uses the top-level value when omitted or undefined.',
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: 'seed',
|
|
780
|
+
type: 'number',
|
|
781
|
+
isOptional: true,
|
|
782
|
+
description:
|
|
783
|
+
'Random sampling seed for this step. Uses the top-level value when omitted or undefined.',
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: 'reasoning',
|
|
787
|
+
type: 'LanguageModelV4CallOptions["reasoning"]',
|
|
788
|
+
isOptional: true,
|
|
789
|
+
description:
|
|
790
|
+
'Reasoning effort for this step. Uses the top-level value when omitted or undefined.',
|
|
791
|
+
},
|
|
729
792
|
{
|
|
730
793
|
name: 'toolChoice',
|
|
731
794
|
type: 'ToolChoice<TOOLS>',
|
|
@@ -123,7 +123,7 @@ To see `ToolLoopAgent` in action, check out [these examples](#examples).
|
|
|
123
123
|
type: 'PrepareStepFunction',
|
|
124
124
|
isOptional: true,
|
|
125
125
|
description:
|
|
126
|
-
'Optional function to mutate step settings or inject state for each agent step.',
|
|
126
|
+
'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, seed, and reasoning. Model call setting overrides apply only to the current step.',
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
name: 'include',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.42",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"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.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.32",
|
|
46
46
|
"@ai-sdk/provider": "4.0.4",
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.15"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@edge-runtime/vm": "^5.0.0",
|
|
@@ -40,7 +40,9 @@ export interface GenerateTextResult<
|
|
|
40
40
|
readonly content: Array<ContentPart<TOOLS>>;
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* The text
|
|
43
|
+
* The concatenation of all text parts generated in the final step.
|
|
44
|
+
* It is an empty string if the final step contains no text parts.
|
|
45
|
+
* Inspect `finalStep.content` to distinguish that case.
|
|
44
46
|
*/
|
|
45
47
|
readonly text: string;
|
|
46
48
|
|
|
@@ -84,6 +84,7 @@ import { text, type Output } from './output';
|
|
|
84
84
|
import type { InferCompleteOutput } from './output-utils';
|
|
85
85
|
import { parseToolCall } from './parse-tool-call';
|
|
86
86
|
import type { PrepareStepFunction } from './prepare-step';
|
|
87
|
+
import { prepareStepCallSettings } from './prepare-step-call-settings';
|
|
87
88
|
import { convertToReasoningOutputs } from './reasoning-output';
|
|
88
89
|
import { resolveToolApproval } from './resolve-tool-approval';
|
|
89
90
|
import type { ResponseMessage } from './response-message';
|
|
@@ -888,6 +889,11 @@ export async function generateText<
|
|
|
888
889
|
prepareStepResult?.providerOptions,
|
|
889
890
|
);
|
|
890
891
|
|
|
892
|
+
const stepCallSettings = prepareStepCallSettings({
|
|
893
|
+
callSettings,
|
|
894
|
+
stepSettings: prepareStepResult,
|
|
895
|
+
});
|
|
896
|
+
|
|
891
897
|
await notify({
|
|
892
898
|
event: {
|
|
893
899
|
callId,
|
|
@@ -921,7 +927,7 @@ export async function generateText<
|
|
|
921
927
|
instructions: stepInstructions,
|
|
922
928
|
messages: stepMessages,
|
|
923
929
|
tools: stepTools,
|
|
924
|
-
...
|
|
930
|
+
...stepCallSettings,
|
|
925
931
|
};
|
|
926
932
|
const languageModelCallStartEvent = {
|
|
927
933
|
callId,
|
|
@@ -951,7 +957,7 @@ export async function generateText<
|
|
|
951
957
|
...languageModelCallStartEvent,
|
|
952
958
|
execute: async () =>
|
|
953
959
|
await stepModel.doGenerate({
|
|
954
|
-
...
|
|
960
|
+
...stepCallSettings,
|
|
955
961
|
tools: stepTools,
|
|
956
962
|
toolChoice: stepToolChoice,
|
|
957
963
|
responseFormat: await output?.responseFormat,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LanguageModelCallOptions } from '../prompt/language-model-call-options';
|
|
2
|
+
import { prepareLanguageModelCallOptions } from '../prompt/prepare-language-model-call-options';
|
|
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: LanguageModelCallOptions;
|
|
15
|
+
stepSettings: LanguageModelCallOptions | undefined;
|
|
16
|
+
}): LanguageModelCallOptions {
|
|
17
|
+
return prepareLanguageModelCallOptions({
|
|
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
|
+
reasoning: stepSettings?.reasoning ?? callSettings.reasoning,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ToolSet,
|
|
8
8
|
} from '@ai-sdk/provider-utils';
|
|
9
9
|
import type { Instructions } from '../prompt';
|
|
10
|
+
import type { LanguageModelCallOptions } from '../prompt/language-model-call-options';
|
|
10
11
|
import type { LanguageModel, ToolChoice } from '../types/language-model';
|
|
11
12
|
import type { ActiveTools } from './active-tools';
|
|
12
13
|
import type { ResponseMessage } from './response-message';
|
|
@@ -95,13 +96,17 @@ export type PrepareStepFunction<
|
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* The result type returned by a {@link PrepareStepFunction},
|
|
98
|
-
* allowing per-step overrides of model,
|
|
99
|
+
* allowing per-step overrides of model call settings, model, tools,
|
|
100
|
+
* instructions, or messages.
|
|
101
|
+
*
|
|
102
|
+
* Model call setting overrides apply only to the current step. Undefined
|
|
103
|
+
* settings fall back to the outer call settings.
|
|
99
104
|
*/
|
|
100
105
|
export type PrepareStepResult<
|
|
101
106
|
TOOLS extends ToolSet,
|
|
102
107
|
RUNTIME_CONTEXT extends Context = Context,
|
|
103
108
|
> =
|
|
104
|
-
| {
|
|
109
|
+
| ({
|
|
105
110
|
/**
|
|
106
111
|
* Optionally override which LanguageModel instance is used for this step.
|
|
107
112
|
*/
|
|
@@ -175,5 +180,5 @@ export type PrepareStepResult<
|
|
|
175
180
|
* container IDs for Anthropic's code execution.
|
|
176
181
|
*/
|
|
177
182
|
providerOptions?: ProviderOptions;
|
|
178
|
-
}
|
|
183
|
+
} & LanguageModelCallOptions)
|
|
179
184
|
| undefined;
|
|
@@ -176,7 +176,8 @@ export type StepResult<
|
|
|
176
176
|
readonly content: Array<ContentPart<TOOLS>>;
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
|
-
* The
|
|
179
|
+
* The concatenation of all text parts generated in this step.
|
|
180
|
+
* It is an empty string if the step contains no text parts.
|
|
180
181
|
*/
|
|
181
182
|
readonly text: string;
|
|
182
183
|
|
|
@@ -113,6 +113,7 @@ import type {
|
|
|
113
113
|
InferPartialOutput,
|
|
114
114
|
} from './output-utils';
|
|
115
115
|
import type { PrepareStepFunction } from './prepare-step';
|
|
116
|
+
import { prepareStepCallSettings } from './prepare-step-call-settings';
|
|
116
117
|
import { convertToReasoningOutputs } from './reasoning-output';
|
|
117
118
|
import type { ResponseMessage } from './response-message';
|
|
118
119
|
import { createRestrictedTelemetryDispatcher } from './restricted-telemetry-dispatcher';
|
|
@@ -915,6 +916,11 @@ function createOutputTransformStream<
|
|
|
915
916
|
textChunk += chunk.text;
|
|
916
917
|
textProviderMetadata = chunk.providerMetadata ?? textProviderMetadata;
|
|
917
918
|
|
|
919
|
+
if (chunk.text.length === 0 && chunk.providerMetadata != null) {
|
|
920
|
+
controller.enqueue({ part: chunk, partialOutput: undefined });
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
918
924
|
// only publish if partial json can be parsed:
|
|
919
925
|
const result = await output.parsePartialOutput({ text });
|
|
920
926
|
|
|
@@ -1963,6 +1969,11 @@ class DefaultStreamTextResult<
|
|
|
1963
1969
|
prepareStepResult?.providerOptions,
|
|
1964
1970
|
);
|
|
1965
1971
|
|
|
1972
|
+
const stepCallSettings = prepareStepCallSettings({
|
|
1973
|
+
callSettings,
|
|
1974
|
+
stepSettings: prepareStepResult,
|
|
1975
|
+
});
|
|
1976
|
+
|
|
1966
1977
|
const stepStartTimestampMs = now();
|
|
1967
1978
|
|
|
1968
1979
|
const { retry } = prepareRetries({ maxRetries, abortSignal });
|
|
@@ -2035,7 +2046,7 @@ class DefaultStreamTextResult<
|
|
|
2035
2046
|
_internal: {
|
|
2036
2047
|
now,
|
|
2037
2048
|
},
|
|
2038
|
-
...
|
|
2049
|
+
...stepCallSettings,
|
|
2039
2050
|
}),
|
|
2040
2051
|
),
|
|
2041
2052
|
);
|
|
@@ -2198,7 +2209,10 @@ class DefaultStreamTextResult<
|
|
|
2198
2209
|
}
|
|
2199
2210
|
|
|
2200
2211
|
case 'text-delta': {
|
|
2201
|
-
if (
|
|
2212
|
+
if (
|
|
2213
|
+
chunk.text.length > 0 ||
|
|
2214
|
+
chunk.providerMetadata != null
|
|
2215
|
+
) {
|
|
2202
2216
|
controller.enqueue(chunk);
|
|
2203
2217
|
}
|
|
2204
2218
|
break;
|