@convex-dev/agent 0.0.1-alpha.1 → 0.0.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +293 -6
  2. package/dist/commonjs/client/index.d.ts +520 -96
  3. package/dist/commonjs/client/index.d.ts.map +1 -1
  4. package/dist/commonjs/client/index.js +210 -131
  5. package/dist/commonjs/client/index.js.map +1 -1
  6. package/dist/commonjs/client/types.d.ts +3 -0
  7. package/dist/commonjs/client/types.d.ts.map +1 -1
  8. package/dist/commonjs/component/messages.d.ts +57 -56
  9. package/dist/commonjs/component/messages.d.ts.map +1 -1
  10. package/dist/commonjs/component/messages.js +184 -147
  11. package/dist/commonjs/component/messages.js.map +1 -1
  12. package/dist/commonjs/component/schema.d.ts +260 -256
  13. package/dist/commonjs/component/schema.d.ts.map +1 -1
  14. package/dist/commonjs/component/schema.js +25 -18
  15. package/dist/commonjs/component/schema.js.map +1 -1
  16. package/dist/commonjs/component/vector/index.d.ts +4 -4
  17. package/dist/commonjs/component/vector/index.d.ts.map +1 -1
  18. package/dist/commonjs/component/vector/index.js +12 -10
  19. package/dist/commonjs/component/vector/index.js.map +1 -1
  20. package/dist/commonjs/component/vector/tables.d.ts +3 -3
  21. package/dist/commonjs/component/vector/tables.js +6 -6
  22. package/dist/commonjs/component/vector/tables.js.map +1 -1
  23. package/dist/commonjs/mapping.d.ts +6 -1
  24. package/dist/commonjs/mapping.d.ts.map +1 -1
  25. package/dist/commonjs/mapping.js +25 -0
  26. package/dist/commonjs/mapping.js.map +1 -1
  27. package/dist/commonjs/validators.d.ts +1376 -1
  28. package/dist/commonjs/validators.d.ts.map +1 -1
  29. package/dist/commonjs/validators.js +28 -1
  30. package/dist/commonjs/validators.js.map +1 -1
  31. package/dist/esm/client/index.d.ts +520 -96
  32. package/dist/esm/client/index.d.ts.map +1 -1
  33. package/dist/esm/client/index.js +210 -131
  34. package/dist/esm/client/index.js.map +1 -1
  35. package/dist/esm/client/types.d.ts +3 -0
  36. package/dist/esm/client/types.d.ts.map +1 -1
  37. package/dist/esm/component/messages.d.ts +57 -56
  38. package/dist/esm/component/messages.d.ts.map +1 -1
  39. package/dist/esm/component/messages.js +184 -147
  40. package/dist/esm/component/messages.js.map +1 -1
  41. package/dist/esm/component/schema.d.ts +260 -256
  42. package/dist/esm/component/schema.d.ts.map +1 -1
  43. package/dist/esm/component/schema.js +25 -18
  44. package/dist/esm/component/schema.js.map +1 -1
  45. package/dist/esm/component/vector/index.d.ts +4 -4
  46. package/dist/esm/component/vector/index.d.ts.map +1 -1
  47. package/dist/esm/component/vector/index.js +12 -10
  48. package/dist/esm/component/vector/index.js.map +1 -1
  49. package/dist/esm/component/vector/tables.d.ts +3 -3
  50. package/dist/esm/component/vector/tables.js +6 -6
  51. package/dist/esm/component/vector/tables.js.map +1 -1
  52. package/dist/esm/mapping.d.ts +6 -1
  53. package/dist/esm/mapping.d.ts.map +1 -1
  54. package/dist/esm/mapping.js +25 -0
  55. package/dist/esm/mapping.js.map +1 -1
  56. package/dist/esm/validators.d.ts +1376 -1
  57. package/dist/esm/validators.d.ts.map +1 -1
  58. package/dist/esm/validators.js +28 -1
  59. package/dist/esm/validators.js.map +1 -1
  60. package/package.json +3 -3
  61. package/src/client/index.ts +384 -276
  62. package/src/client/types.ts +4 -0
  63. package/src/component/_generated/api.d.ts +54 -53
  64. package/src/component/messages.ts +219 -177
  65. package/src/component/schema.ts +25 -18
  66. package/src/component/vector/index.ts +13 -11
  67. package/src/component/vector/tables.ts +6 -6
  68. package/src/mapping.ts +46 -11
  69. package/src/validators.test.ts +9 -0
  70. package/src/validators.ts +36 -1
