@convex-dev/agent 0.0.1-alpha.2 → 0.0.1-alpha.4
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 +91 -95
- package/dist/commonjs/client/index.d.ts +60 -60
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +80 -77
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/client/types.d.ts +1 -1
- package/dist/commonjs/client/types.d.ts.map +1 -1
- package/dist/commonjs/component/messages.d.ts +56 -56
- package/dist/commonjs/component/messages.d.ts.map +1 -1
- package/dist/commonjs/component/messages.js +128 -134
- package/dist/commonjs/component/messages.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +256 -256
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +18 -18
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/vector/index.d.ts +4 -4
- package/dist/commonjs/component/vector/index.d.ts.map +1 -1
- package/dist/commonjs/component/vector/index.js +12 -10
- package/dist/commonjs/component/vector/index.js.map +1 -1
- package/dist/commonjs/component/vector/tables.d.ts +3 -3
- package/dist/commonjs/component/vector/tables.js +6 -6
- package/dist/commonjs/component/vector/tables.js.map +1 -1
- package/dist/commonjs/validators.d.ts +5 -5
- package/dist/commonjs/validators.d.ts.map +1 -1
- package/dist/commonjs/validators.js +3 -3
- package/dist/commonjs/validators.js.map +1 -1
- package/dist/esm/client/index.d.ts +60 -60
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +80 -77
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +1 -1
- package/dist/esm/client/types.d.ts.map +1 -1
- package/dist/esm/component/messages.d.ts +56 -56
- package/dist/esm/component/messages.d.ts.map +1 -1
- package/dist/esm/component/messages.js +128 -134
- package/dist/esm/component/messages.js.map +1 -1
- package/dist/esm/component/schema.d.ts +256 -256
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +18 -18
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/vector/index.d.ts +4 -4
- package/dist/esm/component/vector/index.d.ts.map +1 -1
- package/dist/esm/component/vector/index.js +12 -10
- package/dist/esm/component/vector/index.js.map +1 -1
- package/dist/esm/component/vector/tables.d.ts +3 -3
- package/dist/esm/component/vector/tables.js +6 -6
- package/dist/esm/component/vector/tables.js.map +1 -1
- package/dist/esm/validators.d.ts +5 -5
- package/dist/esm/validators.d.ts.map +1 -1
- package/dist/esm/validators.js +3 -3
- package/dist/esm/validators.js.map +1 -1
- package/package.json +2 -2
- package/src/client/index.ts +133 -127
- package/src/client/types.ts +1 -1
- package/src/component/_generated/api.d.ts +53 -53
- package/src/component/messages.ts +139 -145
- package/src/component/schema.ts +18 -18
- package/src/component/vector/index.ts +13 -11
- package/src/component/vector/tables.ts +6 -6
- package/src/validators.ts +6 -3
package/src/client/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { generateObject, generateText, streamObject, streamText } from "ai";
|
|
|
16
16
|
import { api } from "../component/_generated/api";
|
|
17
17
|
import {
|
|
18
18
|
SearchOptions,
|
|
19
|
-
|
|
19
|
+
vThreadArgs,
|
|
20
20
|
vContextOptions,
|
|
21
21
|
vObjectArgs,
|
|
22
22
|
vStorageOptions,
|
|
@@ -69,16 +69,16 @@ export type ContextOptions = {
|
|
|
69
69
|
messageRange?: { before: number; after: number };
|
|
70
70
|
};
|
|
71
71
|
/**
|
|
72
|
-
* Whether to search across other
|
|
73
|
-
* By default, only the current
|
|
72
|
+
* Whether to search across other threads for relevant messages.
|
|
73
|
+
* By default, only the current thread is searched.
|
|
74
74
|
*/
|
|
75
|
-
|
|
75
|
+
searchOtherThreads?: boolean;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export type StorageOptions = {
|
|
79
79
|
// Defaults to false, allowing you to pass in arbitrary context that will
|
|
80
80
|
// be in addition to automatically fetched content.
|
|
81
|
-
// Pass true to have all input messages saved to the
|
|
81
|
+
// Pass true to have all input messages saved to the thread history.
|
|
82
82
|
saveAllInputMessages?: boolean;
|
|
83
83
|
// Defaults to true
|
|
84
84
|
saveOutputMessages?: boolean;
|
|
@@ -93,7 +93,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
93
93
|
public component: UseApi<typeof api>,
|
|
94
94
|
public options: {
|
|
95
95
|
name?: string;
|
|
96
|
-
|
|
96
|
+
thread: LanguageModelV1;
|
|
97
97
|
textEmbedding?: EmbeddingModelV1<string>;
|
|
98
98
|
instructions?: string;
|
|
99
99
|
tools?: AgentTools;
|
|
@@ -105,118 +105,124 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
105
105
|
) {}
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
* Start a new
|
|
109
|
-
* you pass in a userId you can have it search across other
|
|
108
|
+
* Start a new thread with the agent. This will have a fresh history, though if
|
|
109
|
+
* you pass in a userId you can have it search across other threads for relevant
|
|
110
110
|
* messages as context for the LLM calls.
|
|
111
|
-
* @param ctx The context of the Convex function. From an action, you can
|
|
112
|
-
* with the agent. From a mutation, you can start a
|
|
113
|
-
* to pass to
|
|
114
|
-
* @param args The
|
|
115
|
-
* @returns The
|
|
111
|
+
* @param ctx The context of the Convex function. From an action, you can thread
|
|
112
|
+
* with the agent. From a mutation, you can start a thread and save the threadId
|
|
113
|
+
* to pass to continueThread later.
|
|
114
|
+
* @param args The thread metadata.
|
|
115
|
+
* @returns The threadId of the new thread and the thread object.
|
|
116
116
|
*/
|
|
117
|
-
async
|
|
117
|
+
async createThread(
|
|
118
118
|
ctx: RunActionCtx,
|
|
119
119
|
args: {
|
|
120
120
|
/**
|
|
121
|
-
* The userId to associate with the
|
|
121
|
+
* The userId to associate with the thread. If not provided, the thread will be
|
|
122
122
|
* anonymous.
|
|
123
123
|
*/
|
|
124
124
|
userId?: string;
|
|
125
125
|
/**
|
|
126
|
-
* The parent
|
|
127
|
-
* If the
|
|
128
|
-
* you can pass in the
|
|
126
|
+
* The parent threadIds to merge with.
|
|
127
|
+
* If the thread is a continuation of one or many previous threads,
|
|
128
|
+
* you can pass in the threadIds of the parent threads to merge the histories.
|
|
129
129
|
*/
|
|
130
|
-
|
|
130
|
+
parentThreadIds?: string[];
|
|
131
131
|
/**
|
|
132
|
-
* The title of the
|
|
132
|
+
* The title of the thread. Not currently used.
|
|
133
133
|
*/
|
|
134
134
|
title?: string;
|
|
135
135
|
/**
|
|
136
|
-
* The summary of the
|
|
136
|
+
* The summary of the thread. Not currently used.
|
|
137
137
|
*/
|
|
138
138
|
summary?: string;
|
|
139
139
|
}
|
|
140
140
|
): Promise<{
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
threadId: string;
|
|
142
|
+
thread: Thread<AgentTools>;
|
|
143
143
|
}>;
|
|
144
144
|
/**
|
|
145
|
-
* Start a new
|
|
146
|
-
* you pass in a userId you can have it search across other
|
|
145
|
+
* Start a new thread with the agent. This will have a fresh history, though if
|
|
146
|
+
* you pass in a userId you can have it search across other threads for relevant
|
|
147
147
|
* messages as context for the LLM calls.
|
|
148
148
|
* @param ctx The context of the Convex function. From a mutation, you can
|
|
149
|
-
* start a
|
|
150
|
-
* @param args The
|
|
151
|
-
* @returns The
|
|
149
|
+
* start a thread and save the threadId to pass to continueThread later.
|
|
150
|
+
* @param args The thread metadata.
|
|
151
|
+
* @returns The threadId of the new thread.
|
|
152
152
|
*/
|
|
153
|
-
async
|
|
153
|
+
async createThread(
|
|
154
154
|
ctx: RunMutationCtx,
|
|
155
155
|
args: {
|
|
156
156
|
userId?: string;
|
|
157
|
-
|
|
157
|
+
parentThreadIds?: string[];
|
|
158
158
|
title?: string;
|
|
159
159
|
summary?: string;
|
|
160
160
|
}
|
|
161
161
|
): Promise<{
|
|
162
|
-
|
|
162
|
+
threadId: string;
|
|
163
163
|
}>;
|
|
164
|
-
async
|
|
164
|
+
async createThread(
|
|
165
165
|
ctx: RunActionCtx | RunMutationCtx,
|
|
166
166
|
args: {
|
|
167
167
|
userId: string;
|
|
168
|
-
|
|
168
|
+
parentThreadIds?: string[];
|
|
169
169
|
title?: string;
|
|
170
170
|
summary?: string;
|
|
171
171
|
}
|
|
172
172
|
): Promise<{
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
threadId: string;
|
|
174
|
+
thread?: Thread<AgentTools>;
|
|
175
175
|
}> {
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
const threadDoc = await ctx.runMutation(
|
|
177
|
+
this.component.messages.createThread,
|
|
178
|
+
{
|
|
179
|
+
defaultSystemPrompt: this.options.instructions,
|
|
180
|
+
userId: args.userId,
|
|
181
|
+
title: args.title,
|
|
182
|
+
summary: args.summary,
|
|
183
|
+
parentThreadIds: args.parentThreadIds,
|
|
184
|
+
}
|
|
185
|
+
);
|
|
183
186
|
if (!("runAction" in ctx)) {
|
|
184
|
-
return {
|
|
187
|
+
return { threadId: threadDoc._id };
|
|
185
188
|
}
|
|
186
|
-
const {
|
|
187
|
-
|
|
189
|
+
const { thread } = await this.continueThread(ctx, {
|
|
190
|
+
threadId: threadDoc._id,
|
|
188
191
|
userId: args.userId,
|
|
189
192
|
});
|
|
190
193
|
return {
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
threadId: threadDoc._id,
|
|
195
|
+
thread,
|
|
193
196
|
};
|
|
194
197
|
}
|
|
195
198
|
|
|
196
|
-
async
|
|
199
|
+
async continueThread(
|
|
197
200
|
ctx: RunActionCtx,
|
|
198
201
|
{
|
|
199
|
-
|
|
202
|
+
threadId,
|
|
200
203
|
userId,
|
|
201
204
|
}: {
|
|
202
|
-
|
|
205
|
+
threadId: string;
|
|
203
206
|
/**
|
|
204
|
-
* If supplied, the userId can be used to search across other
|
|
207
|
+
* If supplied, the userId can be used to search across other threads for
|
|
205
208
|
* relevant messages from the same user as context for the LLM calls.
|
|
206
209
|
*/
|
|
207
210
|
userId?: string;
|
|
208
211
|
}
|
|
209
212
|
): Promise<{
|
|
210
|
-
|
|
213
|
+
thread: Thread<AgentTools>;
|
|
211
214
|
}> {
|
|
212
|
-
// return this.component.
|
|
215
|
+
// return this.component.continueThread(ctx, args);
|
|
213
216
|
return {
|
|
214
|
-
|
|
215
|
-
generateText: this.generateText.bind(this, ctx, { userId,
|
|
216
|
-
streamText: this.streamText.bind(this, ctx, { userId,
|
|
217
|
-
generateObject: this.generateObject.bind(this, ctx, {
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
thread: {
|
|
218
|
+
generateText: this.generateText.bind(this, ctx, { userId, threadId }),
|
|
219
|
+
streamText: this.streamText.bind(this, ctx, { userId, threadId }),
|
|
220
|
+
generateObject: this.generateObject.bind(this, ctx, {
|
|
221
|
+
userId,
|
|
222
|
+
threadId,
|
|
223
|
+
}),
|
|
224
|
+
streamObject: this.streamObject.bind(this, ctx, { userId, threadId }),
|
|
225
|
+
} as Thread<AgentTools>,
|
|
220
226
|
};
|
|
221
227
|
}
|
|
222
228
|
|
|
@@ -224,13 +230,13 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
224
230
|
ctx: RunQueryCtx | RunActionCtx,
|
|
225
231
|
args: {
|
|
226
232
|
userId?: string;
|
|
227
|
-
|
|
233
|
+
threadId?: string;
|
|
228
234
|
messages: CoreMessage[];
|
|
229
235
|
parentMessageId?: string;
|
|
230
236
|
} & ContextOptions
|
|
231
237
|
): Promise<CoreMessage[]> {
|
|
232
|
-
assert(args.userId || args.
|
|
233
|
-
// Fetch the latest messages from the
|
|
238
|
+
assert(args.userId || args.threadId, "Specify userId or threadId");
|
|
239
|
+
// Fetch the latest messages from the thread
|
|
234
240
|
const contextMessages: CoreMessage[] = [];
|
|
235
241
|
const opts = this.mergedContextOptions(args);
|
|
236
242
|
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
@@ -240,8 +246,8 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
240
246
|
const searchMessages = await ctx.runAction(
|
|
241
247
|
this.component.messages.searchMessages,
|
|
242
248
|
{
|
|
243
|
-
userId: args.
|
|
244
|
-
|
|
249
|
+
userId: args.searchOtherThreads ? args.userId : undefined,
|
|
250
|
+
threadId: args.threadId,
|
|
245
251
|
parentMessageId: args.parentMessageId,
|
|
246
252
|
...(await this.searchOptionsWithDefaults(opts, args.messages)),
|
|
247
253
|
}
|
|
@@ -249,11 +255,11 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
249
255
|
// TODO: track what messages we used for context
|
|
250
256
|
contextMessages.push(...searchMessages.map((m) => m.message!));
|
|
251
257
|
}
|
|
252
|
-
if (args.
|
|
258
|
+
if (args.threadId) {
|
|
253
259
|
const { messages } = await ctx.runQuery(
|
|
254
|
-
this.component.messages.
|
|
260
|
+
this.component.messages.getThreadMessages,
|
|
255
261
|
{
|
|
256
|
-
|
|
262
|
+
threadId: args.threadId,
|
|
257
263
|
isTool: args.includeToolCalls ?? false,
|
|
258
264
|
limit: args.recentMessages,
|
|
259
265
|
parentMessageId: args.parentMessageId,
|
|
@@ -269,7 +275,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
269
275
|
async saveMessages(
|
|
270
276
|
ctx: RunMutationCtx,
|
|
271
277
|
args: {
|
|
272
|
-
|
|
278
|
+
threadId?: string;
|
|
273
279
|
userId?: string;
|
|
274
280
|
messages: CoreMessageMaybeWithId[];
|
|
275
281
|
pending?: boolean;
|
|
@@ -281,10 +287,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
281
287
|
messageIds: string[];
|
|
282
288
|
}> {
|
|
283
289
|
const result = await ctx.runMutation(this.component.messages.addMessages, {
|
|
284
|
-
|
|
290
|
+
threadId: args.threadId,
|
|
285
291
|
userId: args.userId,
|
|
286
292
|
agentName: this.options.name,
|
|
287
|
-
model: this.options.
|
|
293
|
+
model: this.options.thread.modelId,
|
|
288
294
|
messages: args.messages.map(serializeMessageWithId),
|
|
289
295
|
failPendingSteps: args.failPendingSteps ?? true,
|
|
290
296
|
pending: args.pending ?? false,
|
|
@@ -298,12 +304,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
298
304
|
|
|
299
305
|
async saveStep<TOOLS extends ToolSet>(
|
|
300
306
|
ctx: RunMutationCtx,
|
|
301
|
-
args: {
|
|
307
|
+
args: { threadId: string; messageId: string; step: StepResult<TOOLS> }
|
|
302
308
|
): Promise<void> {
|
|
303
309
|
const step = serializeStep(args.step as StepResult<ToolSet>);
|
|
304
310
|
const messages = serializeNewMessagesInStep(args.step);
|
|
305
311
|
await ctx.runMutation(this.component.messages.addSteps, {
|
|
306
|
-
|
|
312
|
+
threadId: args.threadId,
|
|
307
313
|
messageId: args.messageId,
|
|
308
314
|
steps: [{ step, messages: messages }],
|
|
309
315
|
failPendingSteps: false,
|
|
@@ -314,7 +320,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
314
320
|
async completeMessage<TOOLS extends ToolSet>(
|
|
315
321
|
ctx: RunMutationCtx,
|
|
316
322
|
args: {
|
|
317
|
-
|
|
323
|
+
threadId: string;
|
|
318
324
|
messageId: string;
|
|
319
325
|
result:
|
|
320
326
|
| { kind: "error"; error: string }
|
|
@@ -328,7 +334,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
328
334
|
});
|
|
329
335
|
} else {
|
|
330
336
|
await ctx.runMutation(this.component.messages.addSteps, {
|
|
331
|
-
|
|
337
|
+
threadId: args.threadId,
|
|
332
338
|
messageId: args.messageId,
|
|
333
339
|
steps: [],
|
|
334
340
|
failPendingSteps: true,
|
|
@@ -338,9 +344,9 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
338
344
|
|
|
339
345
|
/**
|
|
340
346
|
* This behaves like {@link generateText} except that it add context based on
|
|
341
|
-
* the userId and
|
|
342
|
-
*
|
|
343
|
-
* however. To do that, use {@link
|
|
347
|
+
* the userId and threadId. It saves the input and resulting messages to the
|
|
348
|
+
* thread, if specified.
|
|
349
|
+
* however. To do that, use {@link continueThread} or {@link saveMessages}.
|
|
344
350
|
* @param ctx The context of the agent.
|
|
345
351
|
* @param args The arguments to the generateText function.
|
|
346
352
|
* @returns The result of the generateText function.
|
|
@@ -353,10 +359,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
353
359
|
ctx: RunActionCtx,
|
|
354
360
|
{
|
|
355
361
|
userId,
|
|
356
|
-
|
|
362
|
+
threadId,
|
|
357
363
|
}: {
|
|
358
364
|
userId?: string;
|
|
359
|
-
|
|
365
|
+
threadId?: string;
|
|
360
366
|
},
|
|
361
367
|
args: TextArgs<
|
|
362
368
|
AgentTools,
|
|
@@ -371,21 +377,21 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
371
377
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
372
378
|
...args,
|
|
373
379
|
userId,
|
|
374
|
-
|
|
380
|
+
threadId,
|
|
375
381
|
messages,
|
|
376
382
|
});
|
|
377
383
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
378
|
-
|
|
384
|
+
threadId,
|
|
379
385
|
userId,
|
|
380
386
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
381
387
|
pending: true,
|
|
382
388
|
parentMessageId: args.parentMessageId,
|
|
383
389
|
});
|
|
384
|
-
const toolCtx = { ...ctx, userId,
|
|
390
|
+
const toolCtx = { ...ctx, userId, threadId, messageId };
|
|
385
391
|
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
386
392
|
try {
|
|
387
393
|
const result = await generateText({
|
|
388
|
-
model: this.options.
|
|
394
|
+
model: this.options.thread,
|
|
389
395
|
messages: [...contextMessages, ...messages],
|
|
390
396
|
system: this.options.instructions,
|
|
391
397
|
maxSteps: this.options.maxSteps,
|
|
@@ -394,10 +400,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
394
400
|
...rest,
|
|
395
401
|
tools,
|
|
396
402
|
onStepFinish: async (step) => {
|
|
397
|
-
if (
|
|
403
|
+
if (threadId && messageId && args.saveOutputMessages) {
|
|
398
404
|
console.log("onStepFinish", step);
|
|
399
405
|
await this.saveStep(ctx, {
|
|
400
|
-
|
|
406
|
+
threadId,
|
|
401
407
|
messageId,
|
|
402
408
|
step,
|
|
403
409
|
});
|
|
@@ -407,7 +413,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
407
413
|
});
|
|
408
414
|
return { ...result, messageId };
|
|
409
415
|
} catch (error) {
|
|
410
|
-
if (
|
|
416
|
+
if (threadId && messageId) {
|
|
411
417
|
console.error("RollbackMessage", messageId);
|
|
412
418
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
413
419
|
messageId,
|
|
@@ -424,7 +430,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
424
430
|
PARTIAL_OUTPUT = never,
|
|
425
431
|
>(
|
|
426
432
|
ctx: RunActionCtx,
|
|
427
|
-
{ userId,
|
|
433
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
428
434
|
args: TextArgs<
|
|
429
435
|
AgentTools,
|
|
430
436
|
TOOLS,
|
|
@@ -438,19 +444,19 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
438
444
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
439
445
|
...args,
|
|
440
446
|
userId,
|
|
441
|
-
|
|
447
|
+
threadId,
|
|
442
448
|
messages,
|
|
443
449
|
});
|
|
444
450
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
445
|
-
|
|
451
|
+
threadId,
|
|
446
452
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
447
453
|
pending: true,
|
|
448
454
|
parentMessageId: args.parentMessageId,
|
|
449
455
|
});
|
|
450
|
-
const toolCtx = { ...ctx, userId,
|
|
456
|
+
const toolCtx = { ...ctx, userId, threadId, messageId };
|
|
451
457
|
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
452
458
|
const result = streamText({
|
|
453
|
-
model: this.options.
|
|
459
|
+
model: this.options.thread,
|
|
454
460
|
messages: [...contextMessages, ...messages],
|
|
455
461
|
system: this.options.instructions,
|
|
456
462
|
maxSteps: this.options.maxSteps,
|
|
@@ -464,7 +470,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
464
470
|
},
|
|
465
471
|
onError: async (error) => {
|
|
466
472
|
console.error("onError", error);
|
|
467
|
-
if (
|
|
473
|
+
if (threadId && messageId) {
|
|
468
474
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
469
475
|
messageId,
|
|
470
476
|
error: (error.error as Error).message,
|
|
@@ -480,9 +486,9 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
480
486
|
},
|
|
481
487
|
onStepFinish: async (step) => {
|
|
482
488
|
console.log("onStepFinish", step);
|
|
483
|
-
if (
|
|
489
|
+
if (threadId && messageId) {
|
|
484
490
|
await this.saveStep(ctx, {
|
|
485
|
-
|
|
491
|
+
threadId,
|
|
486
492
|
messageId,
|
|
487
493
|
step,
|
|
488
494
|
});
|
|
@@ -496,7 +502,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
496
502
|
// TODO: add the crazy number of overloads to get types through
|
|
497
503
|
async generateObject<T>(
|
|
498
504
|
ctx: RunActionCtx,
|
|
499
|
-
{ userId,
|
|
505
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
500
506
|
args: Omit<Parameters<typeof generateObject>[0], "model"> & {
|
|
501
507
|
model?: LanguageModelV1;
|
|
502
508
|
} & { parentMessageId?: string } & ContextOptions &
|
|
@@ -507,16 +513,16 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
507
513
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
508
514
|
...args,
|
|
509
515
|
userId,
|
|
510
|
-
|
|
516
|
+
threadId,
|
|
511
517
|
messages,
|
|
512
518
|
});
|
|
513
519
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
514
|
-
|
|
520
|
+
threadId,
|
|
515
521
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
516
522
|
pending: true,
|
|
517
523
|
});
|
|
518
524
|
const result = (await generateObject({
|
|
519
|
-
model: this.options.
|
|
525
|
+
model: this.options.thread,
|
|
520
526
|
messages: [...contextMessages, ...messages],
|
|
521
527
|
...rest,
|
|
522
528
|
})) as GenerateObjectResult<T>;
|
|
@@ -525,7 +531,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
525
531
|
|
|
526
532
|
async streamObject<T>(
|
|
527
533
|
ctx: RunMutationCtx,
|
|
528
|
-
{ userId,
|
|
534
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
529
535
|
args: Omit<Parameters<typeof streamObject<T>>[0], "model"> & {
|
|
530
536
|
model?: LanguageModelV1;
|
|
531
537
|
} & { parentMessageId?: string } & ContextOptions &
|
|
@@ -538,16 +544,16 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
538
544
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
539
545
|
...args,
|
|
540
546
|
userId,
|
|
541
|
-
|
|
547
|
+
threadId,
|
|
542
548
|
messages,
|
|
543
549
|
});
|
|
544
550
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
545
|
-
|
|
551
|
+
threadId,
|
|
546
552
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
547
553
|
pending: true,
|
|
548
554
|
});
|
|
549
555
|
const result = streamObject<T>({
|
|
550
|
-
model: this.options.
|
|
556
|
+
model: this.options.thread,
|
|
551
557
|
messages: [...contextMessages, ...messages],
|
|
552
558
|
...rest,
|
|
553
559
|
onError: async (error) => {
|
|
@@ -616,27 +622,27 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
616
622
|
return internalActionGeneric({
|
|
617
623
|
args: {
|
|
618
624
|
userId: v.optional(v.string()),
|
|
619
|
-
|
|
625
|
+
threadId: v.optional(v.string()),
|
|
620
626
|
contextOptions: v.optional(vContextOptions),
|
|
621
627
|
storageOptions: v.optional(vStorageOptions),
|
|
622
628
|
maxRetries: v.optional(v.number()),
|
|
623
629
|
|
|
624
|
-
|
|
630
|
+
createThread: v.optional(
|
|
625
631
|
v.object({
|
|
626
|
-
userId: v.string(),
|
|
627
|
-
|
|
632
|
+
userId: v.optional(v.string()),
|
|
633
|
+
parentThreadIds: v.optional(v.array(v.string())),
|
|
628
634
|
title: v.optional(v.string()),
|
|
629
635
|
summary: v.optional(v.string()),
|
|
630
636
|
})
|
|
631
637
|
),
|
|
632
|
-
|
|
638
|
+
continueThread: v.optional(
|
|
633
639
|
v.object({
|
|
634
|
-
|
|
640
|
+
threadId: v.string(),
|
|
635
641
|
userId: v.optional(v.string()),
|
|
636
642
|
})
|
|
637
643
|
),
|
|
638
|
-
generateText: v.optional(
|
|
639
|
-
streamText: v.optional(
|
|
644
|
+
generateText: v.optional(vThreadArgs),
|
|
645
|
+
streamText: v.optional(vThreadArgs),
|
|
640
646
|
generateObject: v.optional(vObjectArgs),
|
|
641
647
|
streamObject: v.optional(
|
|
642
648
|
v.object({ ...vObjectArgs.fields, schema: v.any() })
|
|
@@ -650,21 +656,21 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
650
656
|
const maxRetries = args.maxRetries;
|
|
651
657
|
const commonArgs = {
|
|
652
658
|
userId: args.userId,
|
|
653
|
-
|
|
659
|
+
threadId: args.threadId,
|
|
654
660
|
...contextOptions,
|
|
655
661
|
...args.storageOptions,
|
|
656
662
|
};
|
|
657
|
-
if (args.
|
|
658
|
-
return this.
|
|
659
|
-
userId: args.
|
|
660
|
-
|
|
661
|
-
title: args.
|
|
662
|
-
summary: args.
|
|
663
|
+
if (args.createThread) {
|
|
664
|
+
return this.createThread(ctx, {
|
|
665
|
+
userId: args.createThread.userId,
|
|
666
|
+
parentThreadIds: args.createThread.parentThreadIds,
|
|
667
|
+
title: args.createThread.title,
|
|
668
|
+
summary: args.createThread.summary,
|
|
663
669
|
});
|
|
664
|
-
} else if (args.
|
|
665
|
-
return this.
|
|
666
|
-
|
|
667
|
-
userId: args.
|
|
670
|
+
} else if (args.continueThread) {
|
|
671
|
+
return this.continueThread(ctx, {
|
|
672
|
+
threadId: args.continueThread.threadId,
|
|
673
|
+
userId: args.continueThread.userId,
|
|
668
674
|
});
|
|
669
675
|
} else if (args.generateText) {
|
|
670
676
|
return this.generateText(ctx, commonArgs, {
|
|
@@ -715,7 +721,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
715
721
|
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
|
|
716
722
|
const value = await this.generateText(
|
|
717
723
|
ctx,
|
|
718
|
-
{ userId: ctx.userId,
|
|
724
|
+
{ userId: ctx.userId, threadId: ctx.threadId },
|
|
719
725
|
{
|
|
720
726
|
prompt: JSON.stringify(args),
|
|
721
727
|
parentMessageId: ctx.messageId,
|
|
@@ -731,15 +737,15 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
731
737
|
|
|
732
738
|
export type ToolCtx = RunActionCtx & {
|
|
733
739
|
userId?: string;
|
|
734
|
-
|
|
740
|
+
threadId?: string;
|
|
735
741
|
messageId?: string;
|
|
736
742
|
};
|
|
737
743
|
|
|
738
744
|
/**
|
|
739
745
|
* This is a wrapper around the ai.tool function that adds support for
|
|
740
|
-
* userId and
|
|
746
|
+
* userId and threadId to the tool, if they're called within a thread from an agent.
|
|
741
747
|
* @param tool The AI tool. See https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling
|
|
742
|
-
* @returns The same tool, but with userId and
|
|
748
|
+
* @returns The same tool, but with userId and threadId args support added.
|
|
743
749
|
*/
|
|
744
750
|
export function createTool<
|
|
745
751
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -765,7 +771,7 @@ export function createTool<
|
|
|
765
771
|
throw new Error(
|
|
766
772
|
"To use a Convex tool, you must either provide the ctx" +
|
|
767
773
|
" at definition time (dynamically in an action), or use the Agent to" +
|
|
768
|
-
" call it (which injects the ctx, userId and
|
|
774
|
+
" call it (which injects the ctx, userId and threadId)"
|
|
769
775
|
);
|
|
770
776
|
}
|
|
771
777
|
return convexTool.handler(this.ctx, args, options);
|
|
@@ -822,7 +828,7 @@ type ObjectArgs<
|
|
|
822
828
|
} & ContextOptions &
|
|
823
829
|
StorageOptions;
|
|
824
830
|
|
|
825
|
-
interface
|
|
831
|
+
interface Thread<AgentTools extends ToolSet> {
|
|
826
832
|
generateText<TOOLS extends ToolSet, OUTPUT = never, OUTPUT_PARTIAL = never>(
|
|
827
833
|
args: TextArgs<
|
|
828
834
|
AgentTools,
|
package/src/client/types.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { GenericId } from "convex/values";
|
|
10
10
|
import type { Doc } from "../component/_generated/dataModel";
|
|
11
11
|
|
|
12
|
-
export type
|
|
12
|
+
export type ThreadDoc = OpaqueIds<Doc<"threads">>;
|
|
13
13
|
export type MessageDoc = OpaqueIds<Doc<"messages">>;
|
|
14
14
|
|
|
15
15
|
/* Type utils follow */
|