@convex-dev/agent 0.2.10 → 0.2.11-alpha.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.
Files changed (60) hide show
  1. package/dist/UIMessages.d.ts.map +1 -1
  2. package/dist/UIMessages.js +2 -7
  3. package/dist/UIMessages.js.map +1 -1
  4. package/dist/client/files.d.ts +2 -2
  5. package/dist/client/files.d.ts.map +1 -1
  6. package/dist/client/files.js.map +1 -1
  7. package/dist/client/index.d.ts +20 -20
  8. package/dist/client/index.d.ts.map +1 -1
  9. package/dist/client/index.js +1 -1
  10. package/dist/client/index.js.map +1 -1
  11. package/dist/client/messages.d.ts +5 -5
  12. package/dist/client/messages.d.ts.map +1 -1
  13. package/dist/client/messages.js.map +1 -1
  14. package/dist/client/saveInputMessages.d.ts +2 -2
  15. package/dist/client/saveInputMessages.d.ts.map +1 -1
  16. package/dist/client/saveInputMessages.js.map +1 -1
  17. package/dist/client/search.d.ts +7 -7
  18. package/dist/client/search.d.ts.map +1 -1
  19. package/dist/client/search.js +33 -21
  20. package/dist/client/search.js.map +1 -1
  21. package/dist/client/streaming.d.ts +6 -6
  22. package/dist/client/streaming.d.ts.map +1 -1
  23. package/dist/client/streaming.js.map +1 -1
  24. package/dist/client/threads.d.ts +5 -5
  25. package/dist/client/threads.d.ts.map +1 -1
  26. package/dist/client/threads.js.map +1 -1
  27. package/dist/client/types.d.ts +6 -8
  28. package/dist/client/types.d.ts.map +1 -1
  29. package/dist/deltas.d.ts.map +1 -1
  30. package/dist/deltas.js +7 -18
  31. package/dist/deltas.js.map +1 -1
  32. package/dist/mapping.d.ts +5 -4
  33. package/dist/mapping.d.ts.map +1 -1
  34. package/dist/mapping.js +7 -0
  35. package/dist/mapping.js.map +1 -1
  36. package/dist/shared.d.ts +4 -2
  37. package/dist/shared.d.ts.map +1 -1
  38. package/dist/shared.js +10 -10
  39. package/dist/shared.js.map +1 -1
  40. package/dist/validators.d.ts +1 -0
  41. package/dist/validators.d.ts.map +1 -1
  42. package/dist/validators.js.map +1 -1
  43. package/package.json +1 -1
  44. package/src/UIMessages.ts +8 -8
  45. package/src/client/files.ts +2 -2
  46. package/src/client/index.ts +22 -22
  47. package/src/client/messages.ts +10 -5
  48. package/src/client/saveInputMessages.test.ts +13 -5
  49. package/src/client/saveInputMessages.ts +3 -3
  50. package/src/client/search.test.ts +44 -19
  51. package/src/client/search.ts +54 -37
  52. package/src/client/streaming.ts +7 -6
  53. package/src/client/threads.ts +10 -5
  54. package/src/client/types.ts +6 -8
  55. package/src/deltas.test.ts +24 -14
  56. package/src/deltas.ts +7 -18
  57. package/src/mapping.ts +12 -3
  58. package/src/shared.ts +37 -12
  59. package/src/toUIMessages.test.ts +77 -2
  60. package/src/validators.ts +10 -0
@@ -89,9 +89,7 @@ import type {
89
89
  ObjectSchema,
90
90
  Options,
91
91
  RawRequestResponseHandler,
92
- RunActionCtx,
93
- RunMutationCtx,
94
- RunQueryCtx,
92
+ MutationCtx,
95
93
  StorageOptions,
96
94
  StreamingTextArgs,
97
95
  StreamObjectArgs,
@@ -100,10 +98,12 @@ import type {
100
98
  Thread,
101
99
  UsageHandler,
102
100
  UserActionCtx,
101
+ QueryCtx,
103
102
  } from "./types.js";
104
103
 
105
104
  export { stepCountIs } from "ai";
106
105
  export {
106
+ docsToModelMessages,
107
107
  toModelMessage,
108
108
  //** @deprecated use toModelMessage instead */
109
109
  toModelMessage as deserializeMessage,
@@ -268,7 +268,7 @@ export class Agent<
268
268
  * @returns The threadId of the new thread and the thread object.
269
269
  */
270
270
  async createThread(
271
- ctx: RunActionCtx & CustomCtx,
271
+ ctx: ActionCtx & CustomCtx,
272
272
  args?: {
273
273
  /**
274
274
  * The userId to associate with the thread. If not provided, the thread will be
@@ -295,7 +295,7 @@ export class Agent<
295
295
  * @returns The threadId of the new thread.
296
296
  */
297
297
  async createThread(
298
- ctx: RunMutationCtx,
298
+ ctx: MutationCtx,
299
299
  args?: {
300
300
  /**
301
301
  * The userId to associate with the thread. If not provided, the thread will be
@@ -313,7 +313,7 @@ export class Agent<
313
313
  },
314
314
  ): Promise<{ threadId: string }>;
315
315
  async createThread(
316
- ctx: (ActionCtx & CustomCtx) | RunMutationCtx,
316
+ ctx: (ActionCtx & CustomCtx) | MutationCtx,
317
317
  args?: { userId: string | null; title?: string; summary?: string },
318
318
  ): Promise<{ threadId: string; thread?: Thread<AgentTools> }> {
319
319
  const threadId = await createThread(ctx, this.component, args);
@@ -834,7 +834,7 @@ export class Agent<
834
834
  * @returns The messageId of the saved message.
835
835
  */
836
836
  async saveMessage(
837
- ctx: RunMutationCtx,
837
+ ctx: MutationCtx | ActionCtx,
838
838
  args: SaveMessageArgs & {
839
839
  /**
840
840
  * If true, it will not generate embeddings for the message.
@@ -872,7 +872,7 @@ export class Agent<
872
872
  * @returns
873
873
  */
874
874
  async saveMessages(
875
- ctx: RunMutationCtx | RunActionCtx,
875
+ ctx: MutationCtx | ActionCtx,
876
876
  args: SaveMessagesArgs & {
877
877
  /**
878
878
  * Skip generating embeddings for the messages. Useful if you're
@@ -928,7 +928,7 @@ export class Agent<
928
928
  * @returns The MessageDoc's in a format compatible with usePaginatedQuery.
929
929
  */
930
930
  async listMessages(
931
- ctx: RunQueryCtx,
931
+ ctx: QueryCtx | MutationCtx | ActionCtx,
932
932
  args: {
933
933
  threadId: string;
934
934
  paginationOpts: PaginationOptions;
@@ -948,7 +948,7 @@ export class Agent<
948
948
  * @returns The deltas for each stream from their existing cursor.
949
949
  */
950
950
  async syncStreams(
951
- ctx: RunQueryCtx,
951
+ ctx: QueryCtx | MutationCtx | ActionCtx,
952
952
  args: {
953
953
  threadId: string;
954
954
  streamArgs: StreamArgs | undefined;
@@ -968,7 +968,7 @@ export class Agent<
968
968
  * @returns
969
969
  */
970
970
  async fetchContextMessages(
971
- ctx: RunQueryCtx | RunActionCtx,
971
+ ctx: QueryCtx | MutationCtx | ActionCtx,
972
972
  args: {
973
973
  userId: string | undefined;
974
974
  threadId: string | undefined;
@@ -1030,7 +1030,7 @@ export class Agent<
1030
1030
  * @returns The metadata for the thread.
1031
1031
  */
1032
1032
  async getThreadMetadata(
1033
- ctx: RunQueryCtx,
1033
+ ctx: QueryCtx | MutationCtx | ActionCtx,
1034
1034
  args: { threadId: string },
1035
1035
  ): Promise<ThreadDoc> {
1036
1036
  return getThreadMetadata(ctx, this.component, args);
@@ -1044,7 +1044,7 @@ export class Agent<
1044
1044
  * @returns The updated thread metadata.
1045
1045
  */
1046
1046
  async updateThreadMetadata(
1047
- ctx: RunMutationCtx,
1047
+ ctx: MutationCtx | ActionCtx,
1048
1048
  args: {
1049
1049
  threadId: string;
1050
1050
  patch: Partial<
@@ -1065,7 +1065,7 @@ export class Agent<
1065
1065
  * @returns The embeddings for the messages.
1066
1066
  */
1067
1067
  async generateEmbeddings(
1068
- ctx: RunActionCtx,
1068
+ ctx: ActionCtx,
1069
1069
  args: { userId: string | undefined; threadId: string | undefined },
1070
1070
  messages: (ModelMessage | Message)[],
1071
1071
  ): Promise<
@@ -1091,7 +1091,7 @@ export class Agent<
1091
1091
  * @param args The messageIds to generate embeddings for.
1092
1092
  */
1093
1093
  async generateAndSaveEmbeddings(
1094
- ctx: RunActionCtx,
1094
+ ctx: ActionCtx,
1095
1095
  args: { messageIds: string[] },
1096
1096
  ) {
1097
1097
  const messages = (
@@ -1251,7 +1251,7 @@ export class Agent<
1251
1251
  * the generateText call.
1252
1252
  */
1253
1253
  async finalizeMessage(
1254
- ctx: RunMutationCtx,
1254
+ ctx: MutationCtx | ActionCtx,
1255
1255
  args: {
1256
1256
  messageId: string;
1257
1257
  result: { status: "failed"; error: string } | { status: "success" };
@@ -1269,7 +1269,7 @@ export class Agent<
1269
1269
  * @param args The message fields to update.
1270
1270
  */
1271
1271
  async updateMessage(
1272
- ctx: RunMutationCtx,
1272
+ ctx: MutationCtx | ActionCtx,
1273
1273
  args: {
1274
1274
  /** The id of the message to update. */
1275
1275
  messageId: string;
@@ -1319,7 +1319,7 @@ export class Agent<
1319
1319
  * @param args The ids of the messages to delete.
1320
1320
  */
1321
1321
  async deleteMessages(
1322
- ctx: RunMutationCtx,
1322
+ ctx: MutationCtx | ActionCtx,
1323
1323
  args: { messageIds: string[] },
1324
1324
  ): Promise<void> {
1325
1325
  await ctx.runMutation(this.component.messages.deleteByIds, args);
@@ -1332,7 +1332,7 @@ export class Agent<
1332
1332
  * @param args The id of the message to delete.
1333
1333
  */
1334
1334
  async deleteMessage(
1335
- ctx: RunMutationCtx,
1335
+ ctx: MutationCtx | ActionCtx,
1336
1336
  args: { messageId: string },
1337
1337
  ): Promise<void> {
1338
1338
  await ctx.runMutation(this.component.messages.deleteByIds, {
@@ -1378,7 +1378,7 @@ export class Agent<
1378
1378
  * @param args The range of messages to delete.
1379
1379
  */
1380
1380
  async deleteMessageRange(
1381
- ctx: RunMutationCtx,
1381
+ ctx: MutationCtx | ActionCtx,
1382
1382
  args: {
1383
1383
  threadId: string;
1384
1384
  startOrder: number;
@@ -1404,7 +1404,7 @@ export class Agent<
1404
1404
  * @param args The id of the thread to delete and optionally the page size to use for the delete.
1405
1405
  */
1406
1406
  async deleteThreadAsync(
1407
- ctx: RunMutationCtx,
1407
+ ctx: MutationCtx | ActionCtx,
1408
1408
  args: { threadId: string; pageSize?: number },
1409
1409
  ): Promise<void> {
1410
1410
  await ctx.runMutation(this.component.threads.deleteAllForThreadIdAsync, {
@@ -1421,7 +1421,7 @@ export class Agent<
1421
1421
  * @param args The id of the thread to delete and optionally the page size to use for the delete.
1422
1422
  */
1423
1423
  async deleteThreadSync(
1424
- ctx: RunActionCtx,
1424
+ ctx: ActionCtx,
1425
1425
  args: { threadId: string; pageSize?: number },
1426
1426
  ): Promise<void> {
1427
1427
  await ctx.runAction(this.component.threads.deleteAllForThreadIdSync, {
@@ -12,7 +12,12 @@ import {
12
12
  } from "../validators.js";
13
13
  import { serializeMessage } from "../mapping.js";
14
14
  import { toUIMessages, type UIMessage } from "../UIMessages.js";
15
- import type { AgentComponent, RunMutationCtx, RunQueryCtx } from "./types.js";
15
+ import type {
16
+ AgentComponent,
17
+ MutationCtx,
18
+ QueryCtx,
19
+ ActionCtx,
20
+ } from "./types.js";
16
21
  import { parse } from "convex-helpers/validators";
17
22
 
18
23
  /**
@@ -27,7 +32,7 @@ import { parse } from "convex-helpers/validators";
27
32
  * @returns The MessageDoc's in a format compatible with usePaginatedQuery.
28
33
  */
29
34
  export async function listMessages(
30
- ctx: RunQueryCtx,
35
+ ctx: QueryCtx | MutationCtx | ActionCtx,
31
36
  component: AgentComponent,
32
37
  {
33
38
  threadId,
@@ -58,7 +63,7 @@ export async function listMessages(
58
63
  }
59
64
 
60
65
  export async function listUIMessages(
61
- ctx: RunQueryCtx,
66
+ ctx: QueryCtx | MutationCtx | ActionCtx,
62
67
  component: AgentComponent,
63
68
  args: {
64
69
  threadId: string;
@@ -105,7 +110,7 @@ export type SaveMessagesArgs = {
105
110
  * Explicitly save messages associated with the thread (& user if provided)
106
111
  */
107
112
  export async function saveMessages(
108
- ctx: RunMutationCtx,
113
+ ctx: MutationCtx,
109
114
  component: AgentComponent,
110
115
  args: SaveMessagesArgs & {
111
116
  /**
@@ -193,7 +198,7 @@ export type SaveMessageArgs = {
193
198
  * @returns The messageId of the saved message.
194
199
  */
195
200
  export async function saveMessage(
196
- ctx: RunMutationCtx,
201
+ ctx: MutationCtx,
197
202
  component: AgentComponent,
198
203
  args: SaveMessageArgs & {
199
204
  /**
@@ -1,8 +1,12 @@
1
1
  import { beforeEach, describe, expect, test, vi } from "vitest";
2
2
  import { saveInputMessages } from "./saveInputMessages.js";
3
3
  import type { MessageDoc } from "../validators.js";
4
- import type { RunActionCtx } from "./types.js";
5
- import { defineSchema } from "convex/server";
4
+ import type { ActionCtx } from "./types.js";
5
+ import {
6
+ defineSchema,
7
+ type Auth,
8
+ type StorageActionWriter,
9
+ } from "convex/server";
6
10
  import { initConvexTest } from "./setup.test.js";
7
11
  import { components } from "./setup.test.js";
8
12
 
@@ -59,7 +63,7 @@ describe("saveInputMessages", () => {
59
63
  const mockComponent = components.agent;
60
64
 
61
65
  let t = initConvexTest(schema);
62
- let ctx: RunActionCtx;
66
+ let ctx: ActionCtx;
63
67
 
64
68
  beforeEach(() => {
65
69
  vi.clearAllMocks();
@@ -68,7 +72,9 @@ describe("saveInputMessages", () => {
68
72
  runQuery: t.query,
69
73
  runAction: t.action,
70
74
  runMutation: t.mutation,
71
- } as RunActionCtx;
75
+ auth: {} as Auth,
76
+ storage: {} as StorageActionWriter,
77
+ } as ActionCtx;
72
78
 
73
79
  mockSaveMessages.mockResolvedValue({
74
80
  messages: [
@@ -358,7 +364,9 @@ describe("saveInputMessages", () => {
358
364
  runQuery: vi.fn(),
359
365
  runMutation: vi.fn(),
360
366
  runAction: vi.fn(),
361
- } as RunActionCtx;
367
+ auth: {} as Auth,
368
+ storage: {} as StorageActionWriter,
369
+ } as ActionCtx;
362
370
 
363
371
  await saveInputMessages(actionCtx, mockComponent, {
364
372
  ...defaultArgs,
@@ -2,10 +2,10 @@ import { type ModelMessage } from "ai";
2
2
  import type { MessageDoc } from "../validators.js";
3
3
  import { embedMessages, getPromptArray } from "./search.js";
4
4
  import type {
5
+ ActionCtx,
5
6
  AgentComponent,
6
7
  Config,
7
- RunActionCtx,
8
- RunMutationCtx,
8
+ MutationCtx,
9
9
  } from "./types.js";
10
10
  import { saveMessages } from "./messages.js";
11
11
  import type { Message } from "../validators.js";
@@ -13,7 +13,7 @@ import { assert } from "convex-helpers";
13
13
  import type { VectorDimension } from "../component/vector/tables.js";
14
14
 
15
15
  export async function saveInputMessages(
16
- ctx: RunMutationCtx | RunActionCtx,
16
+ ctx: MutationCtx | ActionCtx,
17
17
  component: AgentComponent,
18
18
  {
19
19
  threadId,
@@ -7,9 +7,14 @@ import {
7
7
  type MockedFunction,
8
8
  } from "vitest";
9
9
  import type { ModelMessage } from "ai";
10
- import { defineSchema } from "convex/server";
10
+ import {
11
+ defineSchema,
12
+ type Auth,
13
+ type StorageActionWriter,
14
+ type StorageReader,
15
+ } from "convex/server";
11
16
  import type { MessageDoc } from "../validators.js";
12
- import type { RunActionCtx, RunQueryCtx } from "./types.js";
17
+ import type { ActionCtx, QueryCtx } from "./types.js";
13
18
  import {
14
19
  fetchContextWithPrompt,
15
20
  fetchContextMessages,
@@ -43,8 +48,8 @@ const schema = defineSchema({});
43
48
 
44
49
  describe("search.ts", () => {
45
50
  let t = initConvexTest(schema);
46
- let mockCtx: RunActionCtx;
47
- let ctx: RunActionCtx;
51
+ let mockCtx: ActionCtx;
52
+ let ctx: ActionCtx;
48
53
 
49
54
  // Shared helper functions
50
55
  async function createTestThread(userId: string) {
@@ -88,13 +93,15 @@ describe("search.ts", () => {
88
93
  runQuery: t.query,
89
94
  runAction: t.action,
90
95
  runMutation: t.mutation,
91
- } as RunActionCtx;
96
+ } as ActionCtx;
92
97
 
93
98
  mockCtx = {
94
99
  runQuery: vi.fn(),
95
100
  runAction: vi.fn(),
96
101
  runMutation: vi.fn(),
97
- } satisfies RunActionCtx;
102
+ auth: {} as Auth,
103
+ storage: {} as StorageActionWriter,
104
+ } satisfies ActionCtx;
98
105
 
99
106
  // Mock process.env to avoid file inlining in tests
100
107
  process.env.CONVEX_CLOUD_URL = "https://example.convex.cloud";
@@ -183,10 +190,25 @@ describe("search.ts", () => {
183
190
  it("should filter out orphaned tool messages", () => {
184
191
  const messages: MessageDoc[] = [
185
192
  {
186
- _id: "1",
193
+ _id: "0",
187
194
  message: { role: "user", content: "Hello" },
188
195
  order: 1,
189
196
  } as MessageDoc,
197
+ {
198
+ _id: "1",
199
+ message: {
200
+ role: "assistant",
201
+ content: [
202
+ {
203
+ type: "tool-call",
204
+ toolCallId: "call_orphaned",
205
+ toolName: "test",
206
+ args: {},
207
+ },
208
+ ],
209
+ },
210
+ order: 1,
211
+ } as MessageDoc,
190
212
  {
191
213
  _id: "2",
192
214
  message: {
@@ -194,18 +216,24 @@ describe("search.ts", () => {
194
216
  content: [
195
217
  {
196
218
  type: "tool-result",
197
- toolCallId: "call_orphaned",
219
+ toolCallId: "result_orphaned",
198
220
  result: "orphaned",
199
221
  },
200
222
  ],
201
223
  },
202
224
  order: 2,
203
225
  } as MessageDoc,
226
+ {
227
+ _id: "3",
228
+ message: { role: "assistant", content: "I'll help you with that" },
229
+ order: 1,
230
+ } as MessageDoc,
204
231
  ];
205
232
 
206
233
  const result = filterOutOrphanedToolMessages(messages);
207
- expect(result).toHaveLength(1);
208
- expect(result[0]._id).toBe("1");
234
+ expect(result).toHaveLength(2);
235
+ expect(result[0]._id).toBe("0");
236
+ expect(result[1]._id).toBe("3");
209
237
  });
210
238
  });
211
239
 
@@ -227,7 +255,7 @@ describe("search.ts", () => {
227
255
  ];
228
256
 
229
257
  (
230
- mockCtx.runQuery as MockedFunction<RunActionCtx["runQuery"]>
258
+ mockCtx.runQuery as MockedFunction<ActionCtx["runQuery"]>
231
259
  ).mockResolvedValue({
232
260
  page: mockPage,
233
261
  });
@@ -269,7 +297,7 @@ describe("search.ts", () => {
269
297
  ];
270
298
 
271
299
  (
272
- mockCtx.runAction as MockedFunction<RunActionCtx["runAction"]>
300
+ mockCtx.runAction as MockedFunction<ActionCtx["runAction"]>
273
301
  ).mockResolvedValue(searchResults);
274
302
 
275
303
  const result = await fetchContextMessages(mockCtx, components.agent, {
@@ -293,7 +321,8 @@ describe("search.ts", () => {
293
321
  const mockQueryCtx = {
294
322
  runQuery: vi.fn().mockResolvedValue({ page: [] }),
295
323
  // No runAction method
296
- } as RunQueryCtx;
324
+ storage: {} as StorageReader,
325
+ } as QueryCtx;
297
326
 
298
327
  await expect(
299
328
  fetchContextMessages(mockQueryCtx, components.agent, {
@@ -948,11 +977,7 @@ describe("search.ts", () => {
948
977
 
949
978
  const contextHandler = vi.fn(async (ctx, args) => {
950
979
  // Put existing responses first to test they're properly identified
951
- return [
952
- ...args.recent,
953
- ...args.existingResponses,
954
- ...args.inputPrompt,
955
- ];
980
+ return [...args.recent, ...args.existingResponses, ...args.inputPrompt];
956
981
  });
957
982
 
958
983
  const result = await fetchContextWithPrompt(ctx, components.agent, {
@@ -979,7 +1004,7 @@ describe("search.ts", () => {
979
1004
  inputPrompt: expect.arrayContaining([
980
1005
  expect.objectContaining({ content: "New replacement prompt" }),
981
1006
  ]),
982
- })
1007
+ }),
983
1008
  );
984
1009
 
985
1010
  expect(result.messages).toHaveLength(4);
@@ -20,15 +20,16 @@ import {
20
20
  } from "../shared.js";
21
21
  import type { Message } from "../validators.js";
22
22
  import type {
23
+ ActionCtx,
23
24
  AgentComponent,
24
25
  Config,
25
26
  ContextOptions,
26
27
  Options,
27
- RunActionCtx,
28
- RunQueryCtx,
28
+ QueryCtx,
29
+ MutationCtx,
29
30
  } from "./types.js";
30
31
  import { inlineMessagesFiles } from "./files.js";
31
- import { toModelMessage } from "../mapping.js";
32
+ import { docsToModelMessages, toModelMessage } from "../mapping.js";
32
33
 
33
34
  const DEFAULT_VECTOR_SCORE_THRESHOLD = 0.0;
34
35
  // 10k characters should be more than enough for most cases, and stays under
@@ -49,7 +50,7 @@ export type GetEmbedding = (text: string) => Promise<{
49
50
  * @returns
50
51
  */
51
52
  export async function fetchContextMessages(
52
- ctx: RunQueryCtx | RunActionCtx,
53
+ ctx: QueryCtx | MutationCtx | ActionCtx,
53
54
  component: AgentComponent,
54
55
  args: {
55
56
  userId: string | undefined;
@@ -85,7 +86,7 @@ export async function fetchContextMessages(
85
86
  }
86
87
 
87
88
  export async function fetchRecentAndSearchMessages(
88
- ctx: RunQueryCtx | RunActionCtx,
89
+ ctx: QueryCtx | MutationCtx | ActionCtx,
89
90
  component: AgentComponent,
90
91
  args: {
91
92
  userId: string | undefined;
@@ -229,23 +230,48 @@ export async function fetchRecentAndSearchMessages(
229
230
  */
230
231
  export function filterOutOrphanedToolMessages(docs: MessageDoc[]) {
231
232
  const toolCallIds = new Set<string>();
233
+ const toolResultIds = new Set<string>();
232
234
  const result: MessageDoc[] = [];
233
235
  for (const doc of docs) {
234
- if (
235
- doc.message?.role === "assistant" &&
236
- Array.isArray(doc.message.content)
237
- ) {
236
+ if (doc.message && Array.isArray(doc.message.content)) {
238
237
  for (const content of doc.message.content) {
239
238
  if (content.type === "tool-call") {
240
239
  toolCallIds.add(content.toolCallId);
240
+ } else if (content.type === "tool-result") {
241
+ toolResultIds.add(content.toolCallId);
241
242
  }
242
243
  }
243
- result.push(doc);
244
+ }
245
+ }
246
+ for (const doc of docs) {
247
+ if (
248
+ doc.message?.role === "assistant" &&
249
+ Array.isArray(doc.message.content)
250
+ ) {
251
+ const content = doc.message.content.filter(
252
+ (p) => p.type !== "tool-call" || toolResultIds.has(p.toolCallId),
253
+ );
254
+ if (content.length) {
255
+ result.push({
256
+ ...doc,
257
+ message: {
258
+ ...doc.message,
259
+ content,
260
+ },
261
+ });
262
+ }
244
263
  } else if (doc.message?.role === "tool") {
245
- if (doc.message.content.every((c) => toolCallIds.has(c.toolCallId))) {
246
- result.push(doc);
247
- } else {
248
- console.debug("Filtering out orphaned tool message", doc);
264
+ const content = doc.message.content.filter((c) =>
265
+ toolCallIds.has(c.toolCallId),
266
+ );
267
+ if (content.length) {
268
+ result.push({
269
+ ...doc,
270
+ message: {
271
+ ...doc.message,
272
+ content,
273
+ },
274
+ });
249
275
  }
250
276
  } else {
251
277
  result.push(doc);
@@ -259,7 +285,7 @@ export function filterOutOrphanedToolMessages(docs: MessageDoc[]) {
259
285
  * This will not save the embeddings to the database.
260
286
  */
261
287
  export async function embedMessages(
262
- ctx: RunActionCtx,
288
+ ctx: ActionCtx,
263
289
  {
264
290
  userId,
265
291
  threadId,
@@ -328,7 +354,7 @@ export async function embedMessages(
328
354
  * @returns The embeddings for the strings, matching the order of the values.
329
355
  */
330
356
  export async function embedMany(
331
- ctx: RunActionCtx,
357
+ ctx: ActionCtx,
332
358
  {
333
359
  userId,
334
360
  threadId,
@@ -386,7 +412,7 @@ export async function embedMany(
386
412
  * @param messages The messages to embed, in the Agent MessageDoc format.
387
413
  */
388
414
  export async function generateAndSaveEmbeddings(
389
- ctx: RunActionCtx,
415
+ ctx: ActionCtx,
390
416
  component: AgentComponent,
391
417
  args: {
392
418
  threadId: string | undefined;
@@ -431,7 +457,7 @@ export async function generateAndSaveEmbeddings(
431
457
  * promptMessageId message.
432
458
  */
433
459
  export async function fetchContextWithPrompt(
434
- ctx: RunActionCtx,
460
+ ctx: ActionCtx,
435
461
  component: AgentComponent,
436
462
  args: {
437
463
  prompt: string | (ModelMessage | Message)[] | undefined;
@@ -522,28 +548,19 @@ export async function fetchContextWithPrompt(
522
548
  }
523
549
  }
524
550
 
525
- const search = searchMessages
526
- .map((m) => m.message)
527
- .filter((m) => !!m)
528
- .map(toModelMessage);
529
- const recent = prePromptDocs
530
- .map((m) => m.message)
531
- .filter((m) => !!m)
532
- .map(toModelMessage);
551
+ const search = docsToModelMessages(searchMessages);
552
+ const recent = docsToModelMessages(prePromptDocs);
533
553
  const inputMessages = messages.map(toModelMessage);
534
554
  const inputPrompt = promptArray.map(toModelMessage);
535
- const existingResponses = existingResponseDocs
536
- .map((m) => m.message)
537
- .filter((m) => !!m)
538
- .map(toModelMessage);
555
+ const existingResponses = docsToModelMessages(existingResponseDocs);
539
556
 
540
- const allMessages = [
541
- ...search,
542
- ...recent,
543
- ...inputMessages,
544
- ...inputPrompt,
545
- ...existingResponses,
546
- ];
557
+ const allMessages = [
558
+ ...search,
559
+ ...recent,
560
+ ...inputMessages,
561
+ ...inputPrompt,
562
+ ...existingResponses,
563
+ ];
547
564
  let processedMessages = args.contextHandler
548
565
  ? await args.contextHandler(ctx, {
549
566
  allMessages,
@@ -19,9 +19,10 @@ import {
19
19
  type StreamMessage,
20
20
  } from "../validators.js";
21
21
  import type {
22
+ ActionCtx,
22
23
  AgentComponent,
23
- RunMutationCtx,
24
- RunQueryCtx,
24
+ MutationCtx,
25
+ QueryCtx,
25
26
  SyncStreamsReturnValue,
26
27
  } from "./types.js";
27
28
 
@@ -45,7 +46,7 @@ export const vStreamMessagesReturnValue = v.object({
45
46
  * @returns The deltas for each stream from their existing cursor.
46
47
  */
47
48
  export async function syncStreams(
48
- ctx: RunQueryCtx,
49
+ ctx: QueryCtx | MutationCtx | ActionCtx,
49
50
  component: AgentComponent,
50
51
  {
51
52
  threadId,
@@ -80,7 +81,7 @@ export async function syncStreams(
80
81
  }
81
82
 
82
83
  export async function abortStream(
83
- ctx: RunMutationCtx,
84
+ ctx: MutationCtx,
84
85
  component: AgentComponent,
85
86
  args: { reason: string } & (
86
87
  | { streamId: string }
@@ -111,7 +112,7 @@ export async function abortStream(
111
112
  * @returns The streams for the thread.
112
113
  */
113
114
  export async function listStreams(
114
- ctx: RunQueryCtx,
115
+ ctx: QueryCtx | MutationCtx | ActionCtx,
115
116
  component: AgentComponent,
116
117
  {
117
118
  threadId,
@@ -212,7 +213,7 @@ export class DeltaStreamer<T> {
212
213
 
213
214
  constructor(
214
215
  public readonly component: AgentComponent,
215
- public readonly ctx: RunMutationCtx,
216
+ public readonly ctx: MutationCtx,
216
217
  config: {
217
218
  throttleMs: number | undefined;
218
219
  onAsyncAbort: (reason: string) => Promise<void>;