ai 7.0.32 → 7.0.34
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 +19 -0
- package/dist/index.js +133 -92
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +45 -1
- package/dist/internal/index.js.map +1 -1
- package/docs/03-ai-sdk-core/65-devtools.mdx +17 -2
- package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +1 -1
- package/docs/05-ai-sdk-rsc/10-migrating-to-ui.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/32-validate-ui-messages.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/71-has-tool-call.mdx +1 -1
- package/docs/07-reference/02-ai-sdk-ui/50-direct-chat-transport.mdx +1 -1
- package/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +1 -1
- package/docs/09-troubleshooting/13-repeated-assistant-messages.mdx +2 -2
- package/package.json +3 -3
- package/src/prompt/convert-to-language-model-prompt.ts +13 -0
- package/src/ui/process-ui-message-stream.ts +109 -61
|
@@ -101,7 +101,22 @@ DevTools captures the following information from your AI SDK calls:
|
|
|
101
101
|
- **Input parameters and prompts**: View the complete input sent to your LLM
|
|
102
102
|
- **Output content and tool calls**: Inspect generated text and tool invocations
|
|
103
103
|
- **Token usage and timing**: Monitor resource consumption and performance
|
|
104
|
-
- **Raw provider data**: Access
|
|
104
|
+
- **Raw provider data**: Access provider request and response payloads when body retention is enabled
|
|
105
|
+
|
|
106
|
+
Telemetry is enabled automatically, but AI SDK 7 excludes raw request and response bodies from step results by default. To make them available to DevTools for `generateText`, enable body retention on the call:
|
|
107
|
+
|
|
108
|
+
```ts highlight="4-7"
|
|
109
|
+
const result = await generateText({
|
|
110
|
+
model: openai('gpt-4o'),
|
|
111
|
+
prompt: 'Hello!',
|
|
112
|
+
include: {
|
|
113
|
+
requestBody: true,
|
|
114
|
+
responseBody: true,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`ToolLoopAgent` accepts the same `include` setting in its constructor. For `streamText` and `ToolLoopAgent.stream()`, only the request body can be retained; use `include: { requestBody: true }`.
|
|
105
120
|
|
|
106
121
|
### Runs and steps
|
|
107
122
|
|
|
@@ -129,6 +144,6 @@ DevTools stores all AI interactions locally in plain text files, including:
|
|
|
129
144
|
- User prompts and messages
|
|
130
145
|
- LLM responses
|
|
131
146
|
- Tool call arguments and results
|
|
132
|
-
- API request and response data
|
|
147
|
+
- API request and response data when body retention is enabled
|
|
133
148
|
|
|
134
149
|
**Only use DevTools in local development environments.** Do not enable DevTools in production or when handling sensitive data.
|
|
@@ -114,7 +114,7 @@ import { dataPartsSchema, metadataSchema } from '@util/schemas';
|
|
|
114
114
|
const tools = {
|
|
115
115
|
weather: tool({
|
|
116
116
|
description: 'Get weather information',
|
|
117
|
-
|
|
117
|
+
inputSchema: z.object({
|
|
118
118
|
location: z.string(),
|
|
119
119
|
units: z.enum(['celsius', 'fahrenheit']),
|
|
120
120
|
}),
|
|
@@ -121,7 +121,7 @@ const result = await generateText({
|
|
|
121
121
|
calculate: calculateTool,
|
|
122
122
|
finalAnswer: {
|
|
123
123
|
description: 'Provide the final answer to the user',
|
|
124
|
-
|
|
124
|
+
inputSchema: z.object({
|
|
125
125
|
answer: z.string(),
|
|
126
126
|
}),
|
|
127
127
|
execute: async ({ answer }) => answer,
|
|
@@ -237,7 +237,7 @@ import { z } from 'zod';
|
|
|
237
237
|
|
|
238
238
|
const weatherTool = tool({
|
|
239
239
|
description: 'Get the current weather',
|
|
240
|
-
|
|
240
|
+
inputSchema: z.object({
|
|
241
241
|
location: z.string().describe('The city and state'),
|
|
242
242
|
}),
|
|
243
243
|
execute: async ({ location }) => {
|
|
@@ -25,7 +25,7 @@ You have two options for handling tool results:
|
|
|
25
25
|
const tools = {
|
|
26
26
|
weather: tool({
|
|
27
27
|
description: 'Get the weather in a location',
|
|
28
|
-
|
|
28
|
+
inputSchema: z.object({
|
|
29
29
|
location: z
|
|
30
30
|
.string()
|
|
31
31
|
.describe('The city and state, e.g. "San Francisco, CA"'),
|
|
@@ -20,7 +20,7 @@ export async function POST(req: Request) {
|
|
|
20
20
|
tools: {
|
|
21
21
|
weather: {
|
|
22
22
|
description: 'Get the weather for a location',
|
|
23
|
-
|
|
23
|
+
inputSchema: z.object({
|
|
24
24
|
location: z.string(),
|
|
25
25
|
}),
|
|
26
26
|
execute: async ({ location }) => {
|
|
@@ -54,7 +54,7 @@ export async function POST(req: Request) {
|
|
|
54
54
|
tools: {
|
|
55
55
|
weather: {
|
|
56
56
|
description: 'Get the weather for a location',
|
|
57
|
-
|
|
57
|
+
inputSchema: z.object({
|
|
58
58
|
location: z.string(),
|
|
59
59
|
}),
|
|
60
60
|
execute: async ({ location }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.34",
|
|
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.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.26",
|
|
46
46
|
"@ai-sdk/provider": "4.0.3",
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.12"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@edge-runtime/vm": "^5.0.0",
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
createDefaultDownloadFunction,
|
|
26
26
|
type DownloadFunction,
|
|
27
27
|
} from '../util/download/download-function';
|
|
28
|
+
import { mergeObjects } from '../util/merge-objects';
|
|
28
29
|
import { convertToLanguageModelV4FilePart } from './file-part-data';
|
|
29
30
|
import { logWarnings } from '../logger/log-warnings';
|
|
30
31
|
import type { Warning } from '../types/warning';
|
|
@@ -108,7 +109,19 @@ export async function convertToLanguageModelPrompt({
|
|
|
108
109
|
|
|
109
110
|
const lastCombinedMessage = combinedMessages.at(-1);
|
|
110
111
|
if (lastCombinedMessage?.role === 'tool') {
|
|
112
|
+
const lastContentPart = lastCombinedMessage.content.at(-1);
|
|
113
|
+
if (
|
|
114
|
+
lastContentPart != null &&
|
|
115
|
+
lastCombinedMessage.providerOptions != null
|
|
116
|
+
) {
|
|
117
|
+
lastContentPart.providerOptions = mergeObjects(
|
|
118
|
+
lastCombinedMessage.providerOptions,
|
|
119
|
+
lastContentPart.providerOptions,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
111
123
|
lastCombinedMessage.content.push(...message.content);
|
|
124
|
+
lastCombinedMessage.providerOptions = message.providerOptions;
|
|
112
125
|
} else {
|
|
113
126
|
combinedMessages.push(message);
|
|
114
127
|
}
|
|
@@ -104,13 +104,43 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
104
104
|
new TransformStream<UIMessageChunk, InferUIMessageChunk<UI_MESSAGE>>({
|
|
105
105
|
async transform(chunk, controller) {
|
|
106
106
|
await runUpdateMessageJob(async ({ state, write }) => {
|
|
107
|
+
function getCurrentStepParts() {
|
|
108
|
+
const parts = state.message.parts;
|
|
109
|
+
let currentStepStartIndex = parts.length - 1;
|
|
110
|
+
|
|
111
|
+
while (
|
|
112
|
+
currentStepStartIndex >= 0 &&
|
|
113
|
+
parts[currentStepStartIndex].type !== 'step-start'
|
|
114
|
+
) {
|
|
115
|
+
currentStepStartIndex--;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return parts.slice(currentStepStartIndex + 1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getCurrentStepToolInvocations() {
|
|
122
|
+
return getCurrentStepParts().filter(isToolUIPart);
|
|
123
|
+
}
|
|
124
|
+
|
|
107
125
|
function getToolInvocation(toolCallId: string) {
|
|
108
|
-
const toolInvocations =
|
|
126
|
+
const toolInvocations = getCurrentStepToolInvocations();
|
|
109
127
|
|
|
110
|
-
|
|
128
|
+
let toolInvocation = toolInvocations.find(
|
|
111
129
|
invocation => invocation.toolCallId === toolCallId,
|
|
112
130
|
);
|
|
113
131
|
|
|
132
|
+
if (toolInvocation == null) {
|
|
133
|
+
const parts = state.message.parts;
|
|
134
|
+
|
|
135
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
136
|
+
const part = parts[i];
|
|
137
|
+
if (isToolUIPart(part) && part.toolCallId === toolCallId) {
|
|
138
|
+
toolInvocation = part;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
114
144
|
if (toolInvocation == null) {
|
|
115
145
|
throw new UIMessageStreamError({
|
|
116
146
|
chunkType: 'tool-invocation',
|
|
@@ -177,12 +207,15 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
177
207
|
providerMetadata?: ProviderMetadata;
|
|
178
208
|
}
|
|
179
209
|
),
|
|
210
|
+
existingPart?: ToolUIPart<InferUIMessageTools<UI_MESSAGE>>,
|
|
180
211
|
) {
|
|
181
|
-
const part =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
part
|
|
185
|
-
|
|
212
|
+
const part =
|
|
213
|
+
existingPart ??
|
|
214
|
+
(getCurrentStepParts().find(
|
|
215
|
+
part =>
|
|
216
|
+
isStaticToolUIPart(part) &&
|
|
217
|
+
part.toolCallId === options.toolCallId,
|
|
218
|
+
) as ToolUIPart<InferUIMessageTools<UI_MESSAGE>> | undefined);
|
|
186
219
|
|
|
187
220
|
const anyOptions = options as any;
|
|
188
221
|
const anyPart = part as any;
|
|
@@ -284,12 +317,15 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
284
317
|
providerMetadata?: ProviderMetadata;
|
|
285
318
|
}
|
|
286
319
|
),
|
|
320
|
+
existingPart?: DynamicToolUIPart,
|
|
287
321
|
) {
|
|
288
|
-
const part =
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
part
|
|
292
|
-
|
|
322
|
+
const part =
|
|
323
|
+
existingPart ??
|
|
324
|
+
(getCurrentStepParts().find(
|
|
325
|
+
part =>
|
|
326
|
+
part.type === 'dynamic-tool' &&
|
|
327
|
+
part.toolCallId === options.toolCallId,
|
|
328
|
+
) as DynamicToolUIPart | undefined);
|
|
293
329
|
|
|
294
330
|
const anyOptions = options as any;
|
|
295
331
|
const anyPart = part as any;
|
|
@@ -540,7 +576,7 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
540
576
|
|
|
541
577
|
case 'tool-input-start': {
|
|
542
578
|
const toolInvocations =
|
|
543
|
-
|
|
579
|
+
getCurrentStepParts().filter(isStaticToolUIPart);
|
|
544
580
|
|
|
545
581
|
// add the partial tool call to the map
|
|
546
582
|
state.partialToolCalls[chunk.toolCallId] = {
|
|
@@ -665,7 +701,7 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
665
701
|
// When a part already exists for this toolCallId (e.g. from
|
|
666
702
|
// tool-input-start), honour its type so we update in place
|
|
667
703
|
// instead of creating a duplicate with a mismatched type.
|
|
668
|
-
const existingPart =
|
|
704
|
+
const existingPart = getCurrentStepParts()
|
|
669
705
|
.filter(isToolUIPart)
|
|
670
706
|
.find(p => p.toolCallId === chunk.toolCallId);
|
|
671
707
|
const isDynamic =
|
|
@@ -756,31 +792,37 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
756
792
|
const toolInvocation = getToolInvocation(chunk.toolCallId);
|
|
757
793
|
|
|
758
794
|
if (toolInvocation.type === 'dynamic-tool') {
|
|
759
|
-
updateDynamicToolPart(
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
795
|
+
updateDynamicToolPart(
|
|
796
|
+
{
|
|
797
|
+
toolCallId: chunk.toolCallId,
|
|
798
|
+
toolName: toolInvocation.toolName,
|
|
799
|
+
state: 'output-available',
|
|
800
|
+
input: (toolInvocation as any).input,
|
|
801
|
+
output: chunk.output,
|
|
802
|
+
preliminary: chunk.preliminary,
|
|
803
|
+
providerExecuted: chunk.providerExecuted,
|
|
804
|
+
providerMetadata: chunk.providerMetadata,
|
|
805
|
+
title: toolInvocation.title,
|
|
806
|
+
toolMetadata: toolInvocation.toolMetadata,
|
|
807
|
+
},
|
|
808
|
+
toolInvocation,
|
|
809
|
+
);
|
|
771
810
|
} else {
|
|
772
|
-
updateToolPart(
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
811
|
+
updateToolPart(
|
|
812
|
+
{
|
|
813
|
+
toolCallId: chunk.toolCallId,
|
|
814
|
+
toolName: getStaticToolName(toolInvocation),
|
|
815
|
+
state: 'output-available',
|
|
816
|
+
input: (toolInvocation as any).input,
|
|
817
|
+
output: chunk.output,
|
|
818
|
+
providerExecuted: chunk.providerExecuted,
|
|
819
|
+
preliminary: chunk.preliminary,
|
|
820
|
+
providerMetadata: chunk.providerMetadata,
|
|
821
|
+
title: toolInvocation.title,
|
|
822
|
+
toolMetadata: toolInvocation.toolMetadata,
|
|
823
|
+
},
|
|
824
|
+
toolInvocation as ToolUIPart<InferUIMessageTools<UI_MESSAGE>>,
|
|
825
|
+
);
|
|
784
826
|
}
|
|
785
827
|
|
|
786
828
|
write();
|
|
@@ -791,30 +833,36 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
|
791
833
|
const toolInvocation = getToolInvocation(chunk.toolCallId);
|
|
792
834
|
|
|
793
835
|
if (toolInvocation.type === 'dynamic-tool') {
|
|
794
|
-
updateDynamicToolPart(
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
836
|
+
updateDynamicToolPart(
|
|
837
|
+
{
|
|
838
|
+
toolCallId: chunk.toolCallId,
|
|
839
|
+
toolName: toolInvocation.toolName,
|
|
840
|
+
state: 'output-error',
|
|
841
|
+
input: (toolInvocation as any).input,
|
|
842
|
+
errorText: chunk.errorText,
|
|
843
|
+
providerExecuted: chunk.providerExecuted,
|
|
844
|
+
providerMetadata: chunk.providerMetadata,
|
|
845
|
+
title: toolInvocation.title,
|
|
846
|
+
toolMetadata: toolInvocation.toolMetadata,
|
|
847
|
+
},
|
|
848
|
+
toolInvocation,
|
|
849
|
+
);
|
|
805
850
|
} else {
|
|
806
|
-
updateToolPart(
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
851
|
+
updateToolPart(
|
|
852
|
+
{
|
|
853
|
+
toolCallId: chunk.toolCallId,
|
|
854
|
+
toolName: getStaticToolName(toolInvocation),
|
|
855
|
+
state: 'output-error',
|
|
856
|
+
input: (toolInvocation as any).input,
|
|
857
|
+
rawInput: (toolInvocation as any).rawInput,
|
|
858
|
+
errorText: chunk.errorText,
|
|
859
|
+
providerExecuted: chunk.providerExecuted,
|
|
860
|
+
providerMetadata: chunk.providerMetadata,
|
|
861
|
+
title: toolInvocation.title,
|
|
862
|
+
toolMetadata: toolInvocation.toolMetadata,
|
|
863
|
+
},
|
|
864
|
+
toolInvocation as ToolUIPart<InferUIMessageTools<UI_MESSAGE>>,
|
|
865
|
+
);
|
|
818
866
|
}
|
|
819
867
|
|
|
820
868
|
write();
|