@convex-dev/agent 0.2.3-alpha.0 → 0.2.4-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/dist/client/definePlaygroundAPI.d.ts +59 -5
- package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/client/files.d.ts +1 -1
- package/dist/client/files.d.ts.map +1 -1
- package/dist/client/files.js.map +1 -1
- package/dist/client/index.d.ts +46 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +14 -13
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +14 -2
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/search.d.ts +14 -2
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/search.js +2 -4
- package/dist/client/search.js.map +1 -1
- package/dist/client/streaming.d.ts +132 -23
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/component/_generated/api.d.ts +189 -0
- package/dist/component/messages.d.ts +149 -20
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +4 -4
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +342 -63
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/mapping.d.ts +4 -4
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +67 -36
- package/dist/mapping.js.map +1 -1
- package/dist/react/deltas.d.ts +3 -3
- package/dist/react/deltas.d.ts.map +1 -1
- package/dist/react/deltas.js +302 -30
- package/dist/react/deltas.js.map +1 -1
- package/dist/react/toUIMessages.d.ts.map +1 -1
- package/dist/react/toUIMessages.js +289 -180
- package/dist/react/toUIMessages.js.map +1 -1
- package/dist/react/useSmoothText.d.ts.map +1 -1
- package/dist/react/useSmoothText.js +15 -6
- package/dist/react/useSmoothText.js.map +1 -1
- package/dist/shared.d.ts +4 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +8 -0
- package/dist/shared.js.map +1 -1
- package/dist/validators.d.ts +662 -104
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +8 -0
- package/dist/validators.js.map +1 -1
- package/package.json +1 -1
- package/src/client/files.ts +4 -4
- package/src/client/index.ts +21 -20
- package/src/client/search.ts +2 -6
- package/src/component/_generated/api.d.ts +189 -0
- package/src/component/messages.ts +4 -3
- package/src/mapping.ts +99 -51
- package/src/react/deltas.ts +368 -48
- package/src/react/toUIMessages.test.ts +186 -0
- package/src/react/toUIMessages.ts +366 -192
- package/src/react/useSmoothText.ts +25 -13
- package/src/shared.ts +14 -0
- package/src/validators.ts +8 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DEFAULT_RECENT_MESSAGES,
|
|
11
11
|
extractText,
|
|
12
12
|
isTool,
|
|
13
|
+
sorted,
|
|
13
14
|
} from "../shared.js";
|
|
14
15
|
import {
|
|
15
16
|
vMessageEmbeddingsWithDimension,
|
|
@@ -631,11 +632,11 @@ export const _fetchSearchMessages = internalQuery({
|
|
|
631
632
|
.map(publicMessage);
|
|
632
633
|
messages.push(...(args.textSearchMessages ?? []));
|
|
633
634
|
// TODO: prioritize more recent messages
|
|
634
|
-
messages
|
|
635
|
+
messages = sorted(messages);
|
|
635
636
|
messages = messages.slice(0, args.limit);
|
|
636
637
|
// Fetch the surrounding messages
|
|
637
638
|
if (!threadId) {
|
|
638
|
-
return messages
|
|
639
|
+
return messages;
|
|
639
640
|
}
|
|
640
641
|
const included: Record<string, Set<number>> = {};
|
|
641
642
|
for (const m of messages) {
|
|
@@ -688,7 +689,7 @@ export const _fetchSearchMessages = internalQuery({
|
|
|
688
689
|
messages.push(publicMessage(r));
|
|
689
690
|
}
|
|
690
691
|
}
|
|
691
|
-
return messages
|
|
692
|
+
return sorted(messages);
|
|
692
693
|
},
|
|
693
694
|
});
|
|
694
695
|
|
package/src/mapping.ts
CHANGED
|
@@ -16,19 +16,21 @@ import {
|
|
|
16
16
|
type TextPart,
|
|
17
17
|
type ToolCallPart,
|
|
18
18
|
type ToolResultPart,
|
|
19
|
+
type ProviderMetadata,
|
|
19
20
|
} from "ai";
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
import {
|
|
22
|
+
vMessageWithMetadata,
|
|
23
|
+
type Message,
|
|
24
|
+
type MessageWithMetadata,
|
|
25
|
+
type Usage,
|
|
26
|
+
type vContent,
|
|
27
|
+
type vFilePart,
|
|
28
|
+
type vImagePart,
|
|
29
|
+
type vReasoningPart,
|
|
30
|
+
type vRedactedReasoningPart,
|
|
31
|
+
type vTextPart,
|
|
32
|
+
type vToolCallPart,
|
|
33
|
+
type vToolResultPart,
|
|
32
34
|
} from "./validators.js";
|
|
33
35
|
import type { ActionCtx, AgentComponent } from "./client/types.js";
|
|
34
36
|
import type { RunMutationCtx } from "./client/types.js";
|
|
@@ -36,8 +38,10 @@ import { MAX_FILE_SIZE, storeFile } from "./client/files.js";
|
|
|
36
38
|
import type { Infer } from "convex/values";
|
|
37
39
|
import {
|
|
38
40
|
convertUint8ArrayToBase64,
|
|
41
|
+
type ProviderOptions,
|
|
39
42
|
type ReasoningPart,
|
|
40
43
|
} from "@ai-sdk/provider-utils";
|
|
44
|
+
import { parse } from "convex-helpers/validators";
|
|
41
45
|
export type AIMessageWithoutId = Omit<AIMessage, "id">;
|
|
42
46
|
|
|
43
47
|
export type SerializeUrlsAndUint8Arrays<T> = T extends URL
|
|
@@ -97,7 +101,9 @@ export async function serializeOrThrow(
|
|
|
97
101
|
} as SerializedMessage;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
export function deserializeMessage(
|
|
104
|
+
export function deserializeMessage(
|
|
105
|
+
message: SerializedMessage | ModelMessage,
|
|
106
|
+
): ModelMessage {
|
|
101
107
|
return {
|
|
102
108
|
...message,
|
|
103
109
|
content: deserializeContent(message.content),
|
|
@@ -171,12 +177,12 @@ export async function serializeNewMessagesInStep<TOOLS extends ToolSet>(
|
|
|
171
177
|
: step.response.messages.slice(-1)
|
|
172
178
|
).map(async (msg): Promise<MessageWithMetadata> => {
|
|
173
179
|
const { message, fileIds } = await serializeMessage(ctx, component, msg);
|
|
174
|
-
return {
|
|
180
|
+
return parse(vMessageWithMetadata, {
|
|
175
181
|
message,
|
|
176
182
|
...(message.role === "tool" ? toolFields : assistantFields),
|
|
177
183
|
text: step.text,
|
|
178
184
|
fileIds,
|
|
179
|
-
};
|
|
185
|
+
});
|
|
180
186
|
}),
|
|
181
187
|
);
|
|
182
188
|
// TODO: capture step.files separately?
|
|
@@ -212,6 +218,16 @@ export async function serializeObjectResult(
|
|
|
212
218
|
};
|
|
213
219
|
}
|
|
214
220
|
|
|
221
|
+
function getMimeOrMediaType(part: { mediaType?: string; mimeType?: string }) {
|
|
222
|
+
if ("mediaType" in part) {
|
|
223
|
+
return part.mediaType;
|
|
224
|
+
}
|
|
225
|
+
if ("mimeType" in part) {
|
|
226
|
+
return part.mimeType;
|
|
227
|
+
}
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
215
231
|
export async function serializeContent(
|
|
216
232
|
ctx: ActionCtx | RunMutationCtx,
|
|
217
233
|
component: AgentComponent,
|
|
@@ -221,14 +237,15 @@ export async function serializeContent(
|
|
|
221
237
|
return { content };
|
|
222
238
|
}
|
|
223
239
|
const fileIds: string[] = [];
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
const metadata: {
|
|
241
|
+
providerOptions?: ProviderOptions;
|
|
242
|
+
providerMetadata?: ProviderMetadata;
|
|
243
|
+
} = {};
|
|
244
|
+
if ("providerOptions" in content) {
|
|
245
|
+
metadata.providerOptions = content.providerOptions as ProviderOptions;
|
|
246
|
+
}
|
|
247
|
+
if ("providerMetadata" in content) {
|
|
248
|
+
metadata.providerMetadata = content.providerMetadata as ProviderMetadata;
|
|
232
249
|
}
|
|
233
250
|
const serialized = await Promise.all(
|
|
234
251
|
content.map(async (part) => {
|
|
@@ -237,7 +254,7 @@ export async function serializeContent(
|
|
|
237
254
|
return {
|
|
238
255
|
type: part.type,
|
|
239
256
|
text: part.text,
|
|
240
|
-
|
|
257
|
+
...metadata,
|
|
241
258
|
} satisfies Infer<typeof vTextPart>;
|
|
242
259
|
}
|
|
243
260
|
case "image": {
|
|
@@ -250,7 +267,7 @@ export async function serializeContent(
|
|
|
250
267
|
ctx,
|
|
251
268
|
component,
|
|
252
269
|
new Blob([image], {
|
|
253
|
-
type:
|
|
270
|
+
type: getMimeOrMediaType(part) || guessMimeType(image),
|
|
254
271
|
}),
|
|
255
272
|
);
|
|
256
273
|
image = file.url;
|
|
@@ -258,8 +275,8 @@ export async function serializeContent(
|
|
|
258
275
|
}
|
|
259
276
|
return {
|
|
260
277
|
type: part.type,
|
|
261
|
-
mimeType:
|
|
262
|
-
|
|
278
|
+
mimeType: getMimeOrMediaType(part),
|
|
279
|
+
...metadata,
|
|
263
280
|
image,
|
|
264
281
|
} satisfies Infer<typeof vImagePart>;
|
|
265
282
|
}
|
|
@@ -269,7 +286,7 @@ export async function serializeContent(
|
|
|
269
286
|
const { file } = await storeFile(
|
|
270
287
|
ctx,
|
|
271
288
|
component,
|
|
272
|
-
new Blob([data], { type:
|
|
289
|
+
new Blob([data], { type: getMimeOrMediaType(part) }),
|
|
273
290
|
);
|
|
274
291
|
data = file.url;
|
|
275
292
|
fileIds.push(file.fileId);
|
|
@@ -278,8 +295,8 @@ export async function serializeContent(
|
|
|
278
295
|
type: part.type,
|
|
279
296
|
data,
|
|
280
297
|
filename: part.filename,
|
|
281
|
-
mimeType:
|
|
282
|
-
|
|
298
|
+
mimeType: getMimeOrMediaType(part)!,
|
|
299
|
+
...metadata,
|
|
283
300
|
} satisfies Infer<typeof vFilePart>;
|
|
284
301
|
}
|
|
285
302
|
case "tool-call": {
|
|
@@ -289,8 +306,8 @@ export async function serializeContent(
|
|
|
289
306
|
args: args ?? null,
|
|
290
307
|
toolCallId: part.toolCallId,
|
|
291
308
|
toolName: part.toolName,
|
|
292
|
-
providerOptions: part.providerOptions,
|
|
293
309
|
providerExecuted: part.providerExecuted,
|
|
310
|
+
...metadata,
|
|
294
311
|
} satisfies Infer<typeof vToolCallPart>;
|
|
295
312
|
}
|
|
296
313
|
case "tool-result": {
|
|
@@ -300,14 +317,14 @@ export async function serializeContent(
|
|
|
300
317
|
result: result ?? null,
|
|
301
318
|
toolCallId: part.toolCallId,
|
|
302
319
|
toolName: part.toolName,
|
|
303
|
-
|
|
320
|
+
...metadata,
|
|
304
321
|
} satisfies Infer<typeof vToolResultPart>;
|
|
305
322
|
}
|
|
306
323
|
case "reasoning": {
|
|
307
324
|
return {
|
|
308
325
|
type: part.type,
|
|
309
326
|
text: part.text,
|
|
310
|
-
|
|
327
|
+
...metadata,
|
|
311
328
|
} satisfies Infer<typeof vReasoningPart>;
|
|
312
329
|
}
|
|
313
330
|
// Not in current generation output, but could be in historical messages
|
|
@@ -315,7 +332,7 @@ export async function serializeContent(
|
|
|
315
332
|
return {
|
|
316
333
|
type: part.type,
|
|
317
334
|
data: part.data,
|
|
318
|
-
|
|
335
|
+
...metadata,
|
|
319
336
|
} satisfies Infer<typeof vRedactedReasoningPart>;
|
|
320
337
|
}
|
|
321
338
|
default:
|
|
@@ -329,62 +346,90 @@ export async function serializeContent(
|
|
|
329
346
|
};
|
|
330
347
|
}
|
|
331
348
|
|
|
332
|
-
export function deserializeContent(
|
|
349
|
+
export function deserializeContent(
|
|
350
|
+
content: SerializedContent | ModelMessage["content"],
|
|
351
|
+
): Content {
|
|
333
352
|
if (typeof content === "string") {
|
|
334
353
|
return content;
|
|
335
354
|
}
|
|
336
355
|
return content.map((part) => {
|
|
356
|
+
const metadata: {
|
|
357
|
+
providerOptions?: ProviderOptions;
|
|
358
|
+
providerMetadata?: ProviderMetadata;
|
|
359
|
+
} = {};
|
|
360
|
+
if ("providerOptions" in part) {
|
|
361
|
+
metadata.providerOptions = part.providerOptions;
|
|
362
|
+
}
|
|
363
|
+
if ("providerMetadata" in part) {
|
|
364
|
+
metadata.providerMetadata = part.providerMetadata;
|
|
365
|
+
}
|
|
337
366
|
switch (part.type) {
|
|
338
367
|
case "text":
|
|
339
368
|
return {
|
|
340
369
|
type: part.type,
|
|
341
370
|
text: part.text,
|
|
342
|
-
|
|
371
|
+
...metadata,
|
|
343
372
|
} satisfies TextPart;
|
|
344
373
|
case "image":
|
|
345
374
|
return {
|
|
346
375
|
type: part.type,
|
|
347
376
|
image: deserializeUrl(part.image),
|
|
348
|
-
mediaType: part
|
|
349
|
-
|
|
377
|
+
mediaType: getMimeOrMediaType(part),
|
|
378
|
+
...metadata,
|
|
350
379
|
} satisfies ImagePart;
|
|
351
380
|
case "file":
|
|
352
381
|
return {
|
|
353
382
|
type: part.type,
|
|
354
383
|
data: deserializeUrl(part.data),
|
|
355
384
|
filename: part.filename,
|
|
356
|
-
mediaType: part
|
|
357
|
-
|
|
385
|
+
mediaType: getMimeOrMediaType(part)!,
|
|
386
|
+
...metadata,
|
|
358
387
|
} satisfies FilePart;
|
|
359
|
-
case "tool-call":
|
|
388
|
+
case "tool-call": {
|
|
389
|
+
const input = "input" in part ? part.input : part.args;
|
|
360
390
|
return {
|
|
361
391
|
type: part.type,
|
|
362
|
-
input:
|
|
363
|
-
providerExecuted: part.providerExecuted,
|
|
392
|
+
input: input ?? null,
|
|
364
393
|
toolCallId: part.toolCallId,
|
|
365
394
|
toolName: part.toolName,
|
|
366
|
-
|
|
395
|
+
providerExecuted: part.providerExecuted,
|
|
396
|
+
...metadata,
|
|
367
397
|
} satisfies ToolCallPart;
|
|
368
|
-
|
|
398
|
+
}
|
|
399
|
+
case "tool-result": {
|
|
400
|
+
const result = "output" in part ? part.output : part.result;
|
|
369
401
|
return {
|
|
370
402
|
type: part.type,
|
|
371
|
-
output:
|
|
403
|
+
output: result ?? null,
|
|
372
404
|
toolCallId: part.toolCallId,
|
|
373
405
|
toolName: part.toolName,
|
|
374
|
-
|
|
406
|
+
...metadata,
|
|
375
407
|
} satisfies ToolResultPart;
|
|
408
|
+
}
|
|
376
409
|
case "reasoning":
|
|
377
410
|
return {
|
|
378
411
|
type: part.type,
|
|
379
412
|
text: part.text,
|
|
380
|
-
|
|
413
|
+
...metadata,
|
|
381
414
|
} satisfies ReasoningPart;
|
|
382
415
|
case "redacted-reasoning":
|
|
383
416
|
// TODO: should we just drop this?
|
|
384
417
|
return {
|
|
385
418
|
type: "reasoning",
|
|
386
|
-
text:
|
|
387
|
-
|
|
419
|
+
text: "",
|
|
420
|
+
...metadata,
|
|
421
|
+
providerOptions: metadata.providerOptions
|
|
422
|
+
? {
|
|
423
|
+
...Object.fromEntries(
|
|
424
|
+
Object.entries(metadata.providerOptions ?? {}).map(
|
|
425
|
+
([key, value]) => [
|
|
426
|
+
key,
|
|
427
|
+
{ ...value, redactedData: part.data },
|
|
428
|
+
],
|
|
429
|
+
),
|
|
430
|
+
),
|
|
431
|
+
}
|
|
432
|
+
: undefined,
|
|
388
433
|
} satisfies ReasoningPart;
|
|
389
434
|
default:
|
|
390
435
|
return part satisfies Content;
|
|
@@ -483,8 +528,11 @@ export function serializeDataOrUrl(
|
|
|
483
528
|
}
|
|
484
529
|
|
|
485
530
|
export function deserializeUrl(
|
|
486
|
-
urlOrString: string | ArrayBuffer,
|
|
531
|
+
urlOrString: string | ArrayBuffer | URL | DataContent,
|
|
487
532
|
): URL | DataContent {
|
|
533
|
+
if (urlOrString instanceof URL) {
|
|
534
|
+
return urlOrString;
|
|
535
|
+
}
|
|
488
536
|
if (typeof urlOrString === "string") {
|
|
489
537
|
if (
|
|
490
538
|
urlOrString.startsWith("http://") ||
|