@convex-dev/agent 0.2.12 → 0.3.1
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/createTool.d.ts.map +1 -1
- package/dist/client/createTool.js +0 -2
- package/dist/client/createTool.js.map +1 -1
- package/dist/client/definePlaygroundAPI.d.ts +10 -10
- package/dist/client/files.d.ts +5 -2
- package/dist/client/files.d.ts.map +1 -1
- package/dist/client/files.js.map +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -8
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +2 -2
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js.map +1 -1
- package/dist/client/saveInputMessages.d.ts.map +1 -1
- package/dist/client/saveInputMessages.js +1 -0
- package/dist/client/saveInputMessages.js.map +1 -1
- package/dist/client/search.d.ts +1 -1
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/start.d.ts.map +1 -1
- package/dist/client/start.js.map +1 -1
- package/dist/client/streaming.d.ts +3 -3
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js.map +1 -1
- package/dist/client/threads.d.ts +6 -6
- package/dist/client/threads.d.ts.map +1 -1
- package/dist/client/threads.js.map +1 -1
- package/dist/client/types.d.ts +6 -25
- package/dist/client/types.d.ts.map +1 -1
- package/dist/component/_generated/api.d.ts +24 -2563
- 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 +2276 -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/messages.d.ts +59 -3
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +157 -39
- package/dist/component/messages.js.map +1 -1
- package/dist/component/streams.d.ts +1 -1
- package/dist/component/threads.d.ts +4 -4
- package/dist/component/users.d.ts +3 -3
- 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.js +1 -1
- package/dist/deltas.js.map +1 -1
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +1 -5
- package/dist/mapping.js.map +1 -1
- package/dist/react/useDeltaStreams.d.ts.map +1 -1
- package/dist/react/useDeltaStreams.js.map +1 -1
- package/dist/react/useStreamingUIMessages.d.ts.map +1 -1
- package/dist/react/useStreamingUIMessages.js +0 -1
- package/dist/react/useStreamingUIMessages.js.map +1 -1
- package/dist/react/useThreadMessages.d.ts.map +1 -1
- package/dist/react/useThreadMessages.js +1 -2
- package/dist/react/useThreadMessages.js.map +1 -1
- package/dist/react/useUIMessages.d.ts.map +1 -1
- package/dist/react/useUIMessages.js +1 -2
- package/dist/react/useUIMessages.js.map +1 -1
- package/package.json +29 -31
- package/src/client/createTool.ts +0 -2
- package/src/client/files.ts +3 -2
- package/src/client/index.test.ts +0 -1
- package/src/client/index.ts +4 -9
- package/src/client/messages.ts +2 -2
- package/src/client/saveInputMessages.test.ts +0 -1
- package/src/client/saveInputMessages.ts +1 -0
- package/src/client/search.test.ts +0 -1
- package/src/client/search.ts +1 -1
- package/src/client/start.ts +3 -8
- package/src/client/streaming.ts +2 -2
- package/src/client/threads.ts +2 -2
- package/src/client/types.ts +13 -61
- package/src/component/_generated/api.ts +64 -0
- package/src/component/_generated/component.ts +2922 -0
- package/src/component/_generated/{server.d.ts → server.ts} +33 -21
- package/src/component/messages.ts +209 -52
- package/src/component/vector/index.ts +1 -3
- package/src/deltas.ts +1 -1
- package/src/mapping.ts +1 -4
- package/src/react/useDeltaStreams.ts +0 -1
- package/src/react/useStreamingUIMessages.ts +0 -2
- package/src/react/useThreadMessages.ts +3 -10
- package/src/react/useUIMessages.ts +2 -6
- package/src/test.ts +2 -1
- package/src/validators.test.ts +14 -7
- package/src/component/_generated/api.d.ts +0 -2587
- package/src/component/_generated/api.js +0 -23
- package/src/component/_generated/server.js +0 -90
- package/src/vitest.config.ts +0 -7
- /package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +0 -0
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import type {
|
|
12
12
|
ActionBuilder,
|
|
13
|
-
AnyComponents,
|
|
14
13
|
HttpActionBuilder,
|
|
15
14
|
MutationBuilder,
|
|
16
15
|
QueryBuilder,
|
|
@@ -19,15 +18,18 @@ import {
|
|
|
19
18
|
GenericQueryCtx,
|
|
20
19
|
GenericDatabaseReader,
|
|
21
20
|
GenericDatabaseWriter,
|
|
22
|
-
|
|
21
|
+
} from "convex/server";
|
|
22
|
+
import {
|
|
23
|
+
actionGeneric,
|
|
24
|
+
httpActionGeneric,
|
|
25
|
+
queryGeneric,
|
|
26
|
+
mutationGeneric,
|
|
27
|
+
internalActionGeneric,
|
|
28
|
+
internalMutationGeneric,
|
|
29
|
+
internalQueryGeneric,
|
|
23
30
|
} from "convex/server";
|
|
24
31
|
import type { DataModel } from "./dataModel.js";
|
|
25
32
|
|
|
26
|
-
type GenericCtx =
|
|
27
|
-
| GenericActionCtx<DataModel>
|
|
28
|
-
| GenericMutationCtx<DataModel>
|
|
29
|
-
| GenericQueryCtx<DataModel>;
|
|
30
|
-
|
|
31
33
|
/**
|
|
32
34
|
* Define a query in this Convex app's public API.
|
|
33
35
|
*
|
|
@@ -36,7 +38,7 @@ type GenericCtx =
|
|
|
36
38
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
37
39
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
38
40
|
*/
|
|
39
|
-
export
|
|
41
|
+
export const query: QueryBuilder<DataModel, "public"> = queryGeneric;
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Define a query that is only accessible from other Convex functions (but not from the client).
|
|
@@ -46,7 +48,8 @@ export declare const query: QueryBuilder<DataModel, "public">;
|
|
|
46
48
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
47
49
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
48
50
|
*/
|
|
49
|
-
export
|
|
51
|
+
export const internalQuery: QueryBuilder<DataModel, "internal"> =
|
|
52
|
+
internalQueryGeneric;
|
|
50
53
|
|
|
51
54
|
/**
|
|
52
55
|
* Define a mutation in this Convex app's public API.
|
|
@@ -56,7 +59,7 @@ export declare const internalQuery: QueryBuilder<DataModel, "internal">;
|
|
|
56
59
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
57
60
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
58
61
|
*/
|
|
59
|
-
export
|
|
62
|
+
export const mutation: MutationBuilder<DataModel, "public"> = mutationGeneric;
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
|
@@ -66,7 +69,8 @@ export declare const mutation: MutationBuilder<DataModel, "public">;
|
|
|
66
69
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
67
70
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
68
71
|
*/
|
|
69
|
-
export
|
|
72
|
+
export const internalMutation: MutationBuilder<DataModel, "internal"> =
|
|
73
|
+
internalMutationGeneric;
|
|
70
74
|
|
|
71
75
|
/**
|
|
72
76
|
* Define an action in this Convex app's public API.
|
|
@@ -79,7 +83,7 @@ export declare const internalMutation: MutationBuilder<DataModel, "internal">;
|
|
|
79
83
|
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
|
80
84
|
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
|
81
85
|
*/
|
|
82
|
-
export
|
|
86
|
+
export const action: ActionBuilder<DataModel, "public"> = actionGeneric;
|
|
83
87
|
|
|
84
88
|
/**
|
|
85
89
|
* Define an action that is only accessible from other Convex functions (but not from the client).
|
|
@@ -87,19 +91,26 @@ export declare const action: ActionBuilder<DataModel, "public">;
|
|
|
87
91
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
|
88
92
|
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
|
89
93
|
*/
|
|
90
|
-
export
|
|
94
|
+
export const internalAction: ActionBuilder<DataModel, "internal"> =
|
|
95
|
+
internalActionGeneric;
|
|
91
96
|
|
|
92
97
|
/**
|
|
93
98
|
* Define an HTTP action.
|
|
94
99
|
*
|
|
95
|
-
*
|
|
96
|
-
* deployment if the requests matches the path and method where
|
|
97
|
-
* is routed. Be sure to route your
|
|
100
|
+
* The wrapped function will be used to respond to HTTP requests received
|
|
101
|
+
* by a Convex deployment if the requests matches the path and method where
|
|
102
|
+
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
|
98
103
|
*
|
|
99
|
-
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
|
104
|
+
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
|
105
|
+
* and a Fetch API `Request` object as its second.
|
|
100
106
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
|
101
107
|
*/
|
|
102
|
-
export
|
|
108
|
+
export const httpAction: HttpActionBuilder = httpActionGeneric;
|
|
109
|
+
|
|
110
|
+
type GenericCtx =
|
|
111
|
+
| GenericActionCtx<DataModel>
|
|
112
|
+
| GenericMutationCtx<DataModel>
|
|
113
|
+
| GenericQueryCtx<DataModel>;
|
|
103
114
|
|
|
104
115
|
/**
|
|
105
116
|
* A set of services for use within Convex query functions.
|
|
@@ -107,8 +118,7 @@ export declare const httpAction: HttpActionBuilder;
|
|
|
107
118
|
* The query context is passed as the first argument to any Convex query
|
|
108
119
|
* function run on the server.
|
|
109
120
|
*
|
|
110
|
-
*
|
|
111
|
-
* read-only.
|
|
121
|
+
* If you're using code generation, use the `QueryCtx` type in `convex/_generated/server.d.ts` instead.
|
|
112
122
|
*/
|
|
113
123
|
export type QueryCtx = GenericQueryCtx<DataModel>;
|
|
114
124
|
|
|
@@ -117,6 +127,8 @@ export type QueryCtx = GenericQueryCtx<DataModel>;
|
|
|
117
127
|
*
|
|
118
128
|
* The mutation context is passed as the first argument to any Convex mutation
|
|
119
129
|
* function run on the server.
|
|
130
|
+
*
|
|
131
|
+
* If you're using code generation, use the `MutationCtx` type in `convex/_generated/server.d.ts` instead.
|
|
120
132
|
*/
|
|
121
133
|
export type MutationCtx = GenericMutationCtx<DataModel>;
|
|
122
134
|
|
|
@@ -24,6 +24,7 @@ import { api, internal } from "./_generated/api.js";
|
|
|
24
24
|
import type { Doc, Id } from "./_generated/dataModel.js";
|
|
25
25
|
import {
|
|
26
26
|
action,
|
|
27
|
+
internalMutation,
|
|
27
28
|
internalQuery,
|
|
28
29
|
mutation,
|
|
29
30
|
type MutationCtx,
|
|
@@ -137,6 +138,9 @@ const addMessagesArgs = {
|
|
|
137
138
|
failPendingSteps: v.optional(v.boolean()),
|
|
138
139
|
// A pending message to update. If the pending message failed, abort.
|
|
139
140
|
pendingMessageId: v.optional(v.id("messages")),
|
|
141
|
+
// if set to true, these messages will not show up in text or vector search
|
|
142
|
+
// results for the userId
|
|
143
|
+
hideFromUserIdSearch: v.optional(v.boolean()),
|
|
140
144
|
};
|
|
141
145
|
export const addMessages = mutation({
|
|
142
146
|
args: addMessagesArgs,
|
|
@@ -160,6 +164,7 @@ async function addMessagesHandler(
|
|
|
160
164
|
messages,
|
|
161
165
|
promptMessageId,
|
|
162
166
|
pendingMessageId,
|
|
167
|
+
hideFromUserIdSearch,
|
|
163
168
|
...rest
|
|
164
169
|
} = args;
|
|
165
170
|
const promptMessage = promptMessageId && (await ctx.db.get(promptMessageId));
|
|
@@ -226,7 +231,7 @@ async function addMessagesHandler(
|
|
|
226
231
|
vector: embeddings.vectors[i]!,
|
|
227
232
|
model: embeddings.model,
|
|
228
233
|
table: "messages",
|
|
229
|
-
userId,
|
|
234
|
+
userId: hideFromUserIdSearch ? undefined : userId,
|
|
230
235
|
threadId,
|
|
231
236
|
});
|
|
232
237
|
}
|
|
@@ -237,7 +242,7 @@ async function addMessagesHandler(
|
|
|
237
242
|
parentMessageId: promptMessageId,
|
|
238
243
|
userId,
|
|
239
244
|
tool: isTool(message.message),
|
|
240
|
-
text: extractText(message.message),
|
|
245
|
+
text: hideFromUserIdSearch ? undefined : extractText(message.message),
|
|
241
246
|
status: fail ? "failed" : (message.status ?? "success"),
|
|
242
247
|
error: fail ? error : message.error,
|
|
243
248
|
} satisfies Omit<
|
|
@@ -439,64 +444,216 @@ export const updateMessage = mutation({
|
|
|
439
444
|
},
|
|
440
445
|
});
|
|
441
446
|
|
|
442
|
-
|
|
447
|
+
const cloneMessageArgs = {
|
|
448
|
+
sourceThreadId: v.id("threads"),
|
|
449
|
+
targetThreadId: v.id("threads"),
|
|
450
|
+
// defaults to false, so searching for a message by userId will not find
|
|
451
|
+
// these copies
|
|
452
|
+
copyUserIdForVectorSearch: v.optional(v.boolean()),
|
|
453
|
+
// defaults to false, so tool calls & responses will be copied
|
|
454
|
+
excludeToolMessages: v.optional(v.boolean()),
|
|
455
|
+
// defaults to copying all messages, but you could just copy success messages.
|
|
456
|
+
statuses: v.optional(v.array(vMessageStatus)),
|
|
457
|
+
// stop at this message id
|
|
458
|
+
upToAndIncludingMessageId: v.optional(v.id("messages")),
|
|
459
|
+
// defaults to 0. the messages will be inserted starting at this order.
|
|
460
|
+
insertAtOrder: v.optional(v.number()),
|
|
461
|
+
};
|
|
462
|
+
export const cloneMessageBatch = internalMutation({
|
|
443
463
|
args: {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
/** What order to sort the messages in. To get the latest, use "desc". */
|
|
447
|
-
order: v.union(v.literal("asc"), v.literal("desc")),
|
|
448
|
-
paginationOpts: v.optional(paginationOptsValidator),
|
|
449
|
-
statuses: v.optional(v.array(vMessageStatus)),
|
|
450
|
-
upToAndIncludingMessageId: v.optional(v.id("messages")),
|
|
464
|
+
...cloneMessageArgs,
|
|
465
|
+
paginationOpts: paginationOptsValidator,
|
|
451
466
|
},
|
|
452
|
-
handler: async (
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
467
|
+
handler: async (
|
|
468
|
+
ctx,
|
|
469
|
+
args,
|
|
470
|
+
): Promise<{
|
|
471
|
+
numCopied: number;
|
|
472
|
+
continueCursor: string;
|
|
473
|
+
isDone: boolean;
|
|
474
|
+
}> => {
|
|
475
|
+
const orderOffset = args.insertAtOrder ?? 0;
|
|
476
|
+
const result = await listMessagesByThreadIdHandler(ctx, {
|
|
477
|
+
threadId: args.sourceThreadId,
|
|
478
|
+
excludeToolMessages: args.excludeToolMessages,
|
|
479
|
+
order: "desc",
|
|
480
|
+
paginationOpts: args.paginationOpts,
|
|
481
|
+
statuses: args.statuses,
|
|
482
|
+
upToAndIncludingMessageId: args.upToAndIncludingMessageId,
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
const existing =
|
|
486
|
+
result.page.length === 0
|
|
487
|
+
? []
|
|
488
|
+
: await mergedStream(
|
|
489
|
+
[true, false].flatMap((tool) =>
|
|
490
|
+
messageStatuses.map((status) =>
|
|
491
|
+
stream(ctx.db, schema)
|
|
492
|
+
.query("messages")
|
|
493
|
+
.withIndex("threadId_status_tool_order_stepOrder", (q) =>
|
|
494
|
+
q
|
|
495
|
+
.eq("threadId", args.targetThreadId)
|
|
496
|
+
.eq("status", status)
|
|
497
|
+
.eq("tool", tool)
|
|
498
|
+
.gte("order", result.page[0].order)
|
|
499
|
+
.lte("order", result.page[result.page.length - 1].order),
|
|
500
|
+
),
|
|
501
|
+
),
|
|
502
|
+
),
|
|
503
|
+
["order", "stepOrder"],
|
|
504
|
+
).collect();
|
|
505
|
+
|
|
506
|
+
await Promise.all(
|
|
507
|
+
result.page
|
|
508
|
+
.filter(
|
|
509
|
+
(m) =>
|
|
510
|
+
!existing.some(
|
|
511
|
+
(e) => e.order === m.order && e.stepOrder === m.stepOrder,
|
|
512
|
+
),
|
|
513
|
+
)
|
|
514
|
+
.map(async (m) => {
|
|
515
|
+
// update file refs
|
|
516
|
+
if (m.fileIds) {
|
|
517
|
+
await changeRefcount(ctx, [], m.fileIds);
|
|
518
|
+
}
|
|
519
|
+
let embeddingId: VectorTableId | undefined = undefined;
|
|
520
|
+
if (m.embeddingId) {
|
|
521
|
+
const vector = await ctx.db.get(m.embeddingId);
|
|
522
|
+
assert(vector, `Vector ${m.embeddingId} not found`);
|
|
523
|
+
const dimension = vector.vector.length;
|
|
524
|
+
validateVectorDimension(dimension);
|
|
525
|
+
embeddingId = await insertVector(ctx, dimension, {
|
|
526
|
+
...pick(vector, ["model", "table", "vector"]),
|
|
527
|
+
userId: args.copyUserIdForVectorSearch
|
|
528
|
+
? vector.userId
|
|
529
|
+
: undefined,
|
|
530
|
+
threadId: args.targetThreadId,
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
await ctx.db.insert("messages", {
|
|
534
|
+
...omit(m, [
|
|
535
|
+
"_id",
|
|
536
|
+
"_creationTime",
|
|
537
|
+
"threadId",
|
|
538
|
+
"order",
|
|
539
|
+
"embeddingId",
|
|
540
|
+
]),
|
|
541
|
+
embeddingId,
|
|
542
|
+
threadId: args.targetThreadId,
|
|
543
|
+
order: orderOffset + m.order,
|
|
544
|
+
});
|
|
545
|
+
}),
|
|
494
546
|
);
|
|
547
|
+
return {
|
|
548
|
+
numCopied: result.page.length,
|
|
549
|
+
continueCursor: result.continueCursor,
|
|
550
|
+
isDone: result.isDone,
|
|
551
|
+
};
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
export const cloneThread = action({
|
|
556
|
+
args: {
|
|
557
|
+
...cloneMessageArgs,
|
|
558
|
+
batchSize: v.optional(v.number()),
|
|
559
|
+
// how many messages to copy
|
|
560
|
+
limit: v.optional(v.number()),
|
|
561
|
+
},
|
|
562
|
+
returns: v.number(),
|
|
563
|
+
handler: async (ctx, args) => {
|
|
564
|
+
let cursor: string | null = null;
|
|
565
|
+
let copiedSoFar = 0;
|
|
566
|
+
while (copiedSoFar < (args.limit ?? Infinity)) {
|
|
567
|
+
const numToCopy = Math.min(
|
|
568
|
+
args.batchSize ?? DEFAULT_RECENT_MESSAGES,
|
|
569
|
+
args.limit ?? Infinity - copiedSoFar,
|
|
570
|
+
);
|
|
571
|
+
const result: {
|
|
572
|
+
numCopied: number;
|
|
573
|
+
continueCursor: string;
|
|
574
|
+
isDone: boolean;
|
|
575
|
+
} = await ctx.runMutation(internal.messages.cloneMessageBatch, {
|
|
576
|
+
...args,
|
|
577
|
+
paginationOpts: {
|
|
578
|
+
cursor,
|
|
579
|
+
numItems: numToCopy,
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
copiedSoFar += result.numCopied;
|
|
583
|
+
cursor = result.continueCursor;
|
|
584
|
+
if (result.isDone) {
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return copiedSoFar;
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
export const listMessagesByThreadIdArgs = {
|
|
593
|
+
threadId: v.id("threads"),
|
|
594
|
+
excludeToolMessages: v.optional(v.boolean()),
|
|
595
|
+
/** What order to sort the messages in. To get the latest, use "desc". */
|
|
596
|
+
order: v.union(v.literal("asc"), v.literal("desc")),
|
|
597
|
+
paginationOpts: v.optional(paginationOptsValidator),
|
|
598
|
+
statuses: v.optional(v.array(vMessageStatus)),
|
|
599
|
+
upToAndIncludingMessageId: v.optional(v.id("messages")),
|
|
600
|
+
};
|
|
601
|
+
export const listMessagesByThreadId = query({
|
|
602
|
+
args: listMessagesByThreadIdArgs,
|
|
603
|
+
handler: async (ctx, args) => {
|
|
604
|
+
const messages = await listMessagesByThreadIdHandler(ctx, args);
|
|
495
605
|
return { ...messages, page: messages.page.map(publicMessage) };
|
|
496
606
|
},
|
|
497
607
|
returns: vPaginationResult(vMessageDoc),
|
|
498
608
|
});
|
|
499
609
|
|
|
610
|
+
async function listMessagesByThreadIdHandler(
|
|
611
|
+
ctx: QueryCtx,
|
|
612
|
+
args: ObjectType<typeof listMessagesByThreadIdArgs>,
|
|
613
|
+
) {
|
|
614
|
+
const statuses = args.statuses ?? vMessageStatus.members.map((m) => m.value);
|
|
615
|
+
const last =
|
|
616
|
+
args.upToAndIncludingMessageId &&
|
|
617
|
+
(await ctx.db.get(args.upToAndIncludingMessageId));
|
|
618
|
+
assert(
|
|
619
|
+
!last || last.threadId === args.threadId,
|
|
620
|
+
"upToAndIncludingMessageId must be a message in the thread",
|
|
621
|
+
);
|
|
622
|
+
const toolOptions = args.excludeToolMessages ? [false] : [true, false];
|
|
623
|
+
const order = args.order ?? "desc";
|
|
624
|
+
const streams = toolOptions.flatMap((tool) =>
|
|
625
|
+
statuses.map((status) =>
|
|
626
|
+
stream(ctx.db, schema)
|
|
627
|
+
.query("messages")
|
|
628
|
+
.withIndex("threadId_status_tool_order_stepOrder", (q) => {
|
|
629
|
+
const qq = q
|
|
630
|
+
.eq("threadId", args.threadId)
|
|
631
|
+
.eq("status", status)
|
|
632
|
+
.eq("tool", tool);
|
|
633
|
+
if (last) {
|
|
634
|
+
return qq.lte("order", last.order);
|
|
635
|
+
}
|
|
636
|
+
return qq;
|
|
637
|
+
})
|
|
638
|
+
.order(order)
|
|
639
|
+
.filterWith(
|
|
640
|
+
// We allow all messages on the same order.
|
|
641
|
+
async (m) => !last || m.order <= last.order,
|
|
642
|
+
),
|
|
643
|
+
),
|
|
644
|
+
);
|
|
645
|
+
const messages = await mergedStream(streams, ["order", "stepOrder"]).paginate(
|
|
646
|
+
args.paginationOpts ?? {
|
|
647
|
+
numItems: DEFAULT_RECENT_MESSAGES,
|
|
648
|
+
cursor: null,
|
|
649
|
+
},
|
|
650
|
+
);
|
|
651
|
+
if (messages.page.length === 0) {
|
|
652
|
+
messages.isDone = true;
|
|
653
|
+
}
|
|
654
|
+
return messages;
|
|
655
|
+
}
|
|
656
|
+
|
|
500
657
|
export const getMessagesByIds = query({
|
|
501
658
|
args: { messageIds: v.array(v.id("messages")) },
|
|
502
659
|
handler: async (ctx, args) => {
|
|
@@ -35,11 +35,9 @@ export const paginate = query({
|
|
|
35
35
|
const tableName = getVectorTableName(args.vectorDimension);
|
|
36
36
|
const vectors = await paginator(ctx.db, schema)
|
|
37
37
|
.query(tableName)
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
38
|
.withIndex("model_table_threadId" as any, (q) =>
|
|
40
39
|
args.table
|
|
41
|
-
?
|
|
42
|
-
(q.eq("model", args.targetModel) as any).eq("table", args.table)
|
|
40
|
+
? (q.eq("model", args.targetModel) as any).eq("table", args.table)
|
|
43
41
|
: q.eq("model", args.targetModel),
|
|
44
42
|
)
|
|
45
43
|
.paginate({
|
package/src/deltas.ts
CHANGED
|
@@ -79,7 +79,7 @@ export async function updateFromUIMessageChunks(
|
|
|
79
79
|
for await (const messagePart of messageStream) {
|
|
80
80
|
assert(
|
|
81
81
|
messagePart.id === message.id,
|
|
82
|
-
`Expecting to only make one UIMessage in a stream
|
|
82
|
+
`Expecting to only make one UIMessage in a stream`,
|
|
83
83
|
);
|
|
84
84
|
message = messagePart;
|
|
85
85
|
}
|
package/src/mapping.ts
CHANGED
|
@@ -60,8 +60,7 @@ export type SerializeUrlsAndUint8Arrays<T> = T extends URL
|
|
|
60
60
|
? ArrayBuffer
|
|
61
61
|
: T extends Array<infer Inner>
|
|
62
62
|
? Array<SerializeUrlsAndUint8Arrays<Inner>>
|
|
63
|
-
:
|
|
64
|
-
T extends Record<string, any>
|
|
63
|
+
: T extends Record<string, any>
|
|
65
64
|
? { [K in keyof T]: SerializeUrlsAndUint8Arrays<T[K]> }
|
|
66
65
|
: T;
|
|
67
66
|
|
|
@@ -109,9 +108,7 @@ export async function serializeOrThrow(
|
|
|
109
108
|
message: ModelMessage | Message,
|
|
110
109
|
): Promise<SerializedMessage> {
|
|
111
110
|
const { content } = await serializeContent(
|
|
112
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
111
|
{} as any,
|
|
114
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
112
|
{} as any,
|
|
116
113
|
message.content,
|
|
117
114
|
);
|
|
@@ -10,7 +10,6 @@ import { useState } from "react";
|
|
|
10
10
|
import { assert } from "convex-helpers";
|
|
11
11
|
|
|
12
12
|
export function useDeltaStreams<
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
13
|
Query extends StreamQuery<any> = StreamQuery<object>,
|
|
15
14
|
>(
|
|
16
15
|
query: Query,
|
|
@@ -13,7 +13,6 @@ import { useDeltaStreams } from "./useDeltaStreams.js";
|
|
|
13
13
|
|
|
14
14
|
// Polyfill structuredClone to support readUIMessageStream on ReactNative
|
|
15
15
|
if (!("structuredClone" in globalThis)) {
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
16
|
void import("@ungap/structured-clone" as any).then(
|
|
18
17
|
({ default: structuredClone }) =>
|
|
19
18
|
(globalThis.structuredClone = structuredClone),
|
|
@@ -38,7 +37,6 @@ export function useStreamingUIMessages<
|
|
|
38
37
|
METADATA = unknown,
|
|
39
38
|
DATA_PARTS extends UIDataTypes = UIDataTypes,
|
|
40
39
|
TOOLS extends UITools = UITools,
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
40
|
Query extends StreamQuery<any> = StreamQuery<object>,
|
|
43
41
|
>(
|
|
44
42
|
query: Query,
|
|
@@ -116,10 +116,7 @@ export type ThreadMessagesResult<
|
|
|
116
116
|
* @returns The messages. If stream is true, it will return a list of messages
|
|
117
117
|
* that includes both full messages and streaming messages.
|
|
118
118
|
*/
|
|
119
|
-
export function useThreadMessages<
|
|
120
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
121
|
-
Query extends ThreadMessagesQuery<any, any>,
|
|
122
|
-
>(
|
|
119
|
+
export function useThreadMessages<Query extends ThreadMessagesQuery<any, any>>(
|
|
123
120
|
query: Query,
|
|
124
121
|
args: ThreadMessagesArgs<Query> | "skip",
|
|
125
122
|
options: {
|
|
@@ -154,8 +151,7 @@ export function useThreadMessages<
|
|
|
154
151
|
args === "skip" ||
|
|
155
152
|
paginated.status === "LoadingFirstPage"
|
|
156
153
|
? "skip"
|
|
157
|
-
:
|
|
158
|
-
({ ...args, paginationOpts: { cursor: null, numItems: 0 } } as any),
|
|
154
|
+
: ({ ...args, paginationOpts: { cursor: null, numItems: 0 } } as any),
|
|
159
155
|
{ startOrder },
|
|
160
156
|
);
|
|
161
157
|
|
|
@@ -222,10 +218,7 @@ export function useThreadMessages<
|
|
|
222
218
|
* you want to pass to the query.
|
|
223
219
|
* @returns The streaming messages.
|
|
224
220
|
*/
|
|
225
|
-
export function useStreamingThreadMessages<
|
|
226
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
-
Query extends StreamQuery<any>,
|
|
228
|
-
>(
|
|
221
|
+
export function useStreamingThreadMessages<Query extends StreamQuery<any>>(
|
|
229
222
|
query: Query,
|
|
230
223
|
args:
|
|
231
224
|
| (StreamQueryArgs<Query> & {
|
|
@@ -122,10 +122,7 @@ export type UIMessagesQueryResult<
|
|
|
122
122
|
* The streaming messages are materialized as UIMessages. The rest are passed
|
|
123
123
|
* through from the query.
|
|
124
124
|
*/
|
|
125
|
-
export function useUIMessages<
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
|
-
Query extends UIMessagesQuery<any, any>,
|
|
128
|
-
>(
|
|
125
|
+
export function useUIMessages<Query extends UIMessagesQuery<any, any>>(
|
|
129
126
|
query: Query,
|
|
130
127
|
args: UIMessagesQueryArgs<Query> | "skip",
|
|
131
128
|
options: {
|
|
@@ -153,8 +150,7 @@ export function useUIMessages<
|
|
|
153
150
|
args === "skip" ||
|
|
154
151
|
paginated.status === "LoadingFirstPage"
|
|
155
152
|
? "skip"
|
|
156
|
-
:
|
|
157
|
-
({ ...args, paginationOpts: { cursor: null, numItems: 0 } } as any),
|
|
153
|
+
: ({ ...args, paginationOpts: { cursor: null, numItems: 0 } } as any),
|
|
158
154
|
{ startOrder, skipStreamIds: options.skipStreamIds },
|
|
159
155
|
);
|
|
160
156
|
|
package/src/test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
1
2
|
import type { TestConvex } from "convex-test";
|
|
2
3
|
import type { GenericSchema, SchemaDefinition } from "convex/server";
|
|
3
4
|
import schema from "./component/schema.js";
|
|
@@ -8,7 +9,7 @@ const modules = import.meta.glob("./component/**/*.ts");
|
|
|
8
9
|
* @param t - The test convex instance, e.g. from calling `convexTest`.
|
|
9
10
|
* @param name - The name of the component, as registered in convex.config.ts.
|
|
10
11
|
*/
|
|
11
|
-
function register(
|
|
12
|
+
export function register(
|
|
12
13
|
t: TestConvex<SchemaDefinition<GenericSchema, boolean>>,
|
|
13
14
|
name: string = "agent",
|
|
14
15
|
) {
|
package/src/validators.test.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import type { Infer } from "convex/values";
|
|
1
|
+
import type { GenericId, Infer } from "convex/values";
|
|
2
2
|
import { expectTypeOf, test } from "vitest";
|
|
3
|
-
import type {
|
|
4
|
-
ContextOptions,
|
|
5
|
-
OpaqueIds,
|
|
6
|
-
StorageOptions,
|
|
7
|
-
} from "./client/types.js";
|
|
3
|
+
import type { ContextOptions, StorageOptions } from "./client/types.js";
|
|
8
4
|
import { vContextOptions, vMessageDoc, vStorageOptions } from "./validators.js";
|
|
9
5
|
import type { Doc } from "./component/_generated/dataModel.js";
|
|
10
6
|
|
|
@@ -14,10 +10,21 @@ expectTypeOf<ContextOptions>().toExtend<Infer<typeof vContextOptions>>();
|
|
|
14
10
|
expectTypeOf<Infer<typeof vStorageOptions>>().toExtend<StorageOptions>();
|
|
15
11
|
expectTypeOf<StorageOptions>().toExtend<Infer<typeof vStorageOptions>>();
|
|
16
12
|
|
|
17
|
-
type MessageBasedOnSchema =
|
|
13
|
+
type MessageBasedOnSchema = IdsToStrings<
|
|
18
14
|
Omit<Doc<"messages">, "files" | "stepId" | "parentMessageId">
|
|
19
15
|
>;
|
|
20
16
|
expectTypeOf<Infer<typeof vMessageDoc>>().toEqualTypeOf<MessageBasedOnSchema>();
|
|
21
17
|
expectTypeOf<MessageBasedOnSchema>().toEqualTypeOf<Infer<typeof vMessageDoc>>();
|
|
22
18
|
|
|
23
19
|
test("noop", () => {});
|
|
20
|
+
|
|
21
|
+
type IdsToStrings<T> =
|
|
22
|
+
T extends GenericId<string>
|
|
23
|
+
? string
|
|
24
|
+
: T extends (infer U)[]
|
|
25
|
+
? IdsToStrings<U>[]
|
|
26
|
+
: T extends ArrayBuffer
|
|
27
|
+
? ArrayBuffer
|
|
28
|
+
: T extends object
|
|
29
|
+
? { [K in keyof T]: IdsToStrings<T[K]> }
|
|
30
|
+
: T;
|