@convex-dev/agent 0.6.0-alpha.1 → 0.6.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/package.json +1 -1
- package/src/UIMessages.ts +135 -0
- package/src/client/index.ts +56 -14
- package/src/client/search.test.ts +4 -5
- package/src/client/search.ts +45 -4
- package/src/client/streaming.integration.test.ts +1206 -0
- package/src/client/streaming.ts +9 -2
- package/src/mapping.test.ts +136 -71
- package/src/mapping.ts +81 -28
- package/dist/UIMessages.d.ts +0 -46
- package/dist/UIMessages.d.ts.map +0 -1
- package/dist/UIMessages.js +0 -546
- package/dist/UIMessages.js.map +0 -1
- package/dist/client/createTool.d.ts +0 -167
- package/dist/client/createTool.d.ts.map +0 -1
- package/dist/client/createTool.js +0 -116
- package/dist/client/createTool.js.map +0 -1
- package/dist/client/defaultComponent.d.ts +0 -11
- package/dist/client/defaultComponent.d.ts.map +0 -1
- package/dist/client/defaultComponent.js +0 -7
- package/dist/client/defaultComponent.js.map +0 -1
- package/dist/client/definePlaygroundAPI.d.ts +0 -1725
- package/dist/client/definePlaygroundAPI.d.ts.map +0 -1
- package/dist/client/definePlaygroundAPI.js +0 -271
- package/dist/client/definePlaygroundAPI.js.map +0 -1
- package/dist/client/files.d.ts +0 -69
- package/dist/client/files.d.ts.map +0 -1
- package/dist/client/files.js +0 -181
- package/dist/client/files.js.map +0 -1
- package/dist/client/index.d.ts +0 -2091
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -895
- package/dist/client/index.js.map +0 -1
- package/dist/client/messages.d.ts +0 -461
- package/dist/client/messages.d.ts.map +0 -1
- package/dist/client/messages.js +0 -106
- package/dist/client/messages.js.map +0 -1
- package/dist/client/mockModel.d.ts +0 -42
- package/dist/client/mockModel.d.ts.map +0 -1
- package/dist/client/mockModel.js +0 -182
- package/dist/client/mockModel.js.map +0 -1
- package/dist/client/saveInputMessages.d.ts +0 -20
- package/dist/client/saveInputMessages.d.ts.map +0 -1
- package/dist/client/saveInputMessages.js +0 -58
- package/dist/client/saveInputMessages.js.map +0 -1
- package/dist/client/search.d.ts +0 -493
- package/dist/client/search.d.ts.map +0 -1
- package/dist/client/search.js +0 -425
- package/dist/client/search.js.map +0 -1
- package/dist/client/start.d.ts +0 -84
- package/dist/client/start.d.ts.map +0 -1
- package/dist/client/start.js +0 -185
- package/dist/client/start.js.map +0 -1
- package/dist/client/streamText.d.ts +0 -46
- package/dist/client/streamText.d.ts.map +0 -1
- package/dist/client/streamText.js +0 -117
- package/dist/client/streamText.js.map +0 -1
- package/dist/client/streaming.d.ts +0 -3778
- package/dist/client/streaming.d.ts.map +0 -1
- package/dist/client/streaming.js +0 -314
- package/dist/client/streaming.js.map +0 -1
- package/dist/client/threads.d.ts +0 -46
- package/dist/client/threads.d.ts.map +0 -1
- package/dist/client/threads.js +0 -49
- package/dist/client/threads.js.map +0 -1
- package/dist/client/types.d.ts +0 -461
- package/dist/client/types.d.ts.map +0 -1
- package/dist/client/types.js +0 -2
- package/dist/client/types.js.map +0 -1
- package/dist/client/utils.d.ts +0 -4
- package/dist/client/utils.d.ts.map +0 -1
- package/dist/client/utils.js +0 -21
- package/dist/client/utils.js.map +0 -1
- package/dist/component/_generated/api.d.ts +0 -48
- package/dist/component/_generated/api.d.ts.map +0 -1
- package/dist/component/_generated/api.js +0 -31
- package/dist/component/_generated/api.js.map +0 -1
- package/dist/component/_generated/component.d.ts +0 -3120
- package/dist/component/_generated/component.d.ts.map +0 -1
- package/dist/component/_generated/component.js +0 -11
- package/dist/component/_generated/component.js.map +0 -1
- package/dist/component/_generated/dataModel.d.ts +0 -46
- package/dist/component/_generated/dataModel.d.ts.map +0 -1
- package/dist/component/_generated/dataModel.js +0 -11
- package/dist/component/_generated/dataModel.js.map +0 -1
- package/dist/component/_generated/server.d.ts +0 -121
- package/dist/component/_generated/server.d.ts.map +0 -1
- package/dist/component/_generated/server.js +0 -78
- package/dist/component/_generated/server.js.map +0 -1
- package/dist/component/apiKeys.d.ts +0 -11
- package/dist/component/apiKeys.d.ts.map +0 -1
- package/dist/component/apiKeys.js +0 -69
- package/dist/component/apiKeys.js.map +0 -1
- package/dist/component/convex.config.d.ts +0 -3
- package/dist/component/convex.config.d.ts.map +0 -1
- package/dist/component/convex.config.js +0 -3
- package/dist/component/convex.config.js.map +0 -1
- package/dist/component/files.d.ts +0 -97
- package/dist/component/files.d.ts.map +0 -1
- package/dist/component/files.js +0 -190
- package/dist/component/files.js.map +0 -1
- package/dist/component/messages.d.ts +0 -3851
- package/dist/component/messages.d.ts.map +0 -1
- package/dist/component/messages.js +0 -757
- package/dist/component/messages.js.map +0 -1
- package/dist/component/schema.d.ts +0 -8026
- package/dist/component/schema.d.ts.map +0 -1
- package/dist/component/schema.js +0 -147
- package/dist/component/schema.js.map +0 -1
- package/dist/component/streams.d.ts +0 -128
- package/dist/component/streams.d.ts.map +0 -1
- package/dist/component/streams.js +0 -413
- package/dist/component/streams.js.map +0 -1
- package/dist/component/threads.d.ts +0 -115
- package/dist/component/threads.d.ts.map +0 -1
- package/dist/component/threads.js +0 -208
- package/dist/component/threads.js.map +0 -1
- package/dist/component/users.d.ts +0 -52
- package/dist/component/users.d.ts.map +0 -1
- package/dist/component/users.js +0 -229
- package/dist/component/users.js.map +0 -1
- package/dist/component/vector/index.d.ts +0 -61
- package/dist/component/vector/index.d.ts.map +0 -1
- package/dist/component/vector/index.js +0 -146
- package/dist/component/vector/index.js.map +0 -1
- package/dist/component/vector/tables.d.ts +0 -58
- package/dist/component/vector/tables.d.ts.map +0 -1
- package/dist/component/vector/tables.js +0 -56
- package/dist/component/vector/tables.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 +0 -72
- package/dist/mapping.d.ts.map +0 -1
- package/dist/mapping.js +0 -677
- package/dist/mapping.js.map +0 -1
- package/dist/react/SmoothText.d.ts +0 -5
- package/dist/react/SmoothText.d.ts.map +0 -1
- package/dist/react/SmoothText.js +0 -6
- package/dist/react/SmoothText.js.map +0 -1
- package/dist/react/index.d.ts +0 -25
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/index.js +0 -70
- package/dist/react/index.js.map +0 -1
- package/dist/react/optimisticallySendMessage.d.ts +0 -42
- package/dist/react/optimisticallySendMessage.d.ts.map +0 -1
- package/dist/react/optimisticallySendMessage.js +0 -74
- package/dist/react/optimisticallySendMessage.js.map +0 -1
- package/dist/react/types.d.ts +0 -12
- package/dist/react/types.d.ts.map +0 -1
- package/dist/react/types.js +0 -2
- package/dist/react/types.js.map +0 -1
- package/dist/react/useDeltaStreams.d.ts +0 -10
- package/dist/react/useDeltaStreams.d.ts.map +0 -1
- package/dist/react/useDeltaStreams.js +0 -106
- package/dist/react/useDeltaStreams.js.map +0 -1
- package/dist/react/useSmoothText.d.ts +0 -27
- package/dist/react/useSmoothText.d.ts.map +0 -1
- package/dist/react/useSmoothText.js +0 -68
- package/dist/react/useSmoothText.js.map +0 -1
- package/dist/react/useStreamingUIMessages.d.ts +0 -22
- 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 +0 -104
- package/dist/react/useThreadMessages.d.ts.map +0 -1
- package/dist/react/useThreadMessages.js +0 -148
- package/dist/react/useThreadMessages.js.map +0 -1
- package/dist/react/useUIMessages.d.ts +0 -96
- package/dist/react/useUIMessages.d.ts.map +0 -1
- package/dist/react/useUIMessages.js +0 -108
- package/dist/react/useUIMessages.js.map +0 -1
- package/dist/shared.d.ts +0 -26
- package/dist/shared.d.ts.map +0 -1
- package/dist/shared.js +0 -67
- package/dist/shared.js.map +0 -1
- package/dist/validators.d.ts +0 -24516
- package/dist/validators.d.ts.map +0 -1
- package/dist/validators.js +0 -475
- package/dist/validators.js.map +0 -1
package/dist/mapping.js
DELETED
|
@@ -1,677 +0,0 @@
|
|
|
1
|
-
import {} from "ai";
|
|
2
|
-
import { vMessageWithMetadata, vToolResultOutput, vToolApprovalRequest, vToolApprovalResponse, } from "./validators.js";
|
|
3
|
-
import { MAX_FILE_SIZE, storeFile } from "./client/files.js";
|
|
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) {
|
|
8
|
-
const { content, fileIds } = await serializeContent(ctx, component, message.content);
|
|
9
|
-
return {
|
|
10
|
-
message: {
|
|
11
|
-
role: message.role,
|
|
12
|
-
content,
|
|
13
|
-
...(message.providerOptions
|
|
14
|
-
? { providerOptions: message.providerOptions }
|
|
15
|
-
: {}),
|
|
16
|
-
},
|
|
17
|
-
fileIds,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
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) {
|
|
43
|
-
return {
|
|
44
|
-
...message,
|
|
45
|
-
content: toModelMessageContent(message.content),
|
|
46
|
-
};
|
|
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
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Merge consecutive tool messages that contain `tool-approval-response` parts
|
|
57
|
-
* into a single tool message. The AI SDK's `collectToolApprovals` only examines
|
|
58
|
-
* the last tool message, so when multiple approvals are saved as separate
|
|
59
|
-
* messages (e.g. approve tool A, then deny tool B), they must be combined
|
|
60
|
-
* for the SDK to process them all.
|
|
61
|
-
*/
|
|
62
|
-
export function mergeApprovalResponseMessages(messages) {
|
|
63
|
-
const result = [];
|
|
64
|
-
for (const msg of messages) {
|
|
65
|
-
const prev = result.at(-1);
|
|
66
|
-
if (msg.role === "tool" &&
|
|
67
|
-
prev?.role === "tool" &&
|
|
68
|
-
Array.isArray(msg.content) &&
|
|
69
|
-
Array.isArray(prev.content) &&
|
|
70
|
-
hasApprovalResponse(msg.content) &&
|
|
71
|
-
hasApprovalResponse(prev.content)) {
|
|
72
|
-
// Clone before merging to avoid mutating the original message's content array
|
|
73
|
-
const cloned = { ...prev, content: [...prev.content] };
|
|
74
|
-
result[result.length - 1] = cloned;
|
|
75
|
-
cloned.content.push(...msg.content);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
result.push(msg);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
function hasApprovalResponse(content) {
|
|
84
|
-
return content.some((p) => p.type === "tool-approval-response");
|
|
85
|
-
}
|
|
86
|
-
export function serializeUsage(usage) {
|
|
87
|
-
return {
|
|
88
|
-
promptTokens: usage.inputTokens ?? 0,
|
|
89
|
-
completionTokens: usage.outputTokens ?? 0,
|
|
90
|
-
totalTokens: usage.totalTokens ?? 0,
|
|
91
|
-
reasoningTokens: usage.reasoningTokens,
|
|
92
|
-
cachedInputTokens: usage.cachedInputTokens,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
export function toModelMessageUsage(usage) {
|
|
96
|
-
return {
|
|
97
|
-
inputTokens: usage.promptTokens,
|
|
98
|
-
outputTokens: usage.completionTokens,
|
|
99
|
-
totalTokens: usage.totalTokens,
|
|
100
|
-
reasoningTokens: usage.reasoningTokens,
|
|
101
|
-
cachedInputTokens: usage.cachedInputTokens,
|
|
102
|
-
// These detail fields are required by LanguageModelUsage type but we don't
|
|
103
|
-
// have the granular data, so we provide empty objects with undefined values.
|
|
104
|
-
inputTokenDetails: {
|
|
105
|
-
cacheReadTokens: undefined,
|
|
106
|
-
cacheWriteTokens: undefined,
|
|
107
|
-
noCacheTokens: undefined,
|
|
108
|
-
},
|
|
109
|
-
outputTokenDetails: {
|
|
110
|
-
textTokens: undefined,
|
|
111
|
-
reasoningTokens: undefined,
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
export function serializeWarnings(warnings) {
|
|
116
|
-
if (!warnings) {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
return warnings.map((warning) => {
|
|
120
|
-
if (warning.type === "compatibility") {
|
|
121
|
-
return {
|
|
122
|
-
type: "unsupported-setting",
|
|
123
|
-
setting: warning.feature,
|
|
124
|
-
details: warning.details,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
return warning;
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
export function toModelMessageWarnings(warnings) {
|
|
131
|
-
if (!warnings) {
|
|
132
|
-
return undefined;
|
|
133
|
-
}
|
|
134
|
-
return warnings.map((warning) => {
|
|
135
|
-
if (warning.type === "unsupported-setting") {
|
|
136
|
-
return {
|
|
137
|
-
type: "compatibility",
|
|
138
|
-
feature: warning.setting,
|
|
139
|
-
details: warning.details,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
return warning;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
export async function serializeNewMessagesInStep(ctx, component, step, model,
|
|
146
|
-
/**
|
|
147
|
-
* If provided, these are the new response messages for this step
|
|
148
|
-
* (pre-sliced by the caller). When not provided, falls back to the
|
|
149
|
-
* existing heuristic of slicing the last 1-2 messages.
|
|
150
|
-
*
|
|
151
|
-
* This is needed for tool approval flows where the SDK adds extra
|
|
152
|
-
* messages (e.g. approval tool-results) at the beginning of
|
|
153
|
-
* responseMessages that the old slice(-1/-2) logic would miss.
|
|
154
|
-
*/
|
|
155
|
-
newResponseMessages) {
|
|
156
|
-
// If there are tool results, there's another message with the tool results
|
|
157
|
-
// ref: https://github.com/vercel/ai/blob/main/packages/ai/src/generate-text/to-response-messages.ts#L120
|
|
158
|
-
const hasToolMessage = step.response.messages.at(-1)?.role === "tool";
|
|
159
|
-
const assistantFields = {
|
|
160
|
-
model: model ? getModelName(model) : undefined,
|
|
161
|
-
provider: model ? getProviderName(model) : undefined,
|
|
162
|
-
providerMetadata: step.providerMetadata,
|
|
163
|
-
reasoning: step.reasoningText,
|
|
164
|
-
reasoningDetails: step.reasoning,
|
|
165
|
-
usage: serializeUsage(step.usage),
|
|
166
|
-
warnings: serializeWarnings(step.warnings),
|
|
167
|
-
finishReason: step.finishReason,
|
|
168
|
-
// Only store the sources on one message
|
|
169
|
-
sources: hasToolMessage ? undefined : step.sources,
|
|
170
|
-
};
|
|
171
|
-
const toolFields = { sources: step.sources };
|
|
172
|
-
// Determine which messages to serialize for this step
|
|
173
|
-
let messagesToSerialize;
|
|
174
|
-
if (newResponseMessages) {
|
|
175
|
-
messagesToSerialize = newResponseMessages;
|
|
176
|
-
}
|
|
177
|
-
else if (hasToolMessage) {
|
|
178
|
-
messagesToSerialize = step.response.messages.slice(-2);
|
|
179
|
-
}
|
|
180
|
-
else if (step.content.length) {
|
|
181
|
-
messagesToSerialize = step.response.messages.slice(-1);
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
messagesToSerialize = [{ role: "assistant", content: [] }];
|
|
185
|
-
}
|
|
186
|
-
const messages = await Promise.all(messagesToSerialize.map(async (msg) => {
|
|
187
|
-
const { message, fileIds } = await serializeMessage(ctx, component, msg);
|
|
188
|
-
return parse(vMessageWithMetadata, {
|
|
189
|
-
message,
|
|
190
|
-
...(message.role === "tool" ? toolFields : assistantFields),
|
|
191
|
-
text: step.text,
|
|
192
|
-
fileIds,
|
|
193
|
-
});
|
|
194
|
-
}));
|
|
195
|
-
// TODO: capture step.files separately?
|
|
196
|
-
return { messages };
|
|
197
|
-
}
|
|
198
|
-
export async function serializeObjectResult(ctx, component, result, model) {
|
|
199
|
-
const text = JSON.stringify(result.object);
|
|
200
|
-
const { message, fileIds } = await serializeMessage(ctx, component, {
|
|
201
|
-
role: "assistant",
|
|
202
|
-
content: text,
|
|
203
|
-
});
|
|
204
|
-
return {
|
|
205
|
-
messages: [
|
|
206
|
-
{
|
|
207
|
-
message,
|
|
208
|
-
model: model ? getModelName(model) : undefined,
|
|
209
|
-
provider: model ? getProviderName(model) : undefined,
|
|
210
|
-
providerMetadata: result.providerMetadata,
|
|
211
|
-
finishReason: result.finishReason,
|
|
212
|
-
text,
|
|
213
|
-
usage: serializeUsage(result.usage),
|
|
214
|
-
warnings: serializeWarnings(result.warnings),
|
|
215
|
-
fileIds,
|
|
216
|
-
},
|
|
217
|
-
],
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
function getMimeOrMediaType(part) {
|
|
221
|
-
if ("mediaType" in part) {
|
|
222
|
-
return part.mediaType;
|
|
223
|
-
}
|
|
224
|
-
if ("mimeType" in part) {
|
|
225
|
-
return part.mimeType;
|
|
226
|
-
}
|
|
227
|
-
return undefined;
|
|
228
|
-
}
|
|
229
|
-
export async function serializeContent(ctx, component, content) {
|
|
230
|
-
if (typeof content === "string") {
|
|
231
|
-
return { content };
|
|
232
|
-
}
|
|
233
|
-
const fileIds = [];
|
|
234
|
-
const serialized = await Promise.all(content.map(async (part) => {
|
|
235
|
-
const metadata = {};
|
|
236
|
-
if ("providerOptions" in part) {
|
|
237
|
-
metadata.providerOptions = part.providerOptions;
|
|
238
|
-
}
|
|
239
|
-
if ("providerMetadata" in part) {
|
|
240
|
-
metadata.providerMetadata = part.providerMetadata;
|
|
241
|
-
}
|
|
242
|
-
switch (part.type) {
|
|
243
|
-
case "text": {
|
|
244
|
-
return {
|
|
245
|
-
type: part.type,
|
|
246
|
-
text: part.text,
|
|
247
|
-
...metadata,
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
case "image": {
|
|
251
|
-
let image = serializeDataOrUrl(part.image);
|
|
252
|
-
if (image instanceof ArrayBuffer &&
|
|
253
|
-
image.byteLength > MAX_FILE_SIZE) {
|
|
254
|
-
const { file } = await storeFile(ctx, component, new Blob([image], {
|
|
255
|
-
type: getMimeOrMediaType(part) || guessMimeType(image),
|
|
256
|
-
}));
|
|
257
|
-
image = file.url;
|
|
258
|
-
fileIds.push(file.fileId);
|
|
259
|
-
}
|
|
260
|
-
return {
|
|
261
|
-
type: part.type,
|
|
262
|
-
mediaType: getMimeOrMediaType(part),
|
|
263
|
-
...metadata,
|
|
264
|
-
image,
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
case "file": {
|
|
268
|
-
let data = serializeDataOrUrl(part.data);
|
|
269
|
-
if (data instanceof ArrayBuffer && data.byteLength > MAX_FILE_SIZE) {
|
|
270
|
-
const { file } = await storeFile(ctx, component, new Blob([data], { type: getMimeOrMediaType(part) }));
|
|
271
|
-
data = file.url;
|
|
272
|
-
fileIds.push(file.fileId);
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
type: part.type,
|
|
276
|
-
data,
|
|
277
|
-
filename: part.filename,
|
|
278
|
-
mediaType: getMimeOrMediaType(part),
|
|
279
|
-
...metadata,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
case "tool-call": {
|
|
283
|
-
// Handle legacy data where only args field exists
|
|
284
|
-
const input = part.input ?? part?.args ?? {};
|
|
285
|
-
return {
|
|
286
|
-
type: part.type,
|
|
287
|
-
input,
|
|
288
|
-
/** @deprecated Use `input` instead. */
|
|
289
|
-
args: input,
|
|
290
|
-
toolCallId: part.toolCallId,
|
|
291
|
-
toolName: part.toolName,
|
|
292
|
-
providerExecuted: part.providerExecuted,
|
|
293
|
-
...metadata,
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
case "tool-result": {
|
|
297
|
-
return normalizeToolResult(part, metadata);
|
|
298
|
-
}
|
|
299
|
-
case "reasoning": {
|
|
300
|
-
return {
|
|
301
|
-
type: part.type,
|
|
302
|
-
text: part.text,
|
|
303
|
-
...metadata,
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
// Not in current generation output, but could be in historical messages
|
|
307
|
-
case "redacted-reasoning": {
|
|
308
|
-
return {
|
|
309
|
-
type: part.type,
|
|
310
|
-
data: part.data,
|
|
311
|
-
...metadata,
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
case "source": {
|
|
315
|
-
return part;
|
|
316
|
-
}
|
|
317
|
-
case "tool-approval-request": {
|
|
318
|
-
return {
|
|
319
|
-
type: part.type,
|
|
320
|
-
approvalId: part.approvalId,
|
|
321
|
-
toolCallId: part.toolCallId,
|
|
322
|
-
...metadata,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
case "tool-approval-response": {
|
|
326
|
-
return {
|
|
327
|
-
type: part.type,
|
|
328
|
-
approvalId: part.approvalId,
|
|
329
|
-
approved: part.approved,
|
|
330
|
-
reason: part.reason,
|
|
331
|
-
providerExecuted: part.providerExecuted,
|
|
332
|
-
...metadata,
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
default:
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
}));
|
|
339
|
-
return {
|
|
340
|
-
content: serialized.filter((p) => p !== null),
|
|
341
|
-
fileIds: fileIds.length > 0 ? fileIds : undefined,
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
export function fromModelMessageContent(content) {
|
|
345
|
-
if (typeof content === "string") {
|
|
346
|
-
return content;
|
|
347
|
-
}
|
|
348
|
-
return content
|
|
349
|
-
.map((part) => {
|
|
350
|
-
const metadata = {};
|
|
351
|
-
if ("providerOptions" in part) {
|
|
352
|
-
metadata.providerOptions = part.providerOptions;
|
|
353
|
-
}
|
|
354
|
-
if ("providerMetadata" in part) {
|
|
355
|
-
metadata.providerMetadata = part.providerMetadata;
|
|
356
|
-
}
|
|
357
|
-
switch (part.type) {
|
|
358
|
-
case "text":
|
|
359
|
-
return part;
|
|
360
|
-
case "image":
|
|
361
|
-
return {
|
|
362
|
-
type: part.type,
|
|
363
|
-
mediaType: getMimeOrMediaType(part),
|
|
364
|
-
...metadata,
|
|
365
|
-
image: serializeDataOrUrl(part.image),
|
|
366
|
-
};
|
|
367
|
-
case "file":
|
|
368
|
-
return {
|
|
369
|
-
type: part.type,
|
|
370
|
-
data: serializeDataOrUrl(part.data),
|
|
371
|
-
filename: part.filename,
|
|
372
|
-
mediaType: getMimeOrMediaType(part),
|
|
373
|
-
...metadata,
|
|
374
|
-
};
|
|
375
|
-
case "tool-call":
|
|
376
|
-
// Handle legacy data where only args field exists
|
|
377
|
-
return {
|
|
378
|
-
type: part.type,
|
|
379
|
-
input: part.input ?? part?.args ?? {},
|
|
380
|
-
/** @deprecated Use `input` instead. */
|
|
381
|
-
args: part.input ?? part?.args ?? {},
|
|
382
|
-
toolCallId: part.toolCallId,
|
|
383
|
-
toolName: part.toolName,
|
|
384
|
-
providerExecuted: part.providerExecuted,
|
|
385
|
-
...metadata,
|
|
386
|
-
};
|
|
387
|
-
case "tool-result":
|
|
388
|
-
return normalizeToolResult(part, metadata);
|
|
389
|
-
case "reasoning":
|
|
390
|
-
return {
|
|
391
|
-
type: part.type,
|
|
392
|
-
text: part.text,
|
|
393
|
-
...metadata,
|
|
394
|
-
};
|
|
395
|
-
case "tool-approval-request":
|
|
396
|
-
return {
|
|
397
|
-
type: part.type,
|
|
398
|
-
approvalId: part.approvalId,
|
|
399
|
-
toolCallId: part.toolCallId,
|
|
400
|
-
...metadata,
|
|
401
|
-
};
|
|
402
|
-
case "tool-approval-response":
|
|
403
|
-
return {
|
|
404
|
-
type: part.type,
|
|
405
|
-
approvalId: part.approvalId,
|
|
406
|
-
approved: part.approved,
|
|
407
|
-
reason: part.reason,
|
|
408
|
-
providerExecuted: part.providerExecuted,
|
|
409
|
-
...metadata,
|
|
410
|
-
};
|
|
411
|
-
// Not in current generation output, but could be in historical messages
|
|
412
|
-
default:
|
|
413
|
-
return null;
|
|
414
|
-
}
|
|
415
|
-
})
|
|
416
|
-
.filter((p) => p !== null);
|
|
417
|
-
}
|
|
418
|
-
export function toModelMessageContent(content) {
|
|
419
|
-
if (typeof content === "string") {
|
|
420
|
-
return content;
|
|
421
|
-
}
|
|
422
|
-
return content
|
|
423
|
-
.map((part) => {
|
|
424
|
-
const metadata = {};
|
|
425
|
-
if ("providerOptions" in part) {
|
|
426
|
-
metadata.providerOptions = part.providerOptions;
|
|
427
|
-
}
|
|
428
|
-
if ("providerMetadata" in part) {
|
|
429
|
-
metadata.providerMetadata = part.providerMetadata;
|
|
430
|
-
}
|
|
431
|
-
switch (part.type) {
|
|
432
|
-
case "text":
|
|
433
|
-
return {
|
|
434
|
-
type: part.type,
|
|
435
|
-
text: part.text,
|
|
436
|
-
...metadata,
|
|
437
|
-
};
|
|
438
|
-
case "image":
|
|
439
|
-
return {
|
|
440
|
-
type: part.type,
|
|
441
|
-
image: toModelMessageDataOrUrl(part.image),
|
|
442
|
-
mediaType: getMimeOrMediaType(part),
|
|
443
|
-
...metadata,
|
|
444
|
-
};
|
|
445
|
-
case "file":
|
|
446
|
-
return {
|
|
447
|
-
type: part.type,
|
|
448
|
-
data: toModelMessageDataOrUrl(part.data),
|
|
449
|
-
filename: part.filename,
|
|
450
|
-
mediaType: getMimeOrMediaType(part),
|
|
451
|
-
...metadata,
|
|
452
|
-
};
|
|
453
|
-
case "tool-call": {
|
|
454
|
-
// Handle legacy data where only args field exists
|
|
455
|
-
const input = part.input ?? part?.args ?? {};
|
|
456
|
-
return {
|
|
457
|
-
type: part.type,
|
|
458
|
-
input,
|
|
459
|
-
toolCallId: part.toolCallId,
|
|
460
|
-
toolName: part.toolName,
|
|
461
|
-
providerExecuted: part.providerExecuted,
|
|
462
|
-
...metadata,
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
case "tool-result": {
|
|
466
|
-
return normalizeToolResult(part, metadata);
|
|
467
|
-
}
|
|
468
|
-
case "reasoning":
|
|
469
|
-
return {
|
|
470
|
-
type: part.type,
|
|
471
|
-
text: part.text,
|
|
472
|
-
...metadata,
|
|
473
|
-
};
|
|
474
|
-
case "redacted-reasoning":
|
|
475
|
-
// TODO: should we just drop this?
|
|
476
|
-
return {
|
|
477
|
-
type: "reasoning",
|
|
478
|
-
text: "",
|
|
479
|
-
...metadata,
|
|
480
|
-
providerOptions: metadata.providerOptions
|
|
481
|
-
? {
|
|
482
|
-
...Object.fromEntries(Object.entries(metadata.providerOptions ?? {}).map(([key, value]) => [
|
|
483
|
-
key,
|
|
484
|
-
{ ...value, redactedData: part.data },
|
|
485
|
-
])),
|
|
486
|
-
}
|
|
487
|
-
: undefined,
|
|
488
|
-
};
|
|
489
|
-
case "source":
|
|
490
|
-
return part;
|
|
491
|
-
case "tool-approval-request":
|
|
492
|
-
return {
|
|
493
|
-
type: part.type,
|
|
494
|
-
approvalId: part.approvalId,
|
|
495
|
-
toolCallId: part.toolCallId,
|
|
496
|
-
...metadata,
|
|
497
|
-
};
|
|
498
|
-
case "tool-approval-response":
|
|
499
|
-
return {
|
|
500
|
-
type: part.type,
|
|
501
|
-
approvalId: part.approvalId,
|
|
502
|
-
approved: part.approved,
|
|
503
|
-
reason: part.reason,
|
|
504
|
-
providerExecuted: part.providerExecuted,
|
|
505
|
-
...metadata,
|
|
506
|
-
};
|
|
507
|
-
default:
|
|
508
|
-
return null;
|
|
509
|
-
}
|
|
510
|
-
})
|
|
511
|
-
.filter((p) => p !== null);
|
|
512
|
-
}
|
|
513
|
-
export function normalizeToolOutput(result) {
|
|
514
|
-
if (typeof result === "string") {
|
|
515
|
-
return {
|
|
516
|
-
type: "text",
|
|
517
|
-
value: result,
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
if (validate(vToolResultOutput, result)) {
|
|
521
|
-
return result;
|
|
522
|
-
}
|
|
523
|
-
return {
|
|
524
|
-
type: "json",
|
|
525
|
-
value: result ?? null,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
function normalizeToolResult(part, metadata) {
|
|
529
|
-
return {
|
|
530
|
-
type: part.type,
|
|
531
|
-
output: part.output
|
|
532
|
-
? validate(vToolResultOutput, part.output)
|
|
533
|
-
? part.output
|
|
534
|
-
: normalizeToolOutput(JSON.stringify(part.output))
|
|
535
|
-
: normalizeToolOutput("result" in part ? part.result : undefined),
|
|
536
|
-
toolCallId: part.toolCallId,
|
|
537
|
-
toolName: part.toolName,
|
|
538
|
-
// Preserve isError flag for error reporting
|
|
539
|
-
...("isError" in part && part.isError ? { isError: true } : {}),
|
|
540
|
-
...metadata,
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Return a best-guess MIME type based on the magic-number signature
|
|
545
|
-
* found at the start of an ArrayBuffer.
|
|
546
|
-
*
|
|
547
|
-
* @param buf – the source ArrayBuffer
|
|
548
|
-
* @returns the detected MIME type, or `"application/octet-stream"` if unknown
|
|
549
|
-
*/
|
|
550
|
-
export function guessMimeType(buf) {
|
|
551
|
-
if (typeof buf === "string") {
|
|
552
|
-
if (buf.match(/^data:\w+\/\w+;base64/)) {
|
|
553
|
-
return buf.split(";")[0].split(":")[1];
|
|
554
|
-
}
|
|
555
|
-
return "text/plain";
|
|
556
|
-
}
|
|
557
|
-
if (buf.byteLength < 4)
|
|
558
|
-
return "application/octet-stream";
|
|
559
|
-
// Read the first 12 bytes (enough for all signatures below)
|
|
560
|
-
const bytes = new Uint8Array(buf.slice(0, 12));
|
|
561
|
-
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
562
|
-
// Helper so we can look at only the needed prefix
|
|
563
|
-
const startsWith = (sig) => hex.startsWith(sig.toLowerCase());
|
|
564
|
-
// --- image formats ---
|
|
565
|
-
if (startsWith("89504e47"))
|
|
566
|
-
return "image/png"; // PNG - 89 50 4E 47
|
|
567
|
-
if (startsWith("ffd8ffdb") ||
|
|
568
|
-
startsWith("ffd8ffe0") ||
|
|
569
|
-
startsWith("ffd8ffee") ||
|
|
570
|
-
startsWith("ffd8ffe1"))
|
|
571
|
-
return "image/jpeg"; // JPEG
|
|
572
|
-
if (startsWith("47494638"))
|
|
573
|
-
return "image/gif"; // GIF
|
|
574
|
-
if (startsWith("424d"))
|
|
575
|
-
return "image/bmp"; // BMP
|
|
576
|
-
if (startsWith("52494646") && hex.substr(16, 8) === "57454250")
|
|
577
|
-
return "image/webp"; // WEBP (RIFF....WEBP)
|
|
578
|
-
if (startsWith("49492a00"))
|
|
579
|
-
return "image/tiff"; // TIFF
|
|
580
|
-
// <svg in hex is 3c 3f 78 6d 6c
|
|
581
|
-
if (startsWith("3c737667"))
|
|
582
|
-
return "image/svg+xml"; // <svg
|
|
583
|
-
if (startsWith("3c3f786d"))
|
|
584
|
-
return "image/svg+xml"; // <?xm
|
|
585
|
-
// --- audio/video ---
|
|
586
|
-
if (startsWith("494433"))
|
|
587
|
-
return "audio/mpeg"; // MP3 (ID3)
|
|
588
|
-
if (startsWith("000001ba") || startsWith("000001b3"))
|
|
589
|
-
return "video/mpeg"; // MPEG container
|
|
590
|
-
if (startsWith("1a45dfa3"))
|
|
591
|
-
return "video/webm"; // WEBM / Matroska
|
|
592
|
-
if (startsWith("00000018") && hex.substr(16, 8) === "66747970")
|
|
593
|
-
return "video/mp4"; // MP4
|
|
594
|
-
if (startsWith("4f676753"))
|
|
595
|
-
return "audio/ogg"; // OGG / Opus
|
|
596
|
-
// --- documents & archives ---
|
|
597
|
-
if (startsWith("25504446"))
|
|
598
|
-
return "application/pdf"; // PDF
|
|
599
|
-
if (startsWith("504b0304") ||
|
|
600
|
-
startsWith("504b0506") ||
|
|
601
|
-
startsWith("504b0708"))
|
|
602
|
-
return "application/zip"; // ZIP / DOCX / PPTX / XLSX / EPUB
|
|
603
|
-
if (startsWith("52617221"))
|
|
604
|
-
return "application/x-rar-compressed"; // RAR
|
|
605
|
-
if (startsWith("7f454c46"))
|
|
606
|
-
return "application/x-elf"; // ELF binaries
|
|
607
|
-
if (startsWith("1f8b08"))
|
|
608
|
-
return "application/gzip"; // GZIP
|
|
609
|
-
if (startsWith("425a68"))
|
|
610
|
-
return "application/x-bzip2"; // BZIP2
|
|
611
|
-
if (startsWith("3c3f786d6c"))
|
|
612
|
-
return "application/xml"; // XML
|
|
613
|
-
// Plain text, JSON and others are trickier—fallback:
|
|
614
|
-
return "application/octet-stream";
|
|
615
|
-
}
|
|
616
|
-
/**
|
|
617
|
-
* Serialize an AI SDK `DataContent` or `URL` to a Convex-serializable format.
|
|
618
|
-
* @param dataOrUrl - The data or URL to serialize.
|
|
619
|
-
* @returns The serialized data as an ArrayBuffer or the URL as a string.
|
|
620
|
-
*/
|
|
621
|
-
export function serializeDataOrUrl(dataOrUrl) {
|
|
622
|
-
if (typeof dataOrUrl === "string") {
|
|
623
|
-
return dataOrUrl;
|
|
624
|
-
}
|
|
625
|
-
if (dataOrUrl instanceof ArrayBuffer) {
|
|
626
|
-
return dataOrUrl; // Already an ArrayBuffer
|
|
627
|
-
}
|
|
628
|
-
if (dataOrUrl instanceof URL) {
|
|
629
|
-
return dataOrUrl.toString();
|
|
630
|
-
}
|
|
631
|
-
return dataOrUrl.buffer.slice(dataOrUrl.byteOffset, dataOrUrl.byteOffset + dataOrUrl.byteLength);
|
|
632
|
-
}
|
|
633
|
-
export function toModelMessageDataOrUrl(urlOrString) {
|
|
634
|
-
if (urlOrString instanceof URL) {
|
|
635
|
-
return urlOrString;
|
|
636
|
-
}
|
|
637
|
-
if (typeof urlOrString === "string") {
|
|
638
|
-
if (urlOrString.startsWith("http://") ||
|
|
639
|
-
urlOrString.startsWith("https://")) {
|
|
640
|
-
return new URL(urlOrString);
|
|
641
|
-
}
|
|
642
|
-
return urlOrString;
|
|
643
|
-
}
|
|
644
|
-
return urlOrString;
|
|
645
|
-
}
|
|
646
|
-
export function toUIFilePart(part) {
|
|
647
|
-
const dataOrUrl = part.type === "image" ? part.image : part.data;
|
|
648
|
-
const url = dataOrUrl instanceof ArrayBuffer
|
|
649
|
-
? convertUint8ArrayToBase64(new Uint8Array(dataOrUrl))
|
|
650
|
-
: dataOrUrl.toString();
|
|
651
|
-
return {
|
|
652
|
-
type: "file",
|
|
653
|
-
mediaType: part.mediaType,
|
|
654
|
-
filename: part.type === "file" ? part.filename : undefined,
|
|
655
|
-
url,
|
|
656
|
-
providerMetadata: part.providerOptions,
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
// Currently unused
|
|
660
|
-
// export function toModelMessages(args: {
|
|
661
|
-
// messages?: ModelMessage[] | AIMessageWithoutId[];
|
|
662
|
-
// }): ModelMessage[] {
|
|
663
|
-
// const messages: ModelMessage[] = [];
|
|
664
|
-
// if (args.messages) {
|
|
665
|
-
// if (
|
|
666
|
-
// args.messages.every(
|
|
667
|
-
// (m) => typeof m === "object" && m !== null && "parts" in m,
|
|
668
|
-
// )
|
|
669
|
-
// ) {
|
|
670
|
-
// messages.push(...convertToModelMessages(args.messages));
|
|
671
|
-
// } else {
|
|
672
|
-
// messages.push(...modelMessageSchema.array().parse(args.messages));
|
|
673
|
-
// }
|
|
674
|
-
// }
|
|
675
|
-
// return messages;
|
|
676
|
-
// }
|
|
677
|
-
//# sourceMappingURL=mapping.js.map
|