@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.
- package/README.md +293 -6
- package/dist/commonjs/client/index.d.ts +520 -96
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +210 -131
- 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 +57 -56
- package/dist/commonjs/component/messages.d.ts.map +1 -1
- package/dist/commonjs/component/messages.js +184 -147
- package/dist/commonjs/component/messages.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +260 -256
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +25 -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/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 +1376 -1
- package/dist/commonjs/validators.d.ts.map +1 -1
- package/dist/commonjs/validators.js +28 -1
- package/dist/commonjs/validators.js.map +1 -1
- package/dist/esm/client/index.d.ts +520 -96
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +210 -131
- 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 +57 -56
- package/dist/esm/component/messages.d.ts.map +1 -1
- package/dist/esm/component/messages.js +184 -147
- package/dist/esm/component/messages.js.map +1 -1
- package/dist/esm/component/schema.d.ts +260 -256
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +25 -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/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 +1376 -1
- package/dist/esm/validators.d.ts.map +1 -1
- package/dist/esm/validators.js +28 -1
- package/dist/esm/validators.js.map +1 -1
- package/package.json +3 -3
- package/src/client/index.ts +384 -276
- package/src/client/types.ts +4 -0
- package/src/component/_generated/api.d.ts +54 -53
- package/src/component/messages.ts +219 -177
- package/src/component/schema.ts +25 -18
- package/src/component/vector/index.ts +13 -11
- package/src/component/vector/tables.ts +6 -6
- package/src/mapping.ts +46 -11
- package/src/validators.test.ts +9 -0
- package/src/validators.ts +36 -1
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
|
+
vThreadArgs,
|
|
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,22 +36,49 @@ 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
|
};
|
|
50
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Whether to search across other threads for relevant messages.
|
|
73
|
+
* By default, only the current thread is searched.
|
|
74
|
+
*/
|
|
75
|
+
searchOtherThreads?: boolean;
|
|
51
76
|
};
|
|
52
77
|
|
|
53
78
|
export type StorageOptions = {
|
|
54
79
|
// Defaults to false, allowing you to pass in arbitrary context that will
|
|
55
80
|
// be in addition to automatically fetched content.
|
|
56
|
-
// Pass true to have all input messages saved to the
|
|
81
|
+
// Pass true to have all input messages saved to the thread history.
|
|
57
82
|
saveAllInputMessages?: boolean;
|
|
58
83
|
// Defaults to true
|
|
59
84
|
saveOutputMessages?: boolean;
|
|
@@ -68,122 +93,136 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
68
93
|
public component: UseApi<typeof api>,
|
|
69
94
|
public options: {
|
|
70
95
|
name?: string;
|
|
71
|
-
|
|
96
|
+
thread: 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
|
|
|
78
107
|
/**
|
|
79
|
-
* Start a new
|
|
80
|
-
* 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
|
|
81
110
|
* messages as context for the LLM calls.
|
|
82
|
-
* @param ctx The context of the Convex function. From an action, you can
|
|
83
|
-
* with the agent. From a mutation, you can start a
|
|
84
|
-
* to pass to
|
|
85
|
-
* @param args The
|
|
86
|
-
* @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.
|
|
87
116
|
*/
|
|
88
|
-
async
|
|
117
|
+
async createThread(
|
|
89
118
|
ctx: RunActionCtx,
|
|
90
119
|
args: {
|
|
91
120
|
/**
|
|
92
|
-
* The userId to associate with the
|
|
121
|
+
* The userId to associate with the thread. If not provided, the thread will be
|
|
93
122
|
* anonymous.
|
|
94
123
|
*/
|
|
95
124
|
userId?: string;
|
|
96
125
|
/**
|
|
97
|
-
* The parent
|
|
98
|
-
* If the
|
|
99
|
-
* 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.
|
|
100
129
|
*/
|
|
101
|
-
|
|
130
|
+
parentThreadIds?: string[];
|
|
102
131
|
/**
|
|
103
|
-
* The title of the
|
|
132
|
+
* The title of the thread. Not currently used.
|
|
104
133
|
*/
|
|
105
134
|
title?: string;
|
|
106
135
|
/**
|
|
107
|
-
* The summary of the
|
|
136
|
+
* The summary of the thread. Not currently used.
|
|
108
137
|
*/
|
|
109
138
|
summary?: string;
|
|
110
139
|
}
|
|
111
140
|
): Promise<{
|
|
112
|
-
|
|
113
|
-
|
|
141
|
+
threadId: string;
|
|
142
|
+
thread: Thread<AgentTools>;
|
|
114
143
|
}>;
|
|
115
144
|
/**
|
|
116
|
-
* Start a new
|
|
117
|
-
* 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
|
|
118
147
|
* messages as context for the LLM calls.
|
|
119
148
|
* @param ctx The context of the Convex function. From a mutation, you can
|
|
120
|
-
* start a
|
|
121
|
-
* @param args The
|
|
122
|
-
* @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.
|
|
123
152
|
*/
|
|
124
|
-
async
|
|
153
|
+
async createThread(
|
|
125
154
|
ctx: RunMutationCtx,
|
|
126
155
|
args: {
|
|
127
156
|
userId?: string;
|
|
128
|
-
|
|
157
|
+
parentThreadIds?: string[];
|
|
129
158
|
title?: string;
|
|
130
159
|
summary?: string;
|
|
131
160
|
}
|
|
132
161
|
): Promise<{
|
|
133
|
-
|
|
162
|
+
threadId: string;
|
|
134
163
|
}>;
|
|
135
|
-
async
|
|
164
|
+
async createThread(
|
|
136
165
|
ctx: RunActionCtx | RunMutationCtx,
|
|
137
166
|
args: {
|
|
138
167
|
userId: string;
|
|
139
|
-
|
|
168
|
+
parentThreadIds?: string[];
|
|
140
169
|
title?: string;
|
|
141
170
|
summary?: string;
|
|
142
171
|
}
|
|
143
172
|
): Promise<{
|
|
144
|
-
|
|
145
|
-
|
|
173
|
+
threadId: string;
|
|
174
|
+
thread?: Thread<AgentTools>;
|
|
146
175
|
}> {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
+
);
|
|
154
186
|
if (!("runAction" in ctx)) {
|
|
155
|
-
return {
|
|
187
|
+
return { threadId: threadDoc._id };
|
|
156
188
|
}
|
|
157
|
-
const {
|
|
158
|
-
|
|
189
|
+
const { thread } = await this.continueThread(ctx, {
|
|
190
|
+
threadId: threadDoc._id,
|
|
159
191
|
userId: args.userId,
|
|
160
192
|
});
|
|
161
193
|
return {
|
|
162
|
-
|
|
163
|
-
|
|
194
|
+
threadId: threadDoc._id,
|
|
195
|
+
thread,
|
|
164
196
|
};
|
|
165
197
|
}
|
|
166
198
|
|
|
167
|
-
async
|
|
199
|
+
async continueThread(
|
|
168
200
|
ctx: RunActionCtx,
|
|
169
201
|
{
|
|
170
|
-
|
|
202
|
+
threadId,
|
|
171
203
|
userId,
|
|
172
204
|
}: {
|
|
173
|
-
|
|
205
|
+
threadId: string;
|
|
206
|
+
/**
|
|
207
|
+
* If supplied, the userId can be used to search across other threads for
|
|
208
|
+
* relevant messages from the same user as context for the LLM calls.
|
|
209
|
+
*/
|
|
174
210
|
userId?: string;
|
|
175
211
|
}
|
|
176
212
|
): Promise<{
|
|
177
|
-
|
|
213
|
+
thread: Thread<AgentTools>;
|
|
178
214
|
}> {
|
|
179
|
-
// return this.component.
|
|
215
|
+
// return this.component.continueThread(ctx, args);
|
|
180
216
|
return {
|
|
181
|
-
|
|
182
|
-
generateText: this.generateText.bind(this, ctx, { userId,
|
|
183
|
-
streamText: this.streamText.bind(this, ctx, { userId,
|
|
184
|
-
generateObject: this.generateObject.bind(this, ctx, {
|
|
185
|
-
|
|
186
|
-
|
|
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>,
|
|
187
226
|
};
|
|
188
227
|
}
|
|
189
228
|
|
|
@@ -191,35 +230,37 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
191
230
|
ctx: RunQueryCtx | RunActionCtx,
|
|
192
231
|
args: {
|
|
193
232
|
userId?: string;
|
|
194
|
-
|
|
233
|
+
threadId?: string;
|
|
195
234
|
messages: CoreMessage[];
|
|
235
|
+
parentMessageId?: string;
|
|
196
236
|
} & ContextOptions
|
|
197
237
|
): Promise<CoreMessage[]> {
|
|
198
|
-
assert(args.userId || args.
|
|
199
|
-
// Fetch the latest messages from the
|
|
238
|
+
assert(args.userId || args.threadId, "Specify userId or threadId");
|
|
239
|
+
// Fetch the latest messages from the thread
|
|
200
240
|
const contextMessages: CoreMessage[] = [];
|
|
201
|
-
|
|
241
|
+
const opts = this.mergedContextOptions(args);
|
|
242
|
+
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
202
243
|
if (!("runAction" in ctx)) {
|
|
203
244
|
throw new Error("searchUserMessages only works in an action");
|
|
204
245
|
}
|
|
205
246
|
const searchMessages = await ctx.runAction(
|
|
206
247
|
this.component.messages.searchMessages,
|
|
207
248
|
{
|
|
208
|
-
userId: args.
|
|
209
|
-
|
|
249
|
+
userId: args.searchOtherThreads ? args.userId : undefined,
|
|
250
|
+
threadId: args.threadId,
|
|
210
251
|
parentMessageId: args.parentMessageId,
|
|
211
|
-
...(await this.searchOptionsWithDefaults(
|
|
252
|
+
...(await this.searchOptionsWithDefaults(opts, args.messages)),
|
|
212
253
|
}
|
|
213
254
|
);
|
|
214
255
|
// TODO: track what messages we used for context
|
|
215
256
|
contextMessages.push(...searchMessages.map((m) => m.message!));
|
|
216
257
|
}
|
|
217
|
-
if (args.
|
|
258
|
+
if (args.threadId) {
|
|
218
259
|
const { messages } = await ctx.runQuery(
|
|
219
|
-
this.component.messages.
|
|
260
|
+
this.component.messages.getThreadMessages,
|
|
220
261
|
{
|
|
221
|
-
|
|
222
|
-
isTool: args.
|
|
262
|
+
threadId: args.threadId,
|
|
263
|
+
isTool: args.includeToolCalls ?? false,
|
|
223
264
|
limit: args.recentMessages,
|
|
224
265
|
parentMessageId: args.parentMessageId,
|
|
225
266
|
order: "desc",
|
|
@@ -234,21 +275,24 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
234
275
|
async saveMessages(
|
|
235
276
|
ctx: RunMutationCtx,
|
|
236
277
|
args: {
|
|
237
|
-
|
|
278
|
+
threadId?: string;
|
|
279
|
+
userId?: string;
|
|
238
280
|
messages: CoreMessageMaybeWithId[];
|
|
239
281
|
pending?: boolean;
|
|
240
282
|
parentMessageId?: string;
|
|
283
|
+
failPendingSteps?: boolean;
|
|
241
284
|
}
|
|
242
285
|
): Promise<{
|
|
243
286
|
lastMessageId: string;
|
|
244
287
|
messageIds: string[];
|
|
245
288
|
}> {
|
|
246
289
|
const result = await ctx.runMutation(this.component.messages.addMessages, {
|
|
247
|
-
|
|
290
|
+
threadId: args.threadId,
|
|
291
|
+
userId: args.userId,
|
|
248
292
|
agentName: this.options.name,
|
|
249
|
-
model: this.options.
|
|
293
|
+
model: this.options.thread.modelId,
|
|
250
294
|
messages: args.messages.map(serializeMessageWithId),
|
|
251
|
-
failPendingSteps: true,
|
|
295
|
+
failPendingSteps: args.failPendingSteps ?? true,
|
|
252
296
|
pending: args.pending ?? false,
|
|
253
297
|
parentMessageId: args.parentMessageId,
|
|
254
298
|
});
|
|
@@ -260,12 +304,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
260
304
|
|
|
261
305
|
async saveStep<TOOLS extends ToolSet>(
|
|
262
306
|
ctx: RunMutationCtx,
|
|
263
|
-
args: {
|
|
307
|
+
args: { threadId: string; messageId: string; step: StepResult<TOOLS> }
|
|
264
308
|
): Promise<void> {
|
|
265
309
|
const step = serializeStep(args.step as StepResult<ToolSet>);
|
|
266
310
|
const messages = serializeNewMessagesInStep(args.step);
|
|
267
311
|
await ctx.runMutation(this.component.messages.addSteps, {
|
|
268
|
-
|
|
312
|
+
threadId: args.threadId,
|
|
269
313
|
messageId: args.messageId,
|
|
270
314
|
steps: [{ step, messages: messages }],
|
|
271
315
|
failPendingSteps: false,
|
|
@@ -276,7 +320,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
276
320
|
async completeMessage<TOOLS extends ToolSet>(
|
|
277
321
|
ctx: RunMutationCtx,
|
|
278
322
|
args: {
|
|
279
|
-
|
|
323
|
+
threadId: string;
|
|
280
324
|
messageId: string;
|
|
281
325
|
result:
|
|
282
326
|
| { kind: "error"; error: string }
|
|
@@ -290,7 +334,7 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
290
334
|
});
|
|
291
335
|
} else {
|
|
292
336
|
await ctx.runMutation(this.component.messages.addSteps, {
|
|
293
|
-
|
|
337
|
+
threadId: args.threadId,
|
|
294
338
|
messageId: args.messageId,
|
|
295
339
|
steps: [],
|
|
296
340
|
failPendingSteps: true,
|
|
@@ -300,9 +344,9 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
300
344
|
|
|
301
345
|
/**
|
|
302
346
|
* This behaves like {@link generateText} except that it add context based on
|
|
303
|
-
* the userId and
|
|
304
|
-
*
|
|
305
|
-
* 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}.
|
|
306
350
|
* @param ctx The context of the agent.
|
|
307
351
|
* @param args The arguments to the generateText function.
|
|
308
352
|
* @returns The result of the generateText function.
|
|
@@ -315,10 +359,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
315
359
|
ctx: RunActionCtx,
|
|
316
360
|
{
|
|
317
361
|
userId,
|
|
318
|
-
|
|
362
|
+
threadId,
|
|
319
363
|
}: {
|
|
320
364
|
userId?: string;
|
|
321
|
-
|
|
365
|
+
threadId?: string;
|
|
322
366
|
},
|
|
323
367
|
args: TextArgs<
|
|
324
368
|
AgentTools,
|
|
@@ -333,30 +377,33 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
333
377
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
334
378
|
...args,
|
|
335
379
|
userId,
|
|
336
|
-
|
|
380
|
+
threadId,
|
|
337
381
|
messages,
|
|
338
382
|
});
|
|
339
383
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
340
|
-
|
|
384
|
+
threadId,
|
|
385
|
+
userId,
|
|
341
386
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
342
387
|
pending: true,
|
|
343
388
|
parentMessageId: args.parentMessageId,
|
|
344
389
|
});
|
|
345
|
-
const
|
|
346
|
-
const tools = wrapTools(
|
|
390
|
+
const toolCtx = { ...ctx, userId, threadId, messageId };
|
|
391
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
347
392
|
try {
|
|
348
393
|
const result = await generateText({
|
|
349
|
-
model: this.options.
|
|
394
|
+
model: this.options.thread,
|
|
350
395
|
messages: [...contextMessages, ...messages],
|
|
351
|
-
system: this.options.
|
|
352
|
-
|
|
396
|
+
system: this.options.instructions,
|
|
397
|
+
maxSteps: this.options.maxSteps,
|
|
353
398
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
354
399
|
toolChoice: args.toolChoice as any,
|
|
355
400
|
...rest,
|
|
401
|
+
tools,
|
|
356
402
|
onStepFinish: async (step) => {
|
|
357
|
-
if (
|
|
403
|
+
if (threadId && messageId && args.saveOutputMessages) {
|
|
404
|
+
console.log("onStepFinish", step);
|
|
358
405
|
await this.saveStep(ctx, {
|
|
359
|
-
|
|
406
|
+
threadId,
|
|
360
407
|
messageId,
|
|
361
408
|
step,
|
|
362
409
|
});
|
|
@@ -366,7 +413,8 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
366
413
|
});
|
|
367
414
|
return { ...result, messageId };
|
|
368
415
|
} catch (error) {
|
|
369
|
-
if (
|
|
416
|
+
if (threadId && messageId) {
|
|
417
|
+
console.error("RollbackMessage", messageId);
|
|
370
418
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
371
419
|
messageId,
|
|
372
420
|
error: (error as Error).message,
|
|
@@ -382,12 +430,12 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
382
430
|
PARTIAL_OUTPUT = never,
|
|
383
431
|
>(
|
|
384
432
|
ctx: RunActionCtx,
|
|
385
|
-
{ userId,
|
|
386
|
-
args:
|
|
433
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
434
|
+
args: TextArgs<
|
|
435
|
+
AgentTools,
|
|
436
|
+
TOOLS,
|
|
387
437
|
Parameters<typeof streamText<TOOLS, OUTPUT, PARTIAL_OUTPUT>>[0]
|
|
388
|
-
>
|
|
389
|
-
ContextOptions &
|
|
390
|
-
StorageOptions
|
|
438
|
+
>
|
|
391
439
|
): Promise<
|
|
392
440
|
StreamTextResult<TOOLS, PARTIAL_OUTPUT> & GenerationOutputMetadata
|
|
393
441
|
> {
|
|
@@ -396,32 +444,33 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
396
444
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
397
445
|
...args,
|
|
398
446
|
userId,
|
|
399
|
-
|
|
447
|
+
threadId,
|
|
400
448
|
messages,
|
|
401
449
|
});
|
|
402
450
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
403
|
-
|
|
451
|
+
threadId,
|
|
404
452
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
405
453
|
pending: true,
|
|
406
454
|
parentMessageId: args.parentMessageId,
|
|
407
455
|
});
|
|
408
|
-
const
|
|
409
|
-
const tools = wrapTools(
|
|
456
|
+
const toolCtx = { ...ctx, userId, threadId, messageId };
|
|
457
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
410
458
|
const result = streamText({
|
|
411
|
-
model: this.options.
|
|
459
|
+
model: this.options.thread,
|
|
412
460
|
messages: [...contextMessages, ...messages],
|
|
413
|
-
system: this.options.
|
|
414
|
-
|
|
461
|
+
system: this.options.instructions,
|
|
462
|
+
maxSteps: this.options.maxSteps,
|
|
415
463
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
416
464
|
toolChoice: args.toolChoice as any,
|
|
417
465
|
...rest,
|
|
466
|
+
tools,
|
|
418
467
|
onChunk: async (chunk) => {
|
|
419
468
|
console.log("onChunk", chunk);
|
|
420
469
|
return args.onChunk?.(chunk);
|
|
421
470
|
},
|
|
422
471
|
onError: async (error) => {
|
|
423
472
|
console.error("onError", error);
|
|
424
|
-
if (
|
|
473
|
+
if (threadId && messageId) {
|
|
425
474
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
426
475
|
messageId,
|
|
427
476
|
error: (error.error as Error).message,
|
|
@@ -437,9 +486,9 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
437
486
|
},
|
|
438
487
|
onStepFinish: async (step) => {
|
|
439
488
|
console.log("onStepFinish", step);
|
|
440
|
-
if (
|
|
489
|
+
if (threadId && messageId) {
|
|
441
490
|
await this.saveStep(ctx, {
|
|
442
|
-
|
|
491
|
+
threadId,
|
|
443
492
|
messageId,
|
|
444
493
|
step,
|
|
445
494
|
});
|
|
@@ -453,10 +502,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
453
502
|
// TODO: add the crazy number of overloads to get types through
|
|
454
503
|
async generateObject<T>(
|
|
455
504
|
ctx: RunActionCtx,
|
|
456
|
-
{ userId,
|
|
505
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
457
506
|
args: Omit<Parameters<typeof generateObject>[0], "model"> & {
|
|
458
507
|
model?: LanguageModelV1;
|
|
459
|
-
} & ContextOptions &
|
|
508
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
460
509
|
StorageOptions
|
|
461
510
|
): Promise<GenerateObjectResult<T> & GenerationOutputMetadata> {
|
|
462
511
|
const { prompt, messages: raw, ...rest } = args;
|
|
@@ -464,16 +513,16 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
464
513
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
465
514
|
...args,
|
|
466
515
|
userId,
|
|
467
|
-
|
|
516
|
+
threadId,
|
|
468
517
|
messages,
|
|
469
518
|
});
|
|
470
519
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
471
|
-
|
|
520
|
+
threadId,
|
|
472
521
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
473
522
|
pending: true,
|
|
474
523
|
});
|
|
475
524
|
const result = (await generateObject({
|
|
476
|
-
model: this.options.
|
|
525
|
+
model: this.options.thread,
|
|
477
526
|
messages: [...contextMessages, ...messages],
|
|
478
527
|
...rest,
|
|
479
528
|
})) as GenerateObjectResult<T>;
|
|
@@ -482,10 +531,10 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
482
531
|
|
|
483
532
|
async streamObject<T>(
|
|
484
533
|
ctx: RunMutationCtx,
|
|
485
|
-
{ userId,
|
|
534
|
+
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
486
535
|
args: Omit<Parameters<typeof streamObject<T>>[0], "model"> & {
|
|
487
536
|
model?: LanguageModelV1;
|
|
488
|
-
} & ContextOptions &
|
|
537
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
489
538
|
StorageOptions
|
|
490
539
|
): Promise<
|
|
491
540
|
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
@@ -495,16 +544,16 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
495
544
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
496
545
|
...args,
|
|
497
546
|
userId,
|
|
498
|
-
|
|
547
|
+
threadId,
|
|
499
548
|
messages,
|
|
500
549
|
});
|
|
501
550
|
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
502
|
-
|
|
551
|
+
threadId,
|
|
503
552
|
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
504
553
|
pending: true,
|
|
505
554
|
});
|
|
506
555
|
const result = streamObject<T>({
|
|
507
|
-
model: this.options.
|
|
556
|
+
model: this.options.thread,
|
|
508
557
|
messages: [...contextMessages, ...messages],
|
|
509
558
|
...rest,
|
|
510
559
|
onError: async (error) => {
|
|
@@ -518,27 +567,41 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
518
567
|
return { ...result, messageId };
|
|
519
568
|
}
|
|
520
569
|
|
|
570
|
+
mergedContextOptions(opts: ContextOptions): ContextOptions {
|
|
571
|
+
const searchOptions = {
|
|
572
|
+
...this.options.contextOptions?.searchOptions,
|
|
573
|
+
...opts.searchOptions,
|
|
574
|
+
};
|
|
575
|
+
return {
|
|
576
|
+
...this.options.contextOptions,
|
|
577
|
+
...opts,
|
|
578
|
+
searchOptions: searchOptions.limit
|
|
579
|
+
? (searchOptions as SearchOptions)
|
|
580
|
+
: undefined,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
521
584
|
async searchOptionsWithDefaults(
|
|
522
|
-
|
|
585
|
+
contextOptions: ContextOptions,
|
|
523
586
|
messages: CoreMessage[]
|
|
524
587
|
): Promise<SearchOptions> {
|
|
525
588
|
assert(
|
|
526
|
-
|
|
527
|
-
|
|
589
|
+
contextOptions.searchOptions?.textSearch ||
|
|
590
|
+
contextOptions.searchOptions?.vectorSearch,
|
|
528
591
|
"searchOptions is required"
|
|
529
592
|
);
|
|
530
593
|
assert(messages.length > 0, "Core messages cannot be empty");
|
|
531
594
|
const text = extractText(messages.at(-1)!);
|
|
532
595
|
const search: SearchOptions = {
|
|
533
|
-
limit:
|
|
596
|
+
limit: contextOptions.searchOptions?.limit ?? 10,
|
|
534
597
|
messageRange: {
|
|
535
598
|
...DEFAULT_MESSAGE_RANGE,
|
|
536
|
-
...
|
|
599
|
+
...contextOptions.searchOptions?.messageRange,
|
|
537
600
|
},
|
|
538
601
|
text: extractText(messages.at(-1)!),
|
|
539
602
|
};
|
|
540
603
|
if (
|
|
541
|
-
|
|
604
|
+
contextOptions.searchOptions?.vectorSearch &&
|
|
542
605
|
text &&
|
|
543
606
|
this.options.textEmbedding
|
|
544
607
|
) {
|
|
@@ -552,71 +615,191 @@ export class Agent<AgentTools extends ToolSet> {
|
|
|
552
615
|
return search;
|
|
553
616
|
}
|
|
554
617
|
|
|
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
|
-
|
|
618
|
+
/**
|
|
619
|
+
*
|
|
620
|
+
*/
|
|
621
|
+
asAction(spec: { contextOptions?: ContextOptions; maxSteps?: number }) {
|
|
622
|
+
return internalActionGeneric({
|
|
623
|
+
args: {
|
|
624
|
+
userId: v.optional(v.string()),
|
|
625
|
+
threadId: v.optional(v.string()),
|
|
626
|
+
contextOptions: v.optional(vContextOptions),
|
|
627
|
+
storageOptions: v.optional(vStorageOptions),
|
|
628
|
+
maxRetries: v.optional(v.number()),
|
|
629
|
+
|
|
630
|
+
createThread: v.optional(
|
|
631
|
+
v.object({
|
|
632
|
+
userId: v.optional(v.string()),
|
|
633
|
+
parentThreadIds: v.optional(v.array(v.string())),
|
|
634
|
+
title: v.optional(v.string()),
|
|
635
|
+
summary: v.optional(v.string()),
|
|
636
|
+
})
|
|
637
|
+
),
|
|
638
|
+
continueThread: v.optional(
|
|
639
|
+
v.object({
|
|
640
|
+
threadId: v.string(),
|
|
641
|
+
userId: v.optional(v.string()),
|
|
642
|
+
})
|
|
643
|
+
),
|
|
644
|
+
generateText: v.optional(vThreadArgs),
|
|
645
|
+
streamText: v.optional(vThreadArgs),
|
|
646
|
+
generateObject: v.optional(vObjectArgs),
|
|
647
|
+
streamObject: v.optional(
|
|
648
|
+
v.object({ ...vObjectArgs.fields, schema: v.any() })
|
|
649
|
+
),
|
|
650
|
+
},
|
|
651
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
652
|
+
handler: async (ctx, args): Promise<any> => {
|
|
653
|
+
const contextOptions =
|
|
654
|
+
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
|
|
655
|
+
const maxSteps = spec.maxSteps ?? this.options.maxSteps;
|
|
656
|
+
const maxRetries = args.maxRetries;
|
|
657
|
+
const commonArgs = {
|
|
658
|
+
userId: args.userId,
|
|
659
|
+
threadId: args.threadId,
|
|
660
|
+
...contextOptions,
|
|
661
|
+
...args.storageOptions,
|
|
662
|
+
};
|
|
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,
|
|
669
|
+
});
|
|
670
|
+
} else if (args.continueThread) {
|
|
671
|
+
return this.continueThread(ctx, {
|
|
672
|
+
threadId: args.continueThread.threadId,
|
|
673
|
+
userId: args.continueThread.userId,
|
|
674
|
+
});
|
|
675
|
+
} else if (args.generateText) {
|
|
676
|
+
return this.generateText(ctx, commonArgs, {
|
|
677
|
+
...args.generateText,
|
|
678
|
+
maxSteps: args.generateText.maxSteps ?? maxSteps,
|
|
679
|
+
maxRetries,
|
|
680
|
+
});
|
|
681
|
+
} else if (args.streamText) {
|
|
682
|
+
return this.streamText(ctx, commonArgs, {
|
|
683
|
+
...args.streamText,
|
|
684
|
+
maxSteps: args.streamText.maxSteps ?? maxSteps,
|
|
685
|
+
maxRetries,
|
|
686
|
+
});
|
|
687
|
+
} else if (args.generateObject) {
|
|
688
|
+
return this.generateObject(ctx, commonArgs, {
|
|
689
|
+
...args.generateObject,
|
|
690
|
+
output: args.generateObject.output ?? "string",
|
|
691
|
+
maxRetries,
|
|
692
|
+
});
|
|
693
|
+
} else if (args.streamObject) {
|
|
694
|
+
return this.streamObject(ctx, commonArgs, {
|
|
695
|
+
...args.streamObject,
|
|
696
|
+
output: args.streamObject.output ?? "string",
|
|
697
|
+
maxRetries,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
});
|
|
588
702
|
}
|
|
589
|
-
}
|
|
590
703
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
704
|
+
/**
|
|
705
|
+
* Create a tool that can call this agent.
|
|
706
|
+
* @param spec The specification for the arguments to this agent.
|
|
707
|
+
* They will be encoded as JSON and passed to the agent.
|
|
708
|
+
* @returns The agent as a tool that can be passed to other agents.
|
|
709
|
+
*/
|
|
710
|
+
asTool(spec: {
|
|
711
|
+
description: string;
|
|
712
|
+
args: Validator<unknown, "required", string>;
|
|
713
|
+
contextOptions?: ContextOptions;
|
|
714
|
+
maxSteps?: number;
|
|
715
|
+
}) {
|
|
716
|
+
return createTool({
|
|
717
|
+
...spec,
|
|
718
|
+
handler: async (ctx, args) => {
|
|
719
|
+
const maxSteps = spec.maxSteps ?? this.options.maxSteps;
|
|
720
|
+
const contextOptions =
|
|
721
|
+
spec.contextOptions && this.mergedContextOptions(spec.contextOptions);
|
|
722
|
+
const value = await this.generateText(
|
|
723
|
+
ctx,
|
|
724
|
+
{ userId: ctx.userId, threadId: ctx.threadId },
|
|
725
|
+
{
|
|
726
|
+
prompt: JSON.stringify(args),
|
|
727
|
+
parentMessageId: ctx.messageId,
|
|
728
|
+
maxSteps,
|
|
729
|
+
...contextOptions,
|
|
730
|
+
}
|
|
731
|
+
);
|
|
732
|
+
return value.text;
|
|
733
|
+
},
|
|
734
|
+
});
|
|
599
735
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
export type ToolCtx = RunActionCtx & {
|
|
739
|
+
userId?: string;
|
|
740
|
+
threadId?: string;
|
|
741
|
+
messageId?: string;
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* This is a wrapper around the ai.tool function that adds support for
|
|
746
|
+
* userId and threadId to the tool, if they're called within a thread from an agent.
|
|
747
|
+
* @param tool The AI tool. See https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling
|
|
748
|
+
* @returns The same tool, but with userId and threadId args support added.
|
|
749
|
+
*/
|
|
750
|
+
export function createTool<
|
|
751
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
752
|
+
V extends Validator<any, any, any>,
|
|
753
|
+
RESULT,
|
|
754
|
+
>(convexTool: {
|
|
755
|
+
args: V;
|
|
756
|
+
description?: string;
|
|
757
|
+
handler: (
|
|
758
|
+
ctx: ToolCtx,
|
|
759
|
+
args: Infer<V>,
|
|
760
|
+
options: ToolExecutionOptions
|
|
761
|
+
) => PromiseLike<RESULT>;
|
|
762
|
+
ctx?: ToolCtx;
|
|
763
|
+
}): Tool<ConvexToZod<V>, RESULT> {
|
|
764
|
+
const tool = {
|
|
765
|
+
__acceptsCtx: true,
|
|
766
|
+
ctx: convexTool.ctx,
|
|
767
|
+
description: convexTool.description,
|
|
768
|
+
parameters: convexToZod(convexTool.args),
|
|
769
|
+
async execute(args: Infer<V>, options: ToolExecutionOptions) {
|
|
770
|
+
if (!this.ctx) {
|
|
771
|
+
throw new Error(
|
|
772
|
+
"To use a Convex tool, you must either provide the ctx" +
|
|
773
|
+
" at definition time (dynamically in an action), or use the Agent to" +
|
|
774
|
+
" call it (which injects the ctx, userId and threadId)"
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
return convexTool.handler(this.ctx, args, options);
|
|
778
|
+
},
|
|
779
|
+
};
|
|
780
|
+
return tool;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
function wrapTools(
|
|
784
|
+
ctx: ToolCtx,
|
|
785
|
+
...toolSets: (ToolSet | undefined)[]
|
|
786
|
+
): ToolSet {
|
|
787
|
+
const output = {} as ToolSet;
|
|
788
|
+
for (const toolSet of toolSets) {
|
|
789
|
+
if (!toolSet) {
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
for (const [name, tool] of Object.entries(toolSet)) {
|
|
793
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
794
|
+
if (!(tool as any).__acceptsCtx) {
|
|
795
|
+
output[name] = tool;
|
|
796
|
+
} else {
|
|
797
|
+
const out = { ...tool, ctx };
|
|
798
|
+
output[name] = out;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
617
801
|
}
|
|
618
|
-
|
|
619
|
-
return messages;
|
|
802
|
+
return output;
|
|
620
803
|
}
|
|
621
804
|
|
|
622
805
|
type TextArgs<
|
|
@@ -629,6 +812,7 @@ type TextArgs<
|
|
|
629
812
|
},
|
|
630
813
|
> = Omit<T, "toolChoice" | "tools" | "model"> & {
|
|
631
814
|
model?: LanguageModelV1;
|
|
815
|
+
parentMessageId?: string;
|
|
632
816
|
} & {
|
|
633
817
|
tools?: TOOLS;
|
|
634
818
|
toolChoice?: ToolChoice<{ [key in keyof TOOLS | keyof AgentTools]: unknown }>;
|
|
@@ -644,7 +828,7 @@ type ObjectArgs<
|
|
|
644
828
|
} & ContextOptions &
|
|
645
829
|
StorageOptions;
|
|
646
830
|
|
|
647
|
-
interface
|
|
831
|
+
interface Thread<AgentTools extends ToolSet> {
|
|
648
832
|
generateText<TOOLS extends ToolSet, OUTPUT = never, OUTPUT_PARTIAL = never>(
|
|
649
833
|
args: TextArgs<
|
|
650
834
|
AgentTools,
|
|
@@ -675,79 +859,3 @@ interface Chat<AgentTools extends ToolSet> {
|
|
|
675
859
|
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
676
860
|
>;
|
|
677
861
|
}
|
|
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
|
-
// }
|