ai 7.0.153 → 7.0.154
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 +11 -0
- package/dist/index.d.ts +224 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +399 -96
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +52 -4
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +26 -20
- package/dist/internal/index.js.map +1 -1
- package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -2
- package/docs/02-getting-started/08-angular.mdx +327 -0
- package/docs/02-getting-started/{03-nextjs-pages-router.mdx → 10-nextjs-pages-router.mdx} +12 -20
- package/docs/02-getting-started/index.mdx +2 -0
- package/docs/03-agents/01-overview.mdx +1 -0
- package/docs/03-agents/04-loop-control.mdx +117 -0
- package/docs/03-agents/06-tool-approvals.mdx +1 -0
- package/docs/03-agents/09-chat-platforms.mdx +164 -0
- package/docs/03-agents/index.mdx +6 -0
- package/docs/03-ai-sdk-core/60-telemetry.mdx +16 -3
- package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +10 -0
- package/docs/04-ai-sdk-ui/21-transport.mdx +86 -0
- package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +46 -0
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +46 -0
- package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +35 -0
- package/package.json +11 -11
- package/src/agent/create-agent-ui-stream-response.ts +3 -0
- package/src/agent/create-agent-ui-stream.ts +16 -0
- package/src/agent/pipe-agent-ui-stream-to-response.ts +3 -0
- package/src/agent/tool-loop-agent-settings.ts +37 -1
- package/src/agent/tool-loop-agent.ts +43 -7
- package/src/generate-text/generate-text-events.ts +37 -0
- package/src/generate-text/generate-text.ts +521 -373
- package/src/generate-text/index.ts +8 -0
- package/src/generate-text/prepare-step.ts +12 -0
- package/src/generate-text/restricted-telemetry-dispatcher.ts +31 -18
- package/src/generate-text/steering.ts +293 -0
- package/src/generate-text/step-result.ts +18 -0
- package/src/generate-text/stream-text.ts +664 -473
- package/src/telemetry/create-telemetry-dispatcher.ts +3 -0
- package/src/telemetry/telemetry.ts +15 -1
- package/src/util/is-caused-by-abort.ts +20 -0
|
@@ -27,8 +27,8 @@ Start by creating a new Next.js application. This command will create a new dire
|
|
|
27
27
|
<div className="mb-4">
|
|
28
28
|
<Note>
|
|
29
29
|
Be sure to select yes when prompted to use the App Router and Tailwind CSS.
|
|
30
|
-
If you are
|
|
31
|
-
|
|
30
|
+
If you are adding the AI SDK to an existing Pages Router application, follow
|
|
31
|
+
the [Pages Router guide](/docs/getting-started/nextjs-pages-router).
|
|
32
32
|
</Note>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Angular
|
|
3
|
+
description: Learn how to build your first agent with the AI SDK and Angular.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Angular Quickstart
|
|
7
|
+
|
|
8
|
+
The AI SDK is a powerful TypeScript library designed to help developers build AI-powered applications.
|
|
9
|
+
|
|
10
|
+
In this quickstart tutorial, you'll build a simple agent with a streaming chat user interface using Angular and an Express backend. Along the way, you'll learn key concepts and techniques that are fundamental to using the AI SDK in your own projects.
|
|
11
|
+
|
|
12
|
+
If you are unfamiliar with the concepts of [Prompt Engineering](/docs/advanced/prompt-engineering) and [HTTP Streaming](/docs/foundations/streaming), you can optionally read these documents first.
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
To follow this quickstart, you'll need:
|
|
17
|
+
|
|
18
|
+
- Node.js 24.15+ (or another [version supported by Angular](https://angular.dev/reference/versions)) and pnpm installed on your local development machine.
|
|
19
|
+
- A [Vercel AI Gateway](https://vercel.com/ai-gateway) API key.
|
|
20
|
+
|
|
21
|
+
If you haven't obtained your Vercel AI Gateway API key, you can do so by [signing up](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai&title=Go+to+AI+Gateway) on the Vercel website.
|
|
22
|
+
|
|
23
|
+
## Set Up Your Application
|
|
24
|
+
|
|
25
|
+
Create a new Angular application using the Angular CLI:
|
|
26
|
+
|
|
27
|
+
<Snippet text="pnpm dlx @angular/cli@latest new my-ai-app --defaults --ssr=false --package-manager=pnpm" />
|
|
28
|
+
|
|
29
|
+
This creates a standalone Angular application. This guide uses client-side rendering, with a separate Express server for the chat API.
|
|
30
|
+
|
|
31
|
+
Navigate to the newly created directory:
|
|
32
|
+
|
|
33
|
+
<Snippet text="cd my-ai-app" />
|
|
34
|
+
|
|
35
|
+
### Install Dependencies
|
|
36
|
+
|
|
37
|
+
Install `ai` and `@ai-sdk/angular`, the AI package and AI SDK's Angular bindings. You'll also install `express` for the backend, `dotenv` to load environment variables, and `zod` to define tool inputs.
|
|
38
|
+
|
|
39
|
+
<InstallPackages packages="ai @ai-sdk/angular express dotenv zod" />
|
|
40
|
+
|
|
41
|
+
Install the TypeScript runner and server type definitions:
|
|
42
|
+
|
|
43
|
+
<InstallPackages packages="tsx @types/express @types/node" dev />
|
|
44
|
+
|
|
45
|
+
<Note>
|
|
46
|
+
This guide uses the Vercel AI Gateway provider, which ships with the `ai`
|
|
47
|
+
package. You can access hundreds of models with one API key, or switch to
|
|
48
|
+
another [AI SDK provider](/providers/ai-sdk-providers).
|
|
49
|
+
</Note>
|
|
50
|
+
|
|
51
|
+
### Configure Your AI Gateway API Key
|
|
52
|
+
|
|
53
|
+
Create a `.env` file in your project root:
|
|
54
|
+
|
|
55
|
+
```env filename=".env"
|
|
56
|
+
AI_GATEWAY_API_KEY=xxxxxxxxx
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Replace `xxxxxxxxx` with your actual Vercel AI Gateway API key. The Express server loads this file using `dotenv`, and the AI SDK's Gateway provider reads `AI_GATEWAY_API_KEY` automatically. Keep the API key on the server and add `.env` to `.gitignore`.
|
|
60
|
+
|
|
61
|
+
## Create an API Route
|
|
62
|
+
|
|
63
|
+
Create `server.ts` in your project root and add the following code:
|
|
64
|
+
|
|
65
|
+
```ts filename="server.ts"
|
|
66
|
+
import {
|
|
67
|
+
streamText,
|
|
68
|
+
type UIMessage,
|
|
69
|
+
convertToModelMessages,
|
|
70
|
+
pipeUIMessageStreamToResponse,
|
|
71
|
+
toUIMessageStream,
|
|
72
|
+
} from 'ai';
|
|
73
|
+
__PROVIDER_IMPORT__;
|
|
74
|
+
import 'dotenv/config';
|
|
75
|
+
import express from 'express';
|
|
76
|
+
|
|
77
|
+
const app = express();
|
|
78
|
+
app.use(express.json());
|
|
79
|
+
|
|
80
|
+
app.post('/api/chat', async (req, res) => {
|
|
81
|
+
const { messages }: { messages: UIMessage[] } = req.body;
|
|
82
|
+
|
|
83
|
+
const result = streamText({
|
|
84
|
+
model: __MODEL__,
|
|
85
|
+
messages: await convertToModelMessages(messages),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await pipeUIMessageStreamToResponse({
|
|
89
|
+
response: res,
|
|
90
|
+
stream: toUIMessageStream({ stream: result.stream }),
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
app.listen(3000, '127.0.0.1', () => {
|
|
95
|
+
console.log('Chat API listening on http://127.0.0.1:3000');
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The server listens on `127.0.0.1` to keep the development API local to your machine. This creates a `POST /api/chat` endpoint. Let's take a look at what happens when it receives a request:
|
|
100
|
+
|
|
101
|
+
1. `express.json()` parses the request body, which contains the conversation's `UIMessage` objects.
|
|
102
|
+
2. [`convertToModelMessages`](/docs/reference/ai-sdk-ui/convert-to-model-messages) converts those UI messages to the format expected by the model.
|
|
103
|
+
3. [`streamText`](/docs/reference/ai-sdk-core/stream-text) calls the model through AI Gateway.
|
|
104
|
+
4. `toUIMessageStream` converts the model's output to the UI message stream format, and `pipeUIMessageStreamToResponse` writes it to the Express response as server-sent events.
|
|
105
|
+
|
|
106
|
+
### Configure the Development Proxy
|
|
107
|
+
|
|
108
|
+
Create `proxy.conf.json` in your project root:
|
|
109
|
+
|
|
110
|
+
```json filename="proxy.conf.json"
|
|
111
|
+
{
|
|
112
|
+
"/api/**": {
|
|
113
|
+
"target": "http://127.0.0.1:3000"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
When you start Angular with this proxy configuration, requests to `/api/chat` are forwarded to the Express server. The browser can use the relative `/api/chat` URL, which is also the default endpoint for the AI SDK's `Chat` class.
|
|
119
|
+
|
|
120
|
+
<Note>
|
|
121
|
+
This proxy is for local development. When deploying, route `/api/chat` to your
|
|
122
|
+
backend, or configure a different API URL using
|
|
123
|
+
[`DefaultChatTransport`](/docs/ai-sdk-ui/transport).
|
|
124
|
+
</Note>
|
|
125
|
+
|
|
126
|
+
## Choosing a Provider
|
|
127
|
+
|
|
128
|
+
The AI SDK supports dozens of model providers through [first-party](/providers/ai-sdk-providers), [OpenAI-compatible](/providers/openai-compatible-providers), and [community](/providers/community-providers) packages.
|
|
129
|
+
|
|
130
|
+
This quickstart uses the [Vercel AI Gateway](https://vercel.com/ai-gateway) provider, which is the default [global provider](/docs/ai-sdk-core/provider-management#global-provider-configuration). You can select a model using a string in your server's configuration:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
model: __MODEL__;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
To use a provider directly, install its package and create a provider instance. Learn more about [provider management](/docs/ai-sdk-core/provider-management#global-provider-configuration).
|
|
137
|
+
|
|
138
|
+
## Wire Up the UI
|
|
139
|
+
|
|
140
|
+
The `@ai-sdk/angular` package provides a `Chat` class that manages messages, streams responses, and exposes the current request status. Its state is backed by Angular signals, so the template updates as new content arrives.
|
|
141
|
+
|
|
142
|
+
Replace `src/app/app.ts` with the following component:
|
|
143
|
+
|
|
144
|
+
```ts filename="src/app/app.ts"
|
|
145
|
+
import { JsonPipe } from '@angular/common';
|
|
146
|
+
import { Component, signal } from '@angular/core';
|
|
147
|
+
import { Chat } from '@ai-sdk/angular';
|
|
148
|
+
|
|
149
|
+
@Component({
|
|
150
|
+
selector: 'app-root',
|
|
151
|
+
imports: [JsonPipe],
|
|
152
|
+
template: `
|
|
153
|
+
<main>
|
|
154
|
+
@for (message of chat.messages; track message.id) {
|
|
155
|
+
<div>
|
|
156
|
+
<strong>{{ message.role === 'user' ? 'User' : 'AI' }}:</strong>
|
|
157
|
+
@for (part of message.parts; track $index) {
|
|
158
|
+
@if (part.type === 'text') {
|
|
159
|
+
<p style="white-space: pre-wrap">{{ part.text }}</p>
|
|
160
|
+
} @else if (part.type.startsWith('tool-')) {
|
|
161
|
+
<pre>{{ part | json }}</pre>
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
</div>
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@if (chat.status === 'submitted') {
|
|
168
|
+
<p>Waiting for a response...</p>
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@if (chat.error; as error) {
|
|
172
|
+
<p role="alert">{{ error.message }}</p>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
<form (submit)="sendMessage($event)">
|
|
176
|
+
<label for="message">Your message</label>
|
|
177
|
+
<input
|
|
178
|
+
id="message"
|
|
179
|
+
#messageInput
|
|
180
|
+
[value]="input()"
|
|
181
|
+
(input)="input.set(messageInput.value)"
|
|
182
|
+
/>
|
|
183
|
+
<button
|
|
184
|
+
type="submit"
|
|
185
|
+
[disabled]="
|
|
186
|
+
chat.status === 'submitted' || chat.status === 'streaming'
|
|
187
|
+
"
|
|
188
|
+
>
|
|
189
|
+
Send
|
|
190
|
+
</button>
|
|
191
|
+
@if (chat.status === 'submitted' || chat.status === 'streaming') {
|
|
192
|
+
<button type="button" (click)="chat.stop()">Stop</button>
|
|
193
|
+
}
|
|
194
|
+
</form>
|
|
195
|
+
</main>
|
|
196
|
+
`,
|
|
197
|
+
})
|
|
198
|
+
export class App {
|
|
199
|
+
readonly chat = new Chat({});
|
|
200
|
+
readonly input = signal('');
|
|
201
|
+
|
|
202
|
+
sendMessage(event: Event) {
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
const text = this.input().trim();
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
!text ||
|
|
208
|
+
this.chat.status === 'submitted' ||
|
|
209
|
+
this.chat.status === 'streaming'
|
|
210
|
+
) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.chat.sendMessage({ text });
|
|
215
|
+
this.input.set('');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
<Note>
|
|
221
|
+
Older Angular projects may name the root component file `app.component.ts` and
|
|
222
|
+
its class `AppComponent`. If you are using an existing project, keep its file
|
|
223
|
+
and class names so the imports in `src/main.ts` continue to work.
|
|
224
|
+
</Note>
|
|
225
|
+
|
|
226
|
+
The component creates one `Chat` instance and uses its reactive properties:
|
|
227
|
+
|
|
228
|
+
- `messages` contains the conversation. Each message has a `role` and an ordered array of `parts`.
|
|
229
|
+
- `sendMessage` sends a user message to `/api/chat` and streams the response into `messages`.
|
|
230
|
+
- `status` indicates whether the chat is ready, submitted, streaming, or in an error state.
|
|
231
|
+
- `error` contains the latest request error.
|
|
232
|
+
- `stop` cancels the current response.
|
|
233
|
+
|
|
234
|
+
Read these properties as `chat.messages`, `chat.status`, and `chat.error`; the `Chat` class manages the underlying signals. The input field uses a separate Angular signal, which is read with `input()`.
|
|
235
|
+
|
|
236
|
+
The template renders text parts as they arrive and uses Angular's `JsonPipe` to display tool calls and results, which you'll add next.
|
|
237
|
+
|
|
238
|
+
## Running Your Application
|
|
239
|
+
|
|
240
|
+
In one terminal, start the Express backend from your project root:
|
|
241
|
+
|
|
242
|
+
<Snippet text="pnpm exec tsx watch server.ts" />
|
|
243
|
+
|
|
244
|
+
In a second terminal, start the Angular development server from the same directory:
|
|
245
|
+
|
|
246
|
+
<Snippet text="pnpm exec ng serve --proxy-config proxy.conf.json" />
|
|
247
|
+
|
|
248
|
+
Open [http://localhost:4200](http://localhost:4200), enter a message, and watch the response stream into the chat interface.
|
|
249
|
+
|
|
250
|
+
<Note>
|
|
251
|
+
If you change `proxy.conf.json`, restart the Angular development server so it
|
|
252
|
+
picks up the new configuration.
|
|
253
|
+
</Note>
|
|
254
|
+
|
|
255
|
+
## Enhance Your Chatbot with Tools
|
|
256
|
+
|
|
257
|
+
[Tools](/docs/ai-sdk-core/tools-and-tool-calling) let a model request actions such as looking up the weather. The server executes the action and returns the result to the model.
|
|
258
|
+
|
|
259
|
+
Replace `server.ts` with the following code to add a weather tool:
|
|
260
|
+
|
|
261
|
+
```ts filename="server.ts"
|
|
262
|
+
import {
|
|
263
|
+
streamText,
|
|
264
|
+
type UIMessage,
|
|
265
|
+
convertToModelMessages,
|
|
266
|
+
pipeUIMessageStreamToResponse,
|
|
267
|
+
toUIMessageStream,
|
|
268
|
+
tool,
|
|
269
|
+
isStepCount,
|
|
270
|
+
} from 'ai';
|
|
271
|
+
__PROVIDER_IMPORT__;
|
|
272
|
+
import 'dotenv/config';
|
|
273
|
+
import express from 'express';
|
|
274
|
+
import * as z4 from 'zod/v4';
|
|
275
|
+
|
|
276
|
+
const app = express();
|
|
277
|
+
app.use(express.json());
|
|
278
|
+
|
|
279
|
+
app.post('/api/chat', async (req, res) => {
|
|
280
|
+
const { messages }: { messages: UIMessage[] } = req.body;
|
|
281
|
+
|
|
282
|
+
const result = streamText({
|
|
283
|
+
model: __MODEL__,
|
|
284
|
+
messages: await convertToModelMessages(messages),
|
|
285
|
+
stopWhen: isStepCount(5),
|
|
286
|
+
tools: {
|
|
287
|
+
weather: tool({
|
|
288
|
+
description: 'Get the weather in a location (fahrenheit)',
|
|
289
|
+
inputSchema: z4.object({
|
|
290
|
+
location: z4.string().describe('The location to get the weather for'),
|
|
291
|
+
}),
|
|
292
|
+
execute: async ({ location }) => {
|
|
293
|
+
const temperature = Math.round(Math.random() * (90 - 32) + 32);
|
|
294
|
+
return { location, temperature };
|
|
295
|
+
},
|
|
296
|
+
}),
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
await pipeUIMessageStreamToResponse({
|
|
301
|
+
response: res,
|
|
302
|
+
stream: toUIMessageStream({ stream: result.stream }),
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
app.listen(3000, '127.0.0.1', () => {
|
|
307
|
+
console.log('Chat API listening on http://127.0.0.1:3000');
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The `weather` tool has a description, an input schema, and an `execute` function. The model uses the description to decide when to call the tool and the schema to generate its input. The server then executes the function and returns its result.
|
|
312
|
+
|
|
313
|
+
This example returns a simulated temperature. You can replace the function with a call to a weather API to return real data.
|
|
314
|
+
|
|
315
|
+
### Enabling Multi-Step Tool Calls
|
|
316
|
+
|
|
317
|
+
By default, a generation stops after one step. Setting `stopWhen: isStepCount(5)` allows the model to continue after receiving a tool result, for up to five steps. It can use the returned weather data to answer the original question.
|
|
318
|
+
|
|
319
|
+
Ask "What's the weather in San Francisco?" in your chat interface. The template displays the `tool-weather` part as JSON, followed by the model's text response. No frontend changes are required: the `Chat` class already handles tool parts in the UI message stream.
|
|
320
|
+
|
|
321
|
+
## Where to Go Next
|
|
322
|
+
|
|
323
|
+
You've built an Angular chat interface that streams responses, calls tools, and uses their results in multi-step generations.
|
|
324
|
+
|
|
325
|
+
- Explore the [Angular example](https://github.com/vercel/ai/tree/main/examples/angular) for chat, completion, and structured output examples.
|
|
326
|
+
- Learn more about [AI SDK UI](/docs/ai-sdk-ui/overview) and [tools and tool calling](/docs/ai-sdk-core/tools-and-tool-calling).
|
|
327
|
+
- Use the [transport API](/docs/ai-sdk-ui/transport) to connect your Angular frontend to an existing backend.
|
|
@@ -1,40 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Next.js Pages Router
|
|
3
|
-
description:
|
|
3
|
+
description: Add an agent with a streaming chat interface to an existing Next.js Pages Router application.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Next.js Pages Router
|
|
6
|
+
# Next.js Pages Router Guide
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
This guide shows how to add an agent with a streaming chat user interface to an existing Next.js Pages Router application.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
<Note>
|
|
11
|
+
For new applications, we recommend the [Next.js App Router
|
|
12
|
+
quickstart](/docs/getting-started/nextjs-app-router).
|
|
13
|
+
</Note>
|
|
11
14
|
|
|
12
15
|
If you are unfamiliar with the concepts of [Prompt Engineering](/docs/advanced/prompt-engineering) and [HTTP Streaming](/docs/foundations/streaming), you can optionally read these documents first.
|
|
13
16
|
|
|
14
17
|
## Prerequisites
|
|
15
18
|
|
|
16
|
-
To follow this
|
|
19
|
+
To follow this guide, you'll need:
|
|
17
20
|
|
|
21
|
+
- An existing Next.js 13+ application using the Pages Router.
|
|
18
22
|
- Node.js 22+ and pnpm installed on your local development machine.
|
|
19
23
|
- A [Vercel AI Gateway](https://vercel.com/ai-gateway) API key.
|
|
20
24
|
|
|
21
25
|
If you haven't obtained your Vercel AI Gateway API key, you can do so by [signing up](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai&title=Go+to+AI+Gateway) on the Vercel website.
|
|
22
26
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
Start by creating a new Next.js application. This command will create a new directory named `my-ai-app` and set up a basic Next.js application inside it.
|
|
26
|
-
|
|
27
|
-
<Note>
|
|
28
|
-
Be sure to select no when prompted to use the App Router. If you are looking
|
|
29
|
-
for the Next.js App Router quickstart guide, you can find it
|
|
30
|
-
[here](/docs/getting-started/nextjs-app-router).
|
|
31
|
-
</Note>
|
|
32
|
-
|
|
33
|
-
<Snippet text="pnpm create next-app@latest my-ai-app" />
|
|
34
|
-
|
|
35
|
-
Navigate to the newly created directory:
|
|
27
|
+
## Set Up Your Application
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
Open a terminal in the root directory of your existing Next.js Pages Router application.
|
|
38
30
|
|
|
39
31
|
### Install dependencies
|
|
40
32
|
|
|
@@ -115,7 +107,7 @@ This Route Handler creates a POST request endpoint at `/api/chat`.
|
|
|
115
107
|
|
|
116
108
|
The AI SDK supports dozens of model providers through [first-party](/providers/ai-sdk-providers), [OpenAI-compatible](/providers/openai-compatible-providers), and [community](/providers/community-providers) packages.
|
|
117
109
|
|
|
118
|
-
This
|
|
110
|
+
This guide uses the [Vercel AI Gateway](https://vercel.com/ai-gateway) provider, which is the default [global provider](/docs/ai-sdk-core/provider-management#global-provider-configuration). This means you can access models using a simple string in the model configuration:
|
|
119
111
|
|
|
120
112
|
```ts
|
|
121
113
|
model: __MODEL__;
|
|
@@ -9,6 +9,8 @@ The following guides are intended to provide you with an introduction to some of
|
|
|
9
9
|
|
|
10
10
|
<QuickstartFrameworkCards />
|
|
11
11
|
|
|
12
|
+
[Using an existing Next.js Pages Router app?](/docs/getting-started/nextjs-pages-router)
|
|
13
|
+
|
|
12
14
|
## Backend Framework Examples
|
|
13
15
|
|
|
14
16
|
You can also use [AI SDK Core](/docs/ai-sdk-core/overview) and [AI SDK UI](/docs/ai-sdk-ui/overview) with the following backend frameworks:
|
|
@@ -139,3 +139,4 @@ Agents are flexible and powerful, but non-deterministic. When you need reliable,
|
|
|
139
139
|
- **[Runtime and Tool Context](/docs/ai-sdk-core/runtime-and-tool-context)** - How to pass shared agent state and per-tool context
|
|
140
140
|
- **[Workflow Patterns](/docs/agents/workflows)** - Structured patterns using core functions for complex workflows
|
|
141
141
|
- **[Loop Control](/docs/agents/loop-control)** - Execution control with stopWhen and prepareStep
|
|
142
|
+
- **[Chat Platforms](/docs/agents/chat-platforms)** - Run agents in Slack, Microsoft Teams, Discord, and more with Chat SDK
|
|
@@ -12,6 +12,8 @@ You can control both the execution flow and the settings at each step of the age
|
|
|
12
12
|
- A tool call needs approval, or
|
|
13
13
|
- A stop condition is met
|
|
14
14
|
|
|
15
|
+
A [steering message](#steering) that is waiting when the model finishes its answer keeps the loop going for another step.
|
|
16
|
+
|
|
15
17
|
The AI SDK provides built-in loop control through two parameters: `stopWhen` for defining stopping conditions and `prepareStep` for modifying settings (model, tools, messages, and more) between steps.
|
|
16
18
|
|
|
17
19
|
## Stop Conditions
|
|
@@ -402,6 +404,121 @@ Unlike `runtimeContext` and `toolsContext`, an experimental sandbox returned fro
|
|
|
402
404
|
only applies to tool execution in that step. Later steps use the top-level
|
|
403
405
|
`experimental_sandbox` unless they return their own experimental sandbox override.
|
|
404
406
|
|
|
407
|
+
## Steering
|
|
408
|
+
|
|
409
|
+
<Note type="warning">Steering is an experimental feature.</Note>
|
|
410
|
+
|
|
411
|
+
Steering adds a user message to a running loop. Use it when a user sends a correction or a follow-up while the agent is still working. The message is added at the next step boundary, after the current step and its tool calls are done, so running tools are never interrupted.
|
|
412
|
+
|
|
413
|
+
Create a steering object with `experimental_createSteering()`, pass it with the `experimental_steering` option, and call `steer()` while the loop is running:
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
import { experimental_createSteering, isStepCount, streamText } from 'ai';
|
|
417
|
+
|
|
418
|
+
const steering = experimental_createSteering();
|
|
419
|
+
|
|
420
|
+
const result = streamText({
|
|
421
|
+
model: __MODEL__,
|
|
422
|
+
tools: { weather },
|
|
423
|
+
stopWhen: isStepCount(10),
|
|
424
|
+
prompt: 'What is the weather in Paris?',
|
|
425
|
+
experimental_steering: steering,
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// e.g. when the user sends another message while the agent is running:
|
|
429
|
+
const outcome = await steering.steer('I meant Paris, Texas.');
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Steering works the same way with `generateText` and `ToolLoopAgent`, because you create the steering object before the call starts:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
const steering = experimental_createSteering();
|
|
436
|
+
|
|
437
|
+
const run = agent.generate({
|
|
438
|
+
prompt: 'What is the weather in Paris?',
|
|
439
|
+
experimental_steering: steering,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
await steering.steer('I meant Paris, Texas.');
|
|
443
|
+
|
|
444
|
+
const result = await run;
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### How Steering Messages Are Delivered
|
|
448
|
+
|
|
449
|
+
- Messages are added in the order they are sent. Each message is its own user message.
|
|
450
|
+
- If the model finishes its answer while a message is waiting, the loop continues for another step.
|
|
451
|
+
- Stop conditions still apply. `generateText` and `streamText` stop after one step by default, so set `stopWhen` to steer them. Agents run up to 20 steps by default.
|
|
452
|
+
- Messages that are sent before the loop starts are added to the first step.
|
|
453
|
+
- `prepareStep` and `onStepStart` receive the steering messages as part of `messages`.
|
|
454
|
+
- A steering object can only be used for one call. Create a new one with `experimental_createSteering()` for each call.
|
|
455
|
+
- For agents, steering is supported by `ToolLoopAgent`. `createAgentUIStream` throws when it gets a steering object with another agent.
|
|
456
|
+
|
|
457
|
+
<Note type="warning">
|
|
458
|
+
`messages` already contains the steering messages in the right place. If
|
|
459
|
+
`prepareStep` returns a `messages` override that is rebuilt from other fields,
|
|
460
|
+
e.g. `initialMessages` and `responseMessages`, the steering messages are
|
|
461
|
+
dropped and `steer()` reports them as not delivered with the reason
|
|
462
|
+
`removed-by-prepare-step`. Build overrides from `messages`, or add the
|
|
463
|
+
steering messages of every step back in order.
|
|
464
|
+
</Note>
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
prepareStep: ({ initialMessages, steps, experimental_steeringMessages }) => ({
|
|
468
|
+
messages: [
|
|
469
|
+
...initialMessages,
|
|
470
|
+
...steps.flatMap(step => [
|
|
471
|
+
...(step.experimental_steeringMessages ?? []),
|
|
472
|
+
...step.response.messages,
|
|
473
|
+
]),
|
|
474
|
+
// steering messages for the current step:
|
|
475
|
+
...(experimental_steeringMessages ?? []),
|
|
476
|
+
],
|
|
477
|
+
}),
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Handling the Outcome
|
|
481
|
+
|
|
482
|
+
`steer()` resolves with the outcome of the message and never rejects:
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
const outcome = await steering.steer('I meant Paris, Texas.', {
|
|
486
|
+
id: messageId,
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
if (outcome.type === 'delivered') {
|
|
490
|
+
console.log(`added to step ${outcome.stepNumber}`);
|
|
491
|
+
} else {
|
|
492
|
+
// the message was not added, e.g. send it as a new message instead:
|
|
493
|
+
console.log(outcome.reason, outcome.message);
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
A message is delivered when it is part of the messages that are sent to the model, after `prepareStep`. It is not delivered when the loop ends before the next step boundary, or when `prepareStep` removes it. The `reason` is one of:
|
|
498
|
+
|
|
499
|
+
- `finished`: the loop ended before the message could be added.
|
|
500
|
+
- `removed-by-prepare-step`: `prepareStep` returned messages without it.
|
|
501
|
+
- `stop-condition`: a stop condition ended the loop.
|
|
502
|
+
- `waiting-for-tool-results`: the loop ended to wait for tool results, e.g. a [tool approval](/docs/agents/tool-approvals).
|
|
503
|
+
- `aborted`: the loop was aborted.
|
|
504
|
+
- `error`: the loop failed.
|
|
505
|
+
|
|
506
|
+
Pass an `id` to make retries safe. Sending a message again with the same `id` returns the outcome of the first message.
|
|
507
|
+
|
|
508
|
+
### Saving Steering Messages
|
|
509
|
+
|
|
510
|
+
Steering messages are not part of `responseMessages`. Each step lists the steering messages that were added to it in `experimental_steeringMessages`, so you can rebuild the full conversation in order:
|
|
511
|
+
|
|
512
|
+
```ts
|
|
513
|
+
const messages = [
|
|
514
|
+
...initialMessages,
|
|
515
|
+
...result.steps.flatMap(step => [
|
|
516
|
+
...(step.experimental_steeringMessages ?? []),
|
|
517
|
+
...step.response.messages,
|
|
518
|
+
]),
|
|
519
|
+
];
|
|
520
|
+
```
|
|
521
|
+
|
|
405
522
|
## Access Step Information
|
|
406
523
|
|
|
407
524
|
Both `stopWhen` and `prepareStep` receive detailed information about the current execution:
|
|
@@ -352,3 +352,4 @@ Every serverless instance that might handle a request needs the same secret, sin
|
|
|
352
352
|
- Author approval rules as code with [Policy-Based Tool Approvals](/docs/agents/policy-tool-approvals) (`@ai-sdk/policy-opa`).
|
|
353
353
|
- Use `needsApproval` only with [`WorkflowAgent`](/docs/agents/workflow-agent), where approvals suspend and resume durable workflow execution.
|
|
354
354
|
- Subagent tools cannot use `toolApproval`; see [Subagents](/docs/agents/subagents#no-tool-approvals-in-subagents).
|
|
355
|
+
- Chat SDK's `createChatTools` marks its write tools and `getUser` as needing approval. A `toolApproval` rule overrides those defaults; see [Chat Platforms](/docs/agents/chat-platforms#give-the-agent-chat-tools).
|