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