package/README.md CHANGED
@@ -4,9 +4,76 @@
4
4
 
5
5
  <!-- START: Include on https://convex.dev/components -->
6
6
 
7
- - [ ] What is some compelling syntax as a hook?
8
- - [ ] Why should you use this component?
9
- - [ ] Links to Stack / other resources?
7
+ AI Agent framework built on Convex.
8
+
9
+ - Automatic storage of chat history, per-user or per-thread.
10
+ - RAG for chat context, via hybrid text & vector search, with configuration options.
11
+ Or use the API to query the history yourself and do it your way.
12
+ - Opt-in search for messages from other threads (for the same specifieduser).
13
+ - Tool calls via the AI SDK, along with Convex-specific helpers.
14
+ - Easy workflow integration with the [Workflow component](https://convex.dev/components/workflow).
15
+ - Reactive & realtime updates to asynchronous threads.
16
+ - Support for streaming text and storing the result in the database.
17
+ - Optionally filter tool calls out of the thread history.
18
+
19
+ Example usage:
20
+
21
+ ```ts
22
+ // Define an agent similarly to the AI SDK
23
+ const supportAgent = new Agent(components.agent, {
24
+ thread: openai.chat("gpt-4o-mini"),
25
+ textEmbedding: openai.embedding("text-embedding-3-small"),
26
+ instructions: "You are a helpful assistant.",
27
+ tools: { accountLookup, fileTicket, sendEmail },
28
+ });
29
+
30
+ // Use the agent from within a normal action:
31
+ export const createThread = action({
32
+ args: { prompt: v.string() },
33
+ handler: async (ctx, { prompt }) => {
34
+ const { threadId, thread } = await supportAgent.createThread(ctx, {});
35
+ const result = await thread.generateText({ prompt });
36
+ return { threadId, text: result.text };
37
+ },
38
+ });
39
+
40
+ // Pick up where you left off:
41
+ export const continueThread = action({
42
+ args: { prompt: v.string(), threadId: v.string() },
43
+ handler: async (ctx, { prompt, threadId }) => {
44
+ // This includes previous message history from the thread automatically.
45
+ const { thread } = await supportAgent.continueThread(ctx, { threadId });
46
+ const result = await thread.generateText({ prompt });
47
+ return result.text;
48
+ },
49
+ });
50
+
51
+ // Or use it within a workflow, specific to a user:
52
+ export const supportAgentStep = supportAgent.asAction({ maxSteps: 10 });
53
+
54
+ const workflow = new WorkflowManager(components.workflow);
55
+ const s = internal.example; // where steps are defined
56
+
57
+ export const supportAgentWorkflow = workflow.define({
58
+ args: { prompt: v.string(), userId: v.string(), threadId: v.string() },
59
+ handler: async (step, { prompt, userId, threadId }) => {
60
+ const suggestion = await step.runAction(s.supportAgentStep, {
61
+ threadId, generateText: { prompt },
62
+ });
63
+ const polished = await step.runAction(s.adaptSuggestionForUser, {
64
+ suggestion, userId,
65
+ });
66
+ await step.runMutation(s.sendUserMessage, { userId, message: polished.message });
67
+ },
68
+ });
69
+ ```
70
+
71
+ Also see the [Stack article](https://stack.convex.dev/ai-agent).
72
+
73
+ Coming soon:
74
+
75
+ - Generate and stream objects
76
+ - Nested agent configuration, with agents as tools to other agents.
10
77
 
11
78
  Found a bug? Feature request? [File it here](https://github.com/get-convex/agent/issues).
12
79
 
@@ -41,15 +108,235 @@ export default app;
41
108
 
42
109
  ## Usage
43
110
 
111
+ ### Configuring the agent
112
+
44
113
  ```ts
45
114
  import { components } from "./_generated/api";
46
115
  import { Agent } from "@convex-dev/agent";
47
116
 
48
- const agent = new Agent(components.agent, {
49
- ...options,
117
+ // Define an agent similarly to the AI SDK
118
+ const supportAgent = new Agent(components.agent, {
119
+ // Note: all of these are optional.
120
+ thread: openai.chat("gpt-4o-mini"),
121
+ // Used for vector search (RAG).
122
+ textEmbedding: openai.embedding("text-embedding-3-small"),
123
+ // Will be the default system prompt if not overriden.
124
+ instructions: "You are a helpful assistant.",
125
+ tools: {
126
+ // Standard AI SDK tool
127
+ myTool: tool({ description, parameters, execute: () => {}}),
128
+ // Convex tool
129
+ myConvexTool: createTool({
130
+ description: "My Convex tool",
131
+ args: v.object({...}),
132
+ handler: async (ctx, args) => {
133
+ return "Hello, world!";
134
+ },
135
+ }),
136
+ },
137
+ // Used for fetching context messages.
138
+ contextOptions: {
139
+ // Whether to include tool messages in the context.
140
+ includeToolCalls: true,
141
+ // How many recent messages to include. These are added after the search
142
+ // messages, and do not count against the search limit.
143
+ recentMessages: 10,
144
+ // Whether to search across other threads for relevant messages.
145
+ // By default, only the current thread is searched.
146
+ searchOtherThreads: true,
147
+ // Options for searching messages.
148
+ searchOptions: {
149
+ // The maximum number of messages to fetch.
150
+ limit: 100,
151
+ // Whether to use text search to find messages.
152
+ textSearch: true,
153
+ // Whether to use vector search to find messages.
154
+ vectorSearch: true,
155
+ // Note, this is after the limit is applied.
156
+ // E.g. this will quadruple the number of messages fetched.
157
+ // (two before, and one after each message found in the search)
158
+ messageRange: { before: 2, after: 1 },
159
+ },
160
+ },
161
+ // Used for storing messages.
162
+ storageOptions: {
163
+ // Defaults to false, allowing you to pass in arbitrary context that will
164
+ // be in addition to automatically fetched content.
165
+ // Pass true to have all input messages saved to the thread history.
166
+ saveAllInputMessages: true,
167
+ // Defaults to true
168
+ saveOutputMessages: true,
169
+ },
170
+ // Used for limiting the number of steps when tool calls are involved.
171
+ maxSteps: 10,
172
+ // Used for limiting the number of retries when a tool call fails.
173
+ maxRetries: 3,
174
+ });
175
+ ```
176
+
177
+ ### Starting a thread
178
+
179
+ You can start a thread from either an action or a mutation.
180
+ If it's in an action, you can also start sending messages.
181
+ The threadId allows you to resume later and maintain message history.
182
+ If you specify a userId, the thread will be associated with that user and messages will be saved to the user's history.
183
+ You can also search the user's history for relevant messages in this thread.
184
+
185
+ ```ts
186
+ // Use the agent from within a normal action:
187
+ export const createThread = action({
188
+ args: { prompt: v.string(), userId: v.string() },
189
+ handler: async (ctx, { prompt, userId }): Promise<{ threadId: string; initialResponse: string }> => {
190
+ // Start a new thread for the user.
191
+ const { threadId, thread } = await supportAgent.createThread(ctx, { userId });
192
+ const result = await thread.generateText({ prompt });
193
+ return { threadId, initialResponse: result.text };
194
+ },
195
+ });
196
+ ```
197
+
198
+ ### Continuing a thread
199
+
200
+ If you specify a userId too, you can search the user's history for relevant messages
201
+ to include in the prompt context.
202
+
203
+ ```ts
204
+ // Pick up where you left off:
205
+ export const continueThread = action({
206
+ args: { prompt: v.string(), threadId: v.string() },
207
+ handler: async (ctx, { prompt, threadId }): Promise<string> => {
208
+ // This includes previous message history from the thread automatically.
209
+ const { thread } = await supportAgent.continueThread(ctx, { threadId });
210
+ const result = await thread.generateText({ prompt });
211
+ return result.text;
212
+ },
213
+ });
214
+ ```
215
+
216
+ ### Exposing the agent as a Convex action
217
+
218
+ ```ts
219
+ export const supportAgentStep = supportAgent.asAction({ maxSteps: 10 });
220
+
221
+ // Then from within another action:
222
+ export const callSupportAgent = action({
223
+ args: { prompt: v.string(), userId: v.string(), threadId: v.string() },
224
+ handler: async (ctx, { prompt, userId, threadId }) => {
225
+ const suggestion = await ctx.runAction(s.supportAgentStep, {
226
+ threadId, userId, generateText: { prompt },
227
+ });
228
+ },
229
+ });
230
+ ```
231
+
232
+ ### Using the agent within a workflow
233
+
234
+ You can use the [Workflow component](https://convex.dev/components/workflow)
235
+ to run, with retries and guarantees of eventually completing, surviving server restarts,
236
+ and more. Read more about durable workflows
237
+ [in this Stack post](https://stack.convex.dev/durable-workflows-and-strong-guarantees).
238
+
239
+ ```ts
240
+ const workflow = new WorkflowManager(components.workflow);
241
+ const s = internal.example; // where steps are defined
242
+
243
+ export const supportAgentWorkflow = workflow.define({
244
+ args: { prompt: v.string(), userId: v.string(), threadId: v.string() },
245
+ handler: async (step, { prompt, userId, threadId }) => {
246
+ const suggestion = await step.runAction(s.supportAgentStep, {
247
+ threadId, userId, generateText: { prompt },
248
+ });
249
+ const polished = await step.runAction(s.adaptSuggestionForUser, {
250
+ threadId, userId, generateText: { prompt: suggestion },
251
+ });
252
+ await step.runMutation(s.sendUserMessage, { userId, message: polished.message });
253
+ },
254
+ });
255
+ ```
256
+
257
+ ### Fetching thread history
258
+
259
+ ```ts
260
+ const messages = await ctx.runQuery(
261
+ components.agent.messages.getThreadMessages,
262
+ { threadId }
263
+ );
264
+ ```
265
+
266
+ ### Generating text for a user without an associated thread
267
+
268
+ ```ts
269
+ const result = await supportAgent.generateText(ctx, { userId }, { prompt });
270
+ ```
271
+
272
+ ### Manually managing messages
273
+
274
+ ```ts
275
+ const messages = await ctx.runQuery(
276
+ components.agent.messages.getThreadMessages,
277
+ { threadId, ...searchOptions }
278
+ );
279
+ ```
280
+
281
+ ```ts
282
+ const messages = await agent.saveMessages(ctx, { threadId, userId, messages });
283
+ ```
284
+
285
+ ```ts
286
+ const messages = await agent.saveSteps(ctx, { threadId, userId, step });
287
+ ```
288
+
289
+ // Update the message from pending to complete, along with any associated steps.
290
+ ```ts
291
+ const messages = await agent.completeMessage(ctx, { threadId, userId, messageId });
292
+ ```
293
+
294
+ ### Manage embeddings
295
+
296
+ ```ts
297
+ const messages = await ctx.runQuery(
298
+ components.agent.embeddings.paginate,
299
+ { vectorDimension: 1536, cursor: null, limit: 10 }
300
+ );
301
+ ```
302
+
303
+ ```ts
304
+ const messages = await ctx.runQuery(
305
+ components.agent.embeddings.deleteBatchForThread,
306
+ { vectorDimension: 1536, targetModel: "gpt-4o-mini", threadId: "123", cursor: null, limit: 10 }
307
+ );
308
+ ```
309
+
310
+ ```ts
311
+ const messages = await ctx.runQuery(
312
+ components.agent.embeddings.insertBatch, {
313
+ vectorDimension: 1536,
314
+ vectors: [
315
+ { model: "gpt-4o-mini", kind: "thread", userId: "123", threadId: "123", vector: embedding, },
316
+ ],
317
+ }
318
+ );
319
+ ```
320
+
321
+ ```ts
322
+ const messages = await ctx.runQuery(components.agent.embeddings.updateBatch, {
323
+ vectors: [
324
+ { model: "gpt-4o-mini", vector: embedding, id: msg.embeddingId },
325
+ ],
326
+ });
327
+ ```
328
+
329
+ ```ts
330
+ const messages = await ctx.runQuery(components.agent.embeddings.deleteBatch, {
331
+ ids: [embeddingId1, embeddingId2],
50
332
  });
51
333
  ```
52
334
 
53
- See more example usage in [example.ts](./example/convex/example.ts).
335
+ See example usage in [example.ts](./example/convex/example.ts).
336
+ Read more in [this Stack post](https://stack.convex.dev/ai-agent).
337
+
338
+ ```sh
339
+ npm i @convex-dev/agent
340
+ ```
54
341
 
55
342
  <!-- END: Include on https://convex.dev/components -->