ai 7.0.147 → 7.0.149
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 +31 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -32
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +2 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +4 -1
- package/dist/internal/index.js.map +1 -1
- package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +7 -0
- package/docs/03-ai-sdk-core/18-code-mode.mdx +3 -1
- package/docs/03-ai-sdk-core/18-tools.mdx +19 -0
- package/docs/03-ai-sdk-core/36-transcription.mdx +40 -39
- package/docs/03-ai-sdk-core/37-speech.mdx +1 -0
- package/docs/03-ai-sdk-core/60-telemetry.mdx +25 -2
- package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +32 -0
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +1 -1
- package/docs/06-advanced/11-secure-url-fetching.mdx +2 -2
- package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +4 -4
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +7 -7
- package/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +1 -1
- package/docs/07-reference/02-ai-sdk-ui/40-create-ui-message-stream.mdx +1 -1
- package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -1
- package/docs/07-reference/05-ai-sdk-errors/ai-tool-choice-violation-error.mdx +12 -7
- package/package.json +12 -12
- package/src/error/tool-choice-violation-error.ts +6 -4
- package/src/generate-text/collect-tool-approvals.ts +10 -0
- package/src/generate-text/generate-text.ts +24 -12
- package/src/generate-text/stream-language-model-call.ts +37 -12
- package/src/generate-text/stream-text.ts +4 -1
- package/src/types/language-model.ts +2 -0
- package/src/ui/chat.ts +40 -12
- package/src/ui-message-stream/ui-message-chunks.ts +1 -0
|
@@ -819,6 +819,13 @@ It supports the following settings:
|
|
|
819
819
|
- `none`: the model must not call tools
|
|
820
820
|
- `{ type: 'tool', toolName: string (typed) }`: the model must call the specified tool
|
|
821
821
|
|
|
822
|
+
When `toolChoice` is `'none'`, the SDK prevents local tool execution even if the
|
|
823
|
+
model returns a tool call. Such responses produce a
|
|
824
|
+
[`ToolChoiceViolationError`](/docs/reference/ai-sdk-errors/ai-tool-choice-violation-error).
|
|
825
|
+
With `streamText`, tool parts are withheld from the stream, so client-side tools
|
|
826
|
+
are not invoked either. Tool call repair and input refinement are skipped for
|
|
827
|
+
rejected tool calls.
|
|
828
|
+
|
|
822
829
|
```ts highlight="19"
|
|
823
830
|
import { z } from 'zod';
|
|
824
831
|
import { generateText, tool } from 'ai';
|
|
@@ -251,6 +251,7 @@ payloads, console output, and tool calls. Override them with
|
|
|
251
251
|
const codeMode = codeModeTool({
|
|
252
252
|
executionPolicy: {
|
|
253
253
|
timeoutMs: 30_000,
|
|
254
|
+
cpuTimeoutMs: 10_000,
|
|
254
255
|
memoryLimitBytes: 64 * 1024 * 1024,
|
|
255
256
|
maxResultBytes: 1024 * 1024,
|
|
256
257
|
maxBridgeRequests: 100,
|
|
@@ -261,7 +262,8 @@ const codeMode = codeModeTool({
|
|
|
261
262
|
|
|
262
263
|
The available limits are:
|
|
263
264
|
|
|
264
|
-
- `timeoutMs`: total execution time
|
|
265
|
+
- `timeoutMs`: total execution time, including time spent waiting on tools
|
|
266
|
+
- `cpuTimeoutMs`: CPU time spent running sandboxed code, excluding tool waits
|
|
265
267
|
- `memoryLimitBytes`: QuickJS memory
|
|
266
268
|
- `maxStackSizeBytes`: QuickJS stack
|
|
267
269
|
- `maxSourceBytes`: generated source code
|
|
@@ -107,6 +107,7 @@ Raw runtime instances need their respective adapters; a custom
|
|
|
107
107
|
| `sandbox` | `Experimental_SandboxSession` | Required session for command execution and file operations. |
|
|
108
108
|
| `workingDirectory` | `string` | Optional absolute starting directory for each command, created if needed. When omitted, uses the sandbox's default directory. |
|
|
109
109
|
| `maxOutputLength` | `number` | Positive integer limiting characters retained from each output stream before a truncation notice. Defaults to `30000`. |
|
|
110
|
+
| `timeout` | `number` | Optional timeout per command execution, in milliseconds (integer from `1` to `2147483647`). No tool-level timeout by default. |
|
|
110
111
|
|
|
111
112
|
The model calls the tool with `{ command: string }` and receives
|
|
112
113
|
`{ stdout, stderr, exitCode }`. Nonzero exit codes are returned so the model can
|
|
@@ -114,6 +115,24 @@ inspect failures and recover. AI SDK cancellation is forwarded to the session.
|
|
|
114
115
|
Output truncation happens after execution and does not limit execution memory or
|
|
115
116
|
duration.
|
|
116
117
|
|
|
118
|
+
### Command timeout
|
|
119
|
+
|
|
120
|
+
Set `timeout` to cancel commands that run longer than the configured duration:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const bash = await createBashTool({
|
|
124
|
+
sandbox,
|
|
125
|
+
timeout: 10_000,
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Each command gets a fresh timeout starting when its execution begins. This does
|
|
130
|
+
not include tool initialization or time waiting for model output or approval.
|
|
131
|
+
The timeout is combined with the caller's abort signal; either can cancel the
|
|
132
|
+
command. The sandbox must honor cancellation. Its result or error is passed
|
|
133
|
+
through; for example, just-bash returns exit code `124` when a running command is
|
|
134
|
+
cancelled. SDK and sandbox timeouts still apply when this option is omitted.
|
|
135
|
+
|
|
117
136
|
### Files and lifecycle
|
|
118
137
|
|
|
119
138
|
Commands use the sandbox's default working directory unless `workingDirectory`
|
|
@@ -331,44 +331,45 @@ try {
|
|
|
331
331
|
|
|
332
332
|
## Transcription Models
|
|
333
333
|
|
|
334
|
-
| Provider | Model
|
|
335
|
-
| ----------------------------------------------------------------------------------- |
|
|
336
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `whisper-1`
|
|
337
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-transcribe`
|
|
338
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-mini-transcribe`
|
|
339
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-transcribe-diarize`
|
|
340
|
-
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v1`
|
|
341
|
-
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v1_experimental`
|
|
342
|
-
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v2`
|
|
343
|
-
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#streaming-transcription-models) | `scribe_v2_realtime`
|
|
344
|
-
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3-turbo`
|
|
345
|
-
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3`
|
|
346
|
-
| [Mistral](/providers/ai-sdk-providers/mistral#transcription-models) | `voxtral-mini-
|
|
347
|
-
| [
|
|
348
|
-
| [Azure
|
|
349
|
-
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe) | `mai-transcribe-
|
|
350
|
-
| [Azure
|
|
351
|
-
| [Azure
|
|
352
|
-
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-
|
|
353
|
-
| [
|
|
354
|
-
| [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `
|
|
355
|
-
| [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `
|
|
356
|
-
| [
|
|
357
|
-
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `
|
|
358
|
-
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `
|
|
359
|
-
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova
|
|
360
|
-
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova-
|
|
361
|
-
| [
|
|
362
|
-
| [
|
|
363
|
-
| [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `universal-3-pro` |
|
|
364
|
-
| [
|
|
365
|
-
| [Fal](/providers/ai-sdk-providers/fal#transcription-models) | `
|
|
366
|
-
| [
|
|
367
|
-
| [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `
|
|
368
|
-
| [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `
|
|
369
|
-
| [
|
|
370
|
-
| [
|
|
371
|
-
| [Cartesia](/providers/ai-sdk-providers/cartesia#
|
|
372
|
-
| [
|
|
334
|
+
| Provider | Model |
|
|
335
|
+
| ----------------------------------------------------------------------------------- | ------------------------------ |
|
|
336
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `whisper-1` |
|
|
337
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-transcribe` |
|
|
338
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-mini-transcribe` |
|
|
339
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#transcription-models) | `gpt-4o-transcribe-diarize` |
|
|
340
|
+
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v1` |
|
|
341
|
+
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v1_experimental` |
|
|
342
|
+
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#transcription-models) | `scribe_v2` |
|
|
343
|
+
| [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#streaming-transcription-models) | `scribe_v2_realtime` |
|
|
344
|
+
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3-turbo` |
|
|
345
|
+
| [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3` |
|
|
346
|
+
| [Mistral](/providers/ai-sdk-providers/mistral#transcription-models) | `voxtral-mini-transcribe-3-0` |
|
|
347
|
+
| [Mistral](/providers/ai-sdk-providers/mistral#transcription-models) | `voxtral-small-transcribe-3-0` |
|
|
348
|
+
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `whisper-1` |
|
|
349
|
+
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe) | `mai-transcribe-2` |
|
|
350
|
+
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe) | `mai-transcribe-1.5` |
|
|
351
|
+
| [Azure MAI](/providers/ai-sdk-providers/azure#mai-transcribe-2-streaming) | `mai-transcribe-2-streaming` |
|
|
352
|
+
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-transcribe` |
|
|
353
|
+
| [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-mini-transcribe` |
|
|
354
|
+
| [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `machine` |
|
|
355
|
+
| [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `low_cost` |
|
|
356
|
+
| [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `fusion` |
|
|
357
|
+
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `base` (+ variants) |
|
|
358
|
+
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `enhanced` (+ variants) |
|
|
359
|
+
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova` (+ variants) |
|
|
360
|
+
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova-2` (+ variants) |
|
|
361
|
+
| [Deepgram](/providers/ai-sdk-providers/deepgram#transcription-models) | `nova-3` (+ variants) |
|
|
362
|
+
| [Gladia](/providers/ai-sdk-providers/gladia#transcription-models) | `default` |
|
|
363
|
+
| [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `universal-3-5-pro` |
|
|
364
|
+
| [AssemblyAI](/providers/ai-sdk-providers/assemblyai#transcription-models) | `universal-3-pro` |
|
|
365
|
+
| [Fal](/providers/ai-sdk-providers/fal#transcription-models) | `whisper` |
|
|
366
|
+
| [Fal](/providers/ai-sdk-providers/fal#transcription-models) | `wizper` |
|
|
367
|
+
| [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `chirp_2` |
|
|
368
|
+
| [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `chirp_3` |
|
|
369
|
+
| [Google Vertex](/providers/ai-sdk-providers/google-vertex#transcription-models) | `telephony` |
|
|
370
|
+
| [xAI](/providers/ai-sdk-providers/xai#transcription-models) | `default` |
|
|
371
|
+
| [Cartesia](/providers/ai-sdk-providers/cartesia#transcription-models) | `ink-whisper` |
|
|
372
|
+
| [Cartesia](/providers/ai-sdk-providers/cartesia#streaming-transcription-models) | `ink-2` |
|
|
373
|
+
| [Fish Audio](/providers/ai-sdk-providers/fish-audio#transcription-models) | `transcribe-1` |
|
|
373
374
|
|
|
374
375
|
Above are a small subset of the transcription models supported by the AI SDK providers. For more, see the respective provider documentation.
|
|
@@ -158,6 +158,7 @@ try {
|
|
|
158
158
|
| [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `tts-1-hd` |
|
|
159
159
|
| [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `gpt-4o-mini-tts` |
|
|
160
160
|
| [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-2603` |
|
|
161
|
+
| [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-3-0` |
|
|
161
162
|
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2.1-flash` |
|
|
162
163
|
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2.1` |
|
|
163
164
|
| [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2-flash` |
|
|
@@ -214,6 +214,29 @@ Properties set to `false` or omitted are excluded. If `telemetry.includeToolsCon
|
|
|
214
214
|
between tool execution context and telemetry event context.
|
|
215
215
|
</Note>
|
|
216
216
|
|
|
217
|
+
## Agent span names
|
|
218
|
+
|
|
219
|
+
`agentSpanName` controls root text/object generation span names. The strings
|
|
220
|
+
`'modelId'` (default) and `'functionId'` select a naming strategy, producing
|
|
221
|
+
`invoke_agent {modelId}` or `invoke_agent {telemetry.functionId}`:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
registerTelemetry(new OpenTelemetry({ agentSpanName: 'functionId' }));
|
|
225
|
+
// With telemetry: { functionId: 'travel-planner' }, the span is:
|
|
226
|
+
// invoke_agent travel-planner
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
For a literal custom name, use a callback returning the complete span name:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
registerTelemetry(new OpenTelemetry({ agentSpanName: () => 'my-custom-span' }));
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The callback receives `{ modelId, functionId }` for dynamic names. If it returns
|
|
236
|
+
`undefined` or throws, the default name is used. The `'functionId'` strategy also
|
|
237
|
+
falls back to `modelId` when `functionId` is absent. Child span names and
|
|
238
|
+
attributes are unchanged.
|
|
239
|
+
|
|
217
240
|
## Custom Tracer
|
|
218
241
|
|
|
219
242
|
If you want your traces to use a `TracerProvider` other than the one provided by the `@opentelemetry/api` singleton, pass a custom `Tracer` to the `OpenTelemetry` constructor:
|
|
@@ -481,7 +504,7 @@ By default, attributes use the `gen_ai.*` prefix. Provider names are mapped to w
|
|
|
481
504
|
|
|
482
505
|
For `generateText` and `streamText`, the integration records 3 types of spans:
|
|
483
506
|
|
|
484
|
-
- **`invoke_agent {modelId}`** (root span, `INTERNAL`): covers the full operation including all steps and tool calls.
|
|
507
|
+
- **`invoke_agent {modelId}`** (default root span name, `INTERNAL`): covers the full operation including all steps and tool calls. Use [`agentSpanName`](#agent-span-names) to customize the name.
|
|
485
508
|
|
|
486
509
|
Initial attributes:
|
|
487
510
|
- `gen_ai.operation.name`: `"invoke_agent"`
|
|
@@ -739,7 +762,7 @@ registerTelemetry(
|
|
|
739
762
|
);
|
|
740
763
|
```
|
|
741
764
|
|
|
742
|
-
This does not create additional AI SDK-specific spans such as `ai.generateText`, `ai.generateText.doGenerate`, or `ai.toolCall`. Instead, it adds only the selected supplemental attributes to the spans emitted by `OpenTelemetry`, such as `invoke_agent {modelId}`, `step {n}`, `chat {modelId}`, and `execute_tool {toolName}`.
|
|
765
|
+
This does not create additional AI SDK-specific spans such as `ai.generateText`, `ai.generateText.doGenerate`, or `ai.toolCall`. Instead, it adds only the selected supplemental attributes to the spans emitted by `OpenTelemetry`, such as the default root span `invoke_agent {modelId}`, `step {n}`, `chat {modelId}`, and `execute_tool {toolName}`.
|
|
743
766
|
|
|
744
767
|
All supplemental attributes are disabled by default. Enable only the data you want to collect:
|
|
745
768
|
|
|
@@ -106,6 +106,38 @@ try {
|
|
|
106
106
|
}
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
### Image Inputs
|
|
110
|
+
|
|
111
|
+
For harness adapters that support images, you can include an image as a file part
|
|
112
|
+
in the latest user message. Set `mediaType` to the image's MIME type:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { readFileSync } from 'node:fs';
|
|
116
|
+
|
|
117
|
+
const result = await agent.generate({
|
|
118
|
+
session,
|
|
119
|
+
messages: [
|
|
120
|
+
{
|
|
121
|
+
role: 'user',
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: 'text',
|
|
125
|
+
text: 'Describe the image in one sentence.',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: 'file',
|
|
129
|
+
mediaType: 'image/png',
|
|
130
|
+
data: readFileSync('image.png'),
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
For image input support, see the
|
|
139
|
+
[adapter capability table](/docs/ai-sdk-harnesses/harness-adapters#adapter-capabilities).
|
|
140
|
+
|
|
109
141
|
## Lifecycle Callbacks
|
|
110
142
|
|
|
111
143
|
Configure lifecycle callbacks on `HarnessAgent` to observe agent calls, model
|
|
@@ -40,7 +40,7 @@ The AI SDK includes the following harness adapters:
|
|
|
40
40
|
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> | <Cross /> |
|
|
41
41
|
| [Cursor](/providers/ai-sdk-harnesses/cursor) | Sandbox via ACP | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Check /> | <Cross /> |
|
|
42
42
|
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> via auto-rejection | <Check /> | <Cross /> |
|
|
43
|
-
| [fx](/providers/ai-sdk-harnesses/fx) | Host process | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <
|
|
43
|
+
| [fx](/providers/ai-sdk-harnesses/fx) | Host process | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
44
44
|
| [GitHub Copilot](/providers/ai-sdk-harnesses/github-copilot) | Sandbox via ACP | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Check /> | <Cross /> |
|
|
45
45
|
| [Grok Build](/providers/ai-sdk-harnesses/grok-build) | Sandbox via ACP | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> | <Cross /> |
|
|
46
46
|
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
@@ -28,8 +28,8 @@ When the SDK fetches a URL taken from a provider response, it:
|
|
|
28
28
|
|
|
29
29
|
- **Rejects private, loopback, and link-local targets** — IPv4 (`10/8`,
|
|
30
30
|
`172.16/12`, `192.168/16`, `127/8`, `169.254/16`, CGNAT, multicast, …) and the
|
|
31
|
-
equivalent IPv6 ranges, plus `localhost
|
|
32
|
-
are rejected too.
|
|
31
|
+
equivalent IPv6 ranges, plus `localhost`, `.local`, `.localhost`, and
|
|
32
|
+
`.internal` hostnames. Non-`http(s)` schemes are rejected too.
|
|
33
33
|
- **Re-validates every redirect hop** — a URL that passes but then redirects to
|
|
34
34
|
an internal address is blocked; the redirect is never followed blindly.
|
|
35
35
|
- **Validates DNS at connection time on Node.js** — every resolved address is
|
|
@@ -1735,7 +1735,7 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
1735
1735
|
},
|
|
1736
1736
|
{
|
|
1737
1737
|
name: 'finishReason',
|
|
1738
|
-
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "other"',
|
|
1738
|
+
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "interrupted" | "other"',
|
|
1739
1739
|
description: 'The unified reason why the generation finished.',
|
|
1740
1740
|
},
|
|
1741
1741
|
{
|
|
@@ -2029,7 +2029,7 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
2029
2029
|
},
|
|
2030
2030
|
{
|
|
2031
2031
|
name: 'finishReason',
|
|
2032
|
-
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "other"',
|
|
2032
|
+
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "interrupted" | "other"',
|
|
2033
2033
|
description: 'The unified reason why the generation finished.',
|
|
2034
2034
|
},
|
|
2035
2035
|
{
|
|
@@ -2634,7 +2634,7 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
2634
2634
|
},
|
|
2635
2635
|
{
|
|
2636
2636
|
name: 'finishReason',
|
|
2637
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
2637
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
2638
2638
|
description: 'The reason the model finished generating the text.',
|
|
2639
2639
|
},
|
|
2640
2640
|
{
|
|
@@ -3039,7 +3039,7 @@ To see `generateText` in action, check out [these examples](#examples).
|
|
|
3039
3039
|
},
|
|
3040
3040
|
{
|
|
3041
3041
|
name: 'finishReason',
|
|
3042
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
3042
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
3043
3043
|
description: 'The reason why the generation finished.',
|
|
3044
3044
|
},
|
|
3045
3045
|
{
|
|
@@ -1411,7 +1411,7 @@ retain the content their contracts require.
|
|
|
1411
1411
|
},
|
|
1412
1412
|
{
|
|
1413
1413
|
name: 'finishReason',
|
|
1414
|
-
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "other"',
|
|
1414
|
+
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "interrupted" | "other"',
|
|
1415
1415
|
description:
|
|
1416
1416
|
'The unified finish reason why the generation finished.',
|
|
1417
1417
|
},
|
|
@@ -1746,7 +1746,7 @@ retain the content their contracts require.
|
|
|
1746
1746
|
parameters: [
|
|
1747
1747
|
{
|
|
1748
1748
|
name: 'finishReason',
|
|
1749
|
-
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "other"',
|
|
1749
|
+
type: '"stop" | "length" | "content-filter" | "tool-calls" | "error" | "interrupted" | "other"',
|
|
1750
1750
|
description:
|
|
1751
1751
|
'The unified finish reason why the generation finished.',
|
|
1752
1752
|
},
|
|
@@ -2674,9 +2674,9 @@ retain the content their contracts require.
|
|
|
2674
2674
|
},
|
|
2675
2675
|
{
|
|
2676
2676
|
name: 'finishReason',
|
|
2677
|
-
type: "PromiseLike<'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'>",
|
|
2677
|
+
type: "PromiseLike<'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'>",
|
|
2678
2678
|
description:
|
|
2679
|
-
'The reason why the generation finished. Automatically consumes the stream.',
|
|
2679
|
+
'The reason why the generation finished. A stream that ends cleanly without its provider completion signal can report "interrupted". Partial output is preserved; interruption alone does not emit an error. Streams that produce no output and no finish chunk still reject with NoOutputGeneratedError. OpenAI-compatible retains its existing error behavior. Automatically consumes the stream.',
|
|
2680
2680
|
},
|
|
2681
2681
|
{
|
|
2682
2682
|
name: 'rawFinishReason',
|
|
@@ -3165,7 +3165,7 @@ retain the content their contracts require.
|
|
|
3165
3165
|
},
|
|
3166
3166
|
{
|
|
3167
3167
|
name: 'finishReason',
|
|
3168
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
3168
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
3169
3169
|
description: 'The reason the model finished generating the text.',
|
|
3170
3170
|
},
|
|
3171
3171
|
{
|
|
@@ -3873,7 +3873,7 @@ retain the content their contracts require.
|
|
|
3873
3873
|
},
|
|
3874
3874
|
{
|
|
3875
3875
|
name: 'finishReason',
|
|
3876
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
3876
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
3877
3877
|
description: 'The reason the model finished generating the text.',
|
|
3878
3878
|
},
|
|
3879
3879
|
{
|
|
@@ -3911,7 +3911,7 @@ retain the content their contracts require.
|
|
|
3911
3911
|
},
|
|
3912
3912
|
{
|
|
3913
3913
|
name: 'finishReason',
|
|
3914
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
3914
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
3915
3915
|
description: 'The reason the model finished generating the text.',
|
|
3916
3916
|
},
|
|
3917
3917
|
{
|
|
@@ -317,7 +317,7 @@ Allows you to easily create a conversational user interface for your chatbot app
|
|
|
317
317
|
},
|
|
318
318
|
{
|
|
319
319
|
name: 'finishReason',
|
|
320
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
320
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
321
321
|
isOptional: true,
|
|
322
322
|
description:
|
|
323
323
|
'The reason why the model finished generating the response. Undefined if the finish reason was not provided by the model.',
|
|
@@ -179,7 +179,7 @@ outcomes and call `setOutcome` once.
|
|
|
179
179
|
name: 'finishReason',
|
|
180
180
|
type: 'FinishReason | undefined',
|
|
181
181
|
description:
|
|
182
|
-
"The reason why the generation finished. One of: 'stop', 'length', 'content-filter', 'tool-calls', 'error', or 'other'.",
|
|
182
|
+
"The reason why the generation finished. One of: 'stop', 'length', 'content-filter', 'tool-calls', 'error', 'interrupted', or 'other'.",
|
|
183
183
|
},
|
|
184
184
|
],
|
|
185
185
|
},
|
|
@@ -649,7 +649,7 @@ To see `streamUI` in action, check out [these examples](#examples).
|
|
|
649
649
|
},
|
|
650
650
|
{
|
|
651
651
|
name: 'finishReason',
|
|
652
|
-
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other'",
|
|
652
|
+
type: "'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'interrupted' | 'other'",
|
|
653
653
|
description: 'The reason the model finished generating the text.',
|
|
654
654
|
},
|
|
655
655
|
{
|
|
@@ -5,14 +5,16 @@ description: Learn how to fix AI SDK ToolChoiceViolationError
|
|
|
5
5
|
|
|
6
6
|
# ToolChoiceViolationError
|
|
7
7
|
|
|
8
|
-
This error occurs when a `generateText` response does not satisfy
|
|
9
|
-
tool choice. It is thrown when `toolChoice` is set to `'
|
|
10
|
-
response contains
|
|
11
|
-
was not called.
|
|
8
|
+
This error occurs when a `generateText` or `streamText` response does not satisfy
|
|
9
|
+
an enforced tool choice. It is thrown when `toolChoice` is set to `'none'` but
|
|
10
|
+
the response contains a tool call, when `'required'` produces no structured tool
|
|
11
|
+
call, or when a specifically selected tool was not called. With `streamText`,
|
|
12
|
+
the error is emitted in the stream. Tool calls returned while `'none'` is selected
|
|
13
|
+
are not executed.
|
|
12
14
|
|
|
13
15
|
The error does not automatically interpret text or reasoning as an executable
|
|
14
|
-
tool call.
|
|
15
|
-
schema validation before executing any recovered call.
|
|
16
|
+
tool call. When tool calls are allowed, you can inspect `content` to implement
|
|
17
|
+
opt-in recovery, including schema validation before executing any recovered call.
|
|
16
18
|
|
|
17
19
|
## Properties
|
|
18
20
|
|
|
@@ -30,7 +32,10 @@ You can check if an error is an instance of `ToolChoiceViolationError` using:
|
|
|
30
32
|
```typescript
|
|
31
33
|
import { ToolChoiceViolationError } from 'ai';
|
|
32
34
|
|
|
33
|
-
if (
|
|
35
|
+
if (
|
|
36
|
+
ToolChoiceViolationError.isInstance(error) &&
|
|
37
|
+
error.toolChoice.type !== 'none'
|
|
38
|
+
) {
|
|
34
39
|
const serializedCall = error.content.find(part => part.type === 'text')?.text;
|
|
35
40
|
|
|
36
41
|
// Parse and validate serializedCall before treating it as a tool call.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.149",
|
|
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,20 +42,20 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.122",
|
|
46
|
+
"@ai-sdk/provider": "4.0.32",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.66"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@ai-sdk/amazon-bedrock": "5.0.
|
|
51
|
-
"@ai-sdk/deepseek": "3.0.
|
|
52
|
-
"@ai-sdk/google": "4.0.
|
|
53
|
-
"@ai-sdk/groq": "4.0.
|
|
54
|
-
"@ai-sdk/huggingface": "2.0.
|
|
55
|
-
"@ai-sdk/moonshotai": "3.0.
|
|
56
|
-
"@ai-sdk/openai": "4.0.
|
|
50
|
+
"@ai-sdk/amazon-bedrock": "5.0.122",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.71",
|
|
52
|
+
"@ai-sdk/google": "4.0.103",
|
|
53
|
+
"@ai-sdk/groq": "4.0.68",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.76",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.75",
|
|
56
|
+
"@ai-sdk/openai": "4.0.100",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.4",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.28",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
@@ -11,7 +11,7 @@ const symbol = Symbol.for(marker);
|
|
|
11
11
|
|
|
12
12
|
type EnforcedToolChoice = Extract<
|
|
13
13
|
LanguageModelV4ToolChoice,
|
|
14
|
-
{ type: 'required' } | { type: 'tool' }
|
|
14
|
+
{ type: 'none' } | { type: 'required' } | { type: 'tool' }
|
|
15
15
|
>;
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -54,9 +54,11 @@ export class ToolChoiceViolationError extends AISDKError {
|
|
|
54
54
|
provider,
|
|
55
55
|
modelId,
|
|
56
56
|
content,
|
|
57
|
-
message = toolChoice.type === '
|
|
58
|
-
? 'Model response
|
|
59
|
-
:
|
|
57
|
+
message = toolChoice.type === 'none'
|
|
58
|
+
? 'Model response contained a tool call even though tool choice was none.'
|
|
59
|
+
: toolChoice.type === 'required'
|
|
60
|
+
? 'Model response did not contain a tool call even though tool choice was required.'
|
|
61
|
+
: `Model response did not contain a call to the required tool '${toolChoice.toolName}'.`,
|
|
60
62
|
}: {
|
|
61
63
|
toolChoice: EnforcedToolChoice;
|
|
62
64
|
finishReason: FinishReason;
|
|
@@ -88,6 +88,7 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
|
|
|
88
88
|
|
|
89
89
|
const approvedToolApprovals: Array<CollectedToolApprovals<TOOLS>> = [];
|
|
90
90
|
const deniedToolApprovals: Array<CollectedToolApprovals<TOOLS>> = [];
|
|
91
|
+
const collectedToolCallIds = new Set<string>();
|
|
91
92
|
|
|
92
93
|
const approvalResponses = lastMessage.content.filter(
|
|
93
94
|
part => part.type === 'tool-approval-response',
|
|
@@ -119,6 +120,15 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
|
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
// Only the first response for a tool call is collected. Later responses
|
|
124
|
+
// (replays, conflicting decisions, or responses to another approval of the
|
|
125
|
+
// same call) would otherwise execute the tool twice or both execute and
|
|
126
|
+
// deny it.
|
|
127
|
+
if (collectedToolCallIds.has(toolCall.toolCallId)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
collectedToolCallIds.add(toolCall.toolCallId);
|
|
131
|
+
|
|
122
132
|
const approval: CollectedToolApprovals<TOOLS> = {
|
|
123
133
|
approvalRequest,
|
|
124
134
|
approvalResponse,
|
|
@@ -939,7 +939,7 @@ export async function generateText<
|
|
|
939
939
|
activeTools: prepareStepResult?.activeTools ?? activeTools,
|
|
940
940
|
});
|
|
941
941
|
const {
|
|
942
|
-
executionTools
|
|
942
|
+
executionTools,
|
|
943
943
|
modelTools: stepModelTools,
|
|
944
944
|
toolCallerMessages,
|
|
945
945
|
} = prepareToolsForToolCallers({
|
|
@@ -969,6 +969,8 @@ export async function generateText<
|
|
|
969
969
|
const stepToolChoice = prepareToolChoice({
|
|
970
970
|
toolChoice: prepareStepResult?.toolChoice ?? toolChoice,
|
|
971
971
|
});
|
|
972
|
+
const stepExecutionTools =
|
|
973
|
+
stepToolChoice.type === 'none' ? undefined : executionTools;
|
|
972
974
|
|
|
973
975
|
const stepMessages = appendToolCallerMessages({
|
|
974
976
|
messages: prepareStepResult?.messages ?? stepInputMessages,
|
|
@@ -1097,8 +1099,16 @@ export async function generateText<
|
|
|
1097
1099
|
parseToolCall({
|
|
1098
1100
|
toolCall,
|
|
1099
1101
|
tools: stepModelTools as TOOLS,
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
+
// tool calls are rejected with tool choice none,
|
|
1103
|
+
// so user callbacks must not process them:
|
|
1104
|
+
repairToolCall:
|
|
1105
|
+
stepToolChoice.type === 'none'
|
|
1106
|
+
? undefined
|
|
1107
|
+
: repairToolCall,
|
|
1108
|
+
refineToolInput:
|
|
1109
|
+
stepToolChoice.type === 'none'
|
|
1110
|
+
? undefined
|
|
1111
|
+
: refineToolInput,
|
|
1102
1112
|
instructions: stepInstructions,
|
|
1103
1113
|
messages: stepMessages,
|
|
1104
1114
|
abortSignal: mergedAbortSignal,
|
|
@@ -1171,18 +1181,19 @@ export async function generateText<
|
|
|
1171
1181
|
});
|
|
1172
1182
|
|
|
1173
1183
|
const enforcedToolChoice =
|
|
1174
|
-
stepToolChoice.type === '
|
|
1175
|
-
stepToolChoice.type === 'tool'
|
|
1176
|
-
? stepToolChoice
|
|
1177
|
-
: undefined;
|
|
1184
|
+
stepToolChoice.type === 'auto' ? undefined : stepToolChoice;
|
|
1178
1185
|
|
|
1179
1186
|
if (
|
|
1180
1187
|
enforcedToolChoice != null &&
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1188
|
+
(enforcedToolChoice.type === 'none'
|
|
1189
|
+
? stepToolCalls.length > 0
|
|
1190
|
+
: currentModelResponse.finishReason.unified !==
|
|
1191
|
+
'interrupted' &&
|
|
1192
|
+
!stepToolCalls.some(
|
|
1193
|
+
toolCall =>
|
|
1194
|
+
enforcedToolChoice.type === 'required' ||
|
|
1195
|
+
toolCall.toolName === enforcedToolChoice.toolName,
|
|
1196
|
+
))
|
|
1186
1197
|
) {
|
|
1187
1198
|
throw new ToolChoiceViolationError({
|
|
1188
1199
|
toolChoice: enforcedToolChoice,
|
|
@@ -1531,6 +1542,7 @@ export async function generateText<
|
|
|
1531
1542
|
}
|
|
1532
1543
|
}
|
|
1533
1544
|
} while (
|
|
1545
|
+
steps[steps.length - 1].finishReason !== 'interrupted' &&
|
|
1534
1546
|
// Continue only after all client tool calls have been executed or denied,
|
|
1535
1547
|
// and if there are client results or pending deferred provider results.
|
|
1536
1548
|
clientToolOutputs.length + deniedToolApprovalResponses.length ===
|