ai 6.0.301 → 6.0.302
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 +14 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +75 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -25
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +1 -1
- package/dist/internal/index.mjs.map +1 -1
- package/docs/02-foundations/04-tools.mdx +1 -1
- package/docs/03-agents/06-memory.mdx +1 -1
- package/docs/03-ai-sdk-core/35-image-generation.mdx +2 -0
- package/docs/03-ai-sdk-core/45-provider-management.mdx +2 -2
- package/package.json +3 -3
- package/src/model/as-language-model-v3.ts +4 -0
- package/src/types/usage.ts +21 -0
- package/src/ui/chat.ts +6 -1
- package/src/ui/convert-to-model-messages.ts +41 -8
- package/src/ui/http-chat-transport.ts +5 -3
- package/src/ui/ui-messages.ts +8 -0
- package/src/ui/unavailable-tool.ts +17 -0
- package/src/ui/validate-ui-messages.ts +12 -3
package/src/types/usage.ts
CHANGED
|
@@ -135,6 +135,12 @@ export function addLanguageModelUsage(
|
|
|
135
135
|
usage1: LanguageModelUsage,
|
|
136
136
|
usage2: LanguageModelUsage,
|
|
137
137
|
): LanguageModelUsage {
|
|
138
|
+
const raw = isNullLanguageModelUsage(usage1)
|
|
139
|
+
? usage2.raw
|
|
140
|
+
: isNullLanguageModelUsage(usage2)
|
|
141
|
+
? usage1.raw
|
|
142
|
+
: undefined;
|
|
143
|
+
|
|
138
144
|
return {
|
|
139
145
|
inputTokens: addTokenCounts(usage1.inputTokens, usage2.inputTokens),
|
|
140
146
|
inputTokenDetails: {
|
|
@@ -171,9 +177,24 @@ export function addLanguageModelUsage(
|
|
|
171
177
|
usage1.cachedInputTokens,
|
|
172
178
|
usage2.cachedInputTokens,
|
|
173
179
|
),
|
|
180
|
+
...(raw == null ? {} : { raw }),
|
|
174
181
|
};
|
|
175
182
|
}
|
|
176
183
|
|
|
184
|
+
function isNullLanguageModelUsage(usage: LanguageModelUsage): boolean {
|
|
185
|
+
return (
|
|
186
|
+
usage.inputTokens == null &&
|
|
187
|
+
usage.inputTokenDetails?.noCacheTokens == null &&
|
|
188
|
+
usage.inputTokenDetails?.cacheReadTokens == null &&
|
|
189
|
+
usage.inputTokenDetails?.cacheWriteTokens == null &&
|
|
190
|
+
usage.outputTokens == null &&
|
|
191
|
+
usage.outputTokenDetails?.textTokens == null &&
|
|
192
|
+
usage.outputTokenDetails?.reasoningTokens == null &&
|
|
193
|
+
usage.totalTokens == null &&
|
|
194
|
+
usage.raw == null
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
177
198
|
function addTokenCounts(
|
|
178
199
|
tokenCount1: number | undefined,
|
|
179
200
|
tokenCount2: number | undefined,
|
package/src/ui/chat.ts
CHANGED
|
@@ -314,7 +314,12 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
|
|
|
314
314
|
status: ChatStatus;
|
|
315
315
|
error?: Error;
|
|
316
316
|
}) {
|
|
317
|
-
if (this.status === status)
|
|
317
|
+
if (this.status === status) {
|
|
318
|
+
if (this.error !== error) {
|
|
319
|
+
this.state.error = error;
|
|
320
|
+
}
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
318
323
|
|
|
319
324
|
this.state.status = status;
|
|
320
325
|
this.state.error = error;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { ToolSet } from '../generate-text/tool-set';
|
|
11
11
|
import { createToolModelOutput } from '../prompt/create-tool-model-output';
|
|
12
12
|
import { MessageConversionError } from '../prompt/message-conversion-error';
|
|
13
|
+
import { getOwn } from '../util/get-own';
|
|
13
14
|
import {
|
|
14
15
|
getToolName,
|
|
15
16
|
isDataUIPart,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
type ToolUIPart,
|
|
28
29
|
type UIMessage,
|
|
29
30
|
} from './ui-messages';
|
|
31
|
+
import { isToolPartFromUnavailableTool } from './unavailable-tool';
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Converts an array of UI messages from useChat into an array of ModelMessages that can be used
|
|
@@ -65,6 +67,39 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
|
|
|
65
67
|
}));
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
async function createModelOutput({
|
|
71
|
+
toolPart,
|
|
72
|
+
toolName,
|
|
73
|
+
output,
|
|
74
|
+
errorMode,
|
|
75
|
+
}: {
|
|
76
|
+
toolPart: ToolUIPart<InferUIMessageTools<UI_MESSAGE>> | DynamicToolUIPart;
|
|
77
|
+
toolName: string;
|
|
78
|
+
output: unknown;
|
|
79
|
+
errorMode: 'none' | 'text' | 'json';
|
|
80
|
+
}) {
|
|
81
|
+
const tool = getOwn(options?.tools, toolName);
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
errorMode === 'none' &&
|
|
85
|
+
tool == null &&
|
|
86
|
+
isToolPartFromUnavailableTool(toolPart)
|
|
87
|
+
) {
|
|
88
|
+
return {
|
|
89
|
+
type: 'text' as const,
|
|
90
|
+
value: 'Tool output omitted because the tool is no longer available.',
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return createToolModelOutput({
|
|
95
|
+
toolCallId: toolPart.toolCallId,
|
|
96
|
+
input: toolPart.input,
|
|
97
|
+
output,
|
|
98
|
+
tool,
|
|
99
|
+
errorMode,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
68
103
|
for (const message of messages) {
|
|
69
104
|
switch (message.role) {
|
|
70
105
|
case 'system': {
|
|
@@ -231,14 +266,13 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
|
|
|
231
266
|
type: 'tool-result',
|
|
232
267
|
toolCallId: part.toolCallId,
|
|
233
268
|
toolName,
|
|
234
|
-
output: await
|
|
235
|
-
|
|
236
|
-
|
|
269
|
+
output: await createModelOutput({
|
|
270
|
+
toolPart: part,
|
|
271
|
+
toolName,
|
|
237
272
|
output:
|
|
238
273
|
part.state === 'output-error'
|
|
239
274
|
? part.errorText
|
|
240
275
|
: part.output,
|
|
241
|
-
tool: options?.tools?.[toolName],
|
|
242
276
|
errorMode:
|
|
243
277
|
part.state === 'output-error' ? 'json' : 'none',
|
|
244
278
|
}),
|
|
@@ -331,14 +365,13 @@ export async function convertToModelMessages<UI_MESSAGE extends UIMessage>(
|
|
|
331
365
|
type: 'tool-result',
|
|
332
366
|
toolCallId: toolPart.toolCallId,
|
|
333
367
|
toolName,
|
|
334
|
-
output: await
|
|
335
|
-
|
|
336
|
-
|
|
368
|
+
output: await createModelOutput({
|
|
369
|
+
toolPart,
|
|
370
|
+
toolName,
|
|
337
371
|
output:
|
|
338
372
|
toolPart.state === 'output-error'
|
|
339
373
|
? toolPart.errorText
|
|
340
374
|
: toolPart.output,
|
|
341
|
-
tool: options?.tools?.[toolName],
|
|
342
375
|
errorMode:
|
|
343
376
|
toolPart.state === 'output-error' ? 'text' : 'none',
|
|
344
377
|
}),
|
|
@@ -11,10 +11,12 @@ import type { UIMessage } from './ui-messages';
|
|
|
11
11
|
|
|
12
12
|
function appendPathToUrl(url: string, path: string): string {
|
|
13
13
|
const queryOrFragmentStart = url.search(/[?#]/);
|
|
14
|
+
const urlPath =
|
|
15
|
+
queryOrFragmentStart === -1 ? url : url.slice(0, queryOrFragmentStart);
|
|
16
|
+
const suffix =
|
|
17
|
+
queryOrFragmentStart === -1 ? '' : url.slice(queryOrFragmentStart);
|
|
14
18
|
|
|
15
|
-
return
|
|
16
|
-
? `${url}${path}`
|
|
17
|
-
: `${url.slice(0, queryOrFragmentStart)}${path}${url.slice(queryOrFragmentStart)}`;
|
|
19
|
+
return `${urlPath.endsWith('/') && path.startsWith('/') ? urlPath.slice(0, -1) : urlPath}${path}${suffix}`;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export type PrepareSendMessagesRequest<UI_MESSAGE extends UIMessage> = (
|
package/src/ui/ui-messages.ts
CHANGED
|
@@ -348,6 +348,14 @@ export type ToolUIPart<TOOLS extends UITools = UITools> = ValueOf<{
|
|
|
348
348
|
export type DynamicToolUIPart = {
|
|
349
349
|
type: 'dynamic-tool';
|
|
350
350
|
|
|
351
|
+
/**
|
|
352
|
+
* `false` when a static tool part was normalized to a dynamic tool part
|
|
353
|
+
* because its current tool schema was unavailable or incompatible.
|
|
354
|
+
*
|
|
355
|
+
* This preserves its static origin across persistence boundaries.
|
|
356
|
+
*/
|
|
357
|
+
dynamic?: false;
|
|
358
|
+
|
|
351
359
|
/**
|
|
352
360
|
* Name of the tool that is being called.
|
|
353
361
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DynamicToolUIPart, ToolUIPart } from './ui-messages';
|
|
2
|
+
|
|
3
|
+
export function markToolPartAsUnavailable(
|
|
4
|
+
part: DynamicToolUIPart,
|
|
5
|
+
): DynamicToolUIPart {
|
|
6
|
+
// Preserve the static tool's provenance across persistence boundaries so
|
|
7
|
+
// model-message conversion never falls back to its unfiltered raw output.
|
|
8
|
+
part.dynamic = false;
|
|
9
|
+
|
|
10
|
+
return part;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isToolPartFromUnavailableTool(
|
|
14
|
+
part: ToolUIPart | DynamicToolUIPart,
|
|
15
|
+
): boolean {
|
|
16
|
+
return part.type === 'dynamic-tool' && part.dynamic === false;
|
|
17
|
+
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { z } from 'zod/v4';
|
|
16
16
|
import { InvalidArgumentError } from '../error';
|
|
17
17
|
import { jsonValueSchema } from '../types/json-value';
|
|
18
|
+
import { getOwn } from '../util/get-own';
|
|
18
19
|
import { isDeepEqualData } from '../util/is-deep-equal-data';
|
|
19
20
|
import { providerMetadataSchema } from '../types/provider-metadata';
|
|
20
21
|
import type {
|
|
@@ -25,6 +26,7 @@ import type {
|
|
|
25
26
|
ToolUIPart,
|
|
26
27
|
UIMessage,
|
|
27
28
|
} from './ui-messages';
|
|
29
|
+
import { markToolPartAsUnavailable } from './unavailable-tool';
|
|
28
30
|
|
|
29
31
|
const toolMetadataSchema: z.ZodType<JSONObject> = z.record(
|
|
30
32
|
z.string(),
|
|
@@ -43,11 +45,11 @@ function isEmptyObject(value: unknown): value is Record<string, never> {
|
|
|
43
45
|
function asDynamicToolPart(toolPart: ToolUIPart): DynamicToolUIPart {
|
|
44
46
|
const { type, ...part } = toolPart;
|
|
45
47
|
|
|
46
|
-
return {
|
|
48
|
+
return markToolPartAsUnavailable({
|
|
47
49
|
...part,
|
|
48
50
|
type: 'dynamic-tool',
|
|
49
51
|
toolName: type.slice(5),
|
|
50
|
-
} as DynamicToolUIPart;
|
|
52
|
+
} as DynamicToolUIPart);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
function getToolPartInputSchemaInput(
|
|
@@ -134,6 +136,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
134
136
|
}),
|
|
135
137
|
z.object({
|
|
136
138
|
type: z.literal('dynamic-tool'),
|
|
139
|
+
dynamic: z.literal(false).optional(),
|
|
137
140
|
toolName: z.string(),
|
|
138
141
|
toolCallId: z.string(),
|
|
139
142
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -148,6 +151,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
148
151
|
}),
|
|
149
152
|
z.object({
|
|
150
153
|
type: z.literal('dynamic-tool'),
|
|
154
|
+
dynamic: z.literal(false).optional(),
|
|
151
155
|
toolName: z.string(),
|
|
152
156
|
toolCallId: z.string(),
|
|
153
157
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -161,6 +165,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
161
165
|
}),
|
|
162
166
|
z.object({
|
|
163
167
|
type: z.literal('dynamic-tool'),
|
|
168
|
+
dynamic: z.literal(false).optional(),
|
|
164
169
|
toolName: z.string(),
|
|
165
170
|
toolCallId: z.string(),
|
|
166
171
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -174,6 +179,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
174
179
|
}),
|
|
175
180
|
z.object({
|
|
176
181
|
type: z.literal('dynamic-tool'),
|
|
182
|
+
dynamic: z.literal(false).optional(),
|
|
177
183
|
toolName: z.string(),
|
|
178
184
|
toolCallId: z.string(),
|
|
179
185
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -187,6 +193,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
187
193
|
}),
|
|
188
194
|
z.object({
|
|
189
195
|
type: z.literal('dynamic-tool'),
|
|
196
|
+
dynamic: z.literal(false).optional(),
|
|
190
197
|
toolName: z.string(),
|
|
191
198
|
toolCallId: z.string(),
|
|
192
199
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -202,6 +209,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
202
209
|
}),
|
|
203
210
|
z.object({
|
|
204
211
|
type: z.literal('dynamic-tool'),
|
|
212
|
+
dynamic: z.literal(false).optional(),
|
|
205
213
|
toolName: z.string(),
|
|
206
214
|
toolCallId: z.string(),
|
|
207
215
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -217,6 +225,7 @@ const uiMessagesSchema = lazySchema(() => {
|
|
|
217
225
|
}),
|
|
218
226
|
z.object({
|
|
219
227
|
type: z.literal('dynamic-tool'),
|
|
228
|
+
dynamic: z.literal(false).optional(),
|
|
220
229
|
toolName: z.string(),
|
|
221
230
|
toolCallId: z.string(),
|
|
222
231
|
toolMetadata: toolMetadataSchema.optional(),
|
|
@@ -451,7 +460,7 @@ async function safeValidateUIMessagesInternal<UI_MESSAGE extends UIMessage>(
|
|
|
451
460
|
InferUIMessageTools<UI_MESSAGE>
|
|
452
461
|
>;
|
|
453
462
|
const toolName = toolPart.type.slice(5);
|
|
454
|
-
const tool = tools
|
|
463
|
+
const tool = getOwn(tools, toolName);
|
|
455
464
|
const isTerminal =
|
|
456
465
|
toolPart.state === 'output-available' ||
|
|
457
466
|
toolPart.state === 'output-error' ||
|