ai 7.0.17 → 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 +29 -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/04-ai-sdk-ui/08-object-generation.mdx +7 -10
- package/docs/07-reference/01-ai-sdk-core/13-generate-video.mdx +3 -2
- package/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx +6 -9
- 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
|
|
|
@@ -5,10 +5,7 @@ description: Learn how to use the useObject hook.
|
|
|
5
5
|
|
|
6
6
|
# Object Generation
|
|
7
7
|
|
|
8
|
-
<Note>
|
|
9
|
-
`useObject` is an experimental feature and only available in React, Svelte,
|
|
10
|
-
and Vue.
|
|
11
|
-
</Note>
|
|
8
|
+
<Note>`useObject` is only available in React, Svelte, and Vue.</Note>
|
|
12
9
|
|
|
13
10
|
The [`useObject`](/docs/reference/ai-sdk-ui/use-object) hook allows you to create interfaces that represent a structured JSON object that is being streamed.
|
|
14
11
|
|
|
@@ -46,7 +43,7 @@ Please note the code for handling `undefined` values in the JSX.
|
|
|
46
43
|
```tsx filename='app/page.tsx'
|
|
47
44
|
'use client';
|
|
48
45
|
|
|
49
|
-
import {
|
|
46
|
+
import { useObject } from '@ai-sdk/react';
|
|
50
47
|
import { notificationSchema } from './api/notifications/schema';
|
|
51
48
|
|
|
52
49
|
export default function Page() {
|
|
@@ -115,7 +112,7 @@ When using `useObject` with enum output mode, your schema must be an object with
|
|
|
115
112
|
```tsx filename='app/classify/page.tsx'
|
|
116
113
|
'use client';
|
|
117
114
|
|
|
118
|
-
import {
|
|
115
|
+
import { useObject } from '@ai-sdk/react';
|
|
119
116
|
import { z } from 'zod';
|
|
120
117
|
|
|
121
118
|
export default function ClassifyPage() {
|
|
@@ -174,7 +171,7 @@ purposes:
|
|
|
174
171
|
```tsx filename='app/page.tsx' highlight="6,13-20,24"
|
|
175
172
|
'use client';
|
|
176
173
|
|
|
177
|
-
import {
|
|
174
|
+
import { useObject } from '@ai-sdk/react';
|
|
178
175
|
|
|
179
176
|
export default function Page() {
|
|
180
177
|
const { isLoading, object, submit } = useObject({
|
|
@@ -211,7 +208,7 @@ The `stop` function can be used to stop the object generation process. This can
|
|
|
211
208
|
```tsx filename='app/page.tsx' highlight="6,14-16"
|
|
212
209
|
'use client';
|
|
213
210
|
|
|
214
|
-
import {
|
|
211
|
+
import { useObject } from '@ai-sdk/react';
|
|
215
212
|
|
|
216
213
|
export default function Page() {
|
|
217
214
|
const { isLoading, stop, object, submit } = useObject({
|
|
@@ -256,7 +253,7 @@ It can be used to display an error message, or to disable the submit button:
|
|
|
256
253
|
```tsx file="app/page.tsx" highlight="6,13"
|
|
257
254
|
'use client';
|
|
258
255
|
|
|
259
|
-
import {
|
|
256
|
+
import { useObject } from '@ai-sdk/react';
|
|
260
257
|
|
|
261
258
|
export default function Page() {
|
|
262
259
|
const { error, object, submit } = useObject({
|
|
@@ -295,7 +292,7 @@ These callbacks can be used to trigger additional actions, such as logging, anal
|
|
|
295
292
|
```tsx filename='app/page.tsx' highlight="10-20"
|
|
296
293
|
'use client';
|
|
297
294
|
|
|
298
|
-
import {
|
|
295
|
+
import { useObject } from '@ai-sdk/react';
|
|
299
296
|
import { notificationSchema } from './api/notifications/schema';
|
|
300
297
|
|
|
301
298
|
export default function Page() {
|
|
@@ -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',
|
|
@@ -3,12 +3,9 @@ title: useObject
|
|
|
3
3
|
description: API reference for the useObject hook.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# `
|
|
6
|
+
# `useObject()`
|
|
7
7
|
|
|
8
|
-
<Note>
|
|
9
|
-
`useObject` is an experimental feature and only available in React, Svelte,
|
|
10
|
-
and Vue.
|
|
11
|
-
</Note>
|
|
8
|
+
<Note>`useObject` is only available in React, Svelte, and Vue.</Note>
|
|
12
9
|
|
|
13
10
|
Allows you to consume text streams that represent a JSON object and parse them into a complete object based on a schema.
|
|
14
11
|
You can use it together with [`streamText`](/docs/reference/ai-sdk-core/stream-text) and [`Output.object()`](/docs/reference/ai-sdk-core/output#output-object) in the backend.
|
|
@@ -16,7 +13,7 @@ You can use it together with [`streamText`](/docs/reference/ai-sdk-core/stream-t
|
|
|
16
13
|
```tsx
|
|
17
14
|
'use client';
|
|
18
15
|
|
|
19
|
-
import {
|
|
16
|
+
import { useObject } from '@ai-sdk/react';
|
|
20
17
|
|
|
21
18
|
export default function Page() {
|
|
22
19
|
const { object, submit } = useObject({
|
|
@@ -38,21 +35,21 @@ export default function Page() {
|
|
|
38
35
|
<Tabs items={['React', 'Svelte', 'Vue']}>
|
|
39
36
|
<Tab>
|
|
40
37
|
<Snippet
|
|
41
|
-
text="import {
|
|
38
|
+
text="import { useObject } from '@ai-sdk/react'"
|
|
42
39
|
dark
|
|
43
40
|
prompt={false}
|
|
44
41
|
/>
|
|
45
42
|
</Tab>
|
|
46
43
|
<Tab>
|
|
47
44
|
<Snippet
|
|
48
|
-
text="import {
|
|
45
|
+
text="import { StructuredObject } from '@ai-sdk/svelte'"
|
|
49
46
|
dark
|
|
50
47
|
prompt={false}
|
|
51
48
|
/>
|
|
52
49
|
</Tab>
|
|
53
50
|
<Tab>
|
|
54
51
|
<Snippet
|
|
55
|
-
text="import {
|
|
52
|
+
text="import { useObject } from '@ai-sdk/vue'"
|
|
56
53
|
dark
|
|
57
54
|
prompt={false}
|
|
58
55
|
/>
|
|
@@ -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
|
|