ai 7.0.18 → 7.0.19
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 +21 -0
- package/dist/index.d.ts +38 -3
- package/dist/index.js +160 -77
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +43 -31
- package/dist/internal/index.js.map +1 -1
- package/docs/02-foundations/02-providers-and-models.mdx +57 -52
- package/docs/02-getting-started/00-choosing-a-provider.mdx +1 -16
- package/docs/02-getting-started/01-navigating-the-library.mdx +12 -12
- package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -36
- package/docs/02-getting-started/03-nextjs-pages-router.mdx +2 -36
- package/docs/02-getting-started/04-svelte.mdx +2 -34
- package/docs/02-getting-started/05-nuxt.mdx +2 -36
- package/docs/02-getting-started/06-nodejs.mdx +1 -18
- package/docs/02-getting-started/07-expo.mdx +3 -62
- package/docs/02-getting-started/08-tanstack-start.mdx +2 -36
- package/docs/02-getting-started/09-coding-agents.mdx +2 -32
- package/docs/03-ai-sdk-core/16-mcp-tools.mdx +44 -0
- package/docs/03-ai-sdk-core/30-embeddings.mdx +18 -18
- package/docs/03-ai-sdk-core/38-video-generation.mdx +22 -3
- package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +1 -28
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +7 -7
- package/docs/03-ai-sdk-harnesses/06-workflow-utilities.mdx +1 -16
- package/docs/03-ai-sdk-harnesses/08-terminal-ui.mdx +1 -28
- package/docs/04-ai-sdk-ui/01-overview.mdx +5 -5
- package/docs/07-reference/01-ai-sdk-core/13-generate-video.mdx +3 -2
- package/docs/07-reference/02-ai-sdk-ui/index.mdx +5 -5
- package/package.json +4 -4
- package/src/generate-text/collect-tool-approvals.ts +17 -4
- package/src/generate-text/execute-tool-call.ts +3 -2
- package/src/generate-text/execute-tools-from-stream.ts +2 -1
- package/src/generate-text/generate-text.ts +5 -4
- package/src/generate-text/index.ts +1 -0
- package/src/generate-text/invoke-tool-callbacks-from-stream.ts +6 -4
- package/src/generate-text/parse-tool-call.ts +5 -4
- package/src/generate-text/resolve-tool-approval.ts +9 -6
- package/src/generate-text/stream-language-model-call.ts +2 -1
- package/src/generate-text/stream-text.ts +3 -2
- package/src/generate-text/to-response-messages.ts +4 -3
- package/src/generate-text/tool-approval-signature.ts +4 -40
- package/src/generate-text/tool-fingerprint.ts +76 -0
- package/src/generate-text/validate-tool-approvals.ts +6 -1
- package/src/generate-video/generate-video.ts +96 -21
- package/src/ui/convert-to-model-messages.ts +3 -2
- package/src/ui/process-ui-message-stream.ts +3 -0
- package/src/ui/validate-ui-messages.ts +2 -1
- package/src/util/canonical-hash.ts +44 -0
- package/src/util/get-own.ts +18 -0
|
@@ -33,22 +33,7 @@ Once you've installed the `ai` package, you already have the full AI SDK documen
|
|
|
33
33
|
|
|
34
34
|
Install the `ai` package if you haven't already:
|
|
35
35
|
|
|
36
|
-
<
|
|
37
|
-
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
38
|
-
<Tab>
|
|
39
|
-
<Snippet text="pnpm add ai" dark />
|
|
40
|
-
</Tab>
|
|
41
|
-
<Tab>
|
|
42
|
-
<Snippet text="npm install ai" dark />
|
|
43
|
-
</Tab>
|
|
44
|
-
<Tab>
|
|
45
|
-
<Snippet text="yarn add ai" dark />
|
|
46
|
-
</Tab>
|
|
47
|
-
<Tab>
|
|
48
|
-
<Snippet text="bun add ai" dark />
|
|
49
|
-
</Tab>
|
|
50
|
-
</Tabs>
|
|
51
|
-
</div>
|
|
36
|
+
<InstallPackages packages="ai" />
|
|
52
37
|
|
|
53
38
|
After installation, your agent can reference the bundled source code and documentation at paths like:
|
|
54
39
|
|
|
@@ -70,22 +55,7 @@ AI SDK DevTools gives you full visibility into your AI SDK calls during developm
|
|
|
70
55
|
|
|
71
56
|
Install the DevTools package:
|
|
72
57
|
|
|
73
|
-
<
|
|
74
|
-
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
75
|
-
<Tab>
|
|
76
|
-
<Snippet text="pnpm add @ai-sdk/devtools" dark />
|
|
77
|
-
</Tab>
|
|
78
|
-
<Tab>
|
|
79
|
-
<Snippet text="npm install @ai-sdk/devtools" dark />
|
|
80
|
-
</Tab>
|
|
81
|
-
<Tab>
|
|
82
|
-
<Snippet text="yarn add @ai-sdk/devtools" dark />
|
|
83
|
-
</Tab>
|
|
84
|
-
<Tab>
|
|
85
|
-
<Snippet text="bun add @ai-sdk/devtools" dark />
|
|
86
|
-
</Tab>
|
|
87
|
-
</Tabs>
|
|
88
|
-
</div>
|
|
58
|
+
<InstallPackages packages="@ai-sdk/devtools" />
|
|
89
59
|
|
|
90
60
|
### Register the integration
|
|
91
61
|
|
|
@@ -518,6 +518,50 @@ Your handler must return an object with an `action` field that can be one of:
|
|
|
518
518
|
- `'decline'`: User chose not to provide the information.
|
|
519
519
|
- `'cancel'`: User cancelled the operation entirely.
|
|
520
520
|
|
|
521
|
+
## Detecting tool-definition drift ("rug pull")
|
|
522
|
+
|
|
523
|
+
An MCP server sends tool definitions (name, description, input schema) when your
|
|
524
|
+
app first connects, and you typically review and approve them at that point.
|
|
525
|
+
Nothing in the protocol prevents the server from later serving a _different_
|
|
526
|
+
definition for the same tool name — for example a description carrying injected
|
|
527
|
+
instructions, or an input schema widened with an extra field. Because the SDK
|
|
528
|
+
uses whatever tools you pass on each call, a mutated definition returned by a
|
|
529
|
+
later `mcpClient.tools()` fetch would be used without any comparison to what was
|
|
530
|
+
approved. This is the MCP ["rug pull"](https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks)
|
|
531
|
+
class of attack.
|
|
532
|
+
|
|
533
|
+
The AI SDK provides two functions to pin the approved definitions and detect
|
|
534
|
+
changes. `fingerprintTools` digests the server-controlled, security-relevant
|
|
535
|
+
fields of each tool (string `description`, resolved input schema, and `title`)
|
|
536
|
+
into a stable map of tool name to digest. `detectToolDrift` diffs two such maps.
|
|
537
|
+
Your app owns baseline storage and the response to drift (block, force
|
|
538
|
+
re-approval, or alert):
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
import { fingerprintTools, detectToolDrift } from 'ai';
|
|
542
|
+
|
|
543
|
+
// Trust time (first connect, human-reviewed): capture and persist the baseline.
|
|
544
|
+
const baseline = await fingerprintTools(await mcpClient.tools());
|
|
545
|
+
|
|
546
|
+
// Every later fetch, before handing tools to generateText:
|
|
547
|
+
const tools = await mcpClient.tools();
|
|
548
|
+
const drift = detectToolDrift(await fingerprintTools(tools), baseline);
|
|
549
|
+
|
|
550
|
+
if (drift.changed.length || drift.added.length) {
|
|
551
|
+
// A pinned definition changed, or a new tool appeared. Block, re-approve,
|
|
552
|
+
// or alert per your policy — do not silently pass `tools` to the model.
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
<Note>
|
|
557
|
+
This detects mutation of a tool's description, input schema, or title — the
|
|
558
|
+
prompt-injection and schema-widening vectors. It cannot detect a
|
|
559
|
+
behavior/endpoint swap where the name, description, and schema are all
|
|
560
|
+
unchanged, because the tool runs remotely on the MCP server and that change is
|
|
561
|
+
invisible to the client. Core stays unopinionated: it does not persist
|
|
562
|
+
baselines or block calls — those are your app's responsibility.
|
|
563
|
+
</Note>
|
|
564
|
+
|
|
521
565
|
## Examples
|
|
522
566
|
|
|
523
567
|
You can see MCP in action in the following examples:
|
|
@@ -219,21 +219,21 @@ const embeddingModelWithDefaults = wrapEmbeddingModel({
|
|
|
219
219
|
|
|
220
220
|
Several providers offer embedding models:
|
|
221
221
|
|
|
222
|
-
| Provider | Model | Embedding Dimensions | Multimodal
|
|
223
|
-
| ----------------------------------------------------------------------------- | ------------------------------- | -------------------- |
|
|
224
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-3-large` | 3072 | <Cross
|
|
225
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-3-small` | 1536 | <Cross
|
|
226
|
-
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-ada-002` | 1536 | <Cross
|
|
227
|
-
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-001` | 3072 | <Cross
|
|
228
|
-
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-2` | 3072 | <Check
|
|
229
|
-
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-2-preview` | 3072 | <Check
|
|
230
|
-
| [Mistral](/providers/ai-sdk-providers/mistral#embedding-models) | `mistral-embed` | 1024 | <Cross
|
|
231
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-v3.0` | 1024 | <Cross
|
|
232
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-v3.0` | 1024 | <Cross
|
|
233
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-light-v3.0` | 384 | <Cross
|
|
234
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-light-v3.0` | 384 | <Cross
|
|
235
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-v2.0` | 4096 | <Cross
|
|
236
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-light-v2.0` | 1024 | <Cross
|
|
237
|
-
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-v2.0` | 768 | <Cross
|
|
238
|
-
| [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock#embedding-models) | `amazon.titan-embed-text-v1` | 1536 | <Cross
|
|
239
|
-
| [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock#embedding-models) | `amazon.titan-embed-text-v2:0` | 1024 | <Cross
|
|
222
|
+
| Provider | Model | Embedding Dimensions | Multimodal |
|
|
223
|
+
| ----------------------------------------------------------------------------- | ------------------------------- | -------------------- | ---------- |
|
|
224
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-3-large` | 3072 | <Cross /> |
|
|
225
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-3-small` | 1536 | <Cross /> |
|
|
226
|
+
| [OpenAI](/providers/ai-sdk-providers/openai#embedding-models) | `text-embedding-ada-002` | 1536 | <Cross /> |
|
|
227
|
+
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-001` | 3072 | <Cross /> |
|
|
228
|
+
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-2` | 3072 | <Check /> |
|
|
229
|
+
| [Google](/providers/ai-sdk-providers/google#embedding-models) | `gemini-embedding-2-preview` | 3072 | <Check /> |
|
|
230
|
+
| [Mistral](/providers/ai-sdk-providers/mistral#embedding-models) | `mistral-embed` | 1024 | <Cross /> |
|
|
231
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-v3.0` | 1024 | <Cross /> |
|
|
232
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-v3.0` | 1024 | <Cross /> |
|
|
233
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-light-v3.0` | 384 | <Cross /> |
|
|
234
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-light-v3.0` | 384 | <Cross /> |
|
|
235
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-v2.0` | 4096 | <Cross /> |
|
|
236
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-english-light-v2.0` | 1024 | <Cross /> |
|
|
237
|
+
| [Cohere](/providers/ai-sdk-providers/cohere#embedding-models) | `embed-multilingual-v2.0` | 768 | <Cross /> |
|
|
238
|
+
| [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock#embedding-models) | `amazon.titan-embed-text-v1` | 1536 | <Cross /> |
|
|
239
|
+
| [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock#embedding-models) | `amazon.titan-embed-text-v2:0` | 1024 | <Cross /> |
|
|
@@ -194,11 +194,11 @@ const { video } = await generateVideo({
|
|
|
194
194
|
});
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
### Reference
|
|
197
|
+
### Reference Inputs
|
|
198
198
|
|
|
199
199
|
Some video models support reference-to-video generation, where you provide one or
|
|
200
|
-
more reference images that the model incorporates into the generated video. Use the `inputReferences` option to pass
|
|
201
|
-
these
|
|
200
|
+
more reference images or videos that the model incorporates into the generated video. Use the `inputReferences` option to pass
|
|
201
|
+
these inputs in a provider-agnostic way:
|
|
202
202
|
|
|
203
203
|
```tsx highlight={"5-8"}
|
|
204
204
|
const { video } = await generateVideo({
|
|
@@ -211,6 +211,25 @@ const { video } = await generateVideo({
|
|
|
211
211
|
});
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
+
For URL-based video references, use the object form with an explicit `mediaType`:
|
|
215
|
+
|
|
216
|
+
```tsx highlight={"5-10"}
|
|
217
|
+
const { video } = await generateVideo({
|
|
218
|
+
model: __VIDEO_MODEL__,
|
|
219
|
+
prompt: 'Match the motion in the reference clip',
|
|
220
|
+
inputReferences: [
|
|
221
|
+
{
|
|
222
|
+
data: 'https://example.com/reference.mp4',
|
|
223
|
+
mediaType: 'video/mp4',
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Providers route each reference by its media type (image vs. video) and emit a
|
|
230
|
+
warning when a reference kind is unsupported (for example, providers that accept
|
|
231
|
+
only image references warn and ignore a video reference).
|
|
232
|
+
|
|
214
233
|
### Providing a Seed
|
|
215
234
|
|
|
216
235
|
You can provide a seed to the `experimental_generateVideo` function to control the output of the video generation process.
|
|
@@ -13,34 +13,7 @@ results while a preconfigured harness powers these results.
|
|
|
13
13
|
|
|
14
14
|
Install the core harness package, a harness adapter, and a sandbox provider:
|
|
15
15
|
|
|
16
|
-
<
|
|
17
|
-
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
18
|
-
<Tab>
|
|
19
|
-
<Snippet
|
|
20
|
-
text="pnpm add @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel"
|
|
21
|
-
dark
|
|
22
|
-
/>
|
|
23
|
-
</Tab>
|
|
24
|
-
<Tab>
|
|
25
|
-
<Snippet
|
|
26
|
-
text="npm install @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel"
|
|
27
|
-
dark
|
|
28
|
-
/>
|
|
29
|
-
</Tab>
|
|
30
|
-
<Tab>
|
|
31
|
-
<Snippet
|
|
32
|
-
text="yarn add @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel"
|
|
33
|
-
dark
|
|
34
|
-
/>
|
|
35
|
-
</Tab>
|
|
36
|
-
<Tab>
|
|
37
|
-
<Snippet
|
|
38
|
-
text="bun add @ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel"
|
|
39
|
-
dark
|
|
40
|
-
/>
|
|
41
|
-
</Tab>
|
|
42
|
-
</Tabs>
|
|
43
|
-
</div>
|
|
16
|
+
<InstallPackages packages="@ai-sdk/harness @ai-sdk/harness-claude-code @ai-sdk/sandbox-vercel" />
|
|
44
17
|
|
|
45
18
|
Bridge-backed harnesses such as Claude Code and Codex require using real network sandbox
|
|
46
19
|
like `@ai-sdk/sandbox-vercel`. Host-runtime harnesses such as Pi can also run with
|
|
@@ -28,10 +28,10 @@ The AI SDK includes the following harness adapters:
|
|
|
28
28
|
|
|
29
29
|
## Adapter Capabilities
|
|
30
30
|
|
|
31
|
-
| Adapter | Runtime location | Custom tools
|
|
32
|
-
| ------------------------------------------------------ | ---------------- |
|
|
33
|
-
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check
|
|
34
|
-
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check
|
|
35
|
-
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check
|
|
36
|
-
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check
|
|
37
|
-
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check
|
|
31
|
+
| Adapter | Runtime location | Custom tools | Custom skills | Built-in tool approval | Built-in tool filtering |
|
|
32
|
+
| ------------------------------------------------------ | ---------------- | ------------ | ------------- | ---------------------- | ---------------------------- |
|
|
33
|
+
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
34
|
+
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
35
|
+
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> via auto-rejection |
|
|
36
|
+
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> via auto-rejection |
|
|
37
|
+
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
@@ -18,22 +18,7 @@ integration.
|
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
21
|
-
<
|
|
22
|
-
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
23
|
-
<Tab>
|
|
24
|
-
<Snippet text="pnpm add @ai-sdk/workflow-harness workflow" dark />
|
|
25
|
-
</Tab>
|
|
26
|
-
<Tab>
|
|
27
|
-
<Snippet text="npm install @ai-sdk/workflow-harness workflow" dark />
|
|
28
|
-
</Tab>
|
|
29
|
-
<Tab>
|
|
30
|
-
<Snippet text="yarn add @ai-sdk/workflow-harness workflow" dark />
|
|
31
|
-
</Tab>
|
|
32
|
-
<Tab>
|
|
33
|
-
<Snippet text="bun add @ai-sdk/workflow-harness workflow" dark />
|
|
34
|
-
</Tab>
|
|
35
|
-
</Tabs>
|
|
36
|
-
</div>
|
|
21
|
+
<InstallPackages packages="@ai-sdk/workflow-harness workflow" />
|
|
37
22
|
|
|
38
23
|
Install the core harness package, a harness adapter, and a sandbox provider as
|
|
39
24
|
shown in [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent).
|
|
@@ -12,34 +12,7 @@ session for the lifetime of the terminal UI.
|
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
<
|
|
16
|
-
<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
|
|
17
|
-
<Tab>
|
|
18
|
-
<Snippet
|
|
19
|
-
text="pnpm add @ai-sdk/tui @ai-sdk/harness @ai-sdk/harness-codex @ai-sdk/sandbox-vercel"
|
|
20
|
-
dark
|
|
21
|
-
/>
|
|
22
|
-
</Tab>
|
|
23
|
-
<Tab>
|
|
24
|
-
<Snippet
|
|
25
|
-
text="npm install @ai-sdk/tui @ai-sdk/harness @ai-sdk/harness-codex @ai-sdk/sandbox-vercel"
|
|
26
|
-
dark
|
|
27
|
-
/>
|
|
28
|
-
</Tab>
|
|
29
|
-
<Tab>
|
|
30
|
-
<Snippet
|
|
31
|
-
text="yarn add @ai-sdk/tui @ai-sdk/harness @ai-sdk/harness-codex @ai-sdk/sandbox-vercel"
|
|
32
|
-
dark
|
|
33
|
-
/>
|
|
34
|
-
</Tab>
|
|
35
|
-
<Tab>
|
|
36
|
-
<Snippet
|
|
37
|
-
text="bun add @ai-sdk/tui @ai-sdk/harness @ai-sdk/harness-codex @ai-sdk/sandbox-vercel"
|
|
38
|
-
dark
|
|
39
|
-
/>
|
|
40
|
-
</Tab>
|
|
41
|
-
</Tabs>
|
|
42
|
-
</div>
|
|
15
|
+
<InstallPackages packages="@ai-sdk/tui @ai-sdk/harness @ai-sdk/harness-codex @ai-sdk/sandbox-vercel" />
|
|
43
16
|
|
|
44
17
|
## Example
|
|
45
18
|
|
|
@@ -24,11 +24,11 @@ Here is a comparison of the supported functions across these frameworks:
|
|
|
24
24
|
|
|
25
25
|
| | [useChat](/docs/reference/ai-sdk-ui/use-chat) | [useCompletion](/docs/reference/ai-sdk-ui/use-completion) | [useObject](/docs/reference/ai-sdk-ui/use-object) | [MCP Apps](/docs/ai-sdk-core/mcp-apps) |
|
|
26
26
|
| --------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | -------------------------------------- |
|
|
27
|
-
| React `@ai-sdk/react` | <Check
|
|
28
|
-
| Vue.js `@ai-sdk/vue` | <Check
|
|
29
|
-
| Svelte `@ai-sdk/svelte` | <Check
|
|
30
|
-
| Angular `@ai-sdk/angular` | <Check
|
|
31
|
-
| [SolidJS](https://github.com/kodehort/ai-sdk-solid) (community) | <Check
|
|
27
|
+
| React `@ai-sdk/react` | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
28
|
+
| Vue.js `@ai-sdk/vue` | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
29
|
+
| Svelte `@ai-sdk/svelte` | <Check /> Chat | <Check /> Completion | <Check /> StructuredObject | <Cross /> |
|
|
30
|
+
| Angular `@ai-sdk/angular` | <Check /> Chat | <Check /> Completion | <Check /> StructuredObject | <Cross /> |
|
|
31
|
+
| [SolidJS](https://github.com/kodehort/ai-sdk-solid) (community) | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
32
32
|
|
|
33
33
|
## Framework Examples
|
|
34
34
|
|
|
@@ -118,9 +118,10 @@ console.log(videos);
|
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
name: 'inputReferences',
|
|
121
|
-
type: 'Array<DataContent>',
|
|
121
|
+
type: 'Array<DataContent | { data: DataContent; mediaType?: string }>',
|
|
122
122
|
isOptional: true,
|
|
123
|
-
description:
|
|
123
|
+
description:
|
|
124
|
+
'Reference image or video inputs for reference-to-video generation. Use the object form with an explicit mediaType for URL-based video references. Providers route each reference by its media type and warn when a reference kind is unsupported.',
|
|
124
125
|
},
|
|
125
126
|
{
|
|
126
127
|
name: 'generateAudio',
|
|
@@ -87,11 +87,11 @@ Here is a comparison of the supported functions across these frameworks:
|
|
|
87
87
|
|
|
88
88
|
| | [useChat](/docs/reference/ai-sdk-ui/use-chat) | [useCompletion](/docs/reference/ai-sdk-ui/use-completion) | [useObject](/docs/reference/ai-sdk-ui/use-object) | [MCP Apps](/docs/ai-sdk-core/mcp-apps) |
|
|
89
89
|
| --------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------- | -------------------------------------- |
|
|
90
|
-
| React `@ai-sdk/react` | <Check
|
|
91
|
-
| Vue.js `@ai-sdk/vue` | <Check
|
|
92
|
-
| Svelte `@ai-sdk/svelte` | <Check
|
|
93
|
-
| Angular `@ai-sdk/angular` | <Check
|
|
94
|
-
| [SolidJS](https://github.com/kodehort/ai-sdk-solid) (community) | <Check
|
|
90
|
+
| React `@ai-sdk/react` | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
91
|
+
| Vue.js `@ai-sdk/vue` | <Check /> Chat | <Check /> | <Check /> | <Cross /> |
|
|
92
|
+
| Svelte `@ai-sdk/svelte` | <Check /> Chat | <Check /> Completion | <Check /> StructuredObject | <Cross /> |
|
|
93
|
+
| Angular `@ai-sdk/angular` | <Check /> Chat | <Check /> Completion | <Check /> StructuredObject | <Cross /> |
|
|
94
|
+
| [SolidJS](https://github.com/kodehort/ai-sdk-solid) (community) | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
95
95
|
|
|
96
96
|
<Note>
|
|
97
97
|
[Contributions](https://github.com/vercel/ai/blob/main/CONTRIBUTING.md) are
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.19",
|
|
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.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.15",
|
|
46
|
+
"@ai-sdk/provider": "4.0.3",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.7"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@edge-runtime/vm": "^5.0.0",
|
|
@@ -36,8 +36,19 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// gather tool calls and prepare lookup
|
|
40
|
-
|
|
39
|
+
// gather tool calls and prepare lookup.
|
|
40
|
+
//
|
|
41
|
+
// These maps are keyed by client-supplied ids (`toolCallId`, `approvalId`)
|
|
42
|
+
// from the message history. Using `Object.create(null)` gives them no
|
|
43
|
+
// prototype, so an id that matches an inherited object property (e.g.
|
|
44
|
+
// `toString`, `constructor`, `__proto__`) is treated as absent instead of
|
|
45
|
+
// resolving to a prototype value and slipping past the `== null` guards
|
|
46
|
+
// below (which would otherwise skip the InvalidToolApproval /
|
|
47
|
+
// ToolCallNotFound checks).
|
|
48
|
+
const toolCallsByToolCallId: Record<
|
|
49
|
+
string,
|
|
50
|
+
TypedToolCall<TOOLS>
|
|
51
|
+
> = Object.create(null);
|
|
41
52
|
for (const message of messages) {
|
|
42
53
|
if (message.role === 'assistant' && typeof message.content !== 'string') {
|
|
43
54
|
const content = message.content;
|
|
@@ -51,7 +62,7 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
|
|
|
51
62
|
|
|
52
63
|
// gather approval responses and prepare lookup
|
|
53
64
|
const toolApprovalRequestsByApprovalId: Record<string, ToolApprovalRequest> =
|
|
54
|
-
|
|
65
|
+
Object.create(null);
|
|
55
66
|
for (const message of messages) {
|
|
56
67
|
if (message.role === 'assistant' && typeof message.content !== 'string') {
|
|
57
68
|
const content = message.content;
|
|
@@ -64,7 +75,9 @@ export function collectToolApprovals<TOOLS extends ToolSet>({
|
|
|
64
75
|
}
|
|
65
76
|
|
|
66
77
|
// gather tool results from the last tool message
|
|
67
|
-
const toolResults: Record<string, TypedToolResult<TOOLS>> =
|
|
78
|
+
const toolResults: Record<string, TypedToolResult<TOOLS>> = Object.create(
|
|
79
|
+
null,
|
|
80
|
+
);
|
|
68
81
|
for (const part of lastMessage.content) {
|
|
69
82
|
if (part.type === 'tool-result') {
|
|
70
83
|
toolResults[part.toolCallId] = part as TypedToolResult<TOOLS>;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type TimeoutConfiguration,
|
|
14
14
|
} from '../prompt/request-options';
|
|
15
15
|
import type { TelemetryDispatcher } from '../telemetry/telemetry';
|
|
16
|
+
import { getOwn } from '../util/get-own';
|
|
16
17
|
import { mergeAbortSignals } from '../util/merge-abort-signals';
|
|
17
18
|
import { notify } from '../util/notify';
|
|
18
19
|
import { now } from '../util/now';
|
|
@@ -83,7 +84,7 @@ export async function executeToolCall<TOOLS extends ToolSet>({
|
|
|
83
84
|
| undefined
|
|
84
85
|
> {
|
|
85
86
|
const { toolName, toolCallId, input } = toolCall;
|
|
86
|
-
const tool = tools
|
|
87
|
+
const tool = getOwn(tools, toolName);
|
|
87
88
|
|
|
88
89
|
if (!isExecutableTool(tool)) {
|
|
89
90
|
return undefined;
|
|
@@ -91,7 +92,7 @@ export async function executeToolCall<TOOLS extends ToolSet>({
|
|
|
91
92
|
|
|
92
93
|
const context = await validateToolContext({
|
|
93
94
|
toolName,
|
|
94
|
-
context: toolsContext
|
|
95
|
+
context: getOwn(toolsContext, toolName),
|
|
95
96
|
contextSchema: tool.contextSchema,
|
|
96
97
|
});
|
|
97
98
|
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
} from '@ai-sdk/provider-utils';
|
|
10
10
|
import type { TimeoutConfiguration } from '../prompt/request-options';
|
|
11
11
|
import type { Telemetry, TelemetryDispatcher } from '../telemetry/telemetry';
|
|
12
|
+
import { getOwn } from '../util/get-own';
|
|
12
13
|
import { executeToolCall } from './execute-tool-call';
|
|
13
14
|
import { resolveToolApproval } from './resolve-tool-approval';
|
|
14
15
|
import type { LanguageModelStreamPart } from './stream-language-model-call';
|
|
@@ -95,7 +96,7 @@ export function executeToolsFromStream<
|
|
|
95
96
|
return;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
const tool = tools
|
|
99
|
+
const tool = getOwn(tools, chunk.toolName);
|
|
99
100
|
|
|
100
101
|
if (tool == null) {
|
|
101
102
|
// ignore tool calls for tools that are not available,
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
type LanguageModelUsage,
|
|
51
51
|
} from '../types/usage';
|
|
52
52
|
import type { DownloadFunction } from '../util/download/download-function';
|
|
53
|
+
import { getOwn } from '../util/get-own';
|
|
53
54
|
import { mergeAbortSignals } from '../util/merge-abort-signals';
|
|
54
55
|
import { mergeObjects } from '../util/merge-objects';
|
|
55
56
|
import { now as originalNow } from '../util/now';
|
|
@@ -717,7 +718,7 @@ export async function generateText<
|
|
|
717
718
|
const modelOutput = await createToolModelOutput({
|
|
718
719
|
toolCallId: output.toolCallId,
|
|
719
720
|
input: output.input,
|
|
720
|
-
tool: tools
|
|
721
|
+
tool: getOwn(tools, output.toolName),
|
|
721
722
|
output:
|
|
722
723
|
output.type === 'tool-result' ? output.output : output.error,
|
|
723
724
|
errorMode: output.type === 'tool-error' ? 'text' : 'none',
|
|
@@ -1040,7 +1041,7 @@ export async function generateText<
|
|
|
1040
1041
|
continue; // ignore invalid tool calls
|
|
1041
1042
|
}
|
|
1042
1043
|
|
|
1043
|
-
const tool = tools
|
|
1044
|
+
const tool = getOwn(tools, toolCall.toolName);
|
|
1044
1045
|
|
|
1045
1046
|
if (tool == null) {
|
|
1046
1047
|
// ignore tool calls for tools that are not available,
|
|
@@ -1234,7 +1235,7 @@ export async function generateText<
|
|
|
1234
1235
|
// the client tool's result is sent back.
|
|
1235
1236
|
for (const toolCall of stepToolCalls) {
|
|
1236
1237
|
if (!toolCall.providerExecuted) continue;
|
|
1237
|
-
const tool = tools
|
|
1238
|
+
const tool = getOwn(tools, toolCall.toolName);
|
|
1238
1239
|
if (tool?.type === 'provider' && tool.supportsDeferredResults) {
|
|
1239
1240
|
// Check if this tool call already has a result in the current response
|
|
1240
1241
|
const hasResultInResponse = currentModelResponse.content.some(
|
|
@@ -1699,7 +1700,7 @@ function asContent<TOOLS extends ToolSet>({
|
|
|
1699
1700
|
// result may be deferred to a later turn. In this case, there's no matching tool-call
|
|
1700
1701
|
// in the current response.
|
|
1701
1702
|
if (toolCall == null) {
|
|
1702
|
-
const tool = tools
|
|
1703
|
+
const tool = getOwn(tools, part.toolName);
|
|
1703
1704
|
const supportsDeferredResults =
|
|
1704
1705
|
tool?.type === 'provider' && tool.supportsDeferredResults;
|
|
1705
1706
|
|
|
@@ -80,6 +80,7 @@ export type {
|
|
|
80
80
|
ToolApprovalConfiguration,
|
|
81
81
|
ToolApprovalStatus,
|
|
82
82
|
} from './tool-approval-configuration';
|
|
83
|
+
export { detectToolDrift, fingerprintTools } from './tool-fingerprint';
|
|
83
84
|
export type { ToolApprovalRequestOutput } from './tool-approval-request-output';
|
|
84
85
|
export type { ToolApprovalResponseOutput } from './tool-approval-response-output';
|
|
85
86
|
export type {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Context, ModelMessage, ToolSet } from '@ai-sdk/provider-utils';
|
|
2
|
+
import { createIdMap } from '../util/create-id-map';
|
|
3
|
+
import { getOwn } from '../util/get-own';
|
|
2
4
|
import type { LanguageModelStreamPart } from './stream-language-model-call';
|
|
3
5
|
|
|
4
6
|
export function invokeToolCallbacksFromStream<
|
|
@@ -19,7 +21,7 @@ export function invokeToolCallbacksFromStream<
|
|
|
19
21
|
}): ReadableStream<LanguageModelStreamPart<TOOLS>> {
|
|
20
22
|
if (tools == null) return stream;
|
|
21
23
|
|
|
22
|
-
const ongoingToolCallToolNames: Record<string, string> =
|
|
24
|
+
const ongoingToolCallToolNames: Record<string, string> = createIdMap();
|
|
23
25
|
|
|
24
26
|
return stream.pipeThrough(
|
|
25
27
|
new TransformStream({
|
|
@@ -30,7 +32,7 @@ export function invokeToolCallbacksFromStream<
|
|
|
30
32
|
case 'tool-input-start': {
|
|
31
33
|
ongoingToolCallToolNames[chunk.id] = chunk.toolName;
|
|
32
34
|
|
|
33
|
-
const tool = tools
|
|
35
|
+
const tool = getOwn(tools, chunk.toolName);
|
|
34
36
|
if (tool?.onInputStart != null) {
|
|
35
37
|
await tool.onInputStart({
|
|
36
38
|
toolCallId: chunk.id,
|
|
@@ -45,7 +47,7 @@ export function invokeToolCallbacksFromStream<
|
|
|
45
47
|
|
|
46
48
|
case 'tool-input-delta': {
|
|
47
49
|
const toolName = ongoingToolCallToolNames[chunk.id];
|
|
48
|
-
const tool = tools
|
|
50
|
+
const tool = getOwn(tools, toolName);
|
|
49
51
|
|
|
50
52
|
if (tool?.onInputDelta != null) {
|
|
51
53
|
await tool.onInputDelta({
|
|
@@ -62,7 +64,7 @@ export function invokeToolCallbacksFromStream<
|
|
|
62
64
|
|
|
63
65
|
case 'tool-call': {
|
|
64
66
|
const toolName = ongoingToolCallToolNames[chunk.toolCallId];
|
|
65
|
-
const tool = tools
|
|
67
|
+
const tool = getOwn(tools, toolName);
|
|
66
68
|
|
|
67
69
|
delete ongoingToolCallToolNames[chunk.toolCallId];
|
|
68
70
|
|
|
@@ -11,6 +11,7 @@ import { InvalidToolInputError } from '../error/invalid-tool-input-error';
|
|
|
11
11
|
import { NoSuchToolError } from '../error/no-such-tool-error';
|
|
12
12
|
import { ToolCallRepairError } from '../error/tool-call-repair-error';
|
|
13
13
|
import type { Instructions } from '../prompt';
|
|
14
|
+
import { getOwn } from '../util/get-own';
|
|
14
15
|
import type { DynamicToolCall, TypedToolCall } from './tool-call';
|
|
15
16
|
import type { ToolCallRepairFunction } from './tool-call-repair-function';
|
|
16
17
|
import type { ToolInputRefinement } from './tool-input-refinement';
|
|
@@ -66,7 +67,7 @@ export async function parseToolCall<TOOLS extends ToolSet>({
|
|
|
66
67
|
toolCall,
|
|
67
68
|
tools,
|
|
68
69
|
inputSchema: async ({ toolName }) => {
|
|
69
|
-
const
|
|
70
|
+
const inputSchema = getOwn(tools, toolName)?.inputSchema;
|
|
70
71
|
return await asSchema(inputSchema).jsonSchema;
|
|
71
72
|
},
|
|
72
73
|
instructions,
|
|
@@ -95,7 +96,7 @@ export async function parseToolCall<TOOLS extends ToolSet>({
|
|
|
95
96
|
// use parsed input when possible
|
|
96
97
|
const parsedInput = await safeParseJSON({ text: toolCall.input });
|
|
97
98
|
const input = parsedInput.success ? parsedInput.value : toolCall.input;
|
|
98
|
-
const tool = tools
|
|
99
|
+
const tool = getOwn(tools, toolCall.toolName);
|
|
99
100
|
|
|
100
101
|
// TODO AI SDK 6: special invalid tool call parts
|
|
101
102
|
return {
|
|
@@ -121,7 +122,7 @@ async function refineParsedToolCallInput<TOOLS extends ToolSet>({
|
|
|
121
122
|
toolCall: TypedToolCall<TOOLS>;
|
|
122
123
|
refineToolInput: ToolInputRefinement<TOOLS> | undefined;
|
|
123
124
|
}): Promise<TypedToolCall<TOOLS>> {
|
|
124
|
-
const refine = refineToolInput
|
|
125
|
+
const refine = getOwn(refineToolInput, toolCall.toolName);
|
|
125
126
|
|
|
126
127
|
if (refine == null) {
|
|
127
128
|
return toolCall;
|
|
@@ -169,7 +170,7 @@ async function doParseToolCall<TOOLS extends ToolSet>({
|
|
|
169
170
|
}): Promise<TypedToolCall<TOOLS>> {
|
|
170
171
|
const toolName = toolCall.toolName as keyof TOOLS & string;
|
|
171
172
|
|
|
172
|
-
const tool = tools
|
|
173
|
+
const tool = getOwn(tools, toolName);
|
|
173
174
|
|
|
174
175
|
if (tool == null) {
|
|
175
176
|
// provider-executed dynamic tools are not part of our list of tools:
|