ai 7.0.2 → 7.0.3

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [728eaa0]
8
+ - @ai-sdk/gateway@4.0.3
9
+
3
10
  ## 7.0.2
4
11
 
5
12
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1089,7 +1089,7 @@ import {
1089
1089
  } from "@ai-sdk/provider-utils";
1090
1090
 
1091
1091
  // src/version.ts
1092
- var VERSION = true ? "7.0.2" : "0.0.0-test";
1092
+ var VERSION = true ? "7.0.3" : "0.0.0-test";
1093
1093
 
1094
1094
  // src/util/download/download.ts
1095
1095
  var download = async ({
@@ -83,7 +83,7 @@ import {
83
83
  } from "@ai-sdk/provider-utils";
84
84
 
85
85
  // src/version.ts
86
- var VERSION = true ? "7.0.2" : "0.0.0-test";
86
+ var VERSION = true ? "7.0.3" : "0.0.0-test";
87
87
 
88
88
  // src/util/download/download.ts
89
89
  var download = async ({
@@ -252,7 +252,7 @@ const result = await agent.generate({
252
252
 
253
253
  `isLoopFinished()` lets the agent keep running until the tool loop naturally finishes, which is useful when memory tools need to read and write before the final response.
254
254
 
255
- Session memory supports two modes: **tool-driven** (the LLM decides when to read/write — good for prototypes) and **hook-driven** (the runtime persists every turn via `prepareCall` + `onFinish` hooks — recommended for production). The other memory tiers (semantic, procedural, episodic, scratchpad) are always LLM-controlled and selective by design.
255
+ Session memory supports two modes: **tool-driven** (the LLM decides when to read/write — good for prototypes) and **hook-driven** (the runtime persists every turn via `prepareCall` + `onEnd` hooks — recommended for production). The other memory tiers (semantic, procedural, episodic, scratchpad) are always LLM-controlled and selective by design.
256
256
 
257
257
  MongoDB memory works with any AI SDK model and embedding provider, with no vendor lock-in beyond MongoDB Atlas.
258
258
 
@@ -49,6 +49,53 @@ const mcpClient = await createMCPClient({
49
49
  });
50
50
  ```
51
51
 
52
+ If the MCP server uses Streamable HTTP sessions, you can reattach to a saved
53
+ session by restoring both the previous session id and initialize result:
54
+
55
+ ```typescript
56
+ import { createMCPClient } from '@ai-sdk/mcp';
57
+
58
+ const savedSession = await loadMcpSession();
59
+ let currentSessionId = savedSession?.sessionId;
60
+
61
+ const mcpClient = await createMCPClient({
62
+ transport: {
63
+ type: 'http',
64
+ url: 'https://your-server.com/mcp',
65
+ initialSessionId: savedSession?.sessionId,
66
+ initialProtocolVersion: savedSession?.initializeResult.protocolVersion,
67
+ terminateSessionOnClose: false,
68
+
69
+ onSessionIdChange: sessionId => {
70
+ currentSessionId = sessionId;
71
+ },
72
+
73
+ onSessionExpired: sessionId => {
74
+ if (currentSessionId === sessionId) {
75
+ currentSessionId = undefined;
76
+ void clearMcpSession();
77
+ }
78
+ },
79
+ },
80
+ initialInitializeResult: savedSession?.initializeResult,
81
+ });
82
+
83
+ if (currentSessionId) {
84
+ await saveMcpSession({
85
+ sessionId: currentSessionId,
86
+ initializeResult: mcpClient.initializeResult,
87
+ });
88
+ }
89
+ ```
90
+
91
+ When `initialInitializeResult` is provided, `createMCPClient` reuses the cached
92
+ initialize metadata and does not send another `initialize` request. When
93
+ `onSessionExpired` is called, the transport has already cleared the session id
94
+ and the request still fails with the underlying HTTP error. Retry by creating a
95
+ fresh client without `initialSessionId` or `initialInitializeResult`.
96
+ Set `terminateSessionOnClose` to `false` when closing only the local client but
97
+ keeping the MCP session available for a later reattach.
98
+
52
99
  Alternatively, you can use `StreamableHTTPClientTransport` from MCP's official TypeScript SDK:
53
100
 
54
101
  ```typescript
@@ -116,8 +163,8 @@ You can also bring your own transport by implementing the `MCPTransport` interfa
116
163
  <Note>
117
164
  The client returned by the `createMCPClient` function is a
118
165
  lightweight client intended for use in tool conversion. It currently does not
119
- support all features of the full MCP client, such as: session
120
- management, resumable streams, and receiving notifications.
166
+ support all features of the full MCP client, such as automatic session
167
+ persistence, resumable streams, and receiving notifications.
121
168
 
122
169
  Authorization via OAuth is supported when using the AI SDK MCP HTTP or SSE
123
170
  transports by providing an `authProvider`.
@@ -288,7 +288,7 @@ for (const file of result.files) {
288
288
  | Provider | Model | Support sizes (`width x height`) or aspect ratios (`width : height`) |
289
289
  | ------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
290
290
  | [xAI Grok](/providers/ai-sdk-providers/xai#image-models) | `grok-imagine-image` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `2:1`, `1:2`, `19.5:9`, `9:19.5`, `20:9`, `9:20`, `auto` |
291
- | [OpenAI](/providers/ai-sdk-providers/openai#image-models) | `gpt-image-1` | 1024x1024, 1536x1024, 1024x1536 |
291
+ | [OpenAI](/providers/ai-sdk-providers/openai#image-models) | `gpt-image-2` | 1024x1024, 1536x1024, 1024x1536 |
292
292
  | [OpenAI](/providers/ai-sdk-providers/openai#image-models) | `dall-e-3` | 1024x1024, 1792x1024, 1024x1792 |
293
293
  | [OpenAI](/providers/ai-sdk-providers/openai#image-models) | `dall-e-2` | 256x256, 512x512, 1024x1024 |
294
294
  | [Amazon Bedrock](/providers/ai-sdk-providers/amazon-bedrock#image-models) | `amazon.nova-canvas-v1:0` | 320-4096 (multiples of 16), 1:4 to 4:1, max 4.2M pixels |
@@ -261,6 +261,81 @@ default working directory and is used as the session working directory. When
261
261
  omitted, regular sessions use the default `<harnessId>-<sessionId>` directory,
262
262
  while `onBootstrap` receives the sandbox's default working directory.
263
263
 
264
+ ## Prepare Reusable Sandboxes
265
+
266
+ Use `prepareHarnessSandboxTemplate()` when you want the sandbox provider to
267
+ create or refresh its reusable template for one harness ahead of time:
268
+
269
+ ```ts
270
+ import { prepareHarnessSandboxTemplate } from '@ai-sdk/harness/agent';
271
+
272
+ await prepareHarnessSandboxTemplate({
273
+ harness: claudeCode,
274
+ sandboxProvider: createVercelSandbox({
275
+ runtime: 'node24',
276
+ ports: [4000],
277
+ }),
278
+ sandboxConfig: {
279
+ bootstrapHash: 'ripgrep-v1',
280
+ onBootstrap: async ({ session, abortSignal }) => {
281
+ await session.run({
282
+ command:
283
+ 'command -v rg >/dev/null || (apt-get update && apt-get install -y ripgrep)',
284
+ abortSignal,
285
+ });
286
+ },
287
+ },
288
+ });
289
+ ```
290
+
291
+ Use `prepareSandboxForHarness()` when you own the native sandbox lifecycle and
292
+ want to snapshot the prepared sandbox yourself. It applies the selected harness
293
+ bootstrap recipes and `sandboxConfig.onBootstrap`, then returns preparation
294
+ metadata. It does not stop or snapshot the sandbox.
295
+
296
+ ```ts
297
+ import { HarnessAgent, prepareSandboxForHarness } from '@ai-sdk/harness/agent';
298
+ import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
299
+ import { Sandbox } from '@vercel/sandbox';
300
+
301
+ const nativeSandbox = await Sandbox.create({
302
+ runtime: 'node24',
303
+ ports: [4000],
304
+ });
305
+ const sandboxProvider = createVercelSandbox({ sandbox: nativeSandbox });
306
+ const session = await sandboxProvider.createSession();
307
+
308
+ const preparation = await prepareSandboxForHarness({
309
+ session: session.restricted(),
310
+ harnesses: [claudeCode, codex],
311
+ sandboxConfig,
312
+ });
313
+
314
+ const { snapshot } = await nativeSandbox.stop();
315
+ if (snapshot == null) {
316
+ throw new Error('Prepared sandbox did not create a snapshot.');
317
+ }
318
+
319
+ const sandboxFromSnapshot = await Sandbox.create({
320
+ source: {
321
+ type: 'snapshot',
322
+ snapshotId: snapshot.id,
323
+ },
324
+ ports: [4000],
325
+ });
326
+
327
+ const agent = new HarnessAgent({
328
+ harness: claudeCode,
329
+ sandbox: createVercelSandbox({
330
+ sandbox: sandboxFromSnapshot,
331
+ bridgePorts: [4000],
332
+ }),
333
+ sandboxConfig,
334
+ });
335
+
336
+ console.log(preparation.identity);
337
+ ```
338
+
264
339
  ## Settings
265
340
 
266
341
  `HarnessAgent` accepts these main settings:
@@ -92,7 +92,7 @@ export async function POST(req: Request) {
92
92
  const result = streamText({
93
93
  model: __MODEL__,
94
94
  messages: await convertToModelMessages(messages),
95
- onFinish() {
95
+ onEnd() {
96
96
  // 4. Update the same data part (reconciliation)
97
97
  writer.write({
98
98
  type: 'data-weather',
@@ -489,7 +489,7 @@ export const AI = createAI({
489
489
 
490
490
  #### After: Save chats using callback function of `streamText`
491
491
 
492
- With AI SDK UI, you will save chats using the `onFinish` callback function of `streamText` in your route handler.
492
+ With AI SDK UI, you will save chats using the `onEnd` callback function of `streamText` in your route handler.
493
493
 
494
494
  ```ts filename="@/app/api/chat/route.ts"
495
495
  import { openai } from '@ai-sdk/openai';
@@ -510,7 +510,7 @@ export async function POST(request) {
510
510
  model: __MODEL__,
511
511
  instructions: 'you are a friendly assistant!',
512
512
  messages: coreMessages,
513
- onFinish: async ({ responseMessages }) => {
513
+ onEnd: async ({ responseMessages }) => {
514
514
  try {
515
515
  await saveChat({
516
516
  id,
@@ -82,7 +82,7 @@ export default function Chat() {
82
82
 
83
83
  When streams are aborted, you may need to perform cleanup operations such as persisting partial results or cleaning up resources. The `onAbort` callback provides a way to handle these scenarios on the server side.
84
84
 
85
- Unlike `onFinish`, which is called when a stream completes normally, `onAbort` is specifically called when a stream is aborted via `AbortSignal`. This distinction allows you to handle normal completion and aborted streams differently.
85
+ Unlike `onEnd`, which is called when a stream completes normally, `onAbort` is specifically called when a stream is aborted via `AbortSignal`. This distinction allows you to handle normal completion and aborted streams differently.
86
86
 
87
87
  <Note>
88
88
  For UI message streams (`toUIMessageStreamResponse`), the `onEnd` callback
@@ -104,7 +104,7 @@ const result = streamText({
104
104
  await savePartialResults(steps);
105
105
  await logAbortEvent(steps.length);
106
106
  },
107
- onFinish: ({ steps, totalUsage }) => {
107
+ onEnd: ({ steps, totalUsage }) => {
108
108
  // Called when stream completes normally
109
109
  await saveFinalResults(steps, totalUsage);
110
110
  },
@@ -118,7 +118,7 @@ You can see a full example of caching with Redis in a Next.js application in our
118
118
 
119
119
  ## Using Lifecycle Callbacks
120
120
 
121
- Alternatively, each AI SDK Core function has special lifecycle callbacks you can use. The one of interest is likely `onFinish`, which is called when the generation is complete. This is where you can cache the full response.
121
+ Alternatively, each AI SDK Core function has special lifecycle callbacks you can use. The one of interest is likely `onEnd`, which is called when the generation is complete. This is where you can cache the full response.
122
122
 
123
123
  Here's an example of how you can implement caching using Vercel KV and Next.js to cache the OpenAI response for 1 hour:
124
124
 
@@ -162,7 +162,7 @@ export async function POST(req: Request) {
162
162
  const result = streamText({
163
163
  model: __MODEL__,
164
164
  messages: await convertToModelMessages(messages),
165
- async onFinish({ text }) {
165
+ async onEnd({ text }) {
166
166
  // Cache the response text:
167
167
  await redis.set(key, text);
168
168
  await redis.expire(key, 60 * 60);
@@ -86,7 +86,7 @@ It currently does not support accepting notifications from an MCP server, and cu
86
86
  parameters: [
87
87
  {
88
88
  name: 'type',
89
- type: "'sse' | 'http",
89
+ type: "'sse' | 'http'",
90
90
  description: 'Use Server-Sent Events for communication',
91
91
  },
92
92
  {
@@ -115,6 +115,48 @@ It currently does not support accepting notifications from an MCP server, and cu
115
115
  description:
116
116
  "Controls how HTTP redirects are handled for transport requests. Set to 'follow' to allow redirect responses. Defaults to 'error' to reject any redirect response, preventing servers from redirecting requests to unintended hosts.",
117
117
  },
118
+ {
119
+ name: 'initialSessionId',
120
+ type: 'string',
121
+ isOptional: true,
122
+ description:
123
+ 'Initial MCP session id to send with resumed Streamable HTTP requests after initialization. Pair with initialInitializeResult when using createMCPClient. Only used by the HTTP transport.',
124
+ },
125
+ {
126
+ name: 'initialProtocolVersion',
127
+ type: 'string',
128
+ isOptional: true,
129
+ description:
130
+ 'Initial MCP protocol version to send before initialize negotiates one. Only used by the HTTP transport.',
131
+ },
132
+ {
133
+ name: 'onSessionIdChange',
134
+ type: '(sessionId: string | undefined) => void',
135
+ isOptional: true,
136
+ description:
137
+ 'Callback invoked when the Streamable HTTP server creates, changes, or clears the MCP session id. Only used by the HTTP transport.',
138
+ },
139
+ {
140
+ name: 'onSessionExpired',
141
+ type: '(sessionId: string) => void',
142
+ isOptional: true,
143
+ description:
144
+ 'Callback invoked when a Streamable HTTP request returns 404 for an existing MCP session id. The transport clears the session id before reporting the underlying HTTP error. Only used by the HTTP transport.',
145
+ },
146
+ {
147
+ name: 'terminateSessionOnClose',
148
+ type: 'boolean',
149
+ isOptional: true,
150
+ description:
151
+ 'Whether close() should send DELETE for the current MCP session id. Set to false when the application intends to reattach to the session later. Defaults to true. Only used by the HTTP transport.',
152
+ },
153
+ {
154
+ name: 'fetch',
155
+ type: 'FetchFunction',
156
+ isOptional: true,
157
+ description:
158
+ 'Optional custom fetch implementation to use for HTTP requests. Useful for runtimes that need a request-local fetch.',
159
+ },
118
160
  ],
119
161
  },
120
162
  ],
@@ -144,6 +186,13 @@ It currently does not support accepting notifications from an MCP server, and cu
144
186
  isOptional: true,
145
187
  description: 'Handler for uncaught errors',
146
188
  },
189
+ {
190
+ name: 'initialInitializeResult',
191
+ type: 'InitializeResult',
192
+ isOptional: true,
193
+ description:
194
+ 'Initialize result from a previous MCP session. When provided, the client starts the transport and reuses this metadata without sending a new initialize request.',
195
+ },
147
196
  {
148
197
  name: 'capabilities',
149
198
  type: 'ClientCapabilities',
@@ -164,6 +213,12 @@ Returns a Promise that resolves to an `MCPClient` with the following properties
164
213
 
165
214
  <PropertiesTable
166
215
  content={[
216
+ {
217
+ name: 'initializeResult',
218
+ type: 'InitializeResult',
219
+ description:
220
+ 'The full initialize result used by this client, either from the server during initialization or from initialInitializeResult.',
221
+ },
167
222
  {
168
223
  name: 'serverInfo',
169
224
  type: 'Configuration',
@@ -13,7 +13,7 @@ import { generateImage, wrapImageModel } from 'ai';
13
13
  import { openai } from '@ai-sdk/openai';
14
14
 
15
15
  const model = wrapImageModel({
16
- model: openai.image('gpt-image-1'),
16
+ model: openai.image('gpt-image-2'),
17
17
  middleware: yourImageModelMiddleware,
18
18
  });
19
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.2",
3
+ "version": "7.0.3",
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,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.2",
45
+ "@ai-sdk/gateway": "4.0.3",
46
46
  "@ai-sdk/provider": "4.0.0",
47
47
  "@ai-sdk/provider-utils": "5.0.0"
48
48
  },