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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/MIGRATION.md +153 -0
  2. package/package.json +4 -2
  3. package/src/UIMessages.ts +135 -0
  4. package/src/client/approval.test.ts +350 -0
  5. package/src/client/createTool.ts +50 -52
  6. package/src/client/index.ts +162 -1
  7. package/src/client/mockModel.ts +9 -2
  8. package/src/client/search.test.ts +4 -5
  9. package/src/client/search.ts +47 -2
  10. package/src/client/start.ts +41 -24
  11. package/src/client/streamText.ts +27 -3
  12. package/src/client/streaming.integration.test.ts +1206 -0
  13. package/src/client/streaming.ts +41 -12
  14. package/src/client/types.ts +14 -12
  15. package/src/component/_generated/component.ts +53 -64
  16. package/src/component/messages.ts +12 -2
  17. package/src/deltas.ts +0 -1
  18. package/src/mapping.test.ts +143 -1
  19. package/src/mapping.ts +115 -6
  20. package/src/react/useDeltaStreams.ts +6 -0
  21. package/dist/UIMessages.d.ts +0 -46
  22. package/dist/UIMessages.d.ts.map +0 -1
  23. package/dist/UIMessages.js +0 -546
  24. package/dist/UIMessages.js.map +0 -1
  25. package/dist/client/createTool.d.ts +0 -170
  26. package/dist/client/createTool.d.ts.map +0 -1
  27. package/dist/client/createTool.js +0 -115
  28. package/dist/client/createTool.js.map +0 -1
  29. package/dist/client/defaultComponent.d.ts +0 -11
  30. package/dist/client/defaultComponent.d.ts.map +0 -1
  31. package/dist/client/defaultComponent.js +0 -7
  32. package/dist/client/defaultComponent.js.map +0 -1
  33. package/dist/client/definePlaygroundAPI.d.ts +0 -1725
  34. package/dist/client/definePlaygroundAPI.d.ts.map +0 -1
  35. package/dist/client/definePlaygroundAPI.js +0 -271
  36. package/dist/client/definePlaygroundAPI.js.map +0 -1
  37. package/dist/client/files.d.ts +0 -69
  38. package/dist/client/files.d.ts.map +0 -1
  39. package/dist/client/files.js +0 -181
  40. package/dist/client/files.js.map +0 -1
  41. package/dist/client/index.d.ts +0 -2044
  42. package/dist/client/index.d.ts.map +0 -1
  43. package/dist/client/index.js +0 -804
  44. package/dist/client/index.js.map +0 -1
  45. package/dist/client/messages.d.ts +0 -461
  46. package/dist/client/messages.d.ts.map +0 -1
  47. package/dist/client/messages.js +0 -106
  48. package/dist/client/messages.js.map +0 -1
  49. package/dist/client/mockModel.d.ts +0 -42
  50. package/dist/client/mockModel.d.ts.map +0 -1
  51. package/dist/client/mockModel.js +0 -175
  52. package/dist/client/mockModel.js.map +0 -1
  53. package/dist/client/saveInputMessages.d.ts +0 -20
  54. package/dist/client/saveInputMessages.d.ts.map +0 -1
  55. package/dist/client/saveInputMessages.js +0 -58
  56. package/dist/client/saveInputMessages.js.map +0 -1
  57. package/dist/client/search.d.ts +0 -493
  58. package/dist/client/search.d.ts.map +0 -1
  59. package/dist/client/search.js +0 -425
  60. package/dist/client/search.js.map +0 -1
  61. package/dist/client/start.d.ts +0 -84
  62. package/dist/client/start.d.ts.map +0 -1
  63. package/dist/client/start.js +0 -171
  64. package/dist/client/start.js.map +0 -1
  65. package/dist/client/streamText.d.ts +0 -46
  66. package/dist/client/streamText.d.ts.map +0 -1
  67. package/dist/client/streamText.js +0 -93
  68. package/dist/client/streamText.js.map +0 -1
  69. package/dist/client/streaming.d.ts +0 -3767
  70. package/dist/client/streaming.d.ts.map +0 -1
  71. package/dist/client/streaming.js +0 -294
  72. package/dist/client/streaming.js.map +0 -1
  73. package/dist/client/threads.d.ts +0 -46
  74. package/dist/client/threads.d.ts.map +0 -1
  75. package/dist/client/threads.js +0 -49
  76. package/dist/client/threads.js.map +0 -1
  77. package/dist/client/types.d.ts +0 -460
  78. package/dist/client/types.d.ts.map +0 -1
  79. package/dist/client/types.js +0 -2
  80. package/dist/client/types.js.map +0 -1
  81. package/dist/client/utils.d.ts +0 -4
  82. package/dist/client/utils.d.ts.map +0 -1
  83. package/dist/client/utils.js +0 -21
  84. package/dist/client/utils.js.map +0 -1
  85. package/dist/component/_generated/api.d.ts +0 -48
  86. package/dist/component/_generated/api.d.ts.map +0 -1
  87. package/dist/component/_generated/api.js +0 -31
  88. package/dist/component/_generated/api.js.map +0 -1
  89. package/dist/component/_generated/component.d.ts +0 -3119
  90. package/dist/component/_generated/component.d.ts.map +0 -1
  91. package/dist/component/_generated/component.js +0 -11
  92. package/dist/component/_generated/component.js.map +0 -1
  93. package/dist/component/_generated/dataModel.d.ts +0 -46
  94. package/dist/component/_generated/dataModel.d.ts.map +0 -1
  95. package/dist/component/_generated/dataModel.js +0 -11
  96. package/dist/component/_generated/dataModel.js.map +0 -1
  97. package/dist/component/_generated/server.d.ts +0 -121
  98. package/dist/component/_generated/server.d.ts.map +0 -1
  99. package/dist/component/_generated/server.js +0 -78
  100. package/dist/component/_generated/server.js.map +0 -1
  101. package/dist/component/apiKeys.d.ts +0 -11
  102. package/dist/component/apiKeys.d.ts.map +0 -1
  103. package/dist/component/apiKeys.js +0 -69
  104. package/dist/component/apiKeys.js.map +0 -1
  105. package/dist/component/convex.config.d.ts +0 -3
  106. package/dist/component/convex.config.d.ts.map +0 -1
  107. package/dist/component/convex.config.js +0 -3
  108. package/dist/component/convex.config.js.map +0 -1
  109. package/dist/component/files.d.ts +0 -97
  110. package/dist/component/files.d.ts.map +0 -1
  111. package/dist/component/files.js +0 -190
  112. package/dist/component/files.js.map +0 -1
  113. package/dist/component/messages.d.ts +0 -3850
  114. package/dist/component/messages.d.ts.map +0 -1
  115. package/dist/component/messages.js +0 -747
  116. package/dist/component/messages.js.map +0 -1
  117. package/dist/component/schema.d.ts +0 -8026
  118. package/dist/component/schema.d.ts.map +0 -1
  119. package/dist/component/schema.js +0 -147
  120. package/dist/component/schema.js.map +0 -1
  121. package/dist/component/streams.d.ts +0 -128
  122. package/dist/component/streams.d.ts.map +0 -1
  123. package/dist/component/streams.js +0 -413
  124. package/dist/component/streams.js.map +0 -1
  125. package/dist/component/threads.d.ts +0 -115
  126. package/dist/component/threads.d.ts.map +0 -1
  127. package/dist/component/threads.js +0 -208
  128. package/dist/component/threads.js.map +0 -1
  129. package/dist/component/users.d.ts +0 -52
  130. package/dist/component/users.d.ts.map +0 -1
  131. package/dist/component/users.js +0 -229
  132. package/dist/component/users.js.map +0 -1
  133. package/dist/component/vector/index.d.ts +0 -61
  134. package/dist/component/vector/index.d.ts.map +0 -1
  135. package/dist/component/vector/index.js +0 -146
  136. package/dist/component/vector/index.js.map +0 -1
  137. package/dist/component/vector/tables.d.ts +0 -58
  138. package/dist/component/vector/tables.d.ts.map +0 -1
  139. package/dist/component/vector/tables.js +0 -56
  140. package/dist/component/vector/tables.js.map +0 -1
  141. package/dist/deltas.d.ts +0 -43
  142. package/dist/deltas.d.ts.map +0 -1
  143. package/dist/deltas.js +0 -447
  144. package/dist/deltas.js.map +0 -1
  145. package/dist/mapping.d.ts +0 -54
  146. package/dist/mapping.d.ts.map +0 -1
  147. package/dist/mapping.js +0 -626
  148. package/dist/mapping.js.map +0 -1
  149. package/dist/react/SmoothText.d.ts +0 -5
  150. package/dist/react/SmoothText.d.ts.map +0 -1
  151. package/dist/react/SmoothText.js +0 -6
  152. package/dist/react/SmoothText.js.map +0 -1
  153. package/dist/react/index.d.ts +0 -25
  154. package/dist/react/index.d.ts.map +0 -1
  155. package/dist/react/index.js +0 -70
  156. package/dist/react/index.js.map +0 -1
  157. package/dist/react/optimisticallySendMessage.d.ts +0 -42
  158. package/dist/react/optimisticallySendMessage.d.ts.map +0 -1
  159. package/dist/react/optimisticallySendMessage.js +0 -74
  160. package/dist/react/optimisticallySendMessage.js.map +0 -1
  161. package/dist/react/types.d.ts +0 -12
  162. package/dist/react/types.d.ts.map +0 -1
  163. package/dist/react/types.js +0 -2
  164. package/dist/react/types.js.map +0 -1
  165. package/dist/react/useDeltaStreams.d.ts +0 -10
  166. package/dist/react/useDeltaStreams.d.ts.map +0 -1
  167. package/dist/react/useDeltaStreams.js +0 -101
  168. package/dist/react/useDeltaStreams.js.map +0 -1
  169. package/dist/react/useSmoothText.d.ts +0 -27
  170. package/dist/react/useSmoothText.d.ts.map +0 -1
  171. package/dist/react/useSmoothText.js +0 -68
  172. package/dist/react/useSmoothText.js.map +0 -1
  173. package/dist/react/useStreamingUIMessages.d.ts +0 -22
  174. package/dist/react/useStreamingUIMessages.d.ts.map +0 -1
  175. package/dist/react/useStreamingUIMessages.js +0 -92
  176. package/dist/react/useStreamingUIMessages.js.map +0 -1
  177. package/dist/react/useThreadMessages.d.ts +0 -104
  178. package/dist/react/useThreadMessages.d.ts.map +0 -1
  179. package/dist/react/useThreadMessages.js +0 -148
  180. package/dist/react/useThreadMessages.js.map +0 -1
  181. package/dist/react/useUIMessages.d.ts +0 -96
  182. package/dist/react/useUIMessages.d.ts.map +0 -1
  183. package/dist/react/useUIMessages.js +0 -108
  184. package/dist/react/useUIMessages.js.map +0 -1
  185. package/dist/shared.d.ts +0 -26
  186. package/dist/shared.d.ts.map +0 -1
  187. package/dist/shared.js +0 -67
  188. package/dist/shared.js.map +0 -1
  189. package/dist/validators.d.ts +0 -24516
  190. package/dist/validators.d.ts.map +0 -1
  191. package/dist/validators.js +0 -475
  192. package/dist/validators.js.map +0 -1
@@ -1,804 +0,0 @@
1
- import { generateObject, generateText, stepCountIs, streamObject } from "ai";
2
- const MIGRATION_URL = "https://github.com/get-convex/agent/blob/main/MIGRATION.md";
3
- const warnedDeprecations = new Set();
4
- function warnDeprecation(key, message) {
5
- if (!warnedDeprecations.has(key)) {
6
- warnedDeprecations.add(key);
7
- console.warn(`[@convex-dev/agent] ${message}\n See: ${MIGRATION_URL}`);
8
- }
9
- }
10
- import { assert, omit, pick } from "convex-helpers";
11
- import { internalActionGeneric, internalMutationGeneric, } from "convex/server";
12
- import { convexToJson, v } from "convex/values";
13
- import {} from "../component/vector/tables.js";
14
- import { toModelMessage, serializeMessage, serializeNewMessagesInStep, serializeObjectResult, } from "../mapping.js";
15
- import { getModelName, getProviderName } from "../shared.js";
16
- import { vMessageEmbeddings, vMessageWithMetadata, vSafeObjectArgs, vTextArgs, } from "../validators.js";
17
- import { listMessages, saveMessages, } from "./messages.js";
18
- import { embedMany, embedMessages, fetchContextMessages, generateAndSaveEmbeddings, } from "./search.js";
19
- import { startGeneration } from "./start.js";
20
- import { syncStreams } from "./streaming.js";
21
- import { createThread, getThreadMetadata } from "./threads.js";
22
- import { streamText } from "./streamText.js";
23
- import { errorToString, willContinue } from "./utils.js";
24
- export { stepCountIs } from "ai";
25
- export { docsToModelMessages, toModelMessage,
26
- //** @deprecated use toModelMessage instead */
27
- toModelMessage as deserializeMessage, guessMimeType, serializeDataOrUrl, serializeMessage, toUIFilePart, } from "../mapping.js";
28
- // NOTE: these are also exported via @convex-dev/agent/validators
29
- // a future version may put them all here or move these over there
30
- export { extractText, isTool, sorted } from "../shared.js";
31
- export { vAssistantMessage, vContent, vContextOptions, vMessage, vMessageDoc, vPaginationResult, vProviderMetadata, vSource, vStorageOptions, vStreamArgs, vSystemMessage, vThreadDoc, vToolMessage, vUsage, vUserMessage, } from "../validators.js";
32
- export { createTool } from "./createTool.js";
33
- export { definePlaygroundAPI, } from "./definePlaygroundAPI.js";
34
- export { getFile, storeFile } from "./files.js";
35
- export { listMessages, listUIMessages, saveMessage, saveMessages, } from "./messages.js";
36
- export { mockModel } from "./mockModel.js";
37
- export { fetchContextMessages, filterOutOrphanedToolMessages, fetchContextWithPrompt, generateAndSaveEmbeddings, embedMessages, embedMany, } from "./search.js";
38
- export { startGeneration } from "./start.js";
39
- export { DEFAULT_STREAMING_OPTIONS, DeltaStreamer, abortStream, compressUIMessageChunks, listStreams, syncStreams, vStreamMessagesReturnValue, } from "./streaming.js";
40
- export { createThread, getThreadMetadata, searchThreadTitles, updateThreadMetadata, } from "./threads.js";
41
- export { toUIMessages, fromUIMessages } from "../UIMessages.js";
42
- export class Agent {
43
- component;
44
- options;
45
- constructor(component, options) {
46
- this.component = component;
47
- this.options = options;
48
- if (this.options.textEmbeddingModel && !this.options.embeddingModel) {
49
- warnDeprecation("textEmbeddingModel", "textEmbeddingModel is deprecated. Use embeddingModel instead.");
50
- }
51
- }
52
- /**
53
- * Get the embedding model, prioritizing embeddingModel over textEmbeddingModel.
54
- * @private
55
- */
56
- getEmbeddingModel() {
57
- return this.options.embeddingModel ?? this.options.textEmbeddingModel;
58
- }
59
- async createThread(ctx, args) {
60
- const threadId = await createThread(ctx, this.component, args);
61
- if (!("runAction" in ctx) || "workflowId" in ctx) {
62
- return { threadId };
63
- }
64
- const { thread } = await this.continueThread(ctx, {
65
- threadId,
66
- userId: args?.userId,
67
- });
68
- return { threadId, thread };
69
- }
70
- /**
71
- * Continues a thread using this agent. Note: threads can be continued
72
- * by different agents. This is a convenience around calling the various
73
- * generate and stream functions with explicit userId and threadId parameters.
74
- * @param ctx The ctx object passed to the action handler
75
- * @param { threadId, userId }: the thread and user to associate the messages with.
76
- * @returns Functions bound to the userId and threadId on a `{thread}` object.
77
- */
78
- async continueThread(ctx, args) {
79
- return {
80
- thread: {
81
- threadId: args.threadId,
82
- getMetadata: this.getThreadMetadata.bind(this, ctx, {
83
- threadId: args.threadId,
84
- }),
85
- updateMetadata: (patch) => ctx.runMutation(this.component.threads.updateThread, {
86
- threadId: args.threadId,
87
- patch,
88
- }),
89
- generateText: this.generateText.bind(this, ctx, args),
90
- streamText: this.streamText.bind(this, ctx, args),
91
- generateObject: this.generateObject.bind(this, ctx, args),
92
- streamObject: this.streamObject.bind(this, ctx, args),
93
- },
94
- };
95
- }
96
- async start(ctx,
97
- /**
98
- * These are the arguments you'll pass to the LLM call such as
99
- * `generateText` or `streamText`. This function will look up the context
100
- * and provide functions to save the steps, abort the generation, and more.
101
- * The type of the arguments returned infers from the type of the arguments
102
- * you pass here.
103
- */
104
- args, options) {
105
- return startGeneration(ctx, this.component, {
106
- ...args,
107
- tools: (args.tools ?? this.options.tools),
108
- system: args.system ?? this.options.instructions,
109
- stopWhen: (args.stopWhen ?? this.options.stopWhen),
110
- }, {
111
- ...this.options,
112
- ...options,
113
- agentName: this.options.name,
114
- agentForToolCtx: this,
115
- });
116
- }
117
- /**
118
- * This behaves like {@link generateText} from the "ai" package except that
119
- * it add context based on the userId and threadId and saves the input and
120
- * resulting messages to the thread, if specified.
121
- * Use {@link continueThread} to get a version of this function already scoped
122
- * to a thread (and optionally userId).
123
- * @param ctx The context passed from the action function calling this.
124
- * @param scope: The user and thread to associate the message with
125
- * @param generateTextArgs The arguments to the generateText function, along
126
- * with {@link AgentPrompt} options, such as promptMessageId.
127
- * @param options Extra controls for the {@link ContextOptions} and {@link StorageOptions}.
128
- * @returns The result of the generateText function.
129
- */
130
- async generateText(ctx, threadOpts,
131
- /**
132
- * The arguments to the generateText function, similar to the ai sdk's
133
- * {@link generateText} function, along with Agent prompt options.
134
- */
135
- generateTextArgs, options) {
136
- const { args, promptMessageId, order, ...call } = await this.start(ctx, generateTextArgs, { ...threadOpts, ...options });
137
- const steps = [];
138
- try {
139
- const result = (await generateText({
140
- ...args,
141
- prepareStep: async (options) => {
142
- const result = await generateTextArgs.prepareStep?.(options);
143
- call.updateModel(result?.model ?? options.model);
144
- return result;
145
- },
146
- onStepFinish: async (step) => {
147
- steps.push(step);
148
- await call.save({ step }, await willContinue(steps, args.stopWhen));
149
- return generateTextArgs.onStepFinish?.(step);
150
- },
151
- }));
152
- const metadata = {
153
- promptMessageId,
154
- order,
155
- savedMessages: call.getSavedMessages(),
156
- messageId: promptMessageId,
157
- };
158
- return Object.assign(result, metadata);
159
- }
160
- catch (error) {
161
- await call.fail(errorToString(error));
162
- throw error;
163
- }
164
- }
165
- /**
166
- * This behaves like {@link streamText} from the "ai" package except that
167
- * it add context based on the userId and threadId and saves the input and
168
- * resulting messages to the thread, if specified.
169
- * Use {@link continueThread} to get a version of this function already scoped
170
- * to a thread (and optionally userId).
171
- */
172
- async streamText(ctx, threadOpts,
173
- /**
174
- * The arguments to the streamText function, similar to the ai sdk's
175
- * {@link streamText} function, along with Agent prompt options.
176
- */
177
- streamTextArgs,
178
- /**
179
- * The {@link ContextOptions} and {@link StorageOptions}
180
- * options to use for fetching contextual messages and saving input/output messages.
181
- */
182
- options) {
183
- return streamText(ctx, this.component, {
184
- ...streamTextArgs,
185
- model: streamTextArgs.model ?? this.options.languageModel,
186
- tools: (streamTextArgs.tools ?? this.options.tools),
187
- system: streamTextArgs.system ?? this.options.instructions,
188
- stopWhen: (streamTextArgs.stopWhen ?? this.options.stopWhen),
189
- }, {
190
- ...threadOpts,
191
- ...this.options,
192
- agentName: this.options.name,
193
- agentForToolCtx: this,
194
- ...options,
195
- });
196
- }
197
- /**
198
- * This behaves like {@link generateObject} from the "ai" package except that
199
- * it add context based on the userId and threadId and saves the input and
200
- * resulting messages to the thread, if specified.
201
- * Use {@link continueThread} to get a version of this function already scoped
202
- * to a thread (and optionally userId).
203
- */
204
- async generateObject(ctx, threadOpts,
205
- /**
206
- * The arguments to the generateObject function, similar to the ai sdk's
207
- * {@link generateObject} function, along with Agent prompt options.
208
- */
209
- generateObjectArgs,
210
- /**
211
- * The {@link ContextOptions} and {@link StorageOptions}
212
- * options to use for fetching contextual messages and saving input/output messages.
213
- */
214
- options) {
215
- const { args, promptMessageId, order, fail, save, getSavedMessages } = await this.start(ctx, generateObjectArgs, { ...threadOpts, ...options });
216
- try {
217
- const result = (await generateObject(args));
218
- await save({ object: result });
219
- const metadata = {
220
- promptMessageId,
221
- order,
222
- savedMessages: getSavedMessages(),
223
- messageId: promptMessageId,
224
- };
225
- return Object.assign(result, metadata);
226
- }
227
- catch (error) {
228
- await fail(errorToString(error));
229
- throw error;
230
- }
231
- }
232
- /**
233
- * This behaves like `streamObject` from the "ai" package except that
234
- * it add context based on the userId and threadId and saves the input and
235
- * resulting messages to the thread, if specified.
236
- * Use {@link continueThread} to get a version of this function already scoped
237
- * to a thread (and optionally userId).
238
- */
239
- async streamObject(ctx, threadOpts,
240
- /**
241
- * The arguments to the streamObject function, similar to the ai sdk's
242
- * {@link streamObject} function, along with Agent prompt options.
243
- */
244
- streamObjectArgs,
245
- /**
246
- * The {@link ContextOptions} and {@link StorageOptions}
247
- * options to use for fetching contextual messages and saving input/output messages.
248
- */
249
- options) {
250
- const { args, promptMessageId, order, fail, save, getSavedMessages } = await this.start(ctx, streamObjectArgs, { ...threadOpts, ...options });
251
- const stream = streamObject({
252
- ...args,
253
- onError: async (error) => {
254
- console.error(" streamObject onError", error);
255
- // TODO: content that we have so far
256
- // content: stream.fullStream.
257
- await fail(errorToString(error.error));
258
- return args.onError?.(error);
259
- },
260
- onFinish: async (result) => {
261
- await save({
262
- object: {
263
- object: result.object,
264
- finishReason: result.error ? "error" : "stop",
265
- usage: result.usage,
266
- warnings: result.warnings,
267
- request: await stream.request,
268
- response: result.response,
269
- providerMetadata: result.providerMetadata,
270
- toJsonResponse: stream.toTextStreamResponse,
271
- reasoning: undefined,
272
- },
273
- });
274
- return args.onFinish?.(result);
275
- },
276
- });
277
- const metadata = {
278
- promptMessageId,
279
- order,
280
- savedMessages: getSavedMessages(),
281
- messageId: promptMessageId,
282
- };
283
- return Object.assign(stream, metadata);
284
- }
285
- /**
286
- * Save a message to the thread.
287
- * @param ctx A ctx object from a mutation or action.
288
- * @param args The message and what to associate it with (user / thread)
289
- * You can pass extra metadata alongside the message, e.g. associated fileIds.
290
- * @returns The messageId of the saved message.
291
- */
292
- async saveMessage(ctx, args) {
293
- const { messages } = await this.saveMessages(ctx, {
294
- threadId: args.threadId,
295
- userId: args.userId,
296
- embeddings: args.embedding
297
- ? { model: args.embedding.model, vectors: [args.embedding.vector] }
298
- : undefined,
299
- messages: args.prompt !== undefined
300
- ? [{ role: "user", content: args.prompt }]
301
- : [args.message],
302
- metadata: args.metadata ? [args.metadata] : undefined,
303
- skipEmbeddings: args.skipEmbeddings,
304
- promptMessageId: args.promptMessageId,
305
- pendingMessageId: args.pendingMessageId,
306
- });
307
- const message = messages.at(-1);
308
- return { messageId: message._id, message };
309
- }
310
- /**
311
- * Explicitly save messages associated with the thread (& user if provided)
312
- * If you have an embedding model set, it will also generate embeddings for
313
- * the messages.
314
- * @param ctx The ctx parameter to a mutation or action.
315
- * @param args The messages and context to save
316
- * @returns
317
- */
318
- async saveMessages(ctx, args) {
319
- let embeddings;
320
- const { skipEmbeddings, ...rest } = args;
321
- if (args.embeddings) {
322
- embeddings = args.embeddings;
323
- }
324
- else if (!skipEmbeddings && this.getEmbeddingModel()) {
325
- if (!("runAction" in ctx)) {
326
- console.warn("You're trying to save messages and generate embeddings, but you're in a mutation. " +
327
- "Pass `skipEmbeddings: true` to skip generating embeddings in the mutation and skip this warning. " +
328
- "They will be generated lazily when you generate or stream text / objects. " +
329
- "You can explicitly generate them asynchronously by using the scheduler to run an action later that calls `agent.generateAndSaveEmbeddings`.");
330
- }
331
- else if ("workflowId" in ctx) {
332
- console.warn("You're trying to save messages and generate embeddings, but you're in a workflow. " +
333
- "Pass `skipEmbeddings: true` to skip generating embeddings in the workflow and skip this warning. " +
334
- "They will be generated lazily when you generate or stream text / objects. " +
335
- "You can explicitly generate them asynchronously by using the scheduler to run an action later that calls `agent.generateAndSaveEmbeddings`.");
336
- }
337
- else {
338
- embeddings = await this.generateEmbeddings(ctx, { userId: args.userId ?? undefined, threadId: args.threadId }, args.messages);
339
- }
340
- }
341
- return saveMessages(ctx, this.component, {
342
- ...rest,
343
- agentName: this.options.name,
344
- embeddings,
345
- });
346
- }
347
- /**
348
- * List messages from a thread.
349
- * @param ctx A ctx object from a query, mutation, or action.
350
- * @param args.threadId The thread to list messages from.
351
- * @param args.paginationOpts Pagination options (e.g. via usePaginatedQuery).
352
- * @param args.excludeToolMessages Whether to exclude tool messages.
353
- * False by default.
354
- * @param args.statuses What statuses to include. All by default.
355
- * @returns The MessageDoc's in a format compatible with usePaginatedQuery.
356
- */
357
- async listMessages(ctx, args) {
358
- return listMessages(ctx, this.component, args);
359
- }
360
- /**
361
- * A function that handles fetching stream deltas, used with the React hooks
362
- * `useThreadMessages` or `useStreamingThreadMessages`.
363
- * @param ctx A ctx object from a query, mutation, or action.
364
- * @param args.threadId The thread to sync streams for.
365
- * @param args.streamArgs The stream arguments with per-stream cursors.
366
- * @returns The deltas for each stream from their existing cursor.
367
- */
368
- async syncStreams(ctx, args) {
369
- return syncStreams(ctx, this.component, args);
370
- }
371
- /**
372
- * Fetch the context messages for a thread.
373
- * @param ctx Either a query, mutation, or action ctx.
374
- * If it is not an action context, you can't do text or
375
- * vector search.
376
- * @param args The associated thread, user, message
377
- * @returns
378
- */
379
- async fetchContextMessages(ctx, args) {
380
- assert(args.userId || args.threadId, "Specify userId or threadId");
381
- const contextOptions = {
382
- ...this.options.contextOptions,
383
- ...args.contextOptions,
384
- };
385
- return fetchContextMessages(ctx, this.component, {
386
- ...args,
387
- contextOptions,
388
- getEmbedding: async (text) => {
389
- assert("runAction" in ctx);
390
- const embeddingModel = this.getEmbeddingModel();
391
- assert(embeddingModel, "An embeddingModel (or textEmbeddingModel) is required to be set on the Agent that you're doing vector search with");
392
- return {
393
- embedding: (await embedMany(ctx, {
394
- ...this.options,
395
- agentName: this.options.name,
396
- userId: args.userId,
397
- threadId: args.threadId,
398
- values: [text],
399
- })).embeddings[0],
400
- embeddingModel: embeddingModel,
401
- };
402
- },
403
- });
404
- }
405
- /**
406
- * Get the metadata for a thread.
407
- * @param ctx A ctx object from a query, mutation, or action.
408
- * @param args.threadId The thread to get the metadata for.
409
- * @returns The metadata for the thread.
410
- */
411
- async getThreadMetadata(ctx, args) {
412
- return getThreadMetadata(ctx, this.component, args);
413
- }
414
- /**
415
- * Update the metadata for a thread.
416
- * @param ctx A ctx object from a mutation or action.
417
- * @param args.threadId The thread to update the metadata for.
418
- * @param args.patch The patch to apply to the thread.
419
- * @returns The updated thread metadata.
420
- */
421
- async updateThreadMetadata(ctx, args) {
422
- const thread = await ctx.runMutation(this.component.threads.updateThread, args);
423
- return thread;
424
- }
425
- /**
426
- * Get the embeddings for a set of messages.
427
- * @param messages The messages to get the embeddings for.
428
- * @returns The embeddings for the messages.
429
- */
430
- async generateEmbeddings(ctx, args, messages) {
431
- return embedMessages(ctx, { ...args, ...this.options, agentName: this.options.name }, messages);
432
- }
433
- /**
434
- * Generate embeddings for a set of messages, and save them to the database.
435
- * It will not generate or save embeddings for messages that already have an
436
- * embedding.
437
- * @param ctx The ctx parameter to an action.
438
- * @param args The messageIds to generate embeddings for.
439
- */
440
- async generateAndSaveEmbeddings(ctx, args) {
441
- const messages = (await ctx.runQuery(this.component.messages.getMessagesByIds, {
442
- messageIds: args.messageIds,
443
- })).filter((m) => m !== null);
444
- if (messages.length !== args.messageIds.length) {
445
- throw new Error("Some messages were not found: " +
446
- args.messageIds
447
- .filter((id) => !messages.some((m) => m?._id === id))
448
- .join(", "));
449
- }
450
- if (messages.some((m) => !m.message)) {
451
- throw new Error("Some messages don't have a message: " +
452
- messages
453
- .filter((m) => !m.message)
454
- .map((m) => m._id)
455
- .join(", "));
456
- }
457
- const embeddingModel = this.getEmbeddingModel();
458
- if (!embeddingModel) {
459
- throw new Error("No embeddings were generated for the messages. You must pass an embeddingModel (or textEmbeddingModel) to the agent constructor.");
460
- }
461
- await generateAndSaveEmbeddings(ctx, this.component, {
462
- ...this.options,
463
- agentName: this.options.name,
464
- threadId: messages[0].threadId,
465
- userId: messages[0].userId,
466
- embeddingModel,
467
- }, messages);
468
- }
469
- /**
470
- * Explicitly save a "step" created by the AI SDK.
471
- * @param ctx The ctx argument to a mutation or action.
472
- * @param args The Step generated by the AI SDK.
473
- */
474
- async saveStep(ctx, args) {
475
- const { messages } = await serializeNewMessagesInStep(ctx, this.component, args.step, {
476
- provider: args.provider ?? getProviderName(this.options.languageModel),
477
- model: args.model ?? getModelName(this.options.languageModel),
478
- });
479
- const embeddings = await this.generateEmbeddings(ctx, { userId: args.userId, threadId: args.threadId }, messages.map((m) => m.message));
480
- return ctx.runMutation(this.component.messages.addMessages, {
481
- userId: args.userId,
482
- threadId: args.threadId,
483
- agentName: this.options.name,
484
- promptMessageId: args.promptMessageId,
485
- messages,
486
- embeddings,
487
- failPendingSteps: false,
488
- });
489
- }
490
- /**
491
- * Manually save the result of a generateObject call to the thread.
492
- * This happens automatically when using {@link generateObject} or {@link streamObject}
493
- * from the `thread` object created by {@link continueThread} or {@link createThread}.
494
- * @param ctx The context passed from the mutation or action function calling this.
495
- * @param args The arguments to the saveObject function.
496
- */
497
- async saveObject(ctx, args) {
498
- const { messages } = await serializeObjectResult(ctx, this.component, args.result, {
499
- model: args.model ??
500
- args.metadata?.model ??
501
- getModelName(this.options.languageModel),
502
- provider: args.provider ??
503
- args.metadata?.provider ??
504
- getProviderName(this.options.languageModel),
505
- });
506
- const embeddings = await this.generateEmbeddings(ctx, { userId: args.userId, threadId: args.threadId }, messages.map((m) => m.message));
507
- return ctx.runMutation(this.component.messages.addMessages, {
508
- userId: args.userId,
509
- threadId: args.threadId,
510
- promptMessageId: args.promptMessageId,
511
- failPendingSteps: false,
512
- messages,
513
- embeddings,
514
- agentName: this.options.name,
515
- });
516
- }
517
- /**
518
- * Commit or rollback a message that was pending.
519
- * This is done automatically when saving messages by default.
520
- * If creating pending messages, you can call this when the full "transaction" is done.
521
- * @param ctx The ctx argument to your mutation or action.
522
- * @param args What message to save. Generally the parent message sent into
523
- * the generateText call.
524
- */
525
- async finalizeMessage(ctx, args) {
526
- await ctx.runMutation(this.component.messages.finalizeMessage, {
527
- messageId: args.messageId,
528
- result: args.result,
529
- });
530
- }
531
- /**
532
- * Update a message by its id.
533
- * @param ctx The ctx argument to your mutation or action.
534
- * @param args The message fields to update.
535
- */
536
- async updateMessage(ctx, args) {
537
- const { message, fileIds } = await serializeMessage(ctx, this.component, args.patch.message);
538
- await ctx.runMutation(this.component.messages.updateMessage, {
539
- messageId: args.messageId,
540
- patch: {
541
- message,
542
- fileIds: args.patch.fileIds
543
- ? [...args.patch.fileIds, ...(fileIds ?? [])]
544
- : fileIds,
545
- status: args.patch.status === "success" ? "success" : "failed",
546
- error: args.patch.error,
547
- },
548
- });
549
- }
550
- /**
551
- * Delete multiple messages by their ids, including their embeddings
552
- * and reduce the refcount of any files they reference.
553
- * @param ctx The ctx argument to your mutation or action.
554
- * @param args The ids of the messages to delete.
555
- */
556
- async deleteMessages(ctx, args) {
557
- await ctx.runMutation(this.component.messages.deleteByIds, args);
558
- }
559
- /**
560
- * Delete a single message by its id, including its embedding
561
- * and reduce the refcount of any files it references.
562
- * @param ctx The ctx argument to your mutation or action.
563
- * @param args The id of the message to delete.
564
- */
565
- async deleteMessage(ctx, args) {
566
- await ctx.runMutation(this.component.messages.deleteByIds, {
567
- messageIds: [args.messageId],
568
- });
569
- }
570
- /**
571
- * Delete a range of messages by their order and step order.
572
- * Each "order" is a set of associated messages in response to the message
573
- * at stepOrder 0.
574
- * The (startOrder, startStepOrder) is inclusive
575
- * and the (endOrder, endStepOrder) is exclusive.
576
- * To delete all messages at "order" 1, you can pass:
577
- * `{ startOrder: 1, endOrder: 2 }`
578
- * To delete a message at step (order=1, stepOrder=1), you can pass:
579
- * `{ startOrder: 1, startStepOrder: 1, endOrder: 1, endStepOrder: 2 }`
580
- * To delete all messages between (1, 1) up to and including (3, 5), you can pass:
581
- * `{ startOrder: 1, startStepOrder: 1, endOrder: 3, endStepOrder: 6 }`
582
- *
583
- * If it cannot do it in one transaction, it returns information you can use
584
- * to resume the deletion.
585
- * e.g.
586
- * ```ts
587
- * let isDone = false;
588
- * let lastOrder = args.startOrder;
589
- * let lastStepOrder = args.startStepOrder ?? 0;
590
- * while (!isDone) {
591
- * // eslint-disable-next-line @typescript-eslint/no-explicit-any
592
- * ({ isDone, lastOrder, lastStepOrder } = await agent.deleteMessageRange(
593
- * ctx,
594
- * {
595
- * threadId: args.threadId,
596
- * startOrder: lastOrder,
597
- * startStepOrder: lastStepOrder,
598
- * endOrder: args.endOrder,
599
- * endStepOrder: args.endStepOrder,
600
- * }
601
- * ));
602
- * }
603
- * ```
604
- * @param ctx The ctx argument to your mutation or action.
605
- * @param args The range of messages to delete.
606
- */
607
- async deleteMessageRange(ctx, args) {
608
- return ctx.runMutation(this.component.messages.deleteByOrder, {
609
- threadId: args.threadId,
610
- startOrder: args.startOrder,
611
- startStepOrder: args.startStepOrder,
612
- endOrder: args.endOrder,
613
- endStepOrder: args.endStepOrder,
614
- });
615
- }
616
- /**
617
- * Delete a thread and all its messages and streams asynchronously (in batches)
618
- * This uses a mutation to that processes one page and recursively queues the
619
- * next page for deletion.
620
- * @param ctx The ctx argument to your mutation or action.
621
- * @param args The id of the thread to delete and optionally the page size to use for the delete.
622
- */
623
- async deleteThreadAsync(ctx, args) {
624
- await ctx.runMutation(this.component.threads.deleteAllForThreadIdAsync, {
625
- threadId: args.threadId,
626
- limit: args.pageSize,
627
- });
628
- }
629
- /**
630
- * Delete a thread and all its messages and streams synchronously.
631
- * This uses an action to iterate through all pages. If the action fails
632
- * partway, it will not automatically restart.
633
- * @param ctx The ctx argument to your action.
634
- * @param args The id of the thread to delete and optionally the page size to use for the delete.
635
- */
636
- async deleteThreadSync(ctx, args) {
637
- await ctx.runAction(this.component.threads.deleteAllForThreadIdSync, {
638
- threadId: args.threadId,
639
- limit: args.pageSize,
640
- });
641
- }
642
- /**
643
- * WORKFLOW UTILITIES
644
- */
645
- /**
646
- * Create a mutation that creates a thread so you can call it from a Workflow.
647
- * e.g.
648
- * ```ts
649
- * // in convex/foo.ts
650
- * export const createThread = weatherAgent.createThreadMutation();
651
- *
652
- * const workflow = new WorkflowManager(components.workflow);
653
- * export const myWorkflow = workflow.define({
654
- * args: {},
655
- * handler: async (step) => {
656
- * const { threadId } = await step.runMutation(internal.foo.createThread);
657
- * // use the threadId to generate text, object, etc.
658
- * },
659
- * });
660
- * ```
661
- * @returns A mutation that creates a thread.
662
- */
663
- createThreadMutation() {
664
- return internalMutationGeneric({
665
- args: {
666
- userId: v.optional(v.string()),
667
- title: v.optional(v.string()),
668
- summary: v.optional(v.string()),
669
- },
670
- handler: async (ctx, args) => {
671
- const { threadId } = await this.createThread(ctx, args);
672
- return { threadId };
673
- },
674
- });
675
- }
676
- /**
677
- * Create an action out of this agent so you can call it from workflows or other actions
678
- * without a wrapping function.
679
- * @param spec Configuration for the agent acting as an action, including
680
- * {@link ContextOptions}, {@link StorageOptions}, and {@link stopWhen}.
681
- */
682
- asTextAction(spec, overrides) {
683
- return internalActionGeneric({
684
- args: vTextArgs,
685
- handler: async (ctx_, args) => {
686
- const stream = args.stream === true ? spec?.stream || true : (spec?.stream ?? false);
687
- const { userId, threadId, prompt, messages, maxSteps, ...rest } = args;
688
- const targetArgs = { userId, threadId };
689
- const llmArgs = {
690
- stopWhen: spec?.stopWhen,
691
- ...overrides,
692
- ...omit(rest, ["storageOptions", "contextOptions", "stream"]),
693
- messages: messages?.map(toModelMessage),
694
- prompt: Array.isArray(prompt) ? prompt.map(toModelMessage) : prompt,
695
- toolChoice: args.toolChoice,
696
- };
697
- if (maxSteps) {
698
- llmArgs.stopWhen = stepCountIs(maxSteps);
699
- }
700
- const opts = {
701
- ...pick(spec, ["contextOptions", "storageOptions"]),
702
- ...pick(args, ["contextOptions", "storageOptions"]),
703
- saveStreamDeltas: stream,
704
- };
705
- const ctx = (spec?.customCtx
706
- ? { ...ctx_, ...spec.customCtx(ctx_, targetArgs, llmArgs) }
707
- : ctx_);
708
- if (stream) {
709
- const result = await this.streamText(ctx, targetArgs, llmArgs, opts);
710
- await result.consumeStream();
711
- return {
712
- text: await result.text,
713
- promptMessageId: result.promptMessageId,
714
- order: result.order,
715
- finishReason: await result.finishReason,
716
- warnings: await result.warnings,
717
- savedMessageIds: result.savedMessages?.map((m) => m._id) ?? [],
718
- };
719
- }
720
- else {
721
- const res = await this.generateText(ctx, targetArgs, llmArgs, opts);
722
- return {
723
- text: res.text,
724
- promptMessageId: res.promptMessageId,
725
- order: res.order,
726
- finishReason: res.finishReason,
727
- warnings: res.warnings,
728
- savedMessageIds: res.savedMessages?.map((m) => m._id) ?? [],
729
- };
730
- }
731
- },
732
- });
733
- }
734
- /**
735
- * Create an action that generates an object out of this agent so you can call
736
- * it from workflows or other actions without a wrapping function.
737
- * @param spec Configuration for the agent acting as an action, including
738
- * the normal parameters to {@link generateObject}, plus {@link ContextOptions}
739
- * and stopWhen.
740
- */
741
- asObjectAction(objectArgs, options) {
742
- return internalActionGeneric({
743
- args: vSafeObjectArgs,
744
- handler: async (ctx_, args) => {
745
- const { userId, threadId, callSettings, ...rest } = args;
746
- const overrides = pick(rest, ["contextOptions", "storageOptions"]);
747
- const targetArgs = { userId, threadId };
748
- const llmArgs = {
749
- ...objectArgs,
750
- ...callSettings,
751
- ...omit(rest, ["storageOptions", "contextOptions"]),
752
- messages: args.messages?.map(toModelMessage),
753
- prompt: Array.isArray(args.prompt)
754
- ? args.prompt.map(toModelMessage)
755
- : args.prompt,
756
- };
757
- const ctx = (options?.customCtx
758
- ? { ...ctx_, ...options.customCtx(ctx_, targetArgs, llmArgs) }
759
- : ctx_);
760
- const value = await this.generateObject(ctx, targetArgs, llmArgs, {
761
- ...this.options,
762
- ...options,
763
- ...overrides,
764
- });
765
- return {
766
- object: convexToJson(value.object),
767
- promptMessageId: value.promptMessageId,
768
- order: value.order,
769
- finishReason: value.finishReason,
770
- warnings: value.warnings,
771
- savedMessageIds: value.savedMessages?.map((m) => m._id) ?? [],
772
- };
773
- },
774
- });
775
- }
776
- /**
777
- * @deprecated Use {@link saveMessages} directly instead.
778
- */
779
- asSaveMessagesMutation() {
780
- return internalMutationGeneric({
781
- args: {
782
- threadId: v.string(),
783
- userId: v.optional(v.string()),
784
- promptMessageId: v.optional(v.string()),
785
- messages: v.array(vMessageWithMetadata),
786
- failPendingSteps: v.optional(v.boolean()),
787
- embeddings: v.optional(vMessageEmbeddings),
788
- },
789
- handler: async (ctx, args) => {
790
- const { messages } = await this.saveMessages(ctx, {
791
- ...args,
792
- messages: args.messages.map((m) => toModelMessage(m.message)),
793
- metadata: args.messages.map(({ message: _, ...m }) => m),
794
- skipEmbeddings: true,
795
- });
796
- return {
797
- lastMessageId: messages.at(-1)._id,
798
- messages: messages.map((m) => pick(m, ["_id", "order", "stepOrder"])),
799
- };
800
- },
801
- });
802
- }
803
- }
804
- //# sourceMappingURL=index.js.map