@convex-dev/agent 0.6.3 → 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/apiKeys.js +5 -5
- package/dist/component/apiKeys.js.map +1 -1
- package/dist/component/files.d.ts.map +1 -1
- package/dist/component/files.js +13 -11
- package/dist/component/files.js.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 +83 -47
- 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 +46 -47
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts.map +1 -1
- package/dist/component/threads.js +8 -9
- package/dist/component/threads.js.map +1 -1
- package/dist/component/users.js +2 -2
- package/dist/component/users.js.map +1 -1
- package/dist/component/vector/index.d.ts.map +1 -1
- package/dist/component/vector/index.js +14 -8
- package/dist/component/vector/index.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 +593 -134
- package/dist/{client → vercel/client}/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/{client → vercel/client}/definePlaygroundAPI.js +13 -9
- 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/vercel/deltas.d.ts +31 -0
- package/dist/vercel/deltas.d.ts.map +1 -0
- package/dist/vercel/deltas.js +525 -0
- package/dist/vercel/deltas.js.map +1 -0
- package/dist/{client → vercel}/index.d.ts +484 -97
- package/dist/vercel/index.d.ts.map +1 -0
- package/dist/{client → vercel}/index.js +65 -38
- package/dist/vercel/index.js.map +1 -0
- package/dist/{mapping.d.ts → vercel/mapping.d.ts} +5 -13
- package/dist/vercel/mapping.d.ts.map +1 -0
- package/dist/{mapping.js → vercel/mapping.js} +411 -112
- 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/vercel/react/useStreamingUIMessages.js +112 -0
- 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 +2 -1
- package/dist/vercel/react/useUIMessages.d.ts.map +1 -0
- package/dist/{react → vercel/react}/useUIMessages.js +8 -4
- package/dist/vercel/react/useUIMessages.js.map +1 -0
- package/package.json +30 -22
- package/src/client/messages.ts +5 -107
- package/src/client/types.ts +0 -621
- package/src/component/_generated/component.ts +1089 -48
- package/src/component/apiKeys.ts +5 -5
- package/src/component/files.test.ts +1 -1
- package/src/component/files.ts +14 -12
- package/src/component/messages.test.ts +273 -1
- package/src/component/messages.ts +99 -57
- package/src/component/streams.ts +80 -64
- package/src/component/threads.ts +12 -9
- package/src/component/users.ts +2 -2
- package/src/component/vector/index.ts +14 -7
- 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} +96 -5
- package/src/{client → vercel/client}/approval.test.ts +48 -19
- package/src/{client → vercel/client}/createTool.ts +63 -23
- package/src/{client → vercel/client}/definePlaygroundAPI.ts +44 -29
- package/src/{client → vercel/client}/files.ts +2 -2
- package/src/{client → vercel/client}/index.test.ts +162 -3
- 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 +7 -4
- 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 +40 -115
- 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/vercel/deltas.test.ts +898 -0
- package/src/vercel/deltas.ts +633 -0
- package/src/{fromUIMessages.test.ts → vercel/fromUIMessages.test.ts} +17 -1
- package/src/{client → vercel}/index.ts +169 -62
- package/src/vercel/mapping.test.ts +965 -0
- package/src/{mapping.ts → vercel/mapping.ts} +501 -131
- 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 +67 -35
- package/src/{react → vercel/react}/useThreadMessages.ts +2 -2
- package/src/{react → vercel/react}/useUIMessages.test.ts +80 -1
- package/src/{react → vercel/react}/useUIMessages.ts +13 -5
- 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 +0 -43
- package/dist/deltas.d.ts.map +0 -1
- package/dist/deltas.js +0 -446
- 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 +0 -92
- 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/src/deltas.test.ts +0 -626
- package/src/deltas.ts +0 -569
- package/src/mapping.test.ts +0 -402
- /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
|
@@ -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,28 +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 messages from a step using a heuristic to determine
|
|
317
|
-
* which response messages are new (last 1-2 messages).
|
|
318
|
-
*/
|
|
319
|
-
export async function serializeNewMessagesInStep<TOOLS extends ToolSet>(
|
|
320
|
-
ctx: ActionCtx,
|
|
321
|
-
component: AgentComponent,
|
|
322
|
-
step: StepResult<TOOLS>,
|
|
323
|
-
model: ModelOrMetadata | undefined,
|
|
324
|
-
): Promise<{ messages: MessageWithMetadata[] }> {
|
|
325
|
-
const hasToolMessage = step.response.messages.at(-1)?.role === "tool";
|
|
326
|
-
let messagesToSerialize: ModelMessage[];
|
|
327
|
-
if (hasToolMessage) {
|
|
328
|
-
messagesToSerialize = step.response.messages.slice(-2);
|
|
329
|
-
} else if (step.content.length) {
|
|
330
|
-
messagesToSerialize = step.response.messages.slice(-1);
|
|
331
|
-
} else {
|
|
332
|
-
messagesToSerialize = [{ role: "assistant" as const, content: [] }];
|
|
333
|
-
}
|
|
334
|
-
return serializeStepMessages(ctx, component, step, model, messagesToSerialize);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
296
|
async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
338
297
|
ctx: ActionCtx,
|
|
339
298
|
component: AgentComponent,
|
|
@@ -344,12 +303,15 @@ async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
|
344
303
|
// If there are tool results, there's another message with the tool results
|
|
345
304
|
// ref: https://github.com/vercel/ai/blob/main/packages/ai/src/generate-text/to-response-messages.ts#L120
|
|
346
305
|
const hasToolMessage = step.response.messages.at(-1)?.role === "tool";
|
|
306
|
+
const resolvedModel = step.model ?? model;
|
|
347
307
|
const assistantFields = {
|
|
348
|
-
model:
|
|
349
|
-
provider:
|
|
308
|
+
model: resolvedModel ? getModelName(resolvedModel) : undefined,
|
|
309
|
+
provider: resolvedModel ? getProviderName(resolvedModel) : undefined,
|
|
350
310
|
providerMetadata: step.providerMetadata,
|
|
351
311
|
reasoning: step.reasoningText,
|
|
352
|
-
reasoningDetails: step.reasoning
|
|
312
|
+
reasoningDetails: step.reasoning.filter(
|
|
313
|
+
(part) => part.type !== "reasoning-file",
|
|
314
|
+
),
|
|
353
315
|
usage: serializeUsage(step.usage),
|
|
354
316
|
warnings: serializeWarnings(step.warnings),
|
|
355
317
|
finishReason: step.finishReason,
|
|
@@ -369,7 +331,6 @@ async function serializeStepMessages<TOOLS extends ToolSet>(
|
|
|
369
331
|
});
|
|
370
332
|
}),
|
|
371
333
|
);
|
|
372
|
-
// TODO: capture step.files separately?
|
|
373
334
|
return { messages };
|
|
374
335
|
}
|
|
375
336
|
|
|
@@ -442,7 +403,9 @@ export async function serializeContent(
|
|
|
442
403
|
} satisfies Infer<typeof vTextPart>;
|
|
443
404
|
}
|
|
444
405
|
case "image": {
|
|
445
|
-
let image =
|
|
406
|
+
let image =
|
|
407
|
+
toStoredProviderReference(part.image) ??
|
|
408
|
+
serializeDataOrUrl(part.image);
|
|
446
409
|
if (
|
|
447
410
|
image instanceof ArrayBuffer &&
|
|
448
411
|
image.byteLength > MAX_FILE_SIZE
|
|
@@ -465,7 +428,9 @@ export async function serializeContent(
|
|
|
465
428
|
} satisfies Infer<typeof vImagePart>;
|
|
466
429
|
}
|
|
467
430
|
case "file": {
|
|
468
|
-
let data =
|
|
431
|
+
let data =
|
|
432
|
+
toStoredProviderReference(part.data) ??
|
|
433
|
+
serializeDataOrUrl(part.data);
|
|
469
434
|
if (data instanceof ArrayBuffer && data.byteLength > MAX_FILE_SIZE) {
|
|
470
435
|
const { file } = await storeFile(
|
|
471
436
|
ctx,
|
|
@@ -494,19 +459,41 @@ export async function serializeContent(
|
|
|
494
459
|
toolCallId: part.toolCallId,
|
|
495
460
|
toolName: part.toolName,
|
|
496
461
|
providerExecuted: part.providerExecuted,
|
|
462
|
+
title: "title" in part ? part.title : undefined,
|
|
463
|
+
toolMetadata:
|
|
464
|
+
"toolMetadata" in part ? part.toolMetadata : undefined,
|
|
497
465
|
...metadata,
|
|
498
466
|
} satisfies Infer<typeof vToolCallPart>;
|
|
499
467
|
}
|
|
500
468
|
case "tool-result": {
|
|
501
|
-
return
|
|
469
|
+
return serializeToolResult(part, metadata);
|
|
502
470
|
}
|
|
503
471
|
case "reasoning": {
|
|
504
472
|
return {
|
|
505
473
|
type: part.type,
|
|
506
474
|
text: part.text,
|
|
475
|
+
signature:
|
|
476
|
+
"signature" in part && typeof part.signature === "string"
|
|
477
|
+
? part.signature
|
|
478
|
+
: undefined,
|
|
507
479
|
...metadata,
|
|
508
480
|
} satisfies Infer<typeof vReasoningPart>;
|
|
509
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
|
+
}
|
|
510
497
|
// Not in current generation output, but could be in historical messages
|
|
511
498
|
case "redacted-reasoning": {
|
|
512
499
|
return {
|
|
@@ -523,6 +510,8 @@ export async function serializeContent(
|
|
|
523
510
|
type: part.type,
|
|
524
511
|
approvalId: part.approvalId,
|
|
525
512
|
toolCallId: part.toolCallId,
|
|
513
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
514
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
526
515
|
...metadata,
|
|
527
516
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
528
517
|
}
|
|
@@ -571,12 +560,16 @@ export function fromModelMessageContent(content: Content): Message["content"] {
|
|
|
571
560
|
type: part.type,
|
|
572
561
|
mediaType: getMimeOrMediaType(part),
|
|
573
562
|
...metadata,
|
|
574
|
-
image:
|
|
563
|
+
image:
|
|
564
|
+
toStoredProviderReference(part.image) ??
|
|
565
|
+
serializeDataOrUrl(part.image),
|
|
575
566
|
} satisfies Infer<typeof vImagePart>;
|
|
576
567
|
case "file":
|
|
577
568
|
return {
|
|
578
569
|
type: part.type,
|
|
579
|
-
data:
|
|
570
|
+
data:
|
|
571
|
+
toStoredProviderReference(part.data) ??
|
|
572
|
+
serializeDataOrUrl(part.data),
|
|
580
573
|
filename: part.filename,
|
|
581
574
|
mediaType: getMimeOrMediaType(part)!,
|
|
582
575
|
...metadata,
|
|
@@ -594,18 +587,38 @@ export function fromModelMessageContent(content: Content): Message["content"] {
|
|
|
594
587
|
...metadata,
|
|
595
588
|
} satisfies Infer<typeof vToolCallPart>;
|
|
596
589
|
case "tool-result":
|
|
597
|
-
return
|
|
590
|
+
return serializeToolResult(part, metadata);
|
|
598
591
|
case "reasoning":
|
|
599
592
|
return {
|
|
600
593
|
type: part.type,
|
|
601
594
|
text: part.text,
|
|
595
|
+
signature:
|
|
596
|
+
"signature" in part && typeof part.signature === "string"
|
|
597
|
+
? part.signature
|
|
598
|
+
: undefined,
|
|
602
599
|
...metadata,
|
|
603
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>;
|
|
604
615
|
case "tool-approval-request":
|
|
605
616
|
return {
|
|
606
617
|
type: part.type,
|
|
607
618
|
approvalId: part.approvalId,
|
|
608
619
|
toolCallId: part.toolCallId,
|
|
620
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
621
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
609
622
|
...metadata,
|
|
610
623
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
611
624
|
case "tool-approval-response":
|
|
@@ -653,14 +666,18 @@ export function toModelMessageContent(
|
|
|
653
666
|
case "image":
|
|
654
667
|
return {
|
|
655
668
|
type: part.type,
|
|
656
|
-
image:
|
|
669
|
+
image: (isStoredProviderReference(part.image)
|
|
670
|
+
? part.image.reference
|
|
671
|
+
: toModelMessageDataOrUrl(part.image)) as ImagePart["image"],
|
|
657
672
|
mediaType: getMimeOrMediaType(part),
|
|
658
673
|
...metadata,
|
|
659
674
|
} satisfies ImagePart;
|
|
660
675
|
case "file":
|
|
661
676
|
return {
|
|
662
677
|
type: part.type,
|
|
663
|
-
data:
|
|
678
|
+
data: (isStoredProviderReference(part.data)
|
|
679
|
+
? { type: "reference" as const, reference: part.data.reference }
|
|
680
|
+
: toModelMessageDataOrUrl(part.data)) as FilePart["data"],
|
|
664
681
|
filename: part.filename,
|
|
665
682
|
mediaType: getMimeOrMediaType(part)!,
|
|
666
683
|
...metadata,
|
|
@@ -678,7 +695,7 @@ export function toModelMessageContent(
|
|
|
678
695
|
} satisfies ToolCallPart;
|
|
679
696
|
}
|
|
680
697
|
case "tool-result": {
|
|
681
|
-
return
|
|
698
|
+
return deserializeToolResult(part, metadata);
|
|
682
699
|
}
|
|
683
700
|
case "reasoning":
|
|
684
701
|
return {
|
|
@@ -686,23 +703,32 @@ export function toModelMessageContent(
|
|
|
686
703
|
text: part.text,
|
|
687
704
|
...metadata,
|
|
688
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 };
|
|
689
717
|
case "redacted-reasoning":
|
|
690
|
-
//
|
|
718
|
+
// Legacy v5 part: round-trip the redacted payload via providerOptions.
|
|
691
719
|
return {
|
|
692
720
|
type: "reasoning",
|
|
693
721
|
text: "",
|
|
694
722
|
...metadata,
|
|
695
723
|
providerOptions: metadata.providerOptions
|
|
696
|
-
?
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
],
|
|
703
|
-
),
|
|
724
|
+
? Object.fromEntries(
|
|
725
|
+
Object.entries(metadata.providerOptions ?? {}).map(
|
|
726
|
+
([key, value]) => [
|
|
727
|
+
key,
|
|
728
|
+
{ ...value, redactedData: part.data },
|
|
729
|
+
],
|
|
704
730
|
),
|
|
705
|
-
|
|
731
|
+
)
|
|
706
732
|
: undefined,
|
|
707
733
|
} satisfies ReasoningPart;
|
|
708
734
|
case "source":
|
|
@@ -712,6 +738,8 @@ export function toModelMessageContent(
|
|
|
712
738
|
type: part.type,
|
|
713
739
|
approvalId: part.approvalId,
|
|
714
740
|
toolCallId: part.toolCallId,
|
|
741
|
+
isAutomatic: "isAutomatic" in part ? part.isAutomatic : undefined,
|
|
742
|
+
signature: "signature" in part ? part.signature : undefined,
|
|
715
743
|
...metadata,
|
|
716
744
|
} satisfies Infer<typeof vToolApprovalRequest>;
|
|
717
745
|
case "tool-approval-response":
|
|
@@ -740,7 +768,7 @@ export function normalizeToolOutput(
|
|
|
740
768
|
};
|
|
741
769
|
}
|
|
742
770
|
if (validate(vToolResultOutput, result)) {
|
|
743
|
-
return result;
|
|
771
|
+
return result as unknown as ToolResultOutput;
|
|
744
772
|
}
|
|
745
773
|
return {
|
|
746
774
|
type: "json",
|
|
@@ -748,28 +776,277 @@ export function normalizeToolOutput(
|
|
|
748
776
|
};
|
|
749
777
|
}
|
|
750
778
|
|
|
751
|
-
function
|
|
779
|
+
function serializeToolResult(
|
|
752
780
|
part: ToolResultPart | Infer<typeof vToolResultPart>,
|
|
753
781
|
metadata: {
|
|
754
782
|
providerOptions?: ProviderOptions;
|
|
755
783
|
providerMetadata?: ProviderMetadata;
|
|
756
784
|
},
|
|
757
|
-
):
|
|
785
|
+
): Infer<typeof vToolResultPart> {
|
|
758
786
|
return {
|
|
759
787
|
type: part.type,
|
|
760
|
-
output:
|
|
761
|
-
|
|
762
|
-
? (part.output
|
|
763
|
-
: normalizeToolOutput(
|
|
764
|
-
|
|
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>),
|
|
765
794
|
toolCallId: part.toolCallId,
|
|
766
795
|
toolName: part.toolName,
|
|
796
|
+
...("providerExecuted" in part
|
|
797
|
+
? { providerExecuted: part.providerExecuted }
|
|
798
|
+
: {}),
|
|
767
799
|
// Preserve isError flag for error reporting
|
|
768
800
|
...("isError" in part && part.isError ? { isError: true } : {}),
|
|
769
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,
|
|
770
822
|
} satisfies ToolResultPart;
|
|
771
823
|
}
|
|
772
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
|
+
|
|
773
1050
|
/**
|
|
774
1051
|
* Return a best-guess MIME type based on the magic-number signature
|
|
775
1052
|
* found at the start of an ArrayBuffer.
|
|
@@ -843,7 +1120,7 @@ export function guessMimeType(buf: ArrayBuffer | string): string {
|
|
|
843
1120
|
* @returns The serialized data as an ArrayBuffer or the URL as a string.
|
|
844
1121
|
*/
|
|
845
1122
|
export function serializeDataOrUrl(
|
|
846
|
-
dataOrUrl: DataContent | URL,
|
|
1123
|
+
dataOrUrl: DataContent | URL | ProviderReference | FileData,
|
|
847
1124
|
): ArrayBuffer | string {
|
|
848
1125
|
if (typeof dataOrUrl === "string") {
|
|
849
1126
|
return dataOrUrl;
|
|
@@ -854,6 +1131,23 @@ export function serializeDataOrUrl(
|
|
|
854
1131
|
if (dataOrUrl instanceof URL) {
|
|
855
1132
|
return dataOrUrl.toString();
|
|
856
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
|
+
}
|
|
857
1151
|
return dataOrUrl.buffer.slice(
|
|
858
1152
|
dataOrUrl.byteOffset,
|
|
859
1153
|
dataOrUrl.byteOffset + dataOrUrl.byteLength,
|
|
@@ -861,8 +1155,14 @@ export function serializeDataOrUrl(
|
|
|
861
1155
|
}
|
|
862
1156
|
|
|
863
1157
|
export function toModelMessageDataOrUrl(
|
|
864
|
-
urlOrString:
|
|
865
|
-
|
|
1158
|
+
urlOrString:
|
|
1159
|
+
| string
|
|
1160
|
+
| ArrayBuffer
|
|
1161
|
+
| URL
|
|
1162
|
+
| DataContent
|
|
1163
|
+
| ProviderReference
|
|
1164
|
+
| FileData,
|
|
1165
|
+
): URL | DataContent | ProviderReference | FileData {
|
|
866
1166
|
if (urlOrString instanceof URL) {
|
|
867
1167
|
return urlOrString;
|
|
868
1168
|
}
|
|
@@ -878,37 +1178,107 @@ export function toModelMessageDataOrUrl(
|
|
|
878
1178
|
return urlOrString;
|
|
879
1179
|
}
|
|
880
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
|
+
|
|
881
1234
|
export function toUIFilePart(part: ImagePart | FilePart): FileUIPart {
|
|
882
1235
|
const dataOrUrl = part.type === "image" ? part.image : part.data;
|
|
883
|
-
const
|
|
884
|
-
dataOrUrl
|
|
885
|
-
|
|
886
|
-
|
|
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");
|
|
887
1244
|
|
|
888
1245
|
return {
|
|
889
1246
|
type: "file",
|
|
890
1247
|
mediaType: part.mediaType!,
|
|
891
1248
|
filename: part.type === "file" ? part.filename : undefined,
|
|
892
1249
|
url,
|
|
1250
|
+
...(providerReference !== undefined ? { providerReference } : {}),
|
|
893
1251
|
providerMetadata: part.providerOptions,
|
|
894
1252
|
};
|
|
895
1253
|
}
|
|
896
1254
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
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
|
+
}
|