@convex-dev/agent 0.2.6-alpha.0 → 0.2.6

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 (98) hide show
  1. package/dist/client/definePlaygroundAPI.d.ts +6 -4
  2. package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
  3. package/dist/client/definePlaygroundAPI.js +15 -6
  4. package/dist/client/definePlaygroundAPI.js.map +1 -1
  5. package/dist/client/index.d.ts +26 -120
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +48 -373
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/client/messages.d.ts +1 -1
  10. package/dist/client/messages.d.ts.map +1 -1
  11. package/dist/client/mockModel.d.ts +3 -3
  12. package/dist/client/mockModel.d.ts.map +1 -1
  13. package/dist/client/mockModel.js +22 -17
  14. package/dist/client/mockModel.js.map +1 -1
  15. package/dist/client/saveInputMessages.d.ts +20 -0
  16. package/dist/client/saveInputMessages.d.ts.map +1 -0
  17. package/dist/client/saveInputMessages.js +57 -0
  18. package/dist/client/saveInputMessages.js.map +1 -0
  19. package/dist/client/search.d.ts +110 -9
  20. package/dist/client/search.d.ts.map +1 -1
  21. package/dist/client/search.js +271 -39
  22. package/dist/client/search.js.map +1 -1
  23. package/dist/client/start.d.ts +83 -0
  24. package/dist/client/start.d.ts.map +1 -0
  25. package/dist/client/start.js +171 -0
  26. package/dist/client/start.js.map +1 -0
  27. package/dist/client/streaming.d.ts +8 -8
  28. package/dist/client/streaming.d.ts.map +1 -1
  29. package/dist/client/streaming.js +2 -1
  30. package/dist/client/streaming.js.map +1 -1
  31. package/dist/client/textStreamParts.d.ts.map +1 -1
  32. package/dist/client/textStreamParts.js +2 -9
  33. package/dist/client/textStreamParts.js.map +1 -1
  34. package/dist/client/threads.d.ts +1 -1
  35. package/dist/client/threads.d.ts.map +1 -1
  36. package/dist/client/types.d.ts +137 -5
  37. package/dist/client/types.d.ts.map +1 -1
  38. package/dist/component/_generated/api.d.ts +11 -3
  39. package/dist/component/messages.d.ts +13 -4
  40. package/dist/component/messages.d.ts.map +1 -1
  41. package/dist/component/messages.js +67 -25
  42. package/dist/component/messages.js.map +1 -1
  43. package/dist/component/schema.d.ts +2 -1643
  44. package/dist/component/schema.d.ts.map +1 -1
  45. package/dist/component/schema.js +0 -24
  46. package/dist/component/schema.js.map +1 -1
  47. package/dist/mapping.d.ts +7 -9
  48. package/dist/mapping.d.ts.map +1 -1
  49. package/dist/mapping.js +73 -7
  50. package/dist/mapping.js.map +1 -1
  51. package/dist/react/deltas.d.ts.map +1 -1
  52. package/dist/react/deltas.js +15 -5
  53. package/dist/react/deltas.js.map +1 -1
  54. package/dist/react/fromUIMessages.d.ts +13 -0
  55. package/dist/react/fromUIMessages.d.ts.map +1 -0
  56. package/dist/react/fromUIMessages.js +70 -0
  57. package/dist/react/fromUIMessages.js.map +1 -0
  58. package/dist/react/toUIMessages.d.ts +5 -2
  59. package/dist/react/toUIMessages.d.ts.map +1 -1
  60. package/dist/react/toUIMessages.js +3 -0
  61. package/dist/react/toUIMessages.js.map +1 -1
  62. package/dist/shared.d.ts +10 -0
  63. package/dist/shared.d.ts.map +1 -1
  64. package/dist/shared.js +26 -0
  65. package/dist/shared.js.map +1 -1
  66. package/dist/validators.d.ts +1640 -0
  67. package/dist/validators.d.ts.map +1 -1
  68. package/dist/validators.js +41 -0
  69. package/dist/validators.js.map +1 -1
  70. package/package.json +1 -1
  71. package/src/client/definePlaygroundAPI.ts +16 -7
  72. package/src/client/index.test.ts +11 -46
  73. package/src/client/index.ts +99 -558
  74. package/src/client/messages.ts +1 -1
  75. package/src/client/mock.json +68 -0
  76. package/src/client/mockModel.ts +34 -23
  77. package/src/client/saveInputMessages.test.ts +576 -0
  78. package/src/client/saveInputMessages.ts +100 -0
  79. package/src/client/search.test.ts +1017 -0
  80. package/src/client/search.ts +446 -68
  81. package/src/client/start.ts +313 -0
  82. package/src/client/stream.json +48 -0
  83. package/src/client/streaming.ts +3 -3
  84. package/src/client/textStreamParts.ts +2 -11
  85. package/src/client/threads.ts +1 -1
  86. package/src/client/types.ts +143 -3
  87. package/src/component/_generated/api.d.ts +11 -3
  88. package/src/component/messages.ts +73 -27
  89. package/src/component/schema.ts +1 -29
  90. package/src/mapping.ts +84 -7
  91. package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  92. package/src/react/deltas.ts +18 -5
  93. package/src/react/fromUIMessages.test.ts +427 -0
  94. package/src/react/fromUIMessages.ts +85 -0
  95. package/src/react/toUIMessages.ts +21 -13
  96. package/src/shared.ts +33 -0
  97. package/src/validators.test.ts +13 -2
  98. package/src/validators.ts +48 -0
@@ -1,36 +1,31 @@
1
- import { embedMany, generateObject, generateText, stepCountIs, streamObject, streamText, } from "ai";
1
+ import { generateObject, generateText, stepCountIs, streamObject, streamText, } from "ai";
2
2
  import { assert, omit, pick } from "convex-helpers";
3
3
  import { internalActionGeneric, internalMutationGeneric, } from "convex/server";
4
4
  import { convexToJson, v } from "convex/values";
5
- import { validateVectorDimension, } from "../component/vector/tables.js";
5
+ import {} from "../component/vector/tables.js";
6
6
  import { deserializeMessage, serializeMessage, serializeNewMessagesInStep, serializeObjectResult, } from "../mapping.js";
7
- import { extractText, isTool } from "../shared.js";
7
+ import { getModelName, getProviderName } from "../shared.js";
8
8
  import { vMessageEmbeddings, vMessageWithMetadata, vSafeObjectArgs, vTextArgs, } from "../validators.js";
9
- import { wrapTools } from "./createTool.js";
10
9
  import { listMessages, saveMessages, } from "./messages.js";
11
- import { fetchContextMessages, getModelName, getProviderName, } from "./search.js";
10
+ import { embedMany, embedMessages, fetchContextMessages, generateAndSaveEmbeddings, } from "./search.js";
11
+ import { start } from "./start.js";
12
12
  import { DeltaStreamer, syncStreams, } from "./streaming.js";
13
13
  import { mergeTransforms, serializeTextStreamingPartsV5, } from "./textStreamParts.js";
14
14
  import { createThread, getThreadMetadata } from "./threads.js";
15
- import { inlineMessagesFiles } from "./files.js";
16
15
  export { stepCountIs } from "ai";
17
- export { vMessageDoc, vThreadDoc } from "../component/schema.js";
18
16
  export { deserializeMessage, serializeDataOrUrl, serializeMessage, guessMimeType, toUIFilePart, } from "../mapping.js";
19
17
  // NOTE: these are also exported via @convex-dev/agent/validators
20
18
  // a future version may put them all here or move these over there
21
- export { vAssistantMessage, vContextOptions, vMessage, vPaginationResult, vProviderMetadata, vStorageOptions, vStreamArgs, vSystemMessage, vToolMessage, vUsage, vUserMessage, vSource, vContent, } from "../validators.js";
19
+ export { vAssistantMessage, vContextOptions, vMessage, vMessageDoc, vPaginationResult, vProviderMetadata, vStorageOptions, vStreamArgs, vSystemMessage, vThreadDoc, vToolMessage, vUsage, vUserMessage, vSource, vContent, } from "../validators.js";
22
20
  export { definePlaygroundAPI, } from "./definePlaygroundAPI.js";
23
21
  export { getFile, storeFile } from "./files.js";
24
22
  export { listMessages, saveMessage, saveMessages, } from "./messages.js";
25
- export { fetchContextMessages, filterOutOrphanedToolMessages, } from "./search.js";
23
+ export { fetchContextMessages, filterOutOrphanedToolMessages, fetchContextWithPrompt, generateAndSaveEmbeddings, embedMessages, embedMany, } from "./search.js";
26
24
  export { abortStream, listStreams, syncStreams, vStreamMessagesReturnValue, } from "./streaming.js";
27
25
  export { createThread, getThreadMetadata, updateThreadMetadata, searchThreadTitles, } from "./threads.js";
28
26
  export { extractText, isTool, sorted } from "../shared.js";
29
27
  export { createTool } from "./createTool.js";
30
28
  export { mockModel } from "./mockModel.js";
31
- // 10k characters should be more than enough for most cases, and stays under
32
- // the 8k token limit for some models.
33
- const MAX_EMBEDDING_TEXT_LENGTH = 10_000;
34
29
  export class Agent {
35
30
  component;
36
31
  options;
@@ -84,147 +79,17 @@ export class Agent {
84
79
  * you pass here.
85
80
  */
86
81
  args, options) {
87
- const { threadId, ...opts } = { ...this.options, ...options };
88
- const context = await this._saveMessagesAndFetchContext(ctx, {
89
- userId: options?.userId,
90
- threadId: options?.threadId,
91
- messages: args.messages,
92
- prompt: args.prompt,
93
- promptMessageId: args.promptMessageId,
94
- ...opts,
95
- });
96
- let pendingMessageId = context.pendingMessageId;
97
- const { messages, promptMessageId, order, stepOrder, userId } = context;
98
- const savedMessages = context.savedMessages ?? [];
99
- const toolCtx = {
100
- ...ctx,
101
- userId,
102
- threadId,
103
- promptMessageId,
104
- agent: this,
105
- };
106
- const tools = wrapTools(toolCtx, args.tools ?? this.options.tools);
107
- const saveOutput = opts.storageOptions?.saveMessages !== "none";
108
- const fail = async (reason) => {
109
- if (threadId && promptMessageId) {
110
- console.error(`Message failed in thread ${threadId} with promptMessageId ${promptMessageId}: ${reason}`);
111
- }
112
- if (pendingMessageId) {
113
- await ctx.runMutation(this.component.messages.finalizeMessage, {
114
- messageId: pendingMessageId,
115
- result: { status: "failed", error: reason },
116
- });
117
- }
118
- };
119
- if (args.abortSignal) {
120
- const abortSignal = args.abortSignal;
121
- abortSignal.addEventListener("abort", async () => {
122
- await fail(abortSignal.reason ?? "Aborted");
123
- }, { once: true });
124
- }
125
- const aiArgs = {
126
- ...this.options.callSettings,
127
- providerOptions: this.options.providerOptions,
128
- ...omit(args, ["messages", "prompt", "promptMessageId"]),
129
- model: args.model ?? this.options.languageModel,
82
+ return start(ctx, this.component, {
83
+ ...args,
84
+ tools: (args.tools ?? this.options.tools),
130
85
  system: args.system ?? this.options.instructions,
131
- messages,
132
- stopWhen: args.stopWhen ??
133
- this.options.stopWhen ??
134
- stepCountIs(this.options.maxSteps ?? 1),
135
- tools,
136
- };
137
- if (pendingMessageId) {
138
- if (!aiArgs._internal?.generateId) {
139
- aiArgs._internal = {
140
- ...aiArgs._internal,
141
- generateId: () => pendingMessageId ?? crypto.randomUUID(),
142
- };
143
- }
144
- }
145
- let activeModel = aiArgs.model;
146
- return {
147
- args: aiArgs,
148
- order: order ?? 0,
149
- stepOrder: stepOrder ?? 0,
150
- userId,
151
- promptMessageId,
152
- getSavedMessages: () => savedMessages,
153
- updateModel: (model) => {
154
- if (model) {
155
- activeModel = model;
156
- }
157
- },
158
- fail,
159
- save: async (toSave, createPendingMessage) => {
160
- if (threadId && promptMessageId && saveOutput) {
161
- const metadata = {
162
- // TODO: get up to date one when user selects mid-generation
163
- model: getModelName(activeModel),
164
- provider: getProviderName(activeModel),
165
- };
166
- const serialized = "object" in toSave
167
- ? await serializeObjectResult(ctx, this.component, toSave.object, metadata)
168
- : await serializeNewMessagesInStep(ctx, this.component, toSave.step, metadata);
169
- const embeddings = await this.generateEmbeddings(ctx, { userId, threadId }, serialized.messages.map((m) => m.message));
170
- if (createPendingMessage) {
171
- serialized.messages.push({
172
- message: { role: "assistant", content: [] },
173
- status: "pending",
174
- });
175
- embeddings?.vectors.push(null);
176
- }
177
- const saved = await ctx.runMutation(this.component.messages.addMessages, {
178
- userId,
179
- threadId,
180
- agentName: this.options.name,
181
- promptMessageId,
182
- pendingMessageId,
183
- messages: serialized.messages,
184
- embeddings,
185
- failPendingSteps: false,
186
- });
187
- const lastMessage = saved.messages.at(-1);
188
- if (createPendingMessage) {
189
- if (lastMessage.status === "failed") {
190
- pendingMessageId = undefined;
191
- savedMessages.push(...saved.messages);
192
- await fail(lastMessage.error ??
193
- "Aborting - the pending message was marked as failed");
194
- }
195
- else {
196
- pendingMessageId = lastMessage._id;
197
- savedMessages.push(...saved.messages.slice(0, -1));
198
- }
199
- }
200
- else {
201
- pendingMessageId = undefined;
202
- savedMessages.push(...saved.messages);
203
- }
204
- }
205
- const output = "object" in toSave ? toSave.object : toSave.step;
206
- if (this.options.rawRequestResponseHandler) {
207
- await this.options.rawRequestResponseHandler(ctx, {
208
- userId,
209
- threadId,
210
- agentName: this.options.name,
211
- request: output.request,
212
- response: output.response,
213
- });
214
- }
215
- if (opts.usageHandler && output.usage) {
216
- await opts.usageHandler(ctx, {
217
- userId,
218
- threadId,
219
- agentName: this.options.name,
220
- model: getModelName(activeModel),
221
- provider: getProviderName(activeModel),
222
- usage: output.usage,
223
- providerMetadata: output.providerMetadata,
224
- });
225
- }
226
- },
227
- };
86
+ stopWhen: (args.stopWhen ?? this.options.stopWhen),
87
+ }, {
88
+ ...this.options,
89
+ ...options,
90
+ agentName: this.options.name,
91
+ agentForToolCtx: this,
92
+ });
228
93
  }
229
94
  /**
230
95
  * This behaves like {@link generateText} from the "ai" package except that
@@ -321,9 +186,6 @@ export class Agent {
321
186
  await streamer?.fail(errorToString(error.error));
322
187
  return streamTextArgs.onError?.(error);
323
188
  },
324
- // onFinish: async (event) => {
325
- // return streamTextArgs.onFinish?.(event);
326
- // },
327
189
  prepareStep: async (options) => {
328
190
  const result = await streamTextArgs.prepareStep?.(options);
329
191
  if (result) {
@@ -343,17 +205,17 @@ export class Agent {
343
205
  return args.onStepFinish?.(step);
344
206
  },
345
207
  });
208
+ if ((typeof options?.saveStreamDeltas === "object" &&
209
+ !options.saveStreamDeltas.returnImmediately) ||
210
+ options?.saveStreamDeltas === true) {
211
+ await result.consumeStream();
212
+ }
346
213
  const metadata = {
347
214
  promptMessageId,
348
215
  order,
349
216
  savedMessages: call.getSavedMessages(),
350
217
  messageId: promptMessageId,
351
218
  };
352
- if ((typeof options?.saveStreamDeltas === "object" &&
353
- !options.saveStreamDeltas.returnImmediately) ||
354
- options?.saveStreamDeltas === true) {
355
- await result.consumeStream();
356
- }
357
219
  return Object.assign(result, metadata);
358
220
  }
359
221
  /**
@@ -549,7 +411,9 @@ export class Agent {
549
411
  assert("runAction" in ctx);
550
412
  assert(this.options.textEmbeddingModel, "A textEmbeddingModel is required to be set on the Agent that you're doing vector search with");
551
413
  return {
552
- embedding: (await this.doEmbed(ctx, {
414
+ embedding: (await embedMany(ctx, {
415
+ ...this.options,
416
+ agentName: this.options.name,
553
417
  userId: args.userId,
554
418
  threadId: args.threadId,
555
419
  values: [text],
@@ -584,40 +448,8 @@ export class Agent {
584
448
  * @param messages The messages to get the embeddings for.
585
449
  * @returns The embeddings for the messages.
586
450
  */
587
- async generateEmbeddings(ctx, { userId, threadId, }, messages) {
588
- if (!this.options.textEmbeddingModel) {
589
- return undefined;
590
- }
591
- let embeddings;
592
- const messageTexts = messages.map((m) => !isTool(m) && extractText(m));
593
- // Find the indexes of the messages that have text.
594
- const textIndexes = messageTexts
595
- .map((t, i) => (t ? i : undefined))
596
- .filter((i) => i !== undefined);
597
- if (textIndexes.length === 0) {
598
- return undefined;
599
- }
600
- const values = messageTexts
601
- .map((t) => t && t.trim().slice(0, MAX_EMBEDDING_TEXT_LENGTH))
602
- .filter((t) => !!t);
603
- // Then embed those messages.
604
- const textEmbeddings = await this.doEmbed(ctx, {
605
- userId,
606
- threadId,
607
- values,
608
- });
609
- // Then assemble the embeddings into a single array with nulls for the messages without text.
610
- const embeddingsOrNull = Array(messages.length).fill(null);
611
- textIndexes.forEach((i, j) => {
612
- embeddingsOrNull[i] = textEmbeddings.embeddings[j];
613
- });
614
- if (textEmbeddings.embeddings.length > 0) {
615
- const dimension = textEmbeddings.embeddings[0].length;
616
- validateVectorDimension(dimension);
617
- const model = getModelName(this.options.textEmbeddingModel);
618
- embeddings = { vectors: embeddingsOrNull, dimension, model };
619
- }
620
- return embeddings;
451
+ async generateEmbeddings(ctx, args, messages) {
452
+ return embedMessages(ctx, { ...args, ...this.options, agentName: this.options.name }, messages);
621
453
  }
622
454
  /**
623
455
  * Generate embeddings for a set of messages, and save them to the database.
@@ -636,9 +468,6 @@ export class Agent {
636
468
  .filter((id) => !messages.some((m) => m?._id === id))
637
469
  .join(", "));
638
470
  }
639
- await this._generateAndSaveEmbeddings(ctx, messages);
640
- }
641
- async _generateAndSaveEmbeddings(ctx, messages) {
642
471
  if (messages.some((m) => !m.message)) {
643
472
  throw new Error("Some messages don't have a message: " +
644
473
  messages
@@ -646,34 +475,17 @@ export class Agent {
646
475
  .map((m) => m._id)
647
476
  .join(", "));
648
477
  }
649
- const messagesMissingEmbeddings = messages.filter((m) => !m.embeddingId);
650
- if (messagesMissingEmbeddings.length === 0) {
651
- return;
478
+ const { textEmbeddingModel } = this.options;
479
+ if (!textEmbeddingModel) {
480
+ throw new Error("No embeddings were generated for the messages. You must pass a textEmbeddingModel to the agent constructor.");
652
481
  }
653
- const embeddings = await this.generateEmbeddings(ctx, {
654
- userId: messagesMissingEmbeddings[0].userId,
655
- threadId: messagesMissingEmbeddings[0].threadId,
656
- }, messagesMissingEmbeddings.map((m) => deserializeMessage(m.message)));
657
- if (!embeddings) {
658
- if (!this.options.textEmbeddingModel) {
659
- throw new Error("No embeddings were generated for the messages. You must pass a textEmbeddingModel to the agent constructor.");
660
- }
661
- throw new Error("No embeddings were generated for these messages: " +
662
- messagesMissingEmbeddings.map((m) => m._id).join(", "));
663
- }
664
- await ctx.runMutation(this.component.vector.index.insertBatch, {
665
- vectorDimension: embeddings.dimension,
666
- vectors: messagesMissingEmbeddings
667
- .map((m, i) => ({
668
- messageId: m._id,
669
- model: embeddings.model,
670
- table: "messages",
671
- userId: m.userId,
672
- threadId: m.threadId,
673
- vector: embeddings.vectors[i],
674
- }))
675
- .filter((v) => v.vector !== null),
676
- });
482
+ await generateAndSaveEmbeddings(ctx, this.component, {
483
+ ...this.options,
484
+ agentName: this.options.name,
485
+ threadId: messages[0].threadId,
486
+ userId: messages[0].userId,
487
+ textEmbeddingModel,
488
+ }, messages);
677
489
  }
678
490
  /**
679
491
  * Explicitly save a "step" created by the AI SDK.
@@ -848,143 +660,6 @@ export class Agent {
848
660
  limit: args.pageSize,
849
661
  });
850
662
  }
851
- async _saveMessagesAndFetchContext(ctx, { userId: argsUserId, threadId, contextOptions, storageOptions, ...args }) {
852
- // If only a promptMessageId is provided, this will be empty.
853
- const messages = args.messages ?? [];
854
- const promptArray = !args.prompt
855
- ? []
856
- : Array.isArray(args.prompt)
857
- ? args.prompt.map((p) => deserializeMessage(p))
858
- : [{ role: "user", content: args.prompt }];
859
- const userId = argsUserId ??
860
- (threadId &&
861
- (await ctx.runQuery(this.component.threads.getThread, { threadId }))
862
- ?.userId) ??
863
- undefined;
864
- // If only a messageId is provided, this will add that message to the end.
865
- const contextMessages = await this.fetchContextMessages(ctx, {
866
- userId,
867
- threadId,
868
- upToAndIncludingMessageId: args.promptMessageId,
869
- messages,
870
- contextOptions,
871
- });
872
- // If it was a promptMessageId, pop it off context messages
873
- // and add to the end of messages.
874
- const promptMessageIndex = args.promptMessageId
875
- ? contextMessages.findIndex((m) => m._id === args.promptMessageId)
876
- : -1;
877
- const promptMessage = promptMessageIndex !== -1
878
- ? contextMessages.splice(promptMessageIndex, 1)[0]
879
- : undefined;
880
- let promptMessageId = promptMessage?._id;
881
- let order = promptMessage?.order;
882
- let stepOrder = promptMessage?.stepOrder;
883
- let savedMessages = undefined;
884
- let pendingMessageId = undefined;
885
- if (threadId && storageOptions?.saveMessages !== "none") {
886
- let saved;
887
- if (messages.length + promptArray.length &&
888
- // If it was a promptMessageId, we don't want to save it again.
889
- (!args.promptMessageId || storageOptions?.saveMessages === "all")) {
890
- const saveAll = storageOptions?.saveMessages === "all";
891
- const coreMessages = [
892
- ...messages,
893
- ...promptArray,
894
- ];
895
- const toSave = saveAll ? coreMessages : coreMessages.slice(-1);
896
- const metadata = Array.from({ length: toSave.length }, () => ({}));
897
- saved = await this.saveMessages(ctx, {
898
- threadId,
899
- userId,
900
- messages: [...toSave, { role: "assistant", content: [] }],
901
- metadata: [...metadata, { status: "pending" }],
902
- // TODO: sanity check
903
- failPendingSteps: !!args.promptMessageId,
904
- });
905
- promptMessageId = saved.messages.at(-2)._id;
906
- }
907
- else {
908
- saved = await this.saveMessages(ctx, {
909
- threadId,
910
- userId,
911
- messages: [{ role: "assistant", content: [] }],
912
- metadata: [{ status: "pending" }],
913
- failPendingSteps: !!args.promptMessageId,
914
- });
915
- }
916
- pendingMessageId = saved.messages.at(-1)._id;
917
- order = saved.messages.at(-1).order;
918
- stepOrder = saved.messages.at(-1).stepOrder;
919
- // Don't return the pending message
920
- savedMessages = saved.messages.slice(0, -1);
921
- }
922
- if (promptMessage?.message) {
923
- if (!args.prompt) {
924
- // If they override the prompt, we skip the existing prompt message.
925
- messages.push(promptMessage.message);
926
- }
927
- // Lazily generate embeddings for the prompt message, if it doesn't have
928
- // embeddings yet. This can happen if the message was saved in a mutation
929
- // where the LLM is not available.
930
- if (!promptMessage.embeddingId && this.options.textEmbeddingModel) {
931
- await this._generateAndSaveEmbeddings(ctx, [promptMessage]);
932
- }
933
- }
934
- const prePrompt = contextMessages.map((m) => m.message).filter((m) => !!m);
935
- let existingResponses = [];
936
- if (promptMessageIndex !== -1) {
937
- // pull any messages that already responded to the prompt off
938
- // and add them after the prompt
939
- existingResponses = prePrompt.splice(promptMessageIndex);
940
- }
941
- let processedMessages = [
942
- ...prePrompt,
943
- ...messages,
944
- ...promptArray,
945
- ...existingResponses,
946
- ].map((m) => deserializeMessage(m));
947
- // Process messages to inline localhost files (if not, file urls pointing to localhost will be sent to LLM providers)
948
- if (process.env.CONVEX_CLOUD_URL?.startsWith("http://127.0.0.1")) {
949
- processedMessages = await inlineMessagesFiles(processedMessages);
950
- }
951
- return {
952
- messages: processedMessages,
953
- userId,
954
- promptMessageId,
955
- pendingMessageId,
956
- savedMessages,
957
- order,
958
- stepOrder,
959
- };
960
- }
961
- async doEmbed(ctx, options) {
962
- const embeddingModel = this.options.textEmbeddingModel;
963
- assert(embeddingModel, "a textEmbeddingModel is required to be set on the Agent that you're doing vector search with");
964
- const result = await embedMany({
965
- ...this.options.callSettings,
966
- model: embeddingModel,
967
- values: options.values,
968
- abortSignal: options.abortSignal,
969
- headers: options.headers,
970
- });
971
- if (this.options.usageHandler && result.usage) {
972
- await this.options.usageHandler(ctx, {
973
- userId: options.userId,
974
- threadId: options.threadId,
975
- agentName: this.options.name,
976
- model: getModelName(embeddingModel),
977
- provider: getProviderName(embeddingModel),
978
- providerMetadata: undefined,
979
- usage: {
980
- inputTokens: result.usage.tokens,
981
- outputTokens: 0,
982
- totalTokens: result.usage.tokens,
983
- },
984
- });
985
- }
986
- return { embeddings: result.embeddings };
987
- }
988
663
  /**
989
664
  * WORKFLOW UTILITIES
990
665
  */
@@ -1030,22 +705,22 @@ export class Agent {
1030
705
  args: vTextArgs,
1031
706
  handler: async (ctx_, args) => {
1032
707
  const stream = args.stream === true ? spec?.stream || true : (spec?.stream ?? false);
1033
- const targetArgs = { userId: args.userId, threadId: args.threadId };
708
+ const { userId, threadId, prompt, messages, maxSteps, ...rest } = args;
709
+ const targetArgs = { userId, threadId };
1034
710
  const llmArgs = {
1035
- stopWhen: spec?.stopWhen ?? this.options.stopWhen,
711
+ stopWhen: spec?.stopWhen,
1036
712
  ...overrides,
1037
- ...omit(args, ["storageOptions", "contextOptions"]),
1038
- messages: args.messages?.map(deserializeMessage),
1039
- prompt: Array.isArray(args.prompt)
1040
- ? args.prompt.map(deserializeMessage)
1041
- : args.prompt,
713
+ ...omit(rest, ["storageOptions", "contextOptions", "stream"]),
714
+ messages: messages?.map(deserializeMessage),
715
+ prompt: Array.isArray(prompt)
716
+ ? prompt.map(deserializeMessage)
717
+ : prompt,
1042
718
  toolChoice: args.toolChoice,
1043
719
  };
1044
- if (args.maxSteps) {
1045
- llmArgs.stopWhen = stepCountIs(args.maxSteps);
720
+ if (maxSteps) {
721
+ llmArgs.stopWhen = stepCountIs(maxSteps);
1046
722
  }
1047
723
  const opts = {
1048
- ...this.options,
1049
724
  ...pick(spec, ["contextOptions", "storageOptions"]),
1050
725
  ...pick(args, ["contextOptions", "storageOptions"]),
1051
726
  saveStreamDeltas: stream,
@@ -1062,7 +737,7 @@ export class Agent {
1062
737
  promptMessageId: result.promptMessageId,
1063
738
  order: result.order,
1064
739
  finishReason: await result.finishReason,
1065
- warnings: result.warnings,
740
+ warnings: await result.warnings,
1066
741
  savedMessageIds: result.savedMessages?.map((m) => m._id) ?? [],
1067
742
  };
1068
743
  }