@convex-dev/agent 0.5.0-alpha.1 → 0.6.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/README.md +32 -27
- package/dist/UIMessages.d.ts +46 -0
- package/dist/UIMessages.d.ts.map +1 -0
- package/dist/UIMessages.js +546 -0
- package/dist/UIMessages.js.map +1 -0
- package/dist/client/createTool.d.ts +129 -27
- package/dist/client/createTool.d.ts.map +1 -1
- package/dist/client/createTool.js +66 -12
- package/dist/client/createTool.js.map +1 -1
- package/dist/client/defaultComponent.d.ts +11 -0
- package/dist/client/defaultComponent.d.ts.map +1 -0
- package/dist/client/defaultComponent.js +7 -0
- package/dist/client/defaultComponent.js.map +1 -0
- package/dist/client/definePlaygroundAPI.d.ts +1323 -192
- package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/client/definePlaygroundAPI.js +52 -28
- package/dist/client/definePlaygroundAPI.js.map +1 -1
- package/dist/client/files.d.ts +20 -7
- package/dist/client/files.d.ts.map +1 -1
- package/dist/client/files.js +68 -11
- package/dist/client/files.js.map +1 -1
- package/dist/client/index.d.ts +1056 -965
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +242 -748
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +461 -0
- package/dist/client/messages.d.ts.map +1 -0
- package/dist/client/messages.js +106 -0
- package/dist/client/messages.js.map +1 -0
- package/dist/client/mockModel.d.ts +42 -0
- package/dist/client/mockModel.d.ts.map +1 -0
- package/dist/client/mockModel.js +175 -0
- package/dist/client/mockModel.js.map +1 -0
- package/dist/client/saveInputMessages.d.ts +20 -0
- package/dist/client/saveInputMessages.d.ts.map +1 -0
- package/dist/client/saveInputMessages.js +58 -0
- package/dist/client/saveInputMessages.js.map +1 -0
- package/dist/client/search.d.ts +346 -35
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/search.js +350 -39
- package/dist/client/search.js.map +1 -1
- package/dist/client/start.d.ts +84 -0
- package/dist/client/start.d.ts.map +1 -0
- package/dist/client/start.js +171 -0
- package/dist/client/start.js.map +1 -0
- package/dist/client/streamText.d.ts +46 -0
- package/dist/client/streamText.d.ts.map +1 -0
- package/dist/client/streamText.js +93 -0
- package/dist/client/streamText.js.map +1 -0
- package/dist/client/streaming.d.ts +3705 -32
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +141 -59
- package/dist/client/streaming.js.map +1 -1
- package/dist/client/threads.d.ts +46 -0
- package/dist/client/threads.d.ts.map +1 -0
- package/dist/client/threads.js +49 -0
- package/dist/client/threads.js.map +1 -0
- package/dist/client/types.d.ts +265 -128
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/utils.d.ts +4 -0
- package/dist/client/utils.d.ts.map +1 -0
- package/dist/client/utils.js +21 -0
- package/dist/client/utils.js.map +1 -0
- package/dist/component/_generated/api.d.ts +24 -2178
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js +10 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +3119 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +4 -18
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +10 -38
- package/dist/component/_generated/server.d.ts.map +1 -1
- package/dist/component/_generated/server.js +9 -5
- package/dist/component/_generated/server.js.map +1 -1
- package/dist/component/files.d.ts +16 -10
- package/dist/component/files.d.ts.map +1 -1
- package/dist/component/files.js +10 -2
- package/dist/component/files.js.map +1 -1
- package/dist/component/messages.d.ts +2553 -342
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +387 -154
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +5697 -3584
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +18 -41
- package/dist/component/schema.js.map +1 -1
- package/dist/component/streams.d.ts +35 -335
- package/dist/component/streams.d.ts.map +1 -1
- package/dist/component/streams.js +114 -73
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts +16 -16
- package/dist/component/users.d.ts +4 -4
- package/dist/component/vector/index.d.ts +1 -1
- package/dist/component/vector/index.d.ts.map +1 -1
- package/dist/component/vector/index.js +1 -3
- package/dist/component/vector/index.js.map +1 -1
- package/dist/deltas.d.ts +43 -0
- package/dist/deltas.d.ts.map +1 -0
- package/dist/deltas.js +447 -0
- package/dist/deltas.js.map +1 -0
- package/dist/mapping.d.ts +20 -20
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +313 -96
- package/dist/mapping.js.map +1 -1
- package/dist/react/SmoothText.d.ts +5 -0
- package/dist/react/SmoothText.d.ts.map +1 -0
- package/dist/react/SmoothText.js +6 -0
- package/dist/react/SmoothText.js.map +1 -0
- package/dist/react/index.d.ts +5 -77
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +6 -160
- package/dist/react/index.js.map +1 -1
- package/dist/react/optimisticallySendMessage.d.ts +36 -3
- package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
- package/dist/react/optimisticallySendMessage.js +35 -9
- package/dist/react/optimisticallySendMessage.js.map +1 -1
- package/dist/react/types.d.ts +4 -18
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/useDeltaStreams.d.ts +10 -0
- package/dist/react/useDeltaStreams.d.ts.map +1 -0
- package/dist/react/useDeltaStreams.js +101 -0
- package/dist/react/useDeltaStreams.js.map +1 -0
- package/dist/react/useSmoothText.d.ts +13 -12
- package/dist/react/useSmoothText.d.ts.map +1 -1
- package/dist/react/useSmoothText.js +32 -15
- package/dist/react/useSmoothText.js.map +1 -1
- package/dist/react/useStreamingUIMessages.d.ts +22 -0
- package/dist/react/useStreamingUIMessages.d.ts.map +1 -0
- package/dist/react/useStreamingUIMessages.js +92 -0
- package/dist/react/useStreamingUIMessages.js.map +1 -0
- package/dist/react/useThreadMessages.d.ts +104 -0
- package/dist/react/useThreadMessages.d.ts.map +1 -0
- package/dist/react/useThreadMessages.js +148 -0
- package/dist/react/useThreadMessages.js.map +1 -0
- package/dist/react/useUIMessages.d.ts +96 -0
- package/dist/react/useUIMessages.d.ts.map +1 -0
- package/dist/react/useUIMessages.js +108 -0
- package/dist/react/useUIMessages.js.map +1 -0
- package/dist/shared.d.ts +20 -4
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +45 -8
- package/dist/shared.js.map +1 -1
- package/dist/validators.d.ts +22981 -5666
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +245 -137
- package/dist/validators.js.map +1 -1
- package/package.json +98 -50
- package/src/UIMessages.combineUIMessages.test.ts +239 -0
- package/src/UIMessages.test.ts +273 -0
- package/src/UIMessages.ts +739 -0
- package/src/client/createTool.ts +293 -76
- package/src/client/defaultComponent.ts +17 -0
- package/src/client/definePlaygroundAPI.ts +67 -31
- package/src/client/files.ts +100 -20
- package/src/client/index.test.ts +40 -85
- package/src/client/index.ts +520 -1290
- package/src/client/messages.ts +237 -0
- package/src/client/mockModel.ts +245 -0
- package/src/client/saveInputMessages.test.ts +583 -0
- package/src/client/saveInputMessages.ts +101 -0
- package/src/client/search.test.ts +1207 -0
- package/src/client/search.ts +577 -70
- package/src/client/start.ts +310 -0
- package/src/client/streamText.ts +163 -0
- package/src/client/streaming.test.ts +186 -0
- package/src/client/streaming.ts +219 -97
- package/src/client/threads.ts +83 -0
- package/src/client/types.ts +368 -219
- package/src/client/utils.ts +27 -0
- package/src/component/_generated/api.ts +64 -0
- package/src/component/_generated/component.ts +4913 -0
- package/src/component/_generated/{server.d.ts → server.ts} +33 -21
- package/src/component/files.ts +11 -2
- package/src/component/messages.test.ts +195 -51
- package/src/component/messages.ts +490 -201
- package/src/component/schema.ts +20 -46
- package/src/component/setup.test.ts +7 -0
- package/src/component/streams.ts +184 -83
- package/src/component/users.test.ts +0 -1
- package/src/component/vector/index.ts +1 -3
- package/src/deltas.test.ts +626 -0
- package/src/deltas.ts +570 -0
- package/src/fromUIMessages.test.ts +497 -0
- package/src/mapping.test.ts +103 -6
- package/src/mapping.ts +422 -161
- package/src/react/SmoothText.tsx +9 -0
- package/src/react/index.ts +10 -230
- package/src/react/optimisticallySendMessage.ts +55 -12
- package/src/react/types.ts +6 -39
- package/src/react/useDeltaStreams.ts +154 -0
- package/src/react/useSmoothText.ts +56 -36
- package/src/react/useStreamingUIMessages.ts +143 -0
- package/src/react/useThreadMessages.ts +262 -0
- package/src/react/useUIMessages.test.ts +255 -0
- package/src/react/useUIMessages.ts +195 -0
- package/src/shared.ts +88 -12
- package/src/test.ts +18 -0
- package/src/toUIMessages.test.ts +1269 -0
- package/src/validators.test.ts +18 -19
- package/src/validators.ts +325 -185
- package/dist/client/_generated/_ignore.d.ts +0 -1
- package/dist/client/_generated/_ignore.d.ts.map +0 -1
- package/dist/client/_generated/_ignore.js +0 -3
- package/dist/client/_generated/_ignore.js.map +0 -1
- package/dist/client/listMessages.d.ts +0 -22
- package/dist/client/listMessages.d.ts.map +0 -1
- package/dist/client/listMessages.js +0 -25
- package/dist/client/listMessages.js.map +0 -1
- package/dist/package.json +0 -3
- package/dist/react/deltas.d.ts +0 -26
- package/dist/react/deltas.d.ts.map +0 -1
- package/dist/react/deltas.js +0 -384
- package/dist/react/deltas.js.map +0 -1
- package/dist/react/toUIMessages.d.ts +0 -15
- package/dist/react/toUIMessages.d.ts.map +0 -1
- package/dist/react/toUIMessages.js +0 -211
- package/dist/react/toUIMessages.js.map +0 -1
- package/src/client/listMessages.ts +0 -38
- package/src/component/_generated/api.d.ts +0 -2202
- package/src/component/_generated/api.js +0 -23
- package/src/component/_generated/server.js +0 -90
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/src/react/deltas.test.ts +0 -315
- package/src/react/deltas.ts +0 -478
- package/src/react/toUIMessages.test.ts +0 -420
- package/src/react/toUIMessages.ts +0 -253
- package/src/vitest.config.ts +0 -7
- /package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +0 -0
package/dist/mapping.js
CHANGED
|
@@ -1,38 +1,84 @@
|
|
|
1
1
|
import {} from "ai";
|
|
2
|
+
import { vMessageWithMetadata, vToolResultOutput, vToolApprovalRequest, vToolApprovalResponse, } from "./validators.js";
|
|
2
3
|
import { MAX_FILE_SIZE, storeFile } from "./client/files.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { convertUint8ArrayToBase64, } from "@ai-sdk/provider-utils";
|
|
5
|
+
import { parse, validate } from "convex-helpers/validators";
|
|
6
|
+
import { getModelName, getProviderName, } from "./shared.js";
|
|
7
|
+
export async function serializeMessage(ctx, component, message) {
|
|
6
8
|
const { content, fileIds } = await serializeContent(ctx, component, message.content);
|
|
7
9
|
return {
|
|
8
10
|
message: {
|
|
9
|
-
|
|
11
|
+
role: message.role,
|
|
10
12
|
content,
|
|
13
|
+
...(message.providerOptions
|
|
14
|
+
? { providerOptions: message.providerOptions }
|
|
15
|
+
: {}),
|
|
11
16
|
},
|
|
12
17
|
fileIds,
|
|
13
18
|
};
|
|
14
19
|
}
|
|
15
|
-
|
|
20
|
+
// Similar to serializeMessage, but doesn't save any files and is looser
|
|
21
|
+
// For use on the frontend / in synchronous environments.
|
|
22
|
+
export function fromModelMessage(message) {
|
|
23
|
+
const content = fromModelMessageContent(message.content);
|
|
24
|
+
return {
|
|
25
|
+
role: message.role,
|
|
26
|
+
content,
|
|
27
|
+
...(message.providerOptions
|
|
28
|
+
? { providerOptions: message.providerOptions }
|
|
29
|
+
: {}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function serializeOrThrow(message) {
|
|
33
|
+
const { content } = await serializeContent({}, {}, message.content);
|
|
34
|
+
return {
|
|
35
|
+
role: message.role,
|
|
36
|
+
content,
|
|
37
|
+
...(message.providerOptions
|
|
38
|
+
? { providerOptions: message.providerOptions }
|
|
39
|
+
: {}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function toModelMessage(message) {
|
|
16
43
|
return {
|
|
17
44
|
...message,
|
|
18
|
-
content:
|
|
45
|
+
content: toModelMessageContent(message.content),
|
|
19
46
|
};
|
|
20
47
|
}
|
|
48
|
+
export function docsToModelMessages(messages) {
|
|
49
|
+
return messages
|
|
50
|
+
.map((m) => m.message)
|
|
51
|
+
.filter((m) => !!m)
|
|
52
|
+
.filter((m) => !!m.content.length)
|
|
53
|
+
.map(toModelMessage);
|
|
54
|
+
}
|
|
21
55
|
export function serializeUsage(usage) {
|
|
22
56
|
return {
|
|
23
57
|
promptTokens: usage.inputTokens ?? 0,
|
|
24
58
|
completionTokens: usage.outputTokens ?? 0,
|
|
25
59
|
totalTokens: usage.totalTokens ?? 0,
|
|
26
60
|
reasoningTokens: usage.reasoningTokens,
|
|
61
|
+
cachedInputTokens: usage.cachedInputTokens,
|
|
27
62
|
};
|
|
28
63
|
}
|
|
29
|
-
export function
|
|
64
|
+
export function toModelMessageUsage(usage) {
|
|
30
65
|
return {
|
|
31
66
|
inputTokens: usage.promptTokens,
|
|
32
67
|
outputTokens: usage.completionTokens,
|
|
33
68
|
totalTokens: usage.totalTokens,
|
|
34
69
|
reasoningTokens: usage.reasoningTokens,
|
|
35
70
|
cachedInputTokens: usage.cachedInputTokens,
|
|
71
|
+
// These detail fields are required by LanguageModelUsage type but we don't
|
|
72
|
+
// have the granular data, so we provide empty objects with undefined values.
|
|
73
|
+
inputTokenDetails: {
|
|
74
|
+
cacheReadTokens: undefined,
|
|
75
|
+
cacheWriteTokens: undefined,
|
|
76
|
+
noCacheTokens: undefined,
|
|
77
|
+
},
|
|
78
|
+
outputTokenDetails: {
|
|
79
|
+
textTokens: undefined,
|
|
80
|
+
reasoningTokens: undefined,
|
|
81
|
+
},
|
|
36
82
|
};
|
|
37
83
|
}
|
|
38
84
|
export function serializeWarnings(warnings) {
|
|
@@ -40,25 +86,38 @@ export function serializeWarnings(warnings) {
|
|
|
40
86
|
return undefined;
|
|
41
87
|
}
|
|
42
88
|
return warnings.map((warning) => {
|
|
43
|
-
if (warning.type
|
|
44
|
-
return
|
|
89
|
+
if (warning.type === "compatibility") {
|
|
90
|
+
return {
|
|
91
|
+
type: "unsupported-setting",
|
|
92
|
+
setting: warning.feature,
|
|
93
|
+
details: warning.details,
|
|
94
|
+
};
|
|
45
95
|
}
|
|
46
|
-
return
|
|
47
|
-
...warning,
|
|
48
|
-
setting: warning.setting.toString(),
|
|
49
|
-
};
|
|
96
|
+
return warning;
|
|
50
97
|
});
|
|
51
98
|
}
|
|
52
|
-
export function
|
|
53
|
-
|
|
54
|
-
|
|
99
|
+
export function toModelMessageWarnings(warnings) {
|
|
100
|
+
if (!warnings) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
return warnings.map((warning) => {
|
|
104
|
+
if (warning.type === "unsupported-setting") {
|
|
105
|
+
return {
|
|
106
|
+
type: "compatibility",
|
|
107
|
+
feature: warning.setting,
|
|
108
|
+
details: warning.details,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return warning;
|
|
112
|
+
});
|
|
55
113
|
}
|
|
56
|
-
export async function serializeNewMessagesInStep(ctx, component, step,
|
|
114
|
+
export async function serializeNewMessagesInStep(ctx, component, step, model) {
|
|
57
115
|
// If there are tool results, there's another message with the tool results
|
|
58
|
-
// ref: https://github.com/vercel/ai/blob/main/packages/ai/
|
|
116
|
+
// ref: https://github.com/vercel/ai/blob/main/packages/ai/src/generate-text/to-response-messages.ts#L120
|
|
117
|
+
const hasToolMessage = step.response.messages.at(-1)?.role === "tool";
|
|
59
118
|
const assistantFields = {
|
|
60
|
-
model:
|
|
61
|
-
provider:
|
|
119
|
+
model: model ? getModelName(model) : undefined,
|
|
120
|
+
provider: model ? getProviderName(model) : undefined,
|
|
62
121
|
providerMetadata: step.providerMetadata,
|
|
63
122
|
reasoning: step.reasoningText,
|
|
64
123
|
reasoningDetails: step.reasoning,
|
|
@@ -66,28 +125,26 @@ export async function serializeNewMessagesInStep(ctx, component, step, metadata)
|
|
|
66
125
|
warnings: serializeWarnings(step.warnings),
|
|
67
126
|
finishReason: step.finishReason,
|
|
68
127
|
// Only store the sources on one message
|
|
69
|
-
sources:
|
|
70
|
-
};
|
|
71
|
-
const toolFields = {
|
|
72
|
-
sources: step.sources,
|
|
128
|
+
sources: hasToolMessage ? undefined : step.sources,
|
|
73
129
|
};
|
|
74
|
-
const
|
|
130
|
+
const toolFields = { sources: step.sources };
|
|
131
|
+
const messages = await Promise.all((hasToolMessage
|
|
75
132
|
? step.response.messages.slice(-2)
|
|
76
|
-
: step.
|
|
77
|
-
|
|
78
|
-
|
|
133
|
+
: step.content.length
|
|
134
|
+
? step.response.messages.slice(-1)
|
|
135
|
+
: [{ role: "assistant", content: [] }]).map(async (msg) => {
|
|
136
|
+
const { message, fileIds } = await serializeMessage(ctx, component, msg);
|
|
137
|
+
return parse(vMessageWithMetadata, {
|
|
79
138
|
message,
|
|
80
|
-
// Let's not store the ID by default here. It's being generated internally
|
|
81
|
-
// and not referenced elsewhere that we know of.
|
|
82
|
-
// id: message.id,
|
|
83
139
|
...(message.role === "tool" ? toolFields : assistantFields),
|
|
84
140
|
text: step.text,
|
|
85
141
|
fileIds,
|
|
86
|
-
};
|
|
142
|
+
});
|
|
87
143
|
}));
|
|
88
|
-
|
|
144
|
+
// TODO: capture step.files separately?
|
|
145
|
+
return { messages };
|
|
89
146
|
}
|
|
90
|
-
export async function serializeObjectResult(ctx, component, result,
|
|
147
|
+
export async function serializeObjectResult(ctx, component, result, model) {
|
|
91
148
|
const text = JSON.stringify(result.object);
|
|
92
149
|
const { message, fileIds } = await serializeMessage(ctx, component, {
|
|
93
150
|
role: "assistant",
|
|
@@ -97,9 +154,8 @@ export async function serializeObjectResult(ctx, component, result, metadata) {
|
|
|
97
154
|
messages: [
|
|
98
155
|
{
|
|
99
156
|
message,
|
|
100
|
-
|
|
101
|
-
model:
|
|
102
|
-
provider: metadata.provider,
|
|
157
|
+
model: model ? getModelName(model) : undefined,
|
|
158
|
+
provider: model ? getProviderName(model) : undefined,
|
|
103
159
|
providerMetadata: result.providerMetadata,
|
|
104
160
|
finishReason: result.finishReason,
|
|
105
161
|
text,
|
|
@@ -110,27 +166,34 @@ export async function serializeObjectResult(ctx, component, result, metadata) {
|
|
|
110
166
|
],
|
|
111
167
|
};
|
|
112
168
|
}
|
|
169
|
+
function getMimeOrMediaType(part) {
|
|
170
|
+
if ("mediaType" in part) {
|
|
171
|
+
return part.mediaType;
|
|
172
|
+
}
|
|
173
|
+
if ("mimeType" in part) {
|
|
174
|
+
return part.mimeType;
|
|
175
|
+
}
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
113
178
|
export async function serializeContent(ctx, component, content) {
|
|
114
179
|
if (typeof content === "string") {
|
|
115
180
|
return { content };
|
|
116
181
|
}
|
|
117
182
|
const fileIds = [];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
183
|
+
const serialized = await Promise.all(content.map(async (part) => {
|
|
184
|
+
const metadata = {};
|
|
185
|
+
if ("providerOptions" in part) {
|
|
186
|
+
metadata.providerOptions = part.providerOptions;
|
|
121
187
|
}
|
|
122
|
-
if ("
|
|
123
|
-
|
|
188
|
+
if ("providerMetadata" in part) {
|
|
189
|
+
metadata.providerMetadata = part.providerMetadata;
|
|
124
190
|
}
|
|
125
|
-
return undefined;
|
|
126
|
-
}
|
|
127
|
-
const serialized = await Promise.all(content.map(async (part) => {
|
|
128
191
|
switch (part.type) {
|
|
129
192
|
case "text": {
|
|
130
193
|
return {
|
|
131
194
|
type: part.type,
|
|
132
195
|
text: part.text,
|
|
133
|
-
|
|
196
|
+
...metadata,
|
|
134
197
|
};
|
|
135
198
|
}
|
|
136
199
|
case "image": {
|
|
@@ -138,22 +201,22 @@ export async function serializeContent(ctx, component, content) {
|
|
|
138
201
|
if (image instanceof ArrayBuffer &&
|
|
139
202
|
image.byteLength > MAX_FILE_SIZE) {
|
|
140
203
|
const { file } = await storeFile(ctx, component, new Blob([image], {
|
|
141
|
-
type:
|
|
204
|
+
type: getMimeOrMediaType(part) || guessMimeType(image),
|
|
142
205
|
}));
|
|
143
206
|
image = file.url;
|
|
144
207
|
fileIds.push(file.fileId);
|
|
145
208
|
}
|
|
146
209
|
return {
|
|
147
210
|
type: part.type,
|
|
148
|
-
|
|
149
|
-
|
|
211
|
+
mediaType: getMimeOrMediaType(part),
|
|
212
|
+
...metadata,
|
|
150
213
|
image,
|
|
151
214
|
};
|
|
152
215
|
}
|
|
153
216
|
case "file": {
|
|
154
217
|
let data = serializeDataOrUrl(part.data);
|
|
155
218
|
if (data instanceof ArrayBuffer && data.byteLength > MAX_FILE_SIZE) {
|
|
156
|
-
const { file } = await storeFile(ctx, component, new Blob([data], { type:
|
|
219
|
+
const { file } = await storeFile(ctx, component, new Blob([data], { type: getMimeOrMediaType(part) }));
|
|
157
220
|
data = file.url;
|
|
158
221
|
fileIds.push(file.fileId);
|
|
159
222
|
}
|
|
@@ -161,116 +224,270 @@ export async function serializeContent(ctx, component, content) {
|
|
|
161
224
|
type: part.type,
|
|
162
225
|
data,
|
|
163
226
|
filename: part.filename,
|
|
164
|
-
|
|
165
|
-
|
|
227
|
+
mediaType: getMimeOrMediaType(part),
|
|
228
|
+
...metadata,
|
|
166
229
|
};
|
|
167
230
|
}
|
|
168
231
|
case "tool-call": {
|
|
169
|
-
|
|
232
|
+
// Handle legacy data where only args field exists
|
|
233
|
+
const input = part.input ?? part?.args ?? {};
|
|
170
234
|
return {
|
|
171
235
|
type: part.type,
|
|
172
|
-
|
|
236
|
+
input,
|
|
237
|
+
/** @deprecated Use `input` instead. */
|
|
238
|
+
args: input,
|
|
173
239
|
toolCallId: part.toolCallId,
|
|
174
240
|
toolName: part.toolName,
|
|
175
|
-
providerOptions: part.providerOptions,
|
|
176
241
|
providerExecuted: part.providerExecuted,
|
|
242
|
+
...metadata,
|
|
177
243
|
};
|
|
178
244
|
}
|
|
179
245
|
case "tool-result": {
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
type: part.type,
|
|
183
|
-
result: result ?? null,
|
|
184
|
-
toolCallId: part.toolCallId,
|
|
185
|
-
toolName: part.toolName,
|
|
186
|
-
providerOptions: part.providerOptions,
|
|
187
|
-
};
|
|
246
|
+
return normalizeToolResult(part, metadata);
|
|
188
247
|
}
|
|
189
248
|
case "reasoning": {
|
|
190
249
|
return {
|
|
191
250
|
type: part.type,
|
|
192
251
|
text: part.text,
|
|
193
|
-
|
|
252
|
+
...metadata,
|
|
194
253
|
};
|
|
195
254
|
}
|
|
255
|
+
// Not in current generation output, but could be in historical messages
|
|
196
256
|
case "redacted-reasoning": {
|
|
197
257
|
return {
|
|
198
258
|
type: part.type,
|
|
199
259
|
data: part.data,
|
|
200
|
-
|
|
260
|
+
...metadata,
|
|
201
261
|
};
|
|
202
262
|
}
|
|
203
|
-
|
|
263
|
+
case "source": {
|
|
204
264
|
return part;
|
|
265
|
+
}
|
|
266
|
+
case "tool-approval-request": {
|
|
267
|
+
return {
|
|
268
|
+
type: part.type,
|
|
269
|
+
approvalId: part.approvalId,
|
|
270
|
+
toolCallId: part.toolCallId,
|
|
271
|
+
...metadata,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
case "tool-approval-response": {
|
|
275
|
+
return {
|
|
276
|
+
type: part.type,
|
|
277
|
+
approvalId: part.approvalId,
|
|
278
|
+
approved: part.approved,
|
|
279
|
+
reason: part.reason,
|
|
280
|
+
providerExecuted: part.providerExecuted,
|
|
281
|
+
...metadata,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
default:
|
|
285
|
+
return null;
|
|
205
286
|
}
|
|
206
287
|
}));
|
|
207
288
|
return {
|
|
208
|
-
content: serialized,
|
|
289
|
+
content: serialized.filter((p) => p !== null),
|
|
209
290
|
fileIds: fileIds.length > 0 ? fileIds : undefined,
|
|
210
291
|
};
|
|
211
292
|
}
|
|
212
|
-
export function
|
|
293
|
+
export function fromModelMessageContent(content) {
|
|
213
294
|
if (typeof content === "string") {
|
|
214
295
|
return content;
|
|
215
296
|
}
|
|
216
|
-
return content
|
|
297
|
+
return content
|
|
298
|
+
.map((part) => {
|
|
299
|
+
const metadata = {};
|
|
300
|
+
if ("providerOptions" in part) {
|
|
301
|
+
metadata.providerOptions = part.providerOptions;
|
|
302
|
+
}
|
|
303
|
+
if ("providerMetadata" in part) {
|
|
304
|
+
metadata.providerMetadata = part.providerMetadata;
|
|
305
|
+
}
|
|
217
306
|
switch (part.type) {
|
|
218
307
|
case "text":
|
|
219
|
-
return
|
|
220
|
-
type: part.type,
|
|
221
|
-
text: part.text,
|
|
222
|
-
providerOptions: part.providerOptions,
|
|
223
|
-
};
|
|
308
|
+
return part;
|
|
224
309
|
case "image":
|
|
225
310
|
return {
|
|
226
311
|
type: part.type,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
312
|
+
mediaType: getMimeOrMediaType(part),
|
|
313
|
+
...metadata,
|
|
314
|
+
image: serializeDataOrUrl(part.image),
|
|
230
315
|
};
|
|
231
316
|
case "file":
|
|
232
317
|
return {
|
|
233
318
|
type: part.type,
|
|
234
|
-
data:
|
|
319
|
+
data: serializeDataOrUrl(part.data),
|
|
235
320
|
filename: part.filename,
|
|
236
|
-
mediaType: part
|
|
237
|
-
|
|
321
|
+
mediaType: getMimeOrMediaType(part),
|
|
322
|
+
...metadata,
|
|
238
323
|
};
|
|
239
324
|
case "tool-call":
|
|
325
|
+
// Handle legacy data where only args field exists
|
|
240
326
|
return {
|
|
241
327
|
type: part.type,
|
|
242
|
-
input: part.args ??
|
|
243
|
-
|
|
328
|
+
input: part.input ?? part?.args ?? {},
|
|
329
|
+
/** @deprecated Use `input` instead. */
|
|
330
|
+
args: part.input ?? part?.args ?? {},
|
|
244
331
|
toolCallId: part.toolCallId,
|
|
245
332
|
toolName: part.toolName,
|
|
246
|
-
|
|
333
|
+
providerExecuted: part.providerExecuted,
|
|
334
|
+
...metadata,
|
|
247
335
|
};
|
|
248
336
|
case "tool-result":
|
|
337
|
+
return normalizeToolResult(part, metadata);
|
|
338
|
+
case "reasoning":
|
|
339
|
+
return {
|
|
340
|
+
type: part.type,
|
|
341
|
+
text: part.text,
|
|
342
|
+
...metadata,
|
|
343
|
+
};
|
|
344
|
+
case "tool-approval-request":
|
|
249
345
|
return {
|
|
250
346
|
type: part.type,
|
|
251
|
-
|
|
347
|
+
approvalId: part.approvalId,
|
|
348
|
+
toolCallId: part.toolCallId,
|
|
349
|
+
...metadata,
|
|
350
|
+
};
|
|
351
|
+
case "tool-approval-response":
|
|
352
|
+
return {
|
|
353
|
+
type: part.type,
|
|
354
|
+
approvalId: part.approvalId,
|
|
355
|
+
approved: part.approved,
|
|
356
|
+
reason: part.reason,
|
|
357
|
+
providerExecuted: part.providerExecuted,
|
|
358
|
+
...metadata,
|
|
359
|
+
};
|
|
360
|
+
// Not in current generation output, but could be in historical messages
|
|
361
|
+
default:
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
.filter((p) => p !== null);
|
|
366
|
+
}
|
|
367
|
+
export function toModelMessageContent(content) {
|
|
368
|
+
if (typeof content === "string") {
|
|
369
|
+
return content;
|
|
370
|
+
}
|
|
371
|
+
return content
|
|
372
|
+
.map((part) => {
|
|
373
|
+
const metadata = {};
|
|
374
|
+
if ("providerOptions" in part) {
|
|
375
|
+
metadata.providerOptions = part.providerOptions;
|
|
376
|
+
}
|
|
377
|
+
if ("providerMetadata" in part) {
|
|
378
|
+
metadata.providerMetadata = part.providerMetadata;
|
|
379
|
+
}
|
|
380
|
+
switch (part.type) {
|
|
381
|
+
case "text":
|
|
382
|
+
return {
|
|
383
|
+
type: part.type,
|
|
384
|
+
text: part.text,
|
|
385
|
+
...metadata,
|
|
386
|
+
};
|
|
387
|
+
case "image":
|
|
388
|
+
return {
|
|
389
|
+
type: part.type,
|
|
390
|
+
image: toModelMessageDataOrUrl(part.image),
|
|
391
|
+
mediaType: getMimeOrMediaType(part),
|
|
392
|
+
...metadata,
|
|
393
|
+
};
|
|
394
|
+
case "file":
|
|
395
|
+
return {
|
|
396
|
+
type: part.type,
|
|
397
|
+
data: toModelMessageDataOrUrl(part.data),
|
|
398
|
+
filename: part.filename,
|
|
399
|
+
mediaType: getMimeOrMediaType(part),
|
|
400
|
+
...metadata,
|
|
401
|
+
};
|
|
402
|
+
case "tool-call": {
|
|
403
|
+
// Handle legacy data where only args field exists
|
|
404
|
+
const input = part.input ?? part?.args ?? {};
|
|
405
|
+
return {
|
|
406
|
+
type: part.type,
|
|
407
|
+
input,
|
|
252
408
|
toolCallId: part.toolCallId,
|
|
253
409
|
toolName: part.toolName,
|
|
254
|
-
|
|
410
|
+
providerExecuted: part.providerExecuted,
|
|
411
|
+
...metadata,
|
|
255
412
|
};
|
|
413
|
+
}
|
|
414
|
+
case "tool-result": {
|
|
415
|
+
return normalizeToolResult(part, metadata);
|
|
416
|
+
}
|
|
256
417
|
case "reasoning":
|
|
257
418
|
return {
|
|
258
419
|
type: part.type,
|
|
259
420
|
text: part.text,
|
|
260
|
-
|
|
261
|
-
state: part.state,
|
|
421
|
+
...metadata,
|
|
262
422
|
};
|
|
263
423
|
case "redacted-reasoning":
|
|
264
424
|
// TODO: should we just drop this?
|
|
265
425
|
return {
|
|
266
426
|
type: "reasoning",
|
|
267
|
-
text:
|
|
268
|
-
|
|
427
|
+
text: "",
|
|
428
|
+
...metadata,
|
|
429
|
+
providerOptions: metadata.providerOptions
|
|
430
|
+
? {
|
|
431
|
+
...Object.fromEntries(Object.entries(metadata.providerOptions ?? {}).map(([key, value]) => [
|
|
432
|
+
key,
|
|
433
|
+
{ ...value, redactedData: part.data },
|
|
434
|
+
])),
|
|
435
|
+
}
|
|
436
|
+
: undefined,
|
|
269
437
|
};
|
|
270
|
-
|
|
438
|
+
case "source":
|
|
271
439
|
return part;
|
|
440
|
+
case "tool-approval-request":
|
|
441
|
+
return {
|
|
442
|
+
type: part.type,
|
|
443
|
+
approvalId: part.approvalId,
|
|
444
|
+
toolCallId: part.toolCallId,
|
|
445
|
+
...metadata,
|
|
446
|
+
};
|
|
447
|
+
case "tool-approval-response":
|
|
448
|
+
return {
|
|
449
|
+
type: part.type,
|
|
450
|
+
approvalId: part.approvalId,
|
|
451
|
+
approved: part.approved,
|
|
452
|
+
reason: part.reason,
|
|
453
|
+
providerExecuted: part.providerExecuted,
|
|
454
|
+
...metadata,
|
|
455
|
+
};
|
|
456
|
+
default:
|
|
457
|
+
return null;
|
|
272
458
|
}
|
|
273
|
-
})
|
|
459
|
+
})
|
|
460
|
+
.filter((p) => p !== null);
|
|
461
|
+
}
|
|
462
|
+
export function normalizeToolOutput(result) {
|
|
463
|
+
if (typeof result === "string") {
|
|
464
|
+
return {
|
|
465
|
+
type: "text",
|
|
466
|
+
value: result,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
if (validate(vToolResultOutput, result)) {
|
|
470
|
+
return result;
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
type: "json",
|
|
474
|
+
value: result ?? null,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function normalizeToolResult(part, metadata) {
|
|
478
|
+
return {
|
|
479
|
+
type: part.type,
|
|
480
|
+
output: part.output
|
|
481
|
+
? validate(vToolResultOutput, part.output)
|
|
482
|
+
? part.output
|
|
483
|
+
: normalizeToolOutput(JSON.stringify(part.output))
|
|
484
|
+
: normalizeToolOutput("result" in part ? part.result : undefined),
|
|
485
|
+
toolCallId: part.toolCallId,
|
|
486
|
+
toolName: part.toolName,
|
|
487
|
+
// Preserve isError flag for error reporting
|
|
488
|
+
...("isError" in part && part.isError ? { isError: true } : {}),
|
|
489
|
+
...metadata,
|
|
490
|
+
};
|
|
274
491
|
}
|
|
275
492
|
/**
|
|
276
493
|
* Return a best-guess MIME type based on the magic-number signature
|
|
@@ -362,7 +579,10 @@ export function serializeDataOrUrl(dataOrUrl) {
|
|
|
362
579
|
}
|
|
363
580
|
return dataOrUrl.buffer.slice(dataOrUrl.byteOffset, dataOrUrl.byteOffset + dataOrUrl.byteLength);
|
|
364
581
|
}
|
|
365
|
-
export function
|
|
582
|
+
export function toModelMessageDataOrUrl(urlOrString) {
|
|
583
|
+
if (urlOrString instanceof URL) {
|
|
584
|
+
return urlOrString;
|
|
585
|
+
}
|
|
366
586
|
if (typeof urlOrString === "string") {
|
|
367
587
|
if (urlOrString.startsWith("http://") ||
|
|
368
588
|
urlOrString.startsWith("https://")) {
|
|
@@ -375,7 +595,7 @@ export function deserializeUrl(urlOrString) {
|
|
|
375
595
|
export function toUIFilePart(part) {
|
|
376
596
|
const dataOrUrl = part.type === "image" ? part.image : part.data;
|
|
377
597
|
const url = dataOrUrl instanceof ArrayBuffer
|
|
378
|
-
?
|
|
598
|
+
? convertUint8ArrayToBase64(new Uint8Array(dataOrUrl))
|
|
379
599
|
: dataOrUrl.toString();
|
|
380
600
|
return {
|
|
381
601
|
type: "file",
|
|
@@ -385,9 +605,6 @@ export function toUIFilePart(part) {
|
|
|
385
605
|
providerMetadata: part.providerOptions,
|
|
386
606
|
};
|
|
387
607
|
}
|
|
388
|
-
function encodeBase64(data) {
|
|
389
|
-
return Buffer.from(data).toString("base64");
|
|
390
|
-
}
|
|
391
608
|
// Currently unused
|
|
392
609
|
// export function toModelMessages(args: {
|
|
393
610
|
// messages?: ModelMessage[] | AIMessageWithoutId[];
|