@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/src/client/index.ts
CHANGED
|
@@ -11,26 +11,24 @@ import type {
|
|
|
11
11
|
ToolChoice,
|
|
12
12
|
ToolExecutionOptions,
|
|
13
13
|
ToolSet,
|
|
14
|
-
Message as UIMessage,
|
|
15
14
|
} from "ai";
|
|
16
|
-
import {
|
|
17
|
-
convertToCoreMessages,
|
|
18
|
-
coreMessageSchema,
|
|
19
|
-
generateObject,
|
|
20
|
-
generateText,
|
|
21
|
-
streamObject,
|
|
22
|
-
streamText,
|
|
23
|
-
} from "ai";
|
|
24
|
-
import type { ZodType } from "zod";
|
|
15
|
+
import { generateObject, generateText, streamObject, streamText } from "ai";
|
|
25
16
|
import { api } from "../component/_generated/api";
|
|
26
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
SearchOptions,
|
|
19
|
+
vChatArgs,
|
|
20
|
+
vContextOptions,
|
|
21
|
+
vObjectArgs,
|
|
22
|
+
vStorageOptions,
|
|
23
|
+
} from "../validators";
|
|
27
24
|
import { RunActionCtx, RunMutationCtx, RunQueryCtx, UseApi } from "./types";
|
|
28
25
|
// TODO: is this the only dependency that needs helpers in client?
|
|
29
26
|
import { assert } from "convex-helpers";
|
|
30
|
-
import { convexToZod } from "convex-helpers/server/zod";
|
|
31
|
-
import {
|
|
32
|
-
import { Infer, Validator } from "convex/values";
|
|
27
|
+
import { ConvexToZod, convexToZod } from "convex-helpers/server/zod";
|
|
28
|
+
import { internalActionGeneric } from "convex/server";
|
|
29
|
+
import { Infer, v, Validator } from "convex/values";
|
|
33
30
|
import {
|
|
31
|
+
promptOrMessagesToCoreMessages,
|
|
34
32
|
serializeMessageWithId,
|
|
35
33
|
serializeNewMessagesInStep,
|
|
36
34
|
serializeStep,
|
|
@@ -38,15 +36,42 @@ import {
|
|
|
38
36
|
import { DEFAULT_MESSAGE_RANGE, extractText } from "../shared";
|
|
39
37
|
|
|
40
38
|
export type ContextOptions = {
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Whether to include tool messages in the context.
|
|
41
|
+
*/
|
|
42
|
+
includeToolCalls?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* How many recent messages to include. These are added after the search
|
|
45
|
+
* messages, and do not count against the search limit.
|
|
46
|
+
*/
|
|
43
47
|
recentMessages?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Options for searching messages.
|
|
50
|
+
*/
|
|
44
51
|
searchOptions?: {
|
|
52
|
+
/**
|
|
53
|
+
* The maximum number of messages to fetch.
|
|
54
|
+
*/
|
|
45
55
|
limit: number;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to use text search to find messages.
|
|
58
|
+
*/
|
|
46
59
|
textSearch?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether to use vector search to find messages.
|
|
62
|
+
*/
|
|
47
63
|
vectorSearch?: boolean;
|
|
48
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Note, this is after the limit is applied.
|
|
66
|
+
* By default this will quadruple the number of messages fetched.
|
|
67
|
+
* (two before, and one after each message found in the search)
|
|
68
|
+
*/
|
|
69
|
+
messageRange?: { before: number; after: number };
|
|
49
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Whether to search across other chats for relevant messages.
|
|
73
|
+
* By default, only the current chat is searched.
|
|
74
|
+
*/
|
|
50
75
|
searchOtherChats?: boolean;
|
|
51
76
|
};
|
|
52
77
|
|
|
@@ -70,8 +95,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
70
95
|
name?: string;
|
|
71
96
|
chat: LanguageModelV1;
|
|
72
97
|
textEmbedding?: EmbeddingModelV1<string>;
|
|
73
|
-
|
|
98
|
+
instructions?: string;
|
|
74
99
|
tools?: AgentTools;
|
|
100
|
+
contextOptions?: ContextOptions;
|
|
101
|
+
// TODO: storageOptions?: StorageOptions;
|
|
102
|
+
maxSteps?: number;
|
|
103
|
+
// TODO: maxRetries?: number;
|
|
75
104
|
}
|
|
76
105
|
) {}
|
|
77
106
|
|
|
@@ -85,7 +114,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
85
114
|
* @param args The chat metadata.
|
|
86
115
|
* @returns The chatId of the new chat and the chat object.
|
|
87
116
|
*/
|
|
88
|
-
async
|
|
117
|
+
async createChat(
|
|
89
118
|
ctx: RunActionCtx,
|
|
90
119
|
args: {
|
|
91
120
|
/**
|
|
@@ -121,7 +150,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
121
150
|
* @param args The chat metadata.
|
|
122
151
|
* @returns The chatId of the new chat.
|
|
123
152
|
*/
|
|
124
|
-
async
|
|
153
|
+
async createChat(
|
|
125
154
|
ctx: RunMutationCtx,
|
|
126
155
|
args: {
|
|
127
156
|
userId?: string;
|
|
@@ -132,7 +161,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
132
161
|
): Promise<{
|
|
133
162
|
chatId: string;
|
|
134
163
|
}>;
|
|
135
|
-
async
|
|
164
|
+
async createChat(
|
|
136
165
|
ctx: RunActionCtx | RunMutationCtx,
|
|
137
166
|
args: {
|
|
138
167
|
userId: string;
|
|
@@ -145,7 +174,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
145
174
|
chat?: Chat<AgentTools>;
|
|
146
175
|
}> {
|
|
147
176
|
const chatDoc = await ctx.runMutation(this.component.messages.createChat, {
|
|
148
|
-
defaultSystemPrompt: this.options.
|
|
177
|
+
defaultSystemPrompt: this.options.instructions,
|
|
149
178
|
userId: args.userId,
|
|
150
179
|
title: args.title,
|
|
151
180
|
summary: args.summary,
|
|
@@ -171,6 +200,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
171
200
|
userId,
|
|
172
201
|
}: {
|
|
173
202
|
chatId: string;
|
|
203
|
+
/**
|
|
204
|
+
* If supplied, the userId can be used to search across other chats for
|
|
205
|
+
* relevant messages from the same user as context for the LLM calls.
|
|
206
|
+
*/
|
|
174
207
|
userId?: string;
|
|
175
208
|
}
|
|
176
209
|
): Promise<{
|
|
@@ -193,12 +226,14 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
193
226
|
userId?: string;
|
|
194
227
|
chatId?: string;
|
|
195
228
|
messages: CoreMessage[];
|
|
229
|
+
parentMessageId?: string;
|
|
196
230
|
} & ContextOptions
|
|
197
231
|
): Promise<CoreMessage[]> {
|
|
198
232
|
assert(args.userId || args.chatId, "Specify userId or chatId");
|
|
199
233
|
// Fetch the latest messages from the chat
|
|
200
234
|
const contextMessages: CoreMessage[] = [];
|
|
201
|
-
|
|
235
|
+
const opts = this.mergedContextOptions(args);
|
|
236
|
+
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
202
237
|
if (!("runAction" in ctx)) {
|
|
203
238
|
throw new Error("searchUserMessages only works in an action");
|
|
204
239
|
}
|
|
@@ -208,7 +243,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
208
243
|
userId: args.searchOtherChats ? args.userId : undefined,
|
|
209
244
|
chatId: args.chatId,
|
|
210
245
|
parentMessageId: args.parentMessageId,
|
|
211
|
-
...(await this.searchOptionsWithDefaults(
|
|
246
|
+
...(await this.searchOptionsWithDefaults(opts, args.messages)),
|
|
212
247
|
}
|
|
213
248
|
);
|
|
214
249
|
// TODO: track what messages we used for context
|
|
@@ -219,7 +254,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
219
254
|
this.component.messages.getChatMessages,
|
|
220
255
|
{
|
|
221
256
|
chatId: args.chatId,
|
|
222
|
-
isTool: args.
|
|
257
|
+
isTool: args.includeToolCalls ?? false,
|
|
223
258
|
limit: args.recentMessages,
|
|
224
259
|
parentMessageId: args.parentMessageId,
|
|
225
260
|
order: "desc",
|
|
@@ -234,10 +269,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
234
269
|
async saveMessages(
|
|
235
270
|
ctx: RunMutationCtx,
|
|
236
271
|
args: {
|
|
237
|
-
chatId
|
|
272
|
+
chatId?: string;
|
|
273
|
+
userId?: string;
|
|
238
274
|
messages: CoreMessageMaybeWithId[];
|
|
239
275
|
pending?: boolean;
|
|
240
276
|
parentMessageId?: string;
|
|
277
|
+
failPendingSteps?: boolean;
|
|
241
278
|
}
|
|
242
279
|
): Promise<{
|
|
243
280
|
lastMessageId: string;
|
|
@@ -245,10 +282,11 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
245
282
|
}> {
|
|
246
283
|
const result = await ctx.runMutation(this.component.messages.addMessages, {
|
|
247
284
|
chatId: args.chatId,
|
|
285
|
+
userId: args.userId,
|
|
248
286
|
agentName: this.options.name,
|
|
249
287
|
model: this.options.chat.modelId,
|
|
250
288
|
messages: args.messages.map(serializeMessageWithId),
|
|
251
|
-
failPendingSteps: true,
|
|
289
|
+
failPendingSteps: args.failPendingSteps ?? true,
|
|
252
290
|
pending: args.pending ?? false,
|
|
253
291
|
parentMessageId: args.parentMessageId,
|
|
254
292
|
});
|
|
@@ -318,7 +356,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
318
356
|
chatId,
|
|
319
357
|
}: {
|
|
320
358
|
userId?: string;
|
|
321
|
-
chatId
|
|
359
|
+
chatId?: string;
|
|
322
360
|
},
|
|
323
361
|
args: TextArgs<
|
|
324
362
|
AgentTools,
|
|
@@ -338,23 +376,26 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
338
376
|
});
|
|
339
377
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
340
378
|
chatId,
|
|
379
|
+
userId,
|
|
341
380
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
342
381
|
pending: true,
|
|
343
382
|
parentMessageId: args.parentMessageId,
|
|
344
383
|
});
|
|
345
|
-
const
|
|
346
|
-
const tools = wrapTools(
|
|
384
|
+
const toolCtx = { ...ctx, userId, chatId, messageId };
|
|
385
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
347
386
|
try {
|
|
348
387
|
const result = await generateText({
|
|
349
388
|
model: this.options.chat,
|
|
350
389
|
messages: [...contextMessages, ...messages],
|
|
351
|
-
system: this.options.
|
|
352
|
-
|
|
390
|
+
system: this.options.instructions,
|
|
391
|
+
maxSteps: this.options.maxSteps,
|
|
353
392
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
354
393
|
toolChoice: args.toolChoice as any,
|
|
355
394
|
...rest,
|
|
395
|
+
tools,
|
|
356
396
|
onStepFinish: async (step) => {
|
|
357
397
|
if (chatId && messageId && args.saveOutputMessages) {
|
|
398
|
+
console.log("onStepFinish", step);
|
|
358
399
|
await this.saveStep(ctx, {
|
|
359
400
|
chatId,
|
|
360
401
|
messageId,
|
|
@@ -367,6 +408,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
367
408
|
return { ...result, messageId };
|
|
368
409
|
} catch (error) {
|
|
369
410
|
if (chatId && messageId) {
|
|
411
|
+
console.error("RollbackMessage", messageId);
|
|
370
412
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
371
413
|
messageId,
|
|
372
414
|
error: (error as Error).message,
|
|
@@ -382,12 +424,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
382
424
|
PARTIAL_OUTPUT = never,
|
|
383
425
|
>(
|
|
384
426
|
ctx: RunActionCtx,
|
|
385
|
-
{ userId, chatId }: { userId?: string; chatId
|
|
386
|
-
args:
|
|
427
|
+
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
428
|
+
args: TextArgs<
|
|
429
|
+
AgentTools,
|
|
430
|
+
TOOLS,
|
|
387
431
|
Parameters<typeof streamText<TOOLS, OUTPUT, PARTIAL_OUTPUT>>[0]
|
|
388
|
-
>
|
|
389
|
-
ContextOptions &
|
|
390
|
-
StorageOptions
|
|
432
|
+
>
|
|
391
433
|
): Promise<
|
|
392
434
|
StreamTextResult<TOOLS, PARTIAL_OUTPUT> & GenerationOutputMetadata
|
|
393
435
|
> {
|
|
@@ -405,16 +447,17 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
405
447
|
pending: true,
|
|
406
448
|
parentMessageId: args.parentMessageId,
|
|
407
449
|
});
|
|
408
|
-
const
|
|
409
|
-
const tools = wrapTools(
|
|
450
|
+
const toolCtx = { ...ctx, userId, chatId, messageId };
|
|
451
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
410
452
|
const result = streamText({
|
|
411
453
|
model: this.options.chat,
|
|
412
454
|
messages: [...contextMessages, ...messages],
|
|
413
|
-
system: this.options.
|
|
414
|
-
|
|
455
|
+
system: this.options.instructions,
|
|
456
|
+
maxSteps: this.options.maxSteps,
|
|
415
457
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
416
458
|
toolChoice: args.toolChoice as any,
|
|
417
459
|
...rest,
|
|
460
|
+
tools,
|
|
418
461
|
onChunk: async (chunk) => {
|
|
419
462
|
console.log("onChunk", chunk);
|
|
420
463
|
return args.onChunk?.(chunk);
|
|
@@ -453,10 +496,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
453
496
|
// TODO: add the crazy number of overloads to get types through
|
|
454
497
|
async generateObject<T>(
|
|
455
498
|
ctx: RunActionCtx,
|
|
456
|
-
{ userId, chatId }: { userId?: string; chatId
|
|
499
|
+
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
457
500
|
args: Omit<Parameters<typeof generateObject>[0], "model"> & {
|
|
458
501
|
model?: LanguageModelV1;
|
|
459
|
-
} & ContextOptions &
|
|
502
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
460
503
|
StorageOptions
|
|
461
504
|
): Promise<GenerateObjectResult<T> & GenerationOutputMetadata> {
|
|
462
505
|
const { prompt, messages: raw, ...rest } = args;
|
|
@@ -482,10 +525,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
482
525
|
|
|
483
526
|
async streamObject<T>(
|
|
484
527
|
ctx: RunMutationCtx,
|
|
485
|
-
{ userId, chatId }: { userId?: string; chatId
|
|
528
|
+
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
486
529
|
args: Omit<Parameters<typeof streamObject<T>>[0], "model"> & {
|
|
487
530
|
model?: LanguageModelV1;
|
|
488
|
-
} & ContextOptions &
|
|
531
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
489
532
|
StorageOptions
|
|
490
533
|
): Promise<
|
|
491
534
|
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
@@ -518,27 +561,41 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
518
561
|
return { ...result, messageId };
|
|
519
562
|
}
|
|
520
563
|
|
|
564
|
+
mergedContextOptions(opts: ContextOptions): ContextOptions {
|
|
565
|
+
const searchOptions = {
|
|
566
|
+
...this.options.contextOptions?.searchOptions,
|
|
567
|
+
...opts.searchOptions,
|
|
568
|
+
};
|
|
569
|
+
return {
|
|
570
|
+
...this.options.contextOptions,
|
|
571
|
+
...opts,
|
|
572
|
+
searchOptions: searchOptions.limit
|
|
573
|
+
? (searchOptions as SearchOptions)
|
|
574
|
+
: undefined,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
521
578
|
async searchOptionsWithDefaults(
|
|
522
|
-
|
|
579
|
+
contextOptions: ContextOptions,
|
|
523
580
|
messages: CoreMessage[]
|
|
524
581
|
): Promise<SearchOptions> {
|
|
525
582
|
assert(
|
|
526
|
-
|
|
527
|
-
|
|
583
|
+
contextOptions.searchOptions?.textSearch ||
|
|
584
|
+
contextOptions.searchOptions?.vectorSearch,
|
|
528
585
|
"searchOptions is required"
|
|
529
586
|
);
|
|
530
587
|
assert(messages.length > 0, "Core messages cannot be empty");
|
|
531
588
|
const text = extractText(messages.at(-1)!);
|
|
532
589
|
const search: SearchOptions = {
|
|
533
|
-
limit:
|
|
590
|
+
limit: contextOptions.searchOptions?.limit ?? 10,
|
|
534
591
|
messageRange: {
|
|
535
592
|
...DEFAULT_MESSAGE_RANGE,
|
|
536
|
-
...
|
|
593
|
+
...contextOptions.searchOptions?.messageRange,
|
|
537
594
|
},
|
|
538
595
|
text: extractText(messages.at(-1)!),
|
|
539
596
|
};
|
|
540
597
|
if (
|
|
541
|
-
|
|
598
|
+
contextOptions.searchOptions?.vectorSearch &&
|
|
542
599
|
text &&
|
|
543
600
|
this.options.textEmbedding
|
|
544
601
|
) {
|
|
@@ -552,71 +609,191 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
552
609
|
return search;
|
|
553
610
|
}
|
|
554
611
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
.
|
|
584
|
-
.
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
612
|
+
/**
|
|
613
|
+
*
|
|
614
|
+
*/
|
|
615
|
+
asAction(spec: { contextOptions?: ContextOptions; maxSteps?: number }) {
|
|
616
|
+
return internalActionGeneric({
|
|
617
|
+
args: {
|
|
618
|
+
userId: v.optional(v.string()),
|
|
619
|
+
chatId: v.optional(v.string()),
|
|
620
|
+
contextOptions: v.optional(vContextOptions),
|
|
621
|
+
storageOptions: v.optional(vStorageOptions),
|
|
622
|
+
maxRetries: v.optional(v.number()),
|
|
623
|
+
|
|
624
|
+
createChat: v.optional(
|
|
625
|
+
v.object({
|
|
626
|
+
userId: v.string(),
|
|
627
|
+
parentChatIds: v.optional(v.array(v.string())),
|
|
628
|
+
title: v.optional(v.string()),
|
|
629
|
+
summary: v.optional(v.string()),
|
|
630
|
+
})
|
|
631
|
+
),
|
|
632
|
+
continueChat: v.optional(
|
|
633
|
+
v.object({
|
|
634
|
+
chatId: v.string(),
|
|
635
|
+
userId: v.optional(v.string()),
|
|
636
|
+
})
|
|
637
|
+
),
|
|
638
|
+
generateText: v.optional(vChatArgs),
|
|
639
|
+
streamText: v.optional(vChatArgs),
|
|
640
|
+
generateObject: v.optional(vObjectArgs),
|
|
641
|
+
streamObject: v.optional(
|
|
642
|
+
v.object({ ...vObjectArgs.fields, schema: v.any() })
|
|
643
|
+
),
|
|
644
|
+
},
|
|
645
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
646
|
+
handler: async (ctx, args): Promise<any> => {
|
|
647
|
+
const contextOptions =
|
|
648
|
+
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
|
|
649
|
+
const maxSteps = spec.maxSteps ?? this.options.maxSteps;
|
|
650
|
+
const maxRetries = args.maxRetries;
|
|
651
|
+
const commonArgs = {
|
|
652
|
+
userId: args.userId,
|
|
653
|
+
chatId: args.chatId,
|
|
654
|
+
...contextOptions,
|
|
655
|
+
...args.storageOptions,
|
|
656
|
+
};
|
|
657
|
+
if (args.createChat) {
|
|
658
|
+
return this.createChat(ctx, {
|
|
659
|
+
userId: args.createChat.userId,
|
|
660
|
+
parentChatIds: args.createChat.parentChatIds,
|
|
661
|
+
title: args.createChat.title,
|
|
662
|
+
summary: args.createChat.summary,
|
|
663
|
+
});
|
|
664
|
+
} else if (args.continueChat) {
|
|
665
|
+
return this.continueChat(ctx, {
|
|
666
|
+
chatId: args.continueChat.chatId,
|
|
667
|
+
userId: args.continueChat.userId,
|
|
668
|
+
});
|
|
669
|
+
} else if (args.generateText) {
|
|
670
|
+
return this.generateText(ctx, commonArgs, {
|
|
671
|
+
...args.generateText,
|
|
672
|
+
maxSteps: args.generateText.maxSteps ?? maxSteps,
|
|
673
|
+
maxRetries,
|
|
674
|
+
});
|
|
675
|
+
} else if (args.streamText) {
|
|
676
|
+
return this.streamText(ctx, commonArgs, {
|
|
677
|
+
...args.streamText,
|
|
678
|
+
maxSteps: args.streamText.maxSteps ?? maxSteps,
|
|
679
|
+
maxRetries,
|
|
680
|
+
});
|
|
681
|
+
} else if (args.generateObject) {
|
|
682
|
+
return this.generateObject(ctx, commonArgs, {
|
|
683
|
+
...args.generateObject,
|
|
684
|
+
output: args.generateObject.output ?? "string",
|
|
685
|
+
maxRetries,
|
|
686
|
+
});
|
|
687
|
+
} else if (args.streamObject) {
|
|
688
|
+
return this.streamObject(ctx, commonArgs, {
|
|
689
|
+
...args.streamObject,
|
|
690
|
+
output: args.streamObject.output ?? "string",
|
|
691
|
+
maxRetries,
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
});
|
|
588
696
|
}
|
|
589
|
-
}
|
|
590
697
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
698
|
+
/**
|
|
699
|
+
* Create a tool that can call this agent.
|
|
700
|
+
* @param spec The specification for the arguments to this agent.
|
|
701
|
+
* They will be encoded as JSON and passed to the agent.
|
|
702
|
+
* @returns The agent as a tool that can be passed to other agents.
|
|
703
|
+
*/
|
|
704
|
+
asTool(spec: {
|
|
705
|
+
description: string;
|
|
706
|
+
args: Validator<unknown, "required", string>;
|
|
707
|
+
contextOptions?: ContextOptions;
|
|
708
|
+
maxSteps?: number;
|
|
709
|
+
}) {
|
|
710
|
+
return createTool({
|
|
711
|
+
...spec,
|
|
712
|
+
handler: async (ctx, args) => {
|
|
713
|
+
const maxSteps = spec.maxSteps ?? this.options.maxSteps;
|
|
714
|
+
const contextOptions =
|
|
715
|
+
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
|
|
716
|
+
const value = await this.generateText(
|
|
717
|
+
ctx,
|
|
718
|
+
{ userId: ctx.userId, chatId: ctx.chatId },
|
|
719
|
+
{
|
|
720
|
+
prompt: JSON.stringify(args),
|
|
721
|
+
parentMessageId: ctx.messageId,
|
|
722
|
+
maxSteps,
|
|
723
|
+
...contextOptions,
|
|
724
|
+
}
|
|
725
|
+
);
|
|
726
|
+
return value.text;
|
|
727
|
+
},
|
|
728
|
+
});
|
|
599
729
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
export type ToolCtx = RunActionCtx & {
|
|
733
|
+
userId?: string;
|
|
734
|
+
chatId?: string;
|
|
735
|
+
messageId?: string;
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* This is a wrapper around the ai.tool function that adds support for
|
|
740
|
+
* userId and chatId to the tool, if they're called within a chat from an agent.
|
|
741
|
+
* @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 chatId args support added.
|
|
743
|
+
*/
|
|
744
|
+
export function createTool<
|
|
745
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
746
|
+
V extends Validator<any, any, any>,
|
|
747
|
+
RESULT,
|
|
748
|
+
>(convexTool: {
|
|
749
|
+
args: V;
|
|
750
|
+
description?: string;
|
|
751
|
+
handler: (
|
|
752
|
+
ctx: ToolCtx,
|
|
753
|
+
args: Infer<V>,
|
|
754
|
+
options: ToolExecutionOptions
|
|
755
|
+
) => PromiseLike<RESULT>;
|
|
756
|
+
ctx?: ToolCtx;
|
|
757
|
+
}): Tool<ConvexToZod<V>, RESULT> {
|
|
758
|
+
const tool = {
|
|
759
|
+
__acceptsCtx: true,
|
|
760
|
+
ctx: convexTool.ctx,
|
|
761
|
+
description: convexTool.description,
|
|
762
|
+
parameters: convexToZod(convexTool.args),
|
|
763
|
+
async execute(args: Infer<V>, options: ToolExecutionOptions) {
|
|
764
|
+
if (!this.ctx) {
|
|
765
|
+
throw new Error(
|
|
766
|
+
"To use a Convex tool, you must either provide the ctx" +
|
|
767
|
+
" at definition time (dynamically in an action), or use the Agent to" +
|
|
768
|
+
" call it (which injects the ctx, userId and chatId)"
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
return convexTool.handler(this.ctx, args, options);
|
|
772
|
+
},
|
|
773
|
+
};
|
|
774
|
+
return tool;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function wrapTools(
|
|
778
|
+
ctx: ToolCtx,
|
|
779
|
+
...toolSets: (ToolSet | undefined)[]
|
|
780
|
+
): ToolSet {
|
|
781
|
+
const output = {} as ToolSet;
|
|
782
|
+
for (const toolSet of toolSets) {
|
|
783
|
+
if (!toolSet) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
for (const [name, tool] of Object.entries(toolSet)) {
|
|
787
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
788
|
+
if (!(tool as any).__acceptsCtx) {
|
|
789
|
+
output[name] = tool;
|
|
790
|
+
} else {
|
|
791
|
+
const out = { ...tool, ctx };
|
|
792
|
+
output[name] = out;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
617
795
|
}
|
|
618
|
-
|
|
619
|
-
return messages;
|
|
796
|
+
return output;
|
|
620
797
|
}
|
|
621
798
|
|
|
622
799
|
type TextArgs<
|
|
@@ -629,6 +806,7 @@ type TextArgs<
|
|
|
629
806
|
},
|
|
630
807
|
> = Omit<T, "toolChoice" | "tools" | "model"> & {
|
|
631
808
|
model?: LanguageModelV1;
|
|
809
|
+
parentMessageId?: string;
|
|
632
810
|
} & {
|
|
633
811
|
tools?: TOOLS;
|
|
634
812
|
toolChoice?: ToolChoice<{ [key in keyof TOOLS | keyof AgentTools]: unknown }>;
|
|
@@ -675,79 +853,3 @@ interface Chat<AgentTools extends ToolSet> {
|
|
|
675
853
|
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
676
854
|
>;
|
|
677
855
|
}
|
|
678
|
-
|
|
679
|
-
// type ToolParameters = ZodTypeAny | Schema<unknown>; // TODO: support convex validator
|
|
680
|
-
// type inferParameters<PARAMETERS extends ToolParameters> =
|
|
681
|
-
// PARAMETERS extends Schema<unknown>
|
|
682
|
-
// ? PARAMETERS["_type"]
|
|
683
|
-
// : PARAMETERS extends z.ZodTypeAny
|
|
684
|
-
// ? z.infer<PARAMETERS>
|
|
685
|
-
// : never;
|
|
686
|
-
/**
|
|
687
|
-
* This is a wrapper around the ai.tool function that adds support for
|
|
688
|
-
* userId and chatId to the tool, if they're called within a chat from an agent.
|
|
689
|
-
* @param tool The AI tool. See https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling
|
|
690
|
-
* @returns The same tool, but with userId and chatId args support added.
|
|
691
|
-
*/
|
|
692
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
693
|
-
export function tool<V extends Validator<any, any, any>, RESULT>(convexTool: {
|
|
694
|
-
args: V;
|
|
695
|
-
description?: string;
|
|
696
|
-
handler: (
|
|
697
|
-
ctx: GenericActionCtx<GenericDataModel> & {
|
|
698
|
-
userId?: string;
|
|
699
|
-
chatId?: string;
|
|
700
|
-
},
|
|
701
|
-
args: Infer<V>,
|
|
702
|
-
options: ToolExecutionOptions
|
|
703
|
-
) => PromiseLike<RESULT>;
|
|
704
|
-
ctx?: GenericActionCtx<GenericDataModel> & {
|
|
705
|
-
userId?: string;
|
|
706
|
-
chatId?: string;
|
|
707
|
-
};
|
|
708
|
-
}): Tool<ZodType<Infer<V>>, RESULT> {
|
|
709
|
-
const tool = {
|
|
710
|
-
__acceptUserIdAndChatId: true,
|
|
711
|
-
description: convexTool.description,
|
|
712
|
-
parameters: convexToZod(convexTool.args),
|
|
713
|
-
execute: async (args: Infer<V>, options: ToolExecutionOptions) => {
|
|
714
|
-
if (!convexTool.ctx) {
|
|
715
|
-
throw new Error(
|
|
716
|
-
"To use a Convex tool, you must either provide the ctx" +
|
|
717
|
-
" at definition time (dynamically in an action), or use the Agent to" +
|
|
718
|
-
" call it (which injects the ctx, userId and chatId)"
|
|
719
|
-
);
|
|
720
|
-
}
|
|
721
|
-
return convexTool.handler(convexTool.ctx, args, options);
|
|
722
|
-
},
|
|
723
|
-
};
|
|
724
|
-
return tool;
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
export function wrapTools(
|
|
728
|
-
actionCtx: RunActionCtx,
|
|
729
|
-
chatId: string,
|
|
730
|
-
userId?: string,
|
|
731
|
-
...toolSets: (ToolSet | undefined)[]
|
|
732
|
-
): ToolSet {
|
|
733
|
-
const ctx = { ...actionCtx, chatId, userId };
|
|
734
|
-
const output = {} as ToolSet;
|
|
735
|
-
for (const toolSet of toolSets) {
|
|
736
|
-
if (!toolSet) {
|
|
737
|
-
continue;
|
|
738
|
-
}
|
|
739
|
-
for (const [name, tool] of Object.entries(toolSet)) {
|
|
740
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
741
|
-
if (!(tool as any).__acceptUserIdAndChatId) {
|
|
742
|
-
output[name] = tool;
|
|
743
|
-
} else {
|
|
744
|
-
const out = { ...tool, ctx };
|
|
745
|
-
output[name] = out;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
return output;
|
|
750
|
-
}
|
|
751
|
-
// export function convexValidatorSchema<T>(validator: Validator<unknown>) {
|
|
752
|
-
// return ai.jsonSchema(convexToJsonSchema(validator));
|
|
753
|
-
// }
|