@convex-dev/agent 0.6.4 → 0.7.0-alpha.0
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/MIGRATION.md +60 -116
- package/dist/client/messages.d.ts +1 -398
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js +3 -47
- package/dist/client/messages.js.map +1 -1
- package/dist/client/types.d.ts +1 -455
- package/dist/client/types.d.ts.map +1 -1
- package/dist/component/_generated/component.d.ts +805 -45
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/messages.d.ts +1252 -201
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +49 -23
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +2593 -332
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/streams.d.ts +7 -1
- package/dist/component/streams.d.ts.map +1 -1
- package/dist/component/streams.js +24 -30
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts.map +1 -1
- package/dist/component/threads.js +1 -2
- package/dist/component/threads.js.map +1 -1
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -5
- package/dist/react/index.js.map +1 -1
- package/dist/shared.d.ts +19 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +4 -4
- package/dist/shared.js.map +1 -1
- package/dist/streaming/materializePersistedUIMessageChunks.d.ts +16 -0
- package/dist/streaming/materializePersistedUIMessageChunks.d.ts.map +1 -0
- package/dist/streaming/materializePersistedUIMessageChunks.js +302 -0
- package/dist/streaming/materializePersistedUIMessageChunks.js.map +1 -0
- package/dist/streaming/persistedUIMessageChunks.d.ts +106 -0
- package/dist/streaming/persistedUIMessageChunks.d.ts.map +1 -0
- package/dist/streaming/persistedUIMessageChunks.js +475 -0
- package/dist/streaming/persistedUIMessageChunks.js.map +1 -0
- package/dist/validators.d.ts +10026 -1055
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +71 -9
- package/dist/validators.js.map +1 -1
- package/dist/{UIMessages.d.ts → vercel/UIMessages.d.ts} +1 -1
- package/dist/vercel/UIMessages.d.ts.map +1 -0
- package/dist/{UIMessages.js → vercel/UIMessages.js} +63 -1
- package/dist/vercel/UIMessages.js.map +1 -0
- package/dist/{client → vercel/client}/createTool.d.ts +23 -16
- package/dist/vercel/client/createTool.d.ts.map +1 -0
- package/dist/{client → vercel/client}/createTool.js +2 -0
- package/dist/vercel/client/createTool.js.map +1 -0
- package/dist/{client → vercel/client}/definePlaygroundAPI.d.ts +533 -79
- package/dist/{client → vercel/client}/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/{client → vercel/client}/definePlaygroundAPI.js +8 -7
- package/dist/vercel/client/definePlaygroundAPI.js.map +1 -0
- package/dist/{client → vercel/client}/files.d.ts +2 -2
- package/dist/vercel/client/files.d.ts.map +1 -0
- package/dist/vercel/client/files.js.map +1 -0
- package/dist/vercel/client/messages.d.ts +542 -0
- package/dist/vercel/client/messages.d.ts.map +1 -0
- package/dist/vercel/client/messages.js +66 -0
- package/dist/vercel/client/messages.js.map +1 -0
- package/dist/{client → vercel/client}/mockModel.d.ts +17 -17
- package/dist/vercel/client/mockModel.d.ts.map +1 -0
- package/dist/{client → vercel/client}/mockModel.js +12 -13
- package/dist/vercel/client/mockModel.js.map +1 -0
- package/dist/{client → vercel/client}/saveInputMessages.d.ts +2 -2
- package/dist/vercel/client/saveInputMessages.d.ts.map +1 -0
- package/dist/vercel/client/saveInputMessages.js.map +1 -0
- package/dist/{client → vercel/client}/search.d.ts +119 -22
- package/dist/vercel/client/search.d.ts.map +1 -0
- package/dist/{client → vercel/client}/search.js +2 -2
- package/dist/vercel/client/search.js.map +1 -0
- package/dist/{client → vercel/client}/start.d.ts +26 -11
- package/dist/vercel/client/start.d.ts.map +1 -0
- package/dist/{client → vercel/client}/start.js +64 -22
- package/dist/vercel/client/start.js.map +1 -0
- package/dist/{client → vercel/client}/streamText.d.ts +13 -12
- package/dist/vercel/client/streamText.d.ts.map +1 -0
- package/dist/{client → vercel/client}/streamText.js +43 -9
- package/dist/vercel/client/streamText.js.map +1 -0
- package/dist/{client → vercel/client}/streaming.d.ts +1410 -183
- package/dist/vercel/client/streaming.d.ts.map +1 -0
- package/dist/{client → vercel/client}/streaming.js +120 -52
- package/dist/vercel/client/streaming.js.map +1 -0
- package/dist/vercel/client/types.d.ts +456 -0
- package/dist/vercel/client/types.d.ts.map +1 -0
- package/dist/vercel/client/types.js +3 -0
- package/dist/vercel/client/types.js.map +1 -0
- package/dist/{client → vercel/client}/utils.d.ts +3 -2
- package/dist/vercel/client/utils.d.ts.map +1 -0
- package/dist/{client → vercel/client}/utils.js +2 -2
- package/dist/vercel/client/utils.js.map +1 -0
- package/dist/{deltas.d.ts → vercel/deltas.d.ts} +3 -4
- package/dist/vercel/deltas.d.ts.map +1 -0
- package/dist/{deltas.js → vercel/deltas.js} +195 -99
- package/dist/vercel/deltas.js.map +1 -0
- package/dist/{client → vercel}/index.d.ts +482 -106
- package/dist/vercel/index.d.ts.map +1 -0
- package/dist/{client → vercel}/index.js +64 -46
- package/dist/vercel/index.js.map +1 -0
- package/dist/{mapping.d.ts → vercel/mapping.d.ts} +5 -19
- package/dist/vercel/mapping.d.ts.map +1 -0
- package/dist/{mapping.js → vercel/mapping.js} +411 -114
- package/dist/vercel/mapping.js.map +1 -0
- package/dist/{react → vercel/react}/optimisticallySendMessage.d.ts +2 -2
- package/dist/vercel/react/optimisticallySendMessage.d.ts.map +1 -0
- package/dist/vercel/react/optimisticallySendMessage.js.map +1 -0
- package/dist/{react → vercel/react}/types.d.ts +1 -1
- package/dist/vercel/react/types.d.ts.map +1 -0
- package/dist/{react → vercel/react}/types.js.map +1 -1
- package/dist/{react → vercel/react}/useDeltaStreams.d.ts +1 -1
- package/dist/vercel/react/useDeltaStreams.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useDeltaStreams.js +1 -1
- package/dist/vercel/react/useDeltaStreams.js.map +1 -0
- package/dist/{react → vercel/react}/useStreamingUIMessages.d.ts +1 -1
- package/dist/vercel/react/useStreamingUIMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useStreamingUIMessages.js +7 -3
- package/dist/vercel/react/useStreamingUIMessages.js.map +1 -0
- package/dist/{react → vercel/react}/useThreadMessages.d.ts +1 -1
- package/dist/vercel/react/useThreadMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useThreadMessages.js +1 -1
- package/dist/vercel/react/useThreadMessages.js.map +1 -0
- package/dist/{react → vercel/react}/useUIMessages.d.ts +1 -1
- package/dist/vercel/react/useUIMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useUIMessages.js +1 -1
- package/dist/vercel/react/useUIMessages.js.map +1 -0
- package/package.json +29 -22
- package/src/client/messages.ts +5 -107
- package/src/client/types.ts +0 -608
- package/src/component/_generated/component.ts +1089 -48
- package/src/component/messages.test.ts +273 -1
- package/src/component/messages.ts +62 -32
- package/src/component/streams.ts +47 -47
- package/src/component/threads.ts +5 -2
- package/src/eslintConfig.test.ts +44 -0
- package/src/react/index.ts +8 -5
- package/src/shared.ts +26 -36
- package/src/streaming/materializePersistedUIMessageChunks.test.ts +513 -0
- package/src/streaming/materializePersistedUIMessageChunks.ts +398 -0
- package/src/streaming/persistedUIMessageChunks.test.ts +205 -0
- package/src/streaming/persistedUIMessageChunks.ts +658 -0
- package/src/validators.test.ts +4 -1
- package/src/validators.ts +89 -8
- package/src/{UIMessages.combineUIMessages.test.ts → vercel/UIMessages.combineUIMessages.test.ts} +4 -1
- package/src/{UIMessages.ts → vercel/UIMessages.ts} +95 -3
- package/src/{client → vercel/client}/approval.test.ts +23 -13
- package/src/{client → vercel/client}/createTool.ts +62 -22
- package/src/{client → vercel/client}/definePlaygroundAPI.ts +15 -16
- package/src/{client → vercel/client}/files.ts +2 -2
- package/src/{client → vercel/client}/index.test.ts +99 -31
- package/src/vercel/client/messages.ts +182 -0
- package/src/{client → vercel/client}/mockModel.ts +38 -39
- package/src/{client → vercel/client}/saveInputMessages.test.ts +1 -1
- package/src/{client → vercel/client}/saveInputMessages.ts +3 -3
- package/src/{client → vercel/client}/search.test.ts +3 -3
- package/src/{client → vercel/client}/search.ts +4 -4
- package/src/{client → vercel/client}/setup.test.ts +6 -3
- package/src/vercel/client/start.test.ts +14 -0
- package/src/{client → vercel/client}/start.ts +147 -36
- package/src/vercel/client/streamText.test.ts +223 -0
- package/src/{client → vercel/client}/streamText.ts +102 -31
- package/src/{client → vercel/client}/streaming.integration.test.ts +6 -3
- package/src/{client → vercel/client}/streaming.test.ts +178 -4
- package/src/{client → vercel/client}/streaming.ts +114 -52
- package/src/vercel/client/types.test.ts +13 -0
- package/src/vercel/client/types.ts +679 -0
- package/src/{client → vercel/client}/utils.ts +13 -7
- package/src/{deltas.test.ts → vercel/deltas.test.ts} +384 -93
- package/src/{deltas.ts → vercel/deltas.ts} +218 -115
- package/src/{fromUIMessages.test.ts → vercel/fromUIMessages.test.ts} +17 -1
- package/src/{client → vercel}/index.ts +167 -84
- package/src/{mapping.test.ts → vercel/mapping.test.ts} +377 -92
- package/src/{mapping.ts → vercel/mapping.ts} +501 -137
- package/src/{react → vercel/react}/optimisticallySendMessage.ts +2 -2
- package/src/{react → vercel/react}/types.ts +1 -1
- package/src/{react → vercel/react}/useDeltaStreams.ts +6 -2
- package/src/{react → vercel/react}/useStreamingUIMessages.ts +7 -3
- package/src/{react → vercel/react}/useThreadMessages.ts +2 -2
- package/src/{react → vercel/react}/useUIMessages.ts +2 -2
- package/src/{toUIMessages.test.ts → vercel/toUIMessages.test.ts} +49 -2
- package/dist/UIMessages.d.ts.map +0 -1
- package/dist/UIMessages.js.map +0 -1
- package/dist/client/createTool.d.ts.map +0 -1
- package/dist/client/createTool.js.map +0 -1
- package/dist/client/definePlaygroundAPI.js.map +0 -1
- package/dist/client/files.d.ts.map +0 -1
- package/dist/client/files.js.map +0 -1
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js.map +0 -1
- package/dist/client/mockModel.d.ts.map +0 -1
- package/dist/client/mockModel.js.map +0 -1
- package/dist/client/saveInputMessages.d.ts.map +0 -1
- package/dist/client/saveInputMessages.js.map +0 -1
- package/dist/client/search.d.ts.map +0 -1
- package/dist/client/search.js.map +0 -1
- package/dist/client/start.d.ts.map +0 -1
- package/dist/client/start.js.map +0 -1
- package/dist/client/streamText.d.ts.map +0 -1
- package/dist/client/streamText.js.map +0 -1
- package/dist/client/streaming.d.ts.map +0 -1
- package/dist/client/streaming.js.map +0 -1
- package/dist/client/utils.d.ts.map +0 -1
- package/dist/client/utils.js.map +0 -1
- package/dist/deltas.d.ts.map +0 -1
- package/dist/deltas.js.map +0 -1
- package/dist/mapping.d.ts.map +0 -1
- package/dist/mapping.js.map +0 -1
- package/dist/react/optimisticallySendMessage.d.ts.map +0 -1
- package/dist/react/optimisticallySendMessage.js.map +0 -1
- package/dist/react/types.d.ts.map +0 -1
- package/dist/react/useDeltaStreams.d.ts.map +0 -1
- package/dist/react/useDeltaStreams.js.map +0 -1
- package/dist/react/useStreamingUIMessages.d.ts.map +0 -1
- package/dist/react/useStreamingUIMessages.js.map +0 -1
- package/dist/react/useThreadMessages.d.ts.map +0 -1
- package/dist/react/useThreadMessages.js.map +0 -1
- package/dist/react/useUIMessages.d.ts.map +0 -1
- package/dist/react/useUIMessages.js.map +0 -1
- package/src/client/streamText.test.ts +0 -102
- /package/dist/{client → vercel/client}/files.js +0 -0
- /package/dist/{client → vercel/client}/saveInputMessages.js +0 -0
- /package/dist/{react → vercel/react}/optimisticallySendMessage.js +0 -0
- /package/dist/{react → vercel/react}/types.js +0 -0
- /package/src/{UIMessages.test.ts → vercel/UIMessages.test.ts} +0 -0
- /package/src/{react → vercel/react}/useUIMessages.test.ts +0 -0
|
@@ -26,7 +26,9 @@ import {
|
|
|
26
26
|
type MessageWithMetadata,
|
|
27
27
|
type Usage,
|
|
28
28
|
type vFilePart,
|
|
29
|
+
type vCustomContentPart,
|
|
29
30
|
type vImagePart,
|
|
31
|
+
type vReasoningFilePart,
|
|
30
32
|
type vReasoningPart,
|
|
31
33
|
type vRedactedReasoningPart,
|
|
32
34
|
type vTextPart,
|
|
@@ -37,22 +39,27 @@ import {
|
|
|
37
39
|
type MessageDoc,
|
|
38
40
|
vToolApprovalRequest,
|
|
39
41
|
vToolApprovalResponse,
|
|
40
|
-
|
|
42
|
+
vProviderReference,
|
|
43
|
+
} from "../validators.js";
|
|
41
44
|
import type { ActionCtx, AgentComponent } from "./client/types.js";
|
|
42
45
|
import type { MutationCtx } from "./client/types.js";
|
|
43
46
|
import { MAX_FILE_SIZE, storeFile } from "./client/files.js";
|
|
44
47
|
import type { Infer } from "convex/values";
|
|
45
48
|
import {
|
|
46
49
|
convertUint8ArrayToBase64,
|
|
50
|
+
type FileData,
|
|
47
51
|
type ProviderOptions,
|
|
52
|
+
type ProviderReference,
|
|
53
|
+
type ReasoningFilePart,
|
|
48
54
|
type ReasoningPart,
|
|
55
|
+
type ToolResultOutput,
|
|
49
56
|
} from "@ai-sdk/provider-utils";
|
|
50
57
|
import { parse, validate } from "convex-helpers/validators";
|
|
51
58
|
import {
|
|
52
59
|
getModelName,
|
|
53
60
|
getProviderName,
|
|
54
61
|
type ModelOrMetadata,
|
|
55
|
-
} from "
|
|
62
|
+
} from "../shared.js";
|
|
56
63
|
export type AIMessageWithoutId = Omit<AIMessage, "id">;
|
|
57
64
|
|
|
58
65
|
export type SerializeUrlsAndUint8Arrays<T> = T extends URL
|
|
@@ -232,32 +239,15 @@ export function autoDenyUnresolvedApprovals(
|
|
|
232
239
|
|
|
233
240
|
export function serializeUsage(usage: LanguageModelUsage): Usage {
|
|
234
241
|
return {
|
|
235
|
-
promptTokens: usage.inputTokens
|
|
236
|
-
completionTokens: usage.outputTokens
|
|
237
|
-
totalTokens: usage.totalTokens ?? 0,
|
|
238
|
-
reasoningTokens: usage.reasoningTokens,
|
|
239
|
-
cachedInputTokens: usage.cachedInputTokens,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export function toModelMessageUsage(usage: Usage): LanguageModelUsage {
|
|
244
|
-
return {
|
|
245
|
-
inputTokens: usage.promptTokens,
|
|
246
|
-
outputTokens: usage.completionTokens,
|
|
242
|
+
promptTokens: usage.inputTokens,
|
|
243
|
+
completionTokens: usage.outputTokens,
|
|
247
244
|
totalTokens: usage.totalTokens,
|
|
248
|
-
reasoningTokens: usage.reasoningTokens,
|
|
249
|
-
cachedInputTokens: usage.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
cacheWriteTokens: undefined,
|
|
255
|
-
noCacheTokens: undefined,
|
|
256
|
-
},
|
|
257
|
-
outputTokenDetails: {
|
|
258
|
-
textTokens: undefined,
|
|
259
|
-
reasoningTokens: undefined,
|
|
260
|
-
},
|
|
245
|
+
reasoningTokens: usage.outputTokenDetails?.reasoningTokens,
|
|
246
|
+
cachedInputTokens: usage.inputTokenDetails?.cacheReadTokens,
|
|
247
|
+
nonCachedInputTokens: usage.inputTokenDetails?.noCacheTokens,
|
|
248
|
+
cacheWriteInputTokens: usage.inputTokenDetails?.cacheWriteTokens,
|
|
249
|
+
textOutputTokens: usage.outputTokenDetails?.textTokens,
|
|
250
|
+
raw: usage.raw,
|
|
261
251
|
};
|
|
262
252
|
}
|
|
263
253
|
|
|
@@ -268,33 +258,24 @@ export function serializeWarnings(
|
|
|
268
258
|
return undefined;
|
|
269
259
|
}
|
|
270
260
|
return warnings.map((warning) => {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
261
|
+
switch (warning.type) {
|
|
262
|
+
case "unsupported":
|
|
263
|
+
case "compatibility":
|
|
264
|
+
return {
|
|
265
|
+
type: warning.type,
|
|
266
|
+
feature: warning.feature,
|
|
267
|
+
details: warning.details,
|
|
268
|
+
};
|
|
269
|
+
case "deprecated":
|
|
270
|
+
return {
|
|
271
|
+
type: warning.type,
|
|
272
|
+
setting: warning.setting,
|
|
273
|
+
message: warning.message,
|
|
274
|
+
};
|
|
275
|
+
case "other":
|
|
276
|
+
return { type: warning.type, message: warning.message };
|
|
277
277
|
}
|
|
278
|
-
|
|
279
|
-
}) as any;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function toModelMessageWarnings(
|
|
283
|
-
warnings: MessageWithMetadata["warnings"],
|
|
284
|
-
): CallWarning[] | undefined {
|
|
285
|
-
if (!warnings) {
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
return warnings.map((warning) => {
|
|
289
|
-
if (warning.type === "unsupported-setting") {
|
|
290
|
-
return {
|
|
291
|
-
type: "compatibility",
|
|
292
|
-
feature: warning.setting,
|
|
293
|
-
details: warning.details,
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
return warning;
|
|
297
|
-
}) as any;
|
|
278
|
+
});
|
|
298
279
|
}
|
|
299
280
|
|
|
300
281
|
/**
|
|
@@ -312,34 +293,6 @@ export async function serializeResponseMessages<TOOLS extends ToolSet>(
|
|
|
312
293
|
return serializeStepMessages(ctx, component, step, model, responseMessages);
|
|
313
294
|
}
|
|
314
295
|
|
|
315
|
-
/**
|
|
316
|
-
* Serialize the new response messages produced by this step.
|
|
317
|
-
*
|
|
318
|
-
* `step.response.messages` is cumulative across steps in AI SDK v6 — each
|
|
319
|
-
* step's array contains all messages from prior steps too. Pass
|
|
320
|
-
* `previousResponseMessageCount` (the prior step's `response.messages.length`,
|
|
321
|
-
* or `0` for the first step) so we slice only the new tail. The parameter is
|
|
322
|
-
* required: defaulting it would silently duplicate every prior message on
|
|
323
|
-
* every multi-step save.
|
|
324
|
-
*/
|
|
325
|
-
export async function serializeNewMessagesInStep<TOOLS extends ToolSet>(
|
|
326
|
-
ctx: ActionCtx,
|
|
327
|
-
component: AgentComponent,
|
|
328
|
-
step: StepResult<TOOLS>,
|
|
329
|
-
model: ModelOrMetadata | undefined,
|
|
330
|
-
previousResponseMessageCount: number,
|
|
331
|
-
): Promise<{ messages: MessageWithMetadata[] }> {
|
|
332
|
-
const newMessages = step.response.messages.slice(previousResponseMessageCount);
|
|
333
|
-
// Keep at least one message in the output so the step still anchors an
|
|
334
|
-
// order slot — downstream `addMessages` relies on each step contributing a
|
|
335
|
-
// row even when AI SDK produced no response messages.
|
|
336
|
-
const messagesToSerialize: ModelMessage[] =
|
|
337
|
-
newMessages.length > 0
|
|
338
|
-
? newMessages
|
|
339
|
-
: [{ role: "assistant" as const, content: [] }];
|
|
340
|
-
return serializeStepMessages(ctx, component, step, model, messagesToSerialize);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
296
|
async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
344
297
|
ctx: ActionCtx,
|
|
345
298
|
component: AgentComponent,
|
|
@@ -350,12 +303,15 @@ async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
|
350
303
|
// If there are tool results, there's another message with the tool results
|
|
351
304
|
// ref: https://github.com/vercel/ai/blob/main/packages/ai/src/generate-text/to-response-messages.ts#L120
|
|
352
305
|
const hasToolMessage = step.response.messages.at(-1)?.role === "tool";
|
|
306
|
+
const resolvedModel = step.model ?? model;
|
|
353
307
|
const assistantFields = {
|
|
354
|
-
model:
|
|
355
|
-
provider:
|
|
308
|
+
model: resolvedModel ? getModelName(resolvedModel) : undefined,
|
|
309
|
+
provider: resolvedModel ? getProviderName(resolvedModel) : undefined,
|
|
356
310
|
providerMetadata: step.providerMetadata,
|
|
357
311
|
reasoning: step.reasoningText,
|
|
358
|
-
reasoningDetails: step.reasoning
|
|
312
|
+
reasoningDetails: step.reasoning.filter(
|
|
313
|
+
(part) => part.type !== "reasoning-file",
|
|
314
|
+
),
|
|
359
315
|
usage: serializeUsage(step.usage),
|
|
360
316
|
warnings: serializeWarnings(step.warnings),
|
|
361
317
|
finishReason: step.finishReason,
|
|
@@ -375,7 +331,6 @@ async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
|
375
331
|
});
|
|
376
332
|
}),
|
|
377
333
|
);
|
|
378
|
-
// TODO: capture step.files separately?
|
|
379
334
|
return { messages };
|
|
380
335
|
}
|
|
381
336
|
|
|
@@ -448,7 +403,9 @@ export async function serializeContent(
|
|
|
448
403
|
} satisfies Infer<typeof vTextPart>;
|
|
449
404
|
}
|
|
450
405
|
case "image": {
|
|
451
|
-
let image =
|
|
406
|
+
let image =
|
|
407
|
+
toStoredProviderReference(part.image) ??
|
|
408
|
+
serializeDataOrUrl(part.image);
|
|
452
409
|
if (
|
|
453
410
|
image instanceof ArrayBuffer &&
|
|
454
411
|
image.byteLength > MAX_FILE_SIZE
|
|
@@ -471,7 +428,9 @@ export async function serializeContent(
|
|
|
471
428
|
} satisfies Infer<typeof vImagePart>;
|
|
472
429
|
}
|
|
473
430
|
case "file": {
|
|
474
|
-
let data =
|
|
431
|
+
let data =
|
|
432
|
+
toStoredProviderReference(part.data) ??
|
|
433
|
+
serializeDataOrUrl(part.data);
|
|
475
434
|
if (data instanceof ArrayBuffer && data.byteLength > MAX_FILE_SIZE) {
|
|
476
435
|
const { file } = await storeFile(
|
|
477
436
|
ctx,
|
|
@@ -500,19 +459,41 @@ export async function serializeContent(
|
|
|
500
459
|
toolCallId: part.toolCallId,
|
|
501
460
|
toolName: part.toolName,
|
|
502
461
|
providerExecuted: part.providerExecuted,
|
|
462
|
+
title: "title" in part ? part.title : undefined,
|
|
463
|
+
toolMetadata:
|
|
464
|
+
"toolMetadata" in part ? part.toolMetadata : undefined,
|
|
503
465
|
...metadata,
|
|
504
466
|
} satisfies Infer<typeof vToolCallPart>;
|
|
505
467
|
}
|
|
506
468
|
case "tool-result": {
|
|
507
|
-
return
|
|
469
|
+
return serializeToolResult(part, metadata);
|
|
508
470
|
}
|
|
509
471
|
case "reasoning": {
|
|
510
472
|
return {
|
|
511
473
|
type: part.type,
|
|
512
474
|
text: part.text,
|
|
475
|
+
signature:
|
|
476
|
+
"signature" in part && typeof part.signature === "string"
|
|
477
|
+
? part.signature
|
|
478
|
+
: undefined,
|
|
513
479
|
...metadata,
|
|
514
480
|
} satisfies Infer<typeof vReasoningPart>;
|
|
515
481
|
}
|
|
482
|
+
case "reasoning-file": {
|
|
483
|
+
return {
|
|
484
|
+
type: part.type,
|
|
485
|
+
...serializeReasoningFile(part),
|
|
486
|
+
mediaType: part.mediaType,
|
|
487
|
+
...metadata,
|
|
488
|
+
} satisfies Infer<typeof vReasoningFilePart>;
|
|
489
|
+
}
|
|
490
|
+
case "custom": {
|
|
491
|
+
return {
|
|
492
|
+
type: part.type,
|
|
493
|
+
kind: part.kind,
|
|
494
|
+
...metadata,
|
|
495
|
+
} satisfies Infer<typeof vCustomContentPart>;
|
|
496
|
+
}
|
|
516
497
|
// Not in current generation output, but could be in historical messages
|
|
517
498
|
case "redacted-reasoning": {
|
|
518
499
|
return {
|
|
@@ -529,6 +510,8 @@ export async function serializeContent(
|
|
|
529
510
|
type: part.type,
|
|
530
511
|
approvalId: part.approvalId,
|
|
531
512
|
toolCallId: part.toolCallId,
|
|
513
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
514
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
532
515
|
...metadata,
|
|
533
516
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
534
517
|
}
|
|
@@ -577,12 +560,16 @@ export function fromModelMessageContent(content: Content): Message["content"] {
|
|
|
577
560
|
type: part.type,
|
|
578
561
|
mediaType: getMimeOrMediaType(part),
|
|
579
562
|
...metadata,
|
|
580
|
-
image:
|
|
563
|
+
image:
|
|
564
|
+
toStoredProviderReference(part.image) ??
|
|
565
|
+
serializeDataOrUrl(part.image),
|
|
581
566
|
} satisfies Infer<typeof vImagePart>;
|
|
582
567
|
case "file":
|
|
583
568
|
return {
|
|
584
569
|
type: part.type,
|
|
585
|
-
data:
|
|
570
|
+
data:
|
|
571
|
+
toStoredProviderReference(part.data) ??
|
|
572
|
+
serializeDataOrUrl(part.data),
|
|
586
573
|
filename: part.filename,
|
|
587
574
|
mediaType: getMimeOrMediaType(part)!,
|
|
588
575
|
...metadata,
|
|
@@ -600,18 +587,38 @@ export function fromModelMessageContent(content: Content): Message["content"] {
|
|
|
600
587
|
...metadata,
|
|
601
588
|
} satisfies Infer<typeof vToolCallPart>;
|
|
602
589
|
case "tool-result":
|
|
603
|
-
return
|
|
590
|
+
return serializeToolResult(part, metadata);
|
|
604
591
|
case "reasoning":
|
|
605
592
|
return {
|
|
606
593
|
type: part.type,
|
|
607
594
|
text: part.text,
|
|
595
|
+
signature:
|
|
596
|
+
"signature" in part && typeof part.signature === "string"
|
|
597
|
+
? part.signature
|
|
598
|
+
: undefined,
|
|
608
599
|
...metadata,
|
|
609
600
|
} satisfies Infer<typeof vReasoningPart>;
|
|
601
|
+
case "reasoning-file": {
|
|
602
|
+
return {
|
|
603
|
+
type: part.type,
|
|
604
|
+
...serializeReasoningFile(part),
|
|
605
|
+
mediaType: part.mediaType,
|
|
606
|
+
...metadata,
|
|
607
|
+
} satisfies Infer<typeof vReasoningFilePart>;
|
|
608
|
+
}
|
|
609
|
+
case "custom":
|
|
610
|
+
return {
|
|
611
|
+
type: part.type,
|
|
612
|
+
kind: part.kind,
|
|
613
|
+
...metadata,
|
|
614
|
+
} satisfies Infer<typeof vCustomContentPart>;
|
|
610
615
|
case "tool-approval-request":
|
|
611
616
|
return {
|
|
612
617
|
type: part.type,
|
|
613
618
|
approvalId: part.approvalId,
|
|
614
619
|
toolCallId: part.toolCallId,
|
|
620
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
621
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
615
622
|
...metadata,
|
|
616
623
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
617
624
|
case "tool-approval-response":
|
|
@@ -659,14 +666,18 @@ export function toModelMessageContent(
|
|
|
659
666
|
case "image":
|
|
660
667
|
return {
|
|
661
668
|
type: part.type,
|
|
662
|
-
image:
|
|
669
|
+
image: (isStoredProviderReference(part.image)
|
|
670
|
+
? part.image.reference
|
|
671
|
+
: toModelMessageDataOrUrl(part.image)) as ImagePart["image"],
|
|
663
672
|
mediaType: getMimeOrMediaType(part),
|
|
664
673
|
...metadata,
|
|
665
674
|
} satisfies ImagePart;
|
|
666
675
|
case "file":
|
|
667
676
|
return {
|
|
668
677
|
type: part.type,
|
|
669
|
-
data:
|
|
678
|
+
data: (isStoredProviderReference(part.data)
|
|
679
|
+
? { type: "reference" as const, reference: part.data.reference }
|
|
680
|
+
: toModelMessageDataOrUrl(part.data)) as FilePart["data"],
|
|
670
681
|
filename: part.filename,
|
|
671
682
|
mediaType: getMimeOrMediaType(part)!,
|
|
672
683
|
...metadata,
|
|
@@ -684,7 +695,7 @@ export function toModelMessageContent(
|
|
|
684
695
|
} satisfies ToolCallPart;
|
|
685
696
|
}
|
|
686
697
|
case "tool-result": {
|
|
687
|
-
return
|
|
698
|
+
return deserializeToolResult(part, metadata);
|
|
688
699
|
}
|
|
689
700
|
case "reasoning":
|
|
690
701
|
return {
|
|
@@ -692,23 +703,32 @@ export function toModelMessageContent(
|
|
|
692
703
|
text: part.text,
|
|
693
704
|
...metadata,
|
|
694
705
|
} satisfies ReasoningPart;
|
|
706
|
+
case "reasoning-file":
|
|
707
|
+
return {
|
|
708
|
+
type: "reasoning-file",
|
|
709
|
+
data: deserializeReasoningFile(
|
|
710
|
+
part as Infer<typeof vReasoningFilePart>,
|
|
711
|
+
),
|
|
712
|
+
mediaType: part.mediaType,
|
|
713
|
+
...metadata,
|
|
714
|
+
} satisfies ReasoningFilePart;
|
|
715
|
+
case "custom":
|
|
716
|
+
return { type: "custom", kind: part.kind, ...metadata };
|
|
695
717
|
case "redacted-reasoning":
|
|
696
|
-
//
|
|
718
|
+
// Legacy v5 part: round-trip the redacted payload via providerOptions.
|
|
697
719
|
return {
|
|
698
720
|
type: "reasoning",
|
|
699
721
|
text: "",
|
|
700
722
|
...metadata,
|
|
701
723
|
providerOptions: metadata.providerOptions
|
|
702
|
-
?
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
],
|
|
709
|
-
),
|
|
724
|
+
? Object.fromEntries(
|
|
725
|
+
Object.entries(metadata.providerOptions ?? {}).map(
|
|
726
|
+
([key, value]) => [
|
|
727
|
+
key,
|
|
728
|
+
{ ...value, redactedData: part.data },
|
|
729
|
+
],
|
|
710
730
|
),
|
|
711
|
-
|
|
731
|
+
)
|
|
712
732
|
: undefined,
|
|
713
733
|
} satisfies ReasoningPart;
|
|
714
734
|
case "source":
|
|
@@ -718,6 +738,8 @@ export function toModelMessageContent(
|
|
|
718
738
|
type: part.type,
|
|
719
739
|
approvalId: part.approvalId,
|
|
720
740
|
toolCallId: part.toolCallId,
|
|
741
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
742
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
721
743
|
...metadata,
|
|
722
744
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
723
745
|
case "tool-approval-response":
|
|
@@ -746,7 +768,7 @@ export function normalizeToolOutput(
|
|
|
746
768
|
};
|
|
747
769
|
}
|
|
748
770
|
if (validate(vToolResultOutput, result)) {
|
|
749
|
-
return result;
|
|
771
|
+
return result as unknown as ToolResultOutput;
|
|
750
772
|
}
|
|
751
773
|
return {
|
|
752
774
|
type: "json",
|
|
@@ -754,28 +776,277 @@ export function normalizeToolOutput(
|
|
|
754
776
|
};
|
|
755
777
|
}
|
|
756
778
|
|
|
757
|
-
function
|
|
779
|
+
function serializeToolResult(
|
|
758
780
|
part: ToolResultPart | Infer<typeof vToolResultPart>,
|
|
759
781
|
metadata: {
|
|
760
782
|
providerOptions?: ProviderOptions;
|
|
761
783
|
providerMetadata?: ProviderMetadata;
|
|
762
784
|
},
|
|
763
|
-
):
|
|
785
|
+
): Infer<typeof vToolResultPart> {
|
|
764
786
|
return {
|
|
765
787
|
type: part.type,
|
|
766
|
-
output:
|
|
767
|
-
|
|
768
|
-
? (part.output
|
|
769
|
-
: normalizeToolOutput(
|
|
770
|
-
|
|
788
|
+
output:
|
|
789
|
+
"output" in part && part.output !== undefined
|
|
790
|
+
? serializeToolResultOutput(part.output)
|
|
791
|
+
: (normalizeToolOutput(
|
|
792
|
+
"result" in part ? part.result : undefined,
|
|
793
|
+
) as Infer<typeof vToolResultOutput>),
|
|
771
794
|
toolCallId: part.toolCallId,
|
|
772
795
|
toolName: part.toolName,
|
|
796
|
+
...("providerExecuted" in part
|
|
797
|
+
? { providerExecuted: part.providerExecuted }
|
|
798
|
+
: {}),
|
|
773
799
|
// Preserve isError flag for error reporting
|
|
774
800
|
...("isError" in part && part.isError ? { isError: true } : {}),
|
|
775
801
|
...metadata,
|
|
802
|
+
} as Infer<typeof vToolResultPart>;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function deserializeToolResult(
|
|
806
|
+
part: ToolResultPart | Infer<typeof vToolResultPart>,
|
|
807
|
+
metadata: {
|
|
808
|
+
providerOptions?: ProviderOptions;
|
|
809
|
+
providerMetadata?: ProviderMetadata;
|
|
810
|
+
},
|
|
811
|
+
): ToolResultPart {
|
|
812
|
+
return {
|
|
813
|
+
type: part.type,
|
|
814
|
+
output:
|
|
815
|
+
"output" in part && part.output !== undefined
|
|
816
|
+
? deserializeToolResultOutput(part.output)
|
|
817
|
+
: normalizeToolOutput("result" in part ? part.result : undefined),
|
|
818
|
+
toolCallId: part.toolCallId,
|
|
819
|
+
toolName: part.toolName,
|
|
820
|
+
...("isError" in part && part.isError ? { isError: true } : {}),
|
|
821
|
+
...metadata,
|
|
776
822
|
} satisfies ToolResultPart;
|
|
777
823
|
}
|
|
778
824
|
|
|
825
|
+
function serializeToolResultOutput(
|
|
826
|
+
output: unknown,
|
|
827
|
+
): Infer<typeof vToolResultOutput> {
|
|
828
|
+
if (output === undefined) {
|
|
829
|
+
return normalizeToolOutput(undefined) as Infer<typeof vToolResultOutput>;
|
|
830
|
+
}
|
|
831
|
+
if (!isRecord(output) || typeof output.type !== "string") {
|
|
832
|
+
return normalizeToolOutput(output as JSONValue) as Infer<
|
|
833
|
+
typeof vToolResultOutput
|
|
834
|
+
>;
|
|
835
|
+
}
|
|
836
|
+
if (output.type !== "content") {
|
|
837
|
+
if (validate(vToolResultOutput, output)) {
|
|
838
|
+
return output as Infer<typeof vToolResultOutput>;
|
|
839
|
+
}
|
|
840
|
+
throw new Error(`Invalid AI SDK 7 tool-result output: ${output.type}`);
|
|
841
|
+
}
|
|
842
|
+
if (!Array.isArray(output.value)) {
|
|
843
|
+
throw new Error("Invalid AI SDK 7 tool-result content output");
|
|
844
|
+
}
|
|
845
|
+
const serialized = {
|
|
846
|
+
...output,
|
|
847
|
+
value: output.value.map(serializeToolResultContentPart),
|
|
848
|
+
};
|
|
849
|
+
if (!validate(vToolResultOutput, serialized)) {
|
|
850
|
+
throw new Error("Invalid AI SDK 7 tool-result content part");
|
|
851
|
+
}
|
|
852
|
+
return serialized as Infer<typeof vToolResultOutput>;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function serializeToolResultContentPart(part: unknown): unknown {
|
|
856
|
+
if (!isRecord(part) || typeof part.type !== "string") {
|
|
857
|
+
throw new Error("Invalid AI SDK 7 tool-result content part");
|
|
858
|
+
}
|
|
859
|
+
if (part.type !== "file") return part;
|
|
860
|
+
if (!isRecord(part.data) || typeof part.data.type !== "string") {
|
|
861
|
+
throw new Error("Invalid AI SDK 7 tool-result file data");
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const common = {
|
|
865
|
+
type: "file" as const,
|
|
866
|
+
mediaType: part.mediaType,
|
|
867
|
+
...(typeof part.filename === "string" ? { filename: part.filename } : {}),
|
|
868
|
+
...(isRecord(part.providerOptions)
|
|
869
|
+
? { providerOptions: part.providerOptions }
|
|
870
|
+
: {}),
|
|
871
|
+
};
|
|
872
|
+
switch (part.data.type) {
|
|
873
|
+
case "data":
|
|
874
|
+
return {
|
|
875
|
+
...common,
|
|
876
|
+
data: {
|
|
877
|
+
type: "data" as const,
|
|
878
|
+
data: serializeDataOrUrl(part.data.data as DataContent),
|
|
879
|
+
},
|
|
880
|
+
};
|
|
881
|
+
case "url": {
|
|
882
|
+
const { url } = part.data;
|
|
883
|
+
if (typeof url !== "string" && !(url instanceof URL)) {
|
|
884
|
+
throw new Error("Invalid AI SDK 7 tool-result file URL");
|
|
885
|
+
}
|
|
886
|
+
return { ...common, data: { type: "url" as const, url: url.toString() } };
|
|
887
|
+
}
|
|
888
|
+
case "text":
|
|
889
|
+
if (typeof part.data.text !== "string") {
|
|
890
|
+
throw new Error("Invalid AI SDK 7 tool-result file text");
|
|
891
|
+
}
|
|
892
|
+
return {
|
|
893
|
+
...common,
|
|
894
|
+
data: { type: "text" as const, text: part.data.text },
|
|
895
|
+
};
|
|
896
|
+
case "reference":
|
|
897
|
+
if (!isProviderReference(part.data.reference)) {
|
|
898
|
+
throw new Error("Invalid AI SDK 7 tool-result file reference");
|
|
899
|
+
}
|
|
900
|
+
return {
|
|
901
|
+
...common,
|
|
902
|
+
data: { type: "reference" as const, reference: part.data.reference },
|
|
903
|
+
};
|
|
904
|
+
default:
|
|
905
|
+
throw new Error(
|
|
906
|
+
`Invalid AI SDK 7 tool-result file data: ${part.data.type}`,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function deserializeToolResultOutput(output: unknown): ToolResultOutput {
|
|
912
|
+
if (!validate(vToolResultOutput, output)) {
|
|
913
|
+
return normalizeToolOutput(output as JSONValue);
|
|
914
|
+
}
|
|
915
|
+
const stored = output as Infer<typeof vToolResultOutput>;
|
|
916
|
+
if (stored.type !== "content") return stored as unknown as ToolResultOutput;
|
|
917
|
+
return {
|
|
918
|
+
type: "content",
|
|
919
|
+
value: stored.value.map(deserializeToolResultContentPart),
|
|
920
|
+
} as ToolResultOutput;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function deserializeToolResultContentPart(
|
|
924
|
+
part: Extract<
|
|
925
|
+
Infer<typeof vToolResultOutput>,
|
|
926
|
+
{ type: "content" }
|
|
927
|
+
>["value"][number],
|
|
928
|
+
) {
|
|
929
|
+
if (part.type === "file") {
|
|
930
|
+
return {
|
|
931
|
+
...part,
|
|
932
|
+
data:
|
|
933
|
+
part.data.type === "url"
|
|
934
|
+
? { type: "url" as const, url: new URL(part.data.url) }
|
|
935
|
+
: part.data,
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
switch (part.type) {
|
|
939
|
+
case "media":
|
|
940
|
+
return {
|
|
941
|
+
type: "file" as const,
|
|
942
|
+
data: { type: "data" as const, data: part.data },
|
|
943
|
+
mediaType: part.mediaType,
|
|
944
|
+
};
|
|
945
|
+
case "file-data":
|
|
946
|
+
return {
|
|
947
|
+
type: "file" as const,
|
|
948
|
+
data: { type: "data" as const, data: part.data },
|
|
949
|
+
mediaType: part.mediaType,
|
|
950
|
+
...(part.filename !== undefined ? { filename: part.filename } : {}),
|
|
951
|
+
...(part.providerOptions !== undefined
|
|
952
|
+
? { providerOptions: part.providerOptions }
|
|
953
|
+
: {}),
|
|
954
|
+
};
|
|
955
|
+
case "file-url":
|
|
956
|
+
return {
|
|
957
|
+
type: "file" as const,
|
|
958
|
+
data: { type: "url" as const, url: new URL(part.url) },
|
|
959
|
+
mediaType: part.mediaType ?? "application/octet-stream",
|
|
960
|
+
...(part.providerOptions !== undefined
|
|
961
|
+
? { providerOptions: part.providerOptions }
|
|
962
|
+
: {}),
|
|
963
|
+
};
|
|
964
|
+
case "file-id":
|
|
965
|
+
case "image-file-id":
|
|
966
|
+
if (typeof part.fileId === "string") return part;
|
|
967
|
+
return {
|
|
968
|
+
type: "file" as const,
|
|
969
|
+
data: {
|
|
970
|
+
type: "reference" as const,
|
|
971
|
+
reference: part.fileId,
|
|
972
|
+
},
|
|
973
|
+
mediaType:
|
|
974
|
+
part.type === "image-file-id" ? "image" : "application/octet-stream",
|
|
975
|
+
...(part.providerOptions !== undefined
|
|
976
|
+
? { providerOptions: part.providerOptions }
|
|
977
|
+
: {}),
|
|
978
|
+
};
|
|
979
|
+
case "file-reference":
|
|
980
|
+
case "image-file-reference":
|
|
981
|
+
return {
|
|
982
|
+
type: "file" as const,
|
|
983
|
+
data: { type: "reference" as const, reference: part.providerReference },
|
|
984
|
+
mediaType:
|
|
985
|
+
part.type === "image-file-reference"
|
|
986
|
+
? "image"
|
|
987
|
+
: "application/octet-stream",
|
|
988
|
+
...(part.providerOptions !== undefined
|
|
989
|
+
? { providerOptions: part.providerOptions }
|
|
990
|
+
: {}),
|
|
991
|
+
};
|
|
992
|
+
case "image-data":
|
|
993
|
+
return {
|
|
994
|
+
type: "file" as const,
|
|
995
|
+
data: { type: "data" as const, data: part.data },
|
|
996
|
+
mediaType: part.mediaType,
|
|
997
|
+
...(part.providerOptions !== undefined
|
|
998
|
+
? { providerOptions: part.providerOptions }
|
|
999
|
+
: {}),
|
|
1000
|
+
};
|
|
1001
|
+
case "image-url":
|
|
1002
|
+
return {
|
|
1003
|
+
type: "file" as const,
|
|
1004
|
+
data: { type: "url" as const, url: new URL(part.url) },
|
|
1005
|
+
mediaType: "image",
|
|
1006
|
+
...(part.providerOptions !== undefined
|
|
1007
|
+
? { providerOptions: part.providerOptions }
|
|
1008
|
+
: {}),
|
|
1009
|
+
};
|
|
1010
|
+
default:
|
|
1011
|
+
return part;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function serializeReasoningFile(
|
|
1016
|
+
part: ReasoningFilePart | Infer<typeof vReasoningFilePart>,
|
|
1017
|
+
): Pick<Infer<typeof vReasoningFilePart>, "url" | "data"> {
|
|
1018
|
+
if ("url" in part && part.url !== undefined) {
|
|
1019
|
+
return { url: part.url.toString() };
|
|
1020
|
+
}
|
|
1021
|
+
if (!("data" in part) || part.data === undefined) {
|
|
1022
|
+
throw new Error("reasoning-file requires data or url");
|
|
1023
|
+
}
|
|
1024
|
+
const { data } = part;
|
|
1025
|
+
if (data instanceof URL) return { url: data.toString() };
|
|
1026
|
+
if (isRecord(data) && data.type === "url" && data.url instanceof URL) {
|
|
1027
|
+
return { url: data.url.toString() };
|
|
1028
|
+
}
|
|
1029
|
+
if (isRecord(data) && data.type === "data") {
|
|
1030
|
+
return { data: serializeDataOrUrl(data.data as DataContent) };
|
|
1031
|
+
}
|
|
1032
|
+
if (isRecord(data) && "type" in data) {
|
|
1033
|
+
throw new Error("Invalid AI SDK 7 reasoning-file data");
|
|
1034
|
+
}
|
|
1035
|
+
return { data: serializeDataOrUrl(data) };
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
function deserializeReasoningFile(
|
|
1039
|
+
part: Infer<typeof vReasoningFilePart>,
|
|
1040
|
+
): Extract<ReasoningFilePart["data"], { type: string }> {
|
|
1041
|
+
if (part.url !== undefined) {
|
|
1042
|
+
return { type: "url", url: new URL(part.url) };
|
|
1043
|
+
}
|
|
1044
|
+
if (part.data !== undefined) {
|
|
1045
|
+
return { type: "data", data: part.data };
|
|
1046
|
+
}
|
|
1047
|
+
throw new Error("reasoning-file requires data or url");
|
|
1048
|
+
}
|
|
1049
|
+
|
|
779
1050
|
/**
|
|
780
1051
|
* Return a best-guess MIME type based on the magic-number signature
|
|
781
1052
|
* found at the start of an ArrayBuffer.
|
|
@@ -849,7 +1120,7 @@ export function guessMimeType(buf: ArrayBuffer | string): string {
|
|
|
849
1120
|
* @returns The serialized data as an ArrayBuffer or the URL as a string.
|
|
850
1121
|
*/
|
|
851
1122
|
export function serializeDataOrUrl(
|
|
852
|
-
dataOrUrl: DataContent | URL,
|
|
1123
|
+
dataOrUrl: DataContent | URL | ProviderReference | FileData,
|
|
853
1124
|
): ArrayBuffer | string {
|
|
854
1125
|
if (typeof dataOrUrl === "string") {
|
|
855
1126
|
return dataOrUrl;
|
|
@@ -860,6 +1131,23 @@ export function serializeDataOrUrl(
|
|
|
860
1131
|
if (dataOrUrl instanceof URL) {
|
|
861
1132
|
return dataOrUrl.toString();
|
|
862
1133
|
}
|
|
1134
|
+
if ("type" in dataOrUrl) {
|
|
1135
|
+
switch (dataOrUrl.type) {
|
|
1136
|
+
case "data":
|
|
1137
|
+
return serializeDataOrUrl(dataOrUrl.data);
|
|
1138
|
+
case "url":
|
|
1139
|
+
return dataOrUrl.url.toString();
|
|
1140
|
+
case "text":
|
|
1141
|
+
return convertUint8ArrayToBase64(
|
|
1142
|
+
new TextEncoder().encode(dataOrUrl.text),
|
|
1143
|
+
);
|
|
1144
|
+
case "reference":
|
|
1145
|
+
throw new Error("Provider references must be stored as references");
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
if (!(dataOrUrl instanceof Uint8Array)) {
|
|
1149
|
+
throw new Error("Unsupported provider reference");
|
|
1150
|
+
}
|
|
863
1151
|
return dataOrUrl.buffer.slice(
|
|
864
1152
|
dataOrUrl.byteOffset,
|
|
865
1153
|
dataOrUrl.byteOffset + dataOrUrl.byteLength,
|
|
@@ -867,8 +1155,14 @@ export function serializeDataOrUrl(
|
|
|
867
1155
|
}
|
|
868
1156
|
|
|
869
1157
|
export function toModelMessageDataOrUrl(
|
|
870
|
-
urlOrString:
|
|
871
|
-
|
|
1158
|
+
urlOrString:
|
|
1159
|
+
| string
|
|
1160
|
+
| ArrayBuffer
|
|
1161
|
+
| URL
|
|
1162
|
+
| DataContent
|
|
1163
|
+
| ProviderReference
|
|
1164
|
+
| FileData,
|
|
1165
|
+
): URL | DataContent | ProviderReference | FileData {
|
|
872
1166
|
if (urlOrString instanceof URL) {
|
|
873
1167
|
return urlOrString;
|
|
874
1168
|
}
|
|
@@ -884,37 +1178,107 @@ export function toModelMessageDataOrUrl(
|
|
|
884
1178
|
return urlOrString;
|
|
885
1179
|
}
|
|
886
1180
|
|
|
1181
|
+
type StoredProviderReference = Infer<typeof vProviderReference>;
|
|
1182
|
+
|
|
1183
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
1184
|
+
return typeof value === "object" && value !== null;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
function isProviderReference(value: unknown): value is ProviderReference {
|
|
1188
|
+
return (
|
|
1189
|
+
isRecord(value) &&
|
|
1190
|
+
!(value instanceof ArrayBuffer) &&
|
|
1191
|
+
!(value instanceof Uint8Array) &&
|
|
1192
|
+
!(value instanceof URL) &&
|
|
1193
|
+
!("type" in value) &&
|
|
1194
|
+
Object.values(value).every((id) => typeof id === "string")
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
function isStoredProviderReference(
|
|
1199
|
+
value: unknown,
|
|
1200
|
+
): value is StoredProviderReference {
|
|
1201
|
+
return (
|
|
1202
|
+
isRecord(value) &&
|
|
1203
|
+
value.type === "reference" &&
|
|
1204
|
+
isProviderReference(value.reference)
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function toStoredProviderReference(
|
|
1209
|
+
value: unknown,
|
|
1210
|
+
): StoredProviderReference | undefined {
|
|
1211
|
+
if (isStoredProviderReference(value)) return value;
|
|
1212
|
+
if (isProviderReference(value))
|
|
1213
|
+
return { type: "reference", reference: value };
|
|
1214
|
+
if (
|
|
1215
|
+
isRecord(value) &&
|
|
1216
|
+
value.type === "reference" &&
|
|
1217
|
+
isProviderReference(value.reference)
|
|
1218
|
+
) {
|
|
1219
|
+
return { type: "reference", reference: value.reference };
|
|
1220
|
+
}
|
|
1221
|
+
return undefined;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
function isFileReference(
|
|
1225
|
+
value: unknown,
|
|
1226
|
+
): value is { type: "reference"; reference: ProviderReference } {
|
|
1227
|
+
return (
|
|
1228
|
+
isRecord(value) &&
|
|
1229
|
+
value.type === "reference" &&
|
|
1230
|
+
isProviderReference(value.reference)
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
887
1234
|
export function toUIFilePart(part: ImagePart | FilePart): FileUIPart {
|
|
888
1235
|
const dataOrUrl = part.type === "image" ? part.image : part.data;
|
|
889
|
-
const
|
|
890
|
-
dataOrUrl
|
|
891
|
-
|
|
892
|
-
|
|
1236
|
+
const providerReference = isProviderReference(dataOrUrl)
|
|
1237
|
+
? dataOrUrl
|
|
1238
|
+
: isFileReference(dataOrUrl)
|
|
1239
|
+
? dataOrUrl.reference
|
|
1240
|
+
: undefined;
|
|
1241
|
+
const url = providerReference
|
|
1242
|
+
? ""
|
|
1243
|
+
: toUIFileUrl(dataOrUrl, part.mediaType ?? "application/octet-stream");
|
|
893
1244
|
|
|
894
1245
|
return {
|
|
895
1246
|
type: "file",
|
|
896
1247
|
mediaType: part.mediaType!,
|
|
897
1248
|
filename: part.type === "file" ? part.filename : undefined,
|
|
898
1249
|
url,
|
|
1250
|
+
...(providerReference !== undefined ? { providerReference } : {}),
|
|
899
1251
|
providerMetadata: part.providerOptions,
|
|
900
1252
|
};
|
|
901
1253
|
}
|
|
902
1254
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1255
|
+
function toUIFileUrl(data: unknown, mediaType: string): string {
|
|
1256
|
+
if (isFileReference(data)) return "";
|
|
1257
|
+
if (isRecord(data) && typeof data.type === "string") {
|
|
1258
|
+
switch (data.type) {
|
|
1259
|
+
case "url":
|
|
1260
|
+
return (data.url as URL).toString();
|
|
1261
|
+
case "data":
|
|
1262
|
+
return toUIFileDataUrl(data.data as DataContent, mediaType);
|
|
1263
|
+
case "text":
|
|
1264
|
+
return toUIFileDataUrl(
|
|
1265
|
+
new TextEncoder().encode(data.text as string),
|
|
1266
|
+
mediaType,
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
if (data instanceof URL) return data.toString();
|
|
1271
|
+
if (typeof data === "string") return data;
|
|
1272
|
+
return toUIFileDataUrl(data as DataContent, mediaType);
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
function toUIFileDataUrl(data: DataContent, mediaType: string): string {
|
|
1276
|
+
if (typeof data === "string") {
|
|
1277
|
+
return data.startsWith("data:") ? data : `data:${mediaType};base64,${data}`;
|
|
1278
|
+
}
|
|
1279
|
+
const bytes =
|
|
1280
|
+
data instanceof ArrayBuffer
|
|
1281
|
+
? new Uint8Array(data)
|
|
1282
|
+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
1283
|
+
return `data:${mediaType};base64,${convertUint8ArrayToBase64(bytes)}`;
|
|
1284
|
+
}
|