@convex-dev/agent 0.1.14-alpha.1 → 0.1.14-alpha.3
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/index.d.ts +100 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +93 -2
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +15 -2
- package/dist/component/files.d.ts +1 -0
- package/dist/component/files.d.ts.map +1 -1
- package/dist/component/files.js +30 -0
- package/dist/component/files.js.map +1 -1
- package/dist/component/messages.d.ts +14 -2
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +49 -19
- package/dist/component/messages.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +133 -2
- package/src/component/_generated/api.d.ts +15 -2
- package/src/component/files.ts +33 -0
- package/src/component/messages.test.ts +249 -22
- package/src/component/messages.ts +56 -16
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
|
@@ -152,14 +152,14 @@ describe("agent", () => {
|
|
|
152
152
|
messages: [{ message: { role: "user", content: "hello" } }],
|
|
153
153
|
});
|
|
154
154
|
const messageId = messages[0]._id as Id<"messages">;
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
157
157
|
messageId,
|
|
158
158
|
patch: {
|
|
159
159
|
message: { role: "user", content: "updated content" },
|
|
160
160
|
},
|
|
161
161
|
});
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
expect(updatedMessage.message).toEqual({
|
|
164
164
|
role: "user",
|
|
165
165
|
content: "updated content",
|
|
@@ -177,10 +177,10 @@ describe("agent", () => {
|
|
|
177
177
|
pending: true,
|
|
178
178
|
});
|
|
179
179
|
const messageId = messages[0]._id as Id<"messages">;
|
|
180
|
-
|
|
180
|
+
|
|
181
181
|
// Initial status should be pending
|
|
182
182
|
expect(messages[0].status).toBe("pending");
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
// Update to success
|
|
185
185
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
186
186
|
messageId,
|
|
@@ -188,7 +188,7 @@ describe("agent", () => {
|
|
|
188
188
|
status: "success",
|
|
189
189
|
},
|
|
190
190
|
});
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
expect(updatedMessage.status).toBe("success");
|
|
193
193
|
});
|
|
194
194
|
|
|
@@ -203,7 +203,7 @@ describe("agent", () => {
|
|
|
203
203
|
pending: true,
|
|
204
204
|
});
|
|
205
205
|
const messageId = messages[0]._id as Id<"messages">;
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
208
208
|
messageId,
|
|
209
209
|
patch: {
|
|
@@ -211,7 +211,7 @@ describe("agent", () => {
|
|
|
211
211
|
error: "Something went wrong",
|
|
212
212
|
},
|
|
213
213
|
});
|
|
214
|
-
|
|
214
|
+
|
|
215
215
|
expect(updatedMessage.status).toBe("failed");
|
|
216
216
|
expect(updatedMessage.error).toBe("Something went wrong");
|
|
217
217
|
});
|
|
@@ -223,22 +223,24 @@ describe("agent", () => {
|
|
|
223
223
|
});
|
|
224
224
|
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
225
225
|
threadId: thread._id as Id<"threads">,
|
|
226
|
-
messages: [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
226
|
+
messages: [
|
|
227
|
+
{
|
|
228
|
+
message: {
|
|
229
|
+
role: "assistant",
|
|
230
|
+
content: [
|
|
231
|
+
{
|
|
232
|
+
type: "tool-call",
|
|
233
|
+
args: { a: 1 },
|
|
234
|
+
toolCallId: "1",
|
|
235
|
+
toolName: "tool",
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
},
|
|
237
239
|
},
|
|
238
|
-
|
|
240
|
+
],
|
|
239
241
|
});
|
|
240
242
|
const messageId = messages[0]._id as Id<"messages">;
|
|
241
|
-
|
|
243
|
+
|
|
242
244
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
243
245
|
messageId,
|
|
244
246
|
patch: {
|
|
@@ -255,7 +257,7 @@ describe("agent", () => {
|
|
|
255
257
|
},
|
|
256
258
|
},
|
|
257
259
|
});
|
|
258
|
-
|
|
260
|
+
|
|
259
261
|
expect(updatedMessage.message).toEqual({
|
|
260
262
|
role: "assistant",
|
|
261
263
|
content: [
|
|
@@ -271,7 +273,7 @@ describe("agent", () => {
|
|
|
271
273
|
|
|
272
274
|
test("updateMessage throws error for non-existent message", async () => {
|
|
273
275
|
const t = convexTest(schema, modules);
|
|
274
|
-
|
|
276
|
+
|
|
275
277
|
await expect(
|
|
276
278
|
t.mutation(api.messages.updateMessage, {
|
|
277
279
|
messageId: "invalidId" as Id<"messages">,
|
|
@@ -281,4 +283,229 @@ describe("agent", () => {
|
|
|
281
283
|
})
|
|
282
284
|
).rejects.toThrow();
|
|
283
285
|
});
|
|
286
|
+
|
|
287
|
+
test("deleteByIds deletes existing messages and returns their IDs", async () => {
|
|
288
|
+
const t = convexTest(schema, modules);
|
|
289
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
290
|
+
userId: "test",
|
|
291
|
+
});
|
|
292
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
293
|
+
threadId: thread._id as Id<"threads">,
|
|
294
|
+
messages: [
|
|
295
|
+
{ message: { role: "user", content: "hello" } },
|
|
296
|
+
{ message: { role: "assistant", content: "world" } },
|
|
297
|
+
{ message: { role: "user", content: "test" } },
|
|
298
|
+
],
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const messageIds = messages.map((m) => m._id as Id<"messages">);
|
|
302
|
+
const deletedIds = await t.mutation(api.messages.deleteByIds, {
|
|
303
|
+
messageIds: [messageIds[0], messageIds[2]], // Delete first and third messages
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
expect(deletedIds).toEqual([messageIds[0], messageIds[2]]);
|
|
307
|
+
|
|
308
|
+
// Verify messages are actually deleted
|
|
309
|
+
const remainingMessages = await t.query(
|
|
310
|
+
api.messages.listMessagesByThreadId,
|
|
311
|
+
{
|
|
312
|
+
threadId: thread._id as Id<"threads">,
|
|
313
|
+
order: "asc",
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
expect(remainingMessages.page).toHaveLength(1);
|
|
317
|
+
expect(remainingMessages.page[0]._id).toBe(messageIds[1]);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("deleteByIds handles non-existent message IDs gracefully", async () => {
|
|
321
|
+
const t = convexTest(schema, modules);
|
|
322
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
323
|
+
userId: "test",
|
|
324
|
+
});
|
|
325
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
326
|
+
threadId: thread._id as Id<"threads">,
|
|
327
|
+
messages: [{ message: { role: "user", content: "hello" } }],
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const messageId = messages[0]._id as Id<"messages">;
|
|
331
|
+
const validDeletedIds = await t.mutation(api.messages.deleteByIds, {
|
|
332
|
+
messageIds: [messageId],
|
|
333
|
+
});
|
|
334
|
+
expect(validDeletedIds).toEqual([messageId]);
|
|
335
|
+
|
|
336
|
+
const deletedIds = await t.mutation(api.messages.deleteByIds, {
|
|
337
|
+
messageIds: [messageId],
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Should only return the valid ID that was actually deleted
|
|
341
|
+
expect(deletedIds).toEqual([]);
|
|
342
|
+
|
|
343
|
+
// Verify the valid message was deleted
|
|
344
|
+
const remainingMessages = await t.query(
|
|
345
|
+
api.messages.listMessagesByThreadId,
|
|
346
|
+
{
|
|
347
|
+
threadId: thread._id as Id<"threads">,
|
|
348
|
+
order: "asc",
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
expect(remainingMessages.page).toHaveLength(0);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test("deleteByOrder deletes messages within specified order range", async () => {
|
|
355
|
+
const t = convexTest(schema, modules);
|
|
356
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
357
|
+
userId: "test",
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Create multiple rounds of messages with different orders
|
|
361
|
+
const { messages: round1 } = await t.mutation(api.messages.addMessages, {
|
|
362
|
+
threadId: thread._id as Id<"threads">,
|
|
363
|
+
messages: [
|
|
364
|
+
{ message: { role: "user", content: "message order 0, step 0" } },
|
|
365
|
+
{ message: { role: "assistant", content: "message order 0, step 1" } },
|
|
366
|
+
],
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
const { messages: round2 } = await t.mutation(api.messages.addMessages, {
|
|
370
|
+
threadId: thread._id as Id<"threads">,
|
|
371
|
+
messages: [
|
|
372
|
+
{ message: { role: "user", content: "message order 1, step 0" } },
|
|
373
|
+
{ message: { role: "assistant", content: "message order 1, step 1" } },
|
|
374
|
+
],
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const { messages: round3 } = await t.mutation(api.messages.addMessages, {
|
|
378
|
+
threadId: thread._id as Id<"threads">,
|
|
379
|
+
messages: [
|
|
380
|
+
{ message: { role: "user", content: "message order 2, step 0" } },
|
|
381
|
+
],
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// Delete messages in order range 0 to 1 (exclusive)
|
|
385
|
+
const result = await t.mutation(api.messages.deleteByOrder, {
|
|
386
|
+
threadId: thread._id as Id<"threads">,
|
|
387
|
+
startOrder: 0,
|
|
388
|
+
endOrder: 1,
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
expect(result.isDone).toBe(true);
|
|
392
|
+
expect(result.lastOrder).toBe(0);
|
|
393
|
+
expect(result.lastStepOrder).toBe(1);
|
|
394
|
+
|
|
395
|
+
// Verify only messages from order 0 were deleted
|
|
396
|
+
const remainingMessages = await t.query(
|
|
397
|
+
api.messages.listMessagesByThreadId,
|
|
398
|
+
{
|
|
399
|
+
threadId: thread._id as Id<"threads">,
|
|
400
|
+
order: "asc",
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
expect(remainingMessages.page).toHaveLength(3); // Should have messages from order 1 and 2
|
|
405
|
+
expect(remainingMessages.page.map((m) => m.order)).toEqual([1, 1, 2]);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test("deleteByOrder handles step order boundaries correctly", async () => {
|
|
409
|
+
const t = convexTest(schema, modules);
|
|
410
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
411
|
+
userId: "test",
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Create messages with the same order but different step orders
|
|
415
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
416
|
+
threadId: thread._id as Id<"threads">,
|
|
417
|
+
messages: [
|
|
418
|
+
{ message: { role: "user", content: "step 0" } },
|
|
419
|
+
{ message: { role: "assistant", content: "step 1" } },
|
|
420
|
+
{ message: { role: "user", content: "step 2" } },
|
|
421
|
+
{ message: { role: "assistant", content: "step 3" } },
|
|
422
|
+
],
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Delete messages from step 1 to step 3 (exclusive)
|
|
426
|
+
const result = await t.mutation(api.messages.deleteByOrder, {
|
|
427
|
+
threadId: thread._id as Id<"threads">,
|
|
428
|
+
startOrder: 0,
|
|
429
|
+
startStepOrder: 1,
|
|
430
|
+
endOrder: 0,
|
|
431
|
+
endStepOrder: 3,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
expect(result.isDone).toBe(true);
|
|
435
|
+
expect(result.lastOrder).toBe(0);
|
|
436
|
+
expect(result.lastStepOrder).toBe(2);
|
|
437
|
+
|
|
438
|
+
// Verify only step 1 and 2 were deleted (step 3 is excluded by upperBoundInclusive: false)
|
|
439
|
+
const remainingMessages = await t.query(
|
|
440
|
+
api.messages.listMessagesByThreadId,
|
|
441
|
+
{
|
|
442
|
+
threadId: thread._id as Id<"threads">,
|
|
443
|
+
order: "asc",
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
expect(remainingMessages.page).toHaveLength(2);
|
|
448
|
+
expect(remainingMessages.page.map((m) => m.stepOrder)).toEqual([0, 3]);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test("deleteByOrder returns isDone false when batch limit is reached", async () => {
|
|
452
|
+
const t = convexTest(schema, modules);
|
|
453
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
454
|
+
userId: "test",
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// This test would be more realistic with 65+ messages, but for test efficiency
|
|
458
|
+
// we'll just verify the basic structure works with fewer messages
|
|
459
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
460
|
+
threadId: thread._id as Id<"threads">,
|
|
461
|
+
messages: [
|
|
462
|
+
{ message: { role: "user", content: "message 1" } },
|
|
463
|
+
{ message: { role: "assistant", content: "message 2" } },
|
|
464
|
+
],
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
const result = await t.mutation(api.messages.deleteByOrder, {
|
|
468
|
+
threadId: thread._id as Id<"threads">,
|
|
469
|
+
startOrder: 0,
|
|
470
|
+
endOrder: 2,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// With only 2 messages, should be done
|
|
474
|
+
expect(result.isDone).toBe(true);
|
|
475
|
+
expect(result.lastOrder).toBe(0);
|
|
476
|
+
expect(result.lastStepOrder).toBe(1);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("deleteByOrder handles empty result set", async () => {
|
|
480
|
+
const t = convexTest(schema, modules);
|
|
481
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
482
|
+
userId: "test",
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
486
|
+
threadId: thread._id as Id<"threads">,
|
|
487
|
+
messages: [{ message: { role: "user", content: "message order 0" } }],
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// Try to delete from a range that doesn't exist
|
|
491
|
+
const result = await t.mutation(api.messages.deleteByOrder, {
|
|
492
|
+
threadId: thread._id as Id<"threads">,
|
|
493
|
+
startOrder: 5,
|
|
494
|
+
endOrder: 10,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
expect(result.isDone).toBe(true);
|
|
498
|
+
expect(result.lastOrder).toBeUndefined();
|
|
499
|
+
expect(result.lastStepOrder).toBeUndefined();
|
|
500
|
+
|
|
501
|
+
// Verify original message is still there
|
|
502
|
+
const remainingMessages = await t.query(
|
|
503
|
+
api.messages.listMessagesByThreadId,
|
|
504
|
+
{
|
|
505
|
+
threadId: thread._id as Id<"threads">,
|
|
506
|
+
order: "asc",
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
expect(remainingMessages.page).toHaveLength(1);
|
|
510
|
+
});
|
|
284
511
|
});
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
type VectorTableId,
|
|
40
40
|
vVectorId,
|
|
41
41
|
} from "./vector/tables.js";
|
|
42
|
+
import { changeRefcount } from "./files.js";
|
|
42
43
|
|
|
43
44
|
/** @deprecated Use *.threads.listMessagesByThreadId instead. */
|
|
44
45
|
export const listThreadsByUserId = _listThreadsByUserId;
|
|
@@ -61,31 +62,28 @@ export async function deleteMessage(
|
|
|
61
62
|
if (messageDoc.embeddingId) {
|
|
62
63
|
await ctx.db.delete(messageDoc.embeddingId);
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const file = await ctx.db.get(fileId);
|
|
67
|
-
if (file) {
|
|
68
|
-
await ctx.db.patch(fileId, { refcount: file.refcount - 1 });
|
|
69
|
-
}
|
|
65
|
+
if (messageDoc.fileIds) {
|
|
66
|
+
await changeRefcount(ctx, messageDoc.fileIds, []);
|
|
70
67
|
}
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
export const
|
|
70
|
+
export const deleteByIds = mutation({
|
|
74
71
|
args: {
|
|
75
72
|
messageIds: v.array(v.id("messages")),
|
|
76
73
|
},
|
|
77
|
-
returns: v.
|
|
74
|
+
returns: v.array(v.id("messages")),
|
|
78
75
|
handler: async (ctx, args) => {
|
|
79
|
-
await Promise.all(
|
|
76
|
+
const deletedMessageIds = await Promise.all(
|
|
80
77
|
args.messageIds.map(async (id) => {
|
|
81
78
|
const message = await ctx.db.get(id);
|
|
82
79
|
if (message) {
|
|
83
80
|
await deleteMessage(ctx, message);
|
|
84
|
-
|
|
85
|
-
console.warn(`Message ${id} not found when trying to delete`);
|
|
81
|
+
return id;
|
|
86
82
|
}
|
|
83
|
+
return null;
|
|
87
84
|
})
|
|
88
85
|
);
|
|
86
|
+
return deletedMessageIds.filter((id) => id !== null);
|
|
89
87
|
},
|
|
90
88
|
});
|
|
91
89
|
|
|
@@ -93,6 +91,46 @@ export const messageStatuses = vMessageDoc.fields.status.members.map(
|
|
|
93
91
|
(m) => m.value
|
|
94
92
|
);
|
|
95
93
|
|
|
94
|
+
export const deleteByOrder = mutation({
|
|
95
|
+
args: {
|
|
96
|
+
threadId: v.id("threads"),
|
|
97
|
+
startOrder: v.number(),
|
|
98
|
+
startStepOrder: v.optional(v.number()),
|
|
99
|
+
endOrder: v.number(),
|
|
100
|
+
endStepOrder: v.optional(v.number()),
|
|
101
|
+
},
|
|
102
|
+
returns: v.object({
|
|
103
|
+
isDone: v.boolean(),
|
|
104
|
+
lastOrder: v.optional(v.number()),
|
|
105
|
+
lastStepOrder: v.optional(v.number()),
|
|
106
|
+
}),
|
|
107
|
+
handler: async (ctx, args) => {
|
|
108
|
+
const messages = await orderedMessagesStream(
|
|
109
|
+
ctx,
|
|
110
|
+
args.threadId,
|
|
111
|
+
"asc",
|
|
112
|
+
args.startOrder
|
|
113
|
+
)
|
|
114
|
+
.narrow({
|
|
115
|
+
lowerBound: args.startStepOrder
|
|
116
|
+
? [args.startOrder, args.startStepOrder]
|
|
117
|
+
: [args.startOrder],
|
|
118
|
+
lowerBoundInclusive: true,
|
|
119
|
+
upperBound: args.endStepOrder
|
|
120
|
+
? [args.endOrder, args.endStepOrder]
|
|
121
|
+
: [args.endOrder],
|
|
122
|
+
upperBoundInclusive: false,
|
|
123
|
+
})
|
|
124
|
+
.take(64);
|
|
125
|
+
await Promise.all(messages.map((m) => deleteMessage(ctx, m)));
|
|
126
|
+
return {
|
|
127
|
+
isDone: messages.length < 64,
|
|
128
|
+
lastOrder: messages[messages.length - 1]?.order,
|
|
129
|
+
lastStepOrder: messages[messages.length - 1]?.stepOrder,
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
96
134
|
const addMessagesArgs = {
|
|
97
135
|
userId: v.optional(v.string()),
|
|
98
136
|
threadId: v.id("threads"),
|
|
@@ -201,11 +239,8 @@ async function addMessagesHandler(
|
|
|
201
239
|
// id: messageId,
|
|
202
240
|
// });
|
|
203
241
|
// }
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
await ctx.db.patch(fileId, {
|
|
207
|
-
refcount: (await ctx.db.get(fileId))!.refcount + 1,
|
|
208
|
-
});
|
|
242
|
+
if (message.fileIds) {
|
|
243
|
+
await changeRefcount(ctx, [], message.fileIds);
|
|
209
244
|
}
|
|
210
245
|
// TODO: delete the associated stream data for the order/stepOrder
|
|
211
246
|
toReturn.push((await ctx.db.get(messageId))!);
|
|
@@ -291,6 +326,7 @@ export const updateMessage = mutation({
|
|
|
291
326
|
messageId: v.id("messages"),
|
|
292
327
|
patch: v.object({
|
|
293
328
|
message: v.optional(vMessageDoc.fields.message),
|
|
329
|
+
fileIds: v.optional(v.array(v.id("files"))),
|
|
294
330
|
status: v.optional(vMessageStatus),
|
|
295
331
|
error: v.optional(v.string()),
|
|
296
332
|
}),
|
|
@@ -300,6 +336,10 @@ export const updateMessage = mutation({
|
|
|
300
336
|
const message = await ctx.db.get(args.messageId);
|
|
301
337
|
assert(message, `Message ${args.messageId} not found`);
|
|
302
338
|
|
|
339
|
+
if (args.patch.fileIds) {
|
|
340
|
+
await changeRefcount(ctx, message.fileIds ?? [], args.patch.fileIds);
|
|
341
|
+
}
|
|
342
|
+
|
|
303
343
|
const patch: Partial<Doc<"messages">> = {
|
|
304
344
|
...args.patch,
|
|
305
345
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"3.2.4","results":[[":client/index.test.ts",{"duration":60.55858325958252,"failed":false}],[":component/messages.test.ts",{"duration":27.41837501525879,"failed":false}]]}
|