@convex-dev/agent 0.0.1-alpha.0 → 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 +521 -62
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +230 -118
- 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 +22 -17
- package/dist/commonjs/component/messages.d.ts.map +1 -1
- package/dist/commonjs/component/messages.js +107 -47
- package/dist/commonjs/component/messages.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +16 -12
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +10 -3
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/vector/index.d.ts +41 -0
- package/dist/commonjs/component/vector/index.d.ts.map +1 -0
- package/dist/commonjs/component/vector/index.js +120 -0
- package/dist/commonjs/component/vector/index.js.map +1 -0
- package/dist/commonjs/component/vector/tables.d.ts.map +1 -1
- package/dist/commonjs/component/vector/tables.js +4 -2
- 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 +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 +521 -62
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +230 -118
- 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 +22 -17
- package/dist/esm/component/messages.d.ts.map +1 -1
- package/dist/esm/component/messages.js +107 -47
- package/dist/esm/component/messages.js.map +1 -1
- package/dist/esm/component/schema.d.ts +16 -12
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +10 -3
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/vector/index.d.ts +41 -0
- package/dist/esm/component/vector/index.d.ts.map +1 -0
- package/dist/esm/component/vector/index.js +120 -0
- package/dist/esm/component/vector/index.js.map +1 -0
- package/dist/esm/component/vector/tables.d.ts.map +1 -1
- package/dist/esm/component/vector/tables.js +4 -2
- 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 +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 +428 -232
- package/src/client/types.ts +4 -0
- package/src/component/_generated/api.d.ts +138 -11
- package/src/component/messages.ts +136 -66
- package/src/component/schema.ts +10 -3
- package/src/component/vector/index.ts +144 -0
- package/src/component/vector/tables.ts +7 -5
- 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
|
@@ -1,60 +1,106 @@
|
|
|
1
|
-
import { api } from "../component/_generated/api";
|
|
2
|
-
import { RunActionCtx, RunMutationCtx, RunQueryCtx, UseApi } from "./types";
|
|
3
1
|
import type { EmbeddingModelV1, LanguageModelV1 } from "@ai-sdk/provider";
|
|
4
|
-
import { Message, MessageStatus, SearchOptions, Step } from "../validators";
|
|
5
2
|
import type {
|
|
6
|
-
StreamTextResult,
|
|
7
|
-
Tool,
|
|
8
|
-
ToolSet,
|
|
9
|
-
StepResult,
|
|
10
|
-
Message as UIMessage,
|
|
11
3
|
CoreMessage,
|
|
12
|
-
GenerateObjectResult,
|
|
13
|
-
StreamObjectResult,
|
|
14
4
|
DeepPartial,
|
|
5
|
+
GenerateObjectResult,
|
|
15
6
|
GenerateTextResult,
|
|
7
|
+
StepResult,
|
|
8
|
+
StreamObjectResult,
|
|
9
|
+
StreamTextResult,
|
|
10
|
+
Tool,
|
|
11
|
+
ToolChoice,
|
|
12
|
+
ToolExecutionOptions,
|
|
13
|
+
ToolSet,
|
|
16
14
|
} from "ai";
|
|
15
|
+
import { generateObject, generateText, streamObject, streamText } from "ai";
|
|
16
|
+
import { api } from "../component/_generated/api";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} from "
|
|
18
|
+
SearchOptions,
|
|
19
|
+
vChatArgs,
|
|
20
|
+
vContextOptions,
|
|
21
|
+
vObjectArgs,
|
|
22
|
+
vStorageOptions,
|
|
23
|
+
} from "../validators";
|
|
24
|
+
import { RunActionCtx, RunMutationCtx, RunQueryCtx, UseApi } from "./types";
|
|
25
25
|
// TODO: is this the only dependency that needs helpers in client?
|
|
26
26
|
import { assert } from "convex-helpers";
|
|
27
|
-
import {
|
|
27
|
+
import { ConvexToZod, convexToZod } from "convex-helpers/server/zod";
|
|
28
|
+
import { internalActionGeneric } from "convex/server";
|
|
29
|
+
import { Infer, v, Validator } from "convex/values";
|
|
28
30
|
import {
|
|
29
|
-
|
|
31
|
+
promptOrMessagesToCoreMessages,
|
|
30
32
|
serializeMessageWithId,
|
|
31
33
|
serializeNewMessagesInStep,
|
|
32
34
|
serializeStep,
|
|
33
35
|
} from "../mapping";
|
|
36
|
+
import { DEFAULT_MESSAGE_RANGE, extractText } from "../shared";
|
|
34
37
|
|
|
35
38
|
export type ContextOptions = {
|
|
36
|
-
|
|
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
|
+
*/
|
|
37
47
|
recentMessages?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Options for searching messages.
|
|
50
|
+
*/
|
|
38
51
|
searchOptions?: {
|
|
52
|
+
/**
|
|
53
|
+
* The maximum number of messages to fetch.
|
|
54
|
+
*/
|
|
39
55
|
limit: number;
|
|
56
|
+
/**
|
|
57
|
+
* Whether to use text search to find messages.
|
|
58
|
+
*/
|
|
40
59
|
textSearch?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether to use vector search to find messages.
|
|
62
|
+
*/
|
|
41
63
|
vectorSearch?: boolean;
|
|
42
|
-
|
|
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 };
|
|
43
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Whether to search across other chats for relevant messages.
|
|
73
|
+
* By default, only the current chat is searched.
|
|
74
|
+
*/
|
|
44
75
|
searchOtherChats?: boolean;
|
|
45
76
|
};
|
|
46
77
|
|
|
78
|
+
export type StorageOptions = {
|
|
79
|
+
// Defaults to false, allowing you to pass in arbitrary context that will
|
|
80
|
+
// be in addition to automatically fetched content.
|
|
81
|
+
// Pass true to have all input messages saved to the chat history.
|
|
82
|
+
saveAllInputMessages?: boolean;
|
|
83
|
+
// Defaults to true
|
|
84
|
+
saveOutputMessages?: boolean;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type GenerationOutputMetadata = { messageId: string };
|
|
88
|
+
|
|
47
89
|
type CoreMessageMaybeWithId = CoreMessage & { id?: string | undefined };
|
|
48
90
|
|
|
49
|
-
export class Agent {
|
|
91
|
+
export class Agent<AgentTools extends ToolSet> {
|
|
50
92
|
constructor(
|
|
51
93
|
public component: UseApi<typeof api>,
|
|
52
94
|
public options: {
|
|
53
95
|
name?: string;
|
|
54
96
|
chat: LanguageModelV1;
|
|
55
97
|
textEmbedding?: EmbeddingModelV1<string>;
|
|
56
|
-
|
|
57
|
-
tools?:
|
|
98
|
+
instructions?: string;
|
|
99
|
+
tools?: AgentTools;
|
|
100
|
+
contextOptions?: ContextOptions;
|
|
101
|
+
// TODO: storageOptions?: StorageOptions;
|
|
102
|
+
maxSteps?: number;
|
|
103
|
+
// TODO: maxRetries?: number;
|
|
58
104
|
}
|
|
59
105
|
) {}
|
|
60
106
|
|
|
@@ -68,7 +114,7 @@ export class Agent {
|
|
|
68
114
|
* @param args The chat metadata.
|
|
69
115
|
* @returns The chatId of the new chat and the chat object.
|
|
70
116
|
*/
|
|
71
|
-
async
|
|
117
|
+
async createChat(
|
|
72
118
|
ctx: RunActionCtx,
|
|
73
119
|
args: {
|
|
74
120
|
/**
|
|
@@ -93,7 +139,7 @@ export class Agent {
|
|
|
93
139
|
}
|
|
94
140
|
): Promise<{
|
|
95
141
|
chatId: string;
|
|
96
|
-
chat: Chat
|
|
142
|
+
chat: Chat<AgentTools>;
|
|
97
143
|
}>;
|
|
98
144
|
/**
|
|
99
145
|
* Start a new chat with the agent. This will have a fresh history, though if
|
|
@@ -104,7 +150,7 @@ export class Agent {
|
|
|
104
150
|
* @param args The chat metadata.
|
|
105
151
|
* @returns The chatId of the new chat.
|
|
106
152
|
*/
|
|
107
|
-
async
|
|
153
|
+
async createChat(
|
|
108
154
|
ctx: RunMutationCtx,
|
|
109
155
|
args: {
|
|
110
156
|
userId?: string;
|
|
@@ -115,7 +161,7 @@ export class Agent {
|
|
|
115
161
|
): Promise<{
|
|
116
162
|
chatId: string;
|
|
117
163
|
}>;
|
|
118
|
-
async
|
|
164
|
+
async createChat(
|
|
119
165
|
ctx: RunActionCtx | RunMutationCtx,
|
|
120
166
|
args: {
|
|
121
167
|
userId: string;
|
|
@@ -125,10 +171,10 @@ export class Agent {
|
|
|
125
171
|
}
|
|
126
172
|
): Promise<{
|
|
127
173
|
chatId: string;
|
|
128
|
-
chat?: Chat
|
|
174
|
+
chat?: Chat<AgentTools>;
|
|
129
175
|
}> {
|
|
130
176
|
const chatDoc = await ctx.runMutation(this.component.messages.createChat, {
|
|
131
|
-
defaultSystemPrompt: this.options.
|
|
177
|
+
defaultSystemPrompt: this.options.instructions,
|
|
132
178
|
userId: args.userId,
|
|
133
179
|
title: args.title,
|
|
134
180
|
summary: args.summary,
|
|
@@ -154,10 +200,14 @@ export class Agent {
|
|
|
154
200
|
userId,
|
|
155
201
|
}: {
|
|
156
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
|
+
*/
|
|
157
207
|
userId?: string;
|
|
158
208
|
}
|
|
159
209
|
): Promise<{
|
|
160
|
-
chat: Chat
|
|
210
|
+
chat: Chat<AgentTools>;
|
|
161
211
|
}> {
|
|
162
212
|
// return this.component.continueChat(ctx, args);
|
|
163
213
|
return {
|
|
@@ -166,7 +216,7 @@ export class Agent {
|
|
|
166
216
|
streamText: this.streamText.bind(this, ctx, { userId, chatId }),
|
|
167
217
|
generateObject: this.generateObject.bind(this, ctx, { userId, chatId }),
|
|
168
218
|
streamObject: this.streamObject.bind(this, ctx, { userId, chatId }),
|
|
169
|
-
} as Chat
|
|
219
|
+
} as Chat<AgentTools>,
|
|
170
220
|
};
|
|
171
221
|
}
|
|
172
222
|
|
|
@@ -176,12 +226,14 @@ export class Agent {
|
|
|
176
226
|
userId?: string;
|
|
177
227
|
chatId?: string;
|
|
178
228
|
messages: CoreMessage[];
|
|
229
|
+
parentMessageId?: string;
|
|
179
230
|
} & ContextOptions
|
|
180
231
|
): Promise<CoreMessage[]> {
|
|
181
232
|
assert(args.userId || args.chatId, "Specify userId or chatId");
|
|
182
233
|
// Fetch the latest messages from the chat
|
|
183
234
|
const contextMessages: CoreMessage[] = [];
|
|
184
|
-
|
|
235
|
+
const opts = this.mergedContextOptions(args);
|
|
236
|
+
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
185
237
|
if (!("runAction" in ctx)) {
|
|
186
238
|
throw new Error("searchUserMessages only works in an action");
|
|
187
239
|
}
|
|
@@ -190,9 +242,11 @@ export class Agent {
|
|
|
190
242
|
{
|
|
191
243
|
userId: args.searchOtherChats ? args.userId : undefined,
|
|
192
244
|
chatId: args.chatId,
|
|
193
|
-
|
|
245
|
+
parentMessageId: args.parentMessageId,
|
|
246
|
+
...(await this.searchOptionsWithDefaults(opts, args.messages)),
|
|
194
247
|
}
|
|
195
248
|
);
|
|
249
|
+
// TODO: track what messages we used for context
|
|
196
250
|
contextMessages.push(...searchMessages.map((m) => m.message!));
|
|
197
251
|
}
|
|
198
252
|
if (args.chatId) {
|
|
@@ -200,8 +254,9 @@ export class Agent {
|
|
|
200
254
|
this.component.messages.getChatMessages,
|
|
201
255
|
{
|
|
202
256
|
chatId: args.chatId,
|
|
203
|
-
isTool: args.
|
|
257
|
+
isTool: args.includeToolCalls ?? false,
|
|
204
258
|
limit: args.recentMessages,
|
|
259
|
+
parentMessageId: args.parentMessageId,
|
|
205
260
|
order: "desc",
|
|
206
261
|
statuses: ["success"],
|
|
207
262
|
}
|
|
@@ -214,45 +269,33 @@ export class Agent {
|
|
|
214
269
|
async saveMessages(
|
|
215
270
|
ctx: RunMutationCtx,
|
|
216
271
|
args: {
|
|
217
|
-
chatId
|
|
272
|
+
chatId?: string;
|
|
273
|
+
userId?: string;
|
|
218
274
|
messages: CoreMessageMaybeWithId[];
|
|
219
|
-
steps?: StepResult<ToolSet>[];
|
|
220
275
|
pending?: boolean;
|
|
276
|
+
parentMessageId?: string;
|
|
277
|
+
failPendingSteps?: boolean;
|
|
221
278
|
}
|
|
222
279
|
): Promise<{
|
|
223
280
|
lastMessageId: string;
|
|
224
|
-
|
|
225
|
-
async saveMessages(
|
|
226
|
-
ctx: RunMutationCtx,
|
|
227
|
-
args: {
|
|
228
|
-
chatId: string;
|
|
229
|
-
messages: CoreMessageMaybeWithId[];
|
|
230
|
-
steps?: StepResult<ToolSet>[];
|
|
231
|
-
pending?: boolean;
|
|
232
|
-
}
|
|
233
|
-
): Promise<{
|
|
234
|
-
lastMessageId?: string;
|
|
281
|
+
messageIds: string[];
|
|
235
282
|
}> {
|
|
236
283
|
const result = await ctx.runMutation(this.component.messages.addMessages, {
|
|
237
284
|
chatId: args.chatId,
|
|
285
|
+
userId: args.userId,
|
|
238
286
|
agentName: this.options.name,
|
|
239
287
|
model: this.options.chat.modelId,
|
|
240
288
|
messages: args.messages.map(serializeMessageWithId),
|
|
241
|
-
failPendingSteps: true,
|
|
289
|
+
failPendingSteps: args.failPendingSteps ?? true,
|
|
242
290
|
pending: args.pending ?? false,
|
|
291
|
+
parentMessageId: args.parentMessageId,
|
|
243
292
|
});
|
|
244
293
|
return {
|
|
245
|
-
lastMessageId: result.messages.at(-1)
|
|
294
|
+
lastMessageId: result.messages.at(-1)!._id,
|
|
295
|
+
messageIds: result.messages.map((m) => m._id),
|
|
246
296
|
};
|
|
247
297
|
}
|
|
248
298
|
|
|
249
|
-
async replaceMessages(
|
|
250
|
-
ctx: RunMutationCtx,
|
|
251
|
-
args: { chatId: string; messages: Message[] }
|
|
252
|
-
): Promise<void> {
|
|
253
|
-
throw new Error("Not implemented");
|
|
254
|
-
}
|
|
255
|
-
|
|
256
299
|
async saveStep<TOOLS extends ToolSet>(
|
|
257
300
|
ctx: RunMutationCtx,
|
|
258
301
|
args: { chatId: string; messageId: string; step: StepResult<TOOLS> }
|
|
@@ -267,6 +310,7 @@ export class Agent {
|
|
|
267
310
|
});
|
|
268
311
|
}
|
|
269
312
|
|
|
313
|
+
// If you manually create a message, call this to either commit or reset it.
|
|
270
314
|
async completeMessage<TOOLS extends ToolSet>(
|
|
271
315
|
ctx: RunMutationCtx,
|
|
272
316
|
args: {
|
|
@@ -274,10 +318,7 @@ export class Agent {
|
|
|
274
318
|
messageId: string;
|
|
275
319
|
result:
|
|
276
320
|
| { kind: "error"; error: string }
|
|
277
|
-
| {
|
|
278
|
-
kind: "success";
|
|
279
|
-
value: { steps: StepResult<TOOLS>[] };
|
|
280
|
-
};
|
|
321
|
+
| { kind: "success"; value: { steps: StepResult<TOOLS>[] } };
|
|
281
322
|
}
|
|
282
323
|
): Promise<void> {
|
|
283
324
|
const result = args.result;
|
|
@@ -317,11 +358,14 @@ export class Agent {
|
|
|
317
358
|
userId?: string;
|
|
318
359
|
chatId?: string;
|
|
319
360
|
},
|
|
320
|
-
args:
|
|
361
|
+
args: TextArgs<
|
|
362
|
+
AgentTools,
|
|
363
|
+
TOOLS,
|
|
321
364
|
Parameters<typeof generateText<TOOLS, OUTPUT, OUTPUT_PARTIAL>>[0]
|
|
322
|
-
>
|
|
323
|
-
|
|
324
|
-
|
|
365
|
+
>
|
|
366
|
+
): Promise<
|
|
367
|
+
GenerateTextResult<TOOLS & AgentTools, OUTPUT> & GenerationOutputMetadata
|
|
368
|
+
> {
|
|
325
369
|
const { prompt, messages: raw, ...rest } = args;
|
|
326
370
|
const messages = promptOrMessagesToCoreMessages({ prompt, messages: raw });
|
|
327
371
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
@@ -330,24 +374,28 @@ export class Agent {
|
|
|
330
374
|
chatId,
|
|
331
375
|
messages,
|
|
332
376
|
});
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
377
|
+
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
378
|
+
chatId,
|
|
379
|
+
userId,
|
|
380
|
+
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
381
|
+
pending: true,
|
|
382
|
+
parentMessageId: args.parentMessageId,
|
|
383
|
+
});
|
|
384
|
+
const toolCtx = { ...ctx, userId, chatId, messageId };
|
|
385
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
343
386
|
try {
|
|
344
387
|
const result = await generateText({
|
|
345
388
|
model: this.options.chat,
|
|
346
389
|
messages: [...contextMessages, ...messages],
|
|
347
|
-
system: this.options.
|
|
390
|
+
system: this.options.instructions,
|
|
391
|
+
maxSteps: this.options.maxSteps,
|
|
392
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
393
|
+
toolChoice: args.toolChoice as any,
|
|
348
394
|
...rest,
|
|
395
|
+
tools,
|
|
349
396
|
onStepFinish: async (step) => {
|
|
350
|
-
if (chatId && messageId) {
|
|
397
|
+
if (chatId && messageId && args.saveOutputMessages) {
|
|
398
|
+
console.log("onStepFinish", step);
|
|
351
399
|
await this.saveStep(ctx, {
|
|
352
400
|
chatId,
|
|
353
401
|
messageId,
|
|
@@ -357,9 +405,10 @@ export class Agent {
|
|
|
357
405
|
return args.onStepFinish?.(step);
|
|
358
406
|
},
|
|
359
407
|
});
|
|
360
|
-
return result;
|
|
408
|
+
return { ...result, messageId };
|
|
361
409
|
} catch (error) {
|
|
362
410
|
if (chatId && messageId) {
|
|
411
|
+
console.error("RollbackMessage", messageId);
|
|
363
412
|
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
364
413
|
messageId,
|
|
365
414
|
error: (error as Error).message,
|
|
@@ -374,13 +423,16 @@ export class Agent {
|
|
|
374
423
|
OUTPUT = never,
|
|
375
424
|
PARTIAL_OUTPUT = never,
|
|
376
425
|
>(
|
|
377
|
-
ctx:
|
|
426
|
+
ctx: RunActionCtx,
|
|
378
427
|
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
379
|
-
args:
|
|
428
|
+
args: TextArgs<
|
|
429
|
+
AgentTools,
|
|
430
|
+
TOOLS,
|
|
380
431
|
Parameters<typeof streamText<TOOLS, OUTPUT, PARTIAL_OUTPUT>>[0]
|
|
381
|
-
>
|
|
382
|
-
|
|
383
|
-
|
|
432
|
+
>
|
|
433
|
+
): Promise<
|
|
434
|
+
StreamTextResult<TOOLS, PARTIAL_OUTPUT> & GenerationOutputMetadata
|
|
435
|
+
> {
|
|
384
436
|
const { prompt, messages: raw, ...rest } = args;
|
|
385
437
|
const messages = promptOrMessagesToCoreMessages({ prompt, messages: raw });
|
|
386
438
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
@@ -389,21 +441,23 @@ export class Agent {
|
|
|
389
441
|
chatId,
|
|
390
442
|
messages,
|
|
391
443
|
});
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
return streamText({
|
|
444
|
+
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
445
|
+
chatId,
|
|
446
|
+
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
447
|
+
pending: true,
|
|
448
|
+
parentMessageId: args.parentMessageId,
|
|
449
|
+
});
|
|
450
|
+
const toolCtx = { ...ctx, userId, chatId, messageId };
|
|
451
|
+
const tools = wrapTools(toolCtx, this.options.tools, args.tools) as TOOLS;
|
|
452
|
+
const result = streamText({
|
|
403
453
|
model: this.options.chat,
|
|
404
454
|
messages: [...contextMessages, ...messages],
|
|
405
|
-
system: this.options.
|
|
455
|
+
system: this.options.instructions,
|
|
456
|
+
maxSteps: this.options.maxSteps,
|
|
457
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
458
|
+
toolChoice: args.toolChoice as any,
|
|
406
459
|
...rest,
|
|
460
|
+
tools,
|
|
407
461
|
onChunk: async (chunk) => {
|
|
408
462
|
console.log("onChunk", chunk);
|
|
409
463
|
return args.onChunk?.(chunk);
|
|
@@ -436,16 +490,18 @@ export class Agent {
|
|
|
436
490
|
return args.onStepFinish?.(step);
|
|
437
491
|
},
|
|
438
492
|
});
|
|
493
|
+
return { ...result, messageId };
|
|
439
494
|
}
|
|
440
495
|
|
|
441
|
-
// TODO:
|
|
442
|
-
async generateObject<
|
|
496
|
+
// TODO: add the crazy number of overloads to get types through
|
|
497
|
+
async generateObject<T>(
|
|
443
498
|
ctx: RunActionCtx,
|
|
444
499
|
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
445
|
-
args: Omit<Parameters<typeof generateObject
|
|
500
|
+
args: Omit<Parameters<typeof generateObject>[0], "model"> & {
|
|
446
501
|
model?: LanguageModelV1;
|
|
447
|
-
} & ContextOptions
|
|
448
|
-
|
|
502
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
503
|
+
StorageOptions
|
|
504
|
+
): Promise<GenerateObjectResult<T> & GenerationOutputMetadata> {
|
|
449
505
|
const { prompt, messages: raw, ...rest } = args;
|
|
450
506
|
const messages = promptOrMessagesToCoreMessages({ prompt, messages: raw });
|
|
451
507
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
@@ -454,11 +510,17 @@ export class Agent {
|
|
|
454
510
|
chatId,
|
|
455
511
|
messages,
|
|
456
512
|
});
|
|
457
|
-
|
|
513
|
+
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
514
|
+
chatId,
|
|
515
|
+
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
516
|
+
pending: true,
|
|
517
|
+
});
|
|
518
|
+
const result = (await generateObject({
|
|
458
519
|
model: this.options.chat,
|
|
459
520
|
messages: [...contextMessages, ...messages],
|
|
460
521
|
...rest,
|
|
461
|
-
}) as
|
|
522
|
+
})) as GenerateObjectResult<T>;
|
|
523
|
+
return { ...result, messageId };
|
|
462
524
|
}
|
|
463
525
|
|
|
464
526
|
async streamObject<T>(
|
|
@@ -466,8 +528,11 @@ export class Agent {
|
|
|
466
528
|
{ userId, chatId }: { userId?: string; chatId?: string },
|
|
467
529
|
args: Omit<Parameters<typeof streamObject<T>>[0], "model"> & {
|
|
468
530
|
model?: LanguageModelV1;
|
|
469
|
-
} & ContextOptions
|
|
470
|
-
|
|
531
|
+
} & { parentMessageId?: string } & ContextOptions &
|
|
532
|
+
StorageOptions
|
|
533
|
+
): Promise<
|
|
534
|
+
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
535
|
+
> {
|
|
471
536
|
const { prompt, messages: raw, ...rest } = args;
|
|
472
537
|
const messages = promptOrMessagesToCoreMessages({ prompt, messages: raw });
|
|
473
538
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
@@ -476,7 +541,12 @@ export class Agent {
|
|
|
476
541
|
chatId,
|
|
477
542
|
messages,
|
|
478
543
|
});
|
|
479
|
-
|
|
544
|
+
const { lastMessageId: messageId } = await this.saveMessages(ctx, {
|
|
545
|
+
chatId,
|
|
546
|
+
messages: args.saveAllInputMessages ? messages : messages.slice(-1),
|
|
547
|
+
pending: true,
|
|
548
|
+
});
|
|
549
|
+
const result = streamObject<T>({
|
|
480
550
|
model: this.options.chat,
|
|
481
551
|
messages: [...contextMessages, ...messages],
|
|
482
552
|
...rest,
|
|
@@ -488,29 +558,44 @@ export class Agent {
|
|
|
488
558
|
console.log("onFinish", result);
|
|
489
559
|
},
|
|
490
560
|
}) as StreamObjectResult<DeepPartial<T>, T, never>;
|
|
561
|
+
return { ...result, messageId };
|
|
491
562
|
}
|
|
492
563
|
|
|
493
|
-
|
|
494
|
-
|
|
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
|
+
|
|
578
|
+
async searchOptionsWithDefaults(
|
|
579
|
+
contextOptions: ContextOptions,
|
|
495
580
|
messages: CoreMessage[]
|
|
496
581
|
): Promise<SearchOptions> {
|
|
497
582
|
assert(
|
|
498
|
-
|
|
499
|
-
|
|
583
|
+
contextOptions.searchOptions?.textSearch ||
|
|
584
|
+
contextOptions.searchOptions?.vectorSearch,
|
|
500
585
|
"searchOptions is required"
|
|
501
586
|
);
|
|
502
587
|
assert(messages.length > 0, "Core messages cannot be empty");
|
|
503
588
|
const text = extractText(messages.at(-1)!);
|
|
504
589
|
const search: SearchOptions = {
|
|
505
|
-
limit:
|
|
590
|
+
limit: contextOptions.searchOptions?.limit ?? 10,
|
|
506
591
|
messageRange: {
|
|
507
592
|
...DEFAULT_MESSAGE_RANGE,
|
|
508
|
-
...
|
|
593
|
+
...contextOptions.searchOptions?.messageRange,
|
|
509
594
|
},
|
|
510
595
|
text: extractText(messages.at(-1)!),
|
|
511
596
|
};
|
|
512
597
|
if (
|
|
513
|
-
|
|
598
|
+
contextOptions.searchOptions?.vectorSearch &&
|
|
514
599
|
text &&
|
|
515
600
|
this.options.textEmbedding
|
|
516
601
|
) {
|
|
@@ -524,136 +609,247 @@ export class Agent {
|
|
|
524
609
|
return search;
|
|
525
610
|
}
|
|
526
611
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
.
|
|
556
|
-
.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
+
});
|
|
560
696
|
}
|
|
561
697
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
+
});
|
|
729
|
+
}
|
|
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
|
+
}
|
|
569
795
|
}
|
|
796
|
+
return output;
|
|
570
797
|
}
|
|
571
798
|
|
|
572
|
-
|
|
799
|
+
type TextArgs<
|
|
800
|
+
AgentTools extends ToolSet,
|
|
801
|
+
TOOLS extends ToolSet,
|
|
802
|
+
T extends {
|
|
803
|
+
toolChoice?: ToolChoice<TOOLS & AgentTools>;
|
|
804
|
+
tools?: TOOLS;
|
|
805
|
+
model: LanguageModelV1;
|
|
806
|
+
},
|
|
807
|
+
> = Omit<T, "toolChoice" | "tools" | "model"> & {
|
|
808
|
+
model?: LanguageModelV1;
|
|
809
|
+
parentMessageId?: string;
|
|
810
|
+
} & {
|
|
811
|
+
tools?: TOOLS;
|
|
812
|
+
toolChoice?: ToolChoice<{ [key in keyof TOOLS | keyof AgentTools]: unknown }>;
|
|
813
|
+
} & ContextOptions &
|
|
814
|
+
StorageOptions;
|
|
815
|
+
|
|
816
|
+
type ObjectArgs<
|
|
817
|
+
T extends {
|
|
818
|
+
model: LanguageModelV1;
|
|
819
|
+
},
|
|
820
|
+
> = Omit<T, "model"> & {
|
|
821
|
+
model?: LanguageModelV1;
|
|
822
|
+
} & ContextOptions &
|
|
823
|
+
StorageOptions;
|
|
824
|
+
|
|
825
|
+
interface Chat<AgentTools extends ToolSet> {
|
|
573
826
|
generateText<TOOLS extends ToolSet, OUTPUT = never, OUTPUT_PARTIAL = never>(
|
|
574
|
-
args:
|
|
827
|
+
args: TextArgs<
|
|
828
|
+
AgentTools,
|
|
829
|
+
TOOLS,
|
|
575
830
|
Parameters<typeof generateText<TOOLS, OUTPUT, OUTPUT_PARTIAL>>[0]
|
|
576
831
|
>
|
|
577
|
-
): Promise<
|
|
832
|
+
): Promise<
|
|
833
|
+
GenerateTextResult<TOOLS & AgentTools, OUTPUT> & GenerationOutputMetadata
|
|
834
|
+
>;
|
|
835
|
+
|
|
578
836
|
streamText<TOOLS extends ToolSet, OUTPUT = never, PARTIAL_OUTPUT = never>(
|
|
579
|
-
args:
|
|
837
|
+
args: TextArgs<
|
|
838
|
+
AgentTools,
|
|
839
|
+
TOOLS,
|
|
580
840
|
Parameters<typeof streamText<TOOLS, OUTPUT, PARTIAL_OUTPUT>>[0]
|
|
581
841
|
>
|
|
582
|
-
): Promise<
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
842
|
+
): Promise<
|
|
843
|
+
StreamTextResult<TOOLS & AgentTools, PARTIAL_OUTPUT> &
|
|
844
|
+
GenerationOutputMetadata
|
|
845
|
+
>;
|
|
846
|
+
// TODO: add all the overloads
|
|
847
|
+
generateObject<T>(
|
|
848
|
+
args: ObjectArgs<Parameters<typeof generateObject>[0]>
|
|
849
|
+
): Promise<GenerateObjectResult<T> & GenerationOutputMetadata>;
|
|
588
850
|
streamObject<T>(
|
|
589
|
-
args:
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// type ToolParameters = ZodTypeAny | Schema<unknown>; // TODO: support convex validator
|
|
596
|
-
// type inferParameters<PARAMETERS extends ToolParameters> =
|
|
597
|
-
// PARAMETERS extends Schema<unknown>
|
|
598
|
-
// ? PARAMETERS["_type"]
|
|
599
|
-
// : PARAMETERS extends z.ZodTypeAny
|
|
600
|
-
// ? z.infer<PARAMETERS>
|
|
601
|
-
// : never;
|
|
602
|
-
// /**
|
|
603
|
-
// * This is a wrapper around the ai.tool function that adds support for
|
|
604
|
-
// * userId and chatId to the tool, if they're called within a chat from an agent.
|
|
605
|
-
// * @param tool The AI tool. See https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling
|
|
606
|
-
// * @returns The same tool, but with userId and chatId args support added.
|
|
607
|
-
// */
|
|
608
|
-
// export function tool<PARAMETERS extends ToolParameters, RESULT>(
|
|
609
|
-
// tool: Tool<PARAMETERS, RESULT> & {
|
|
610
|
-
// execute: (
|
|
611
|
-
// args: inferParameters<PARAMETERS> & { userId?: string; chatId?: string },
|
|
612
|
-
// options: ToolExecutionOptions
|
|
613
|
-
// ) => PromiseLike<RESULT>;
|
|
614
|
-
// }
|
|
615
|
-
// ): Tool<PARAMETERS, RESULT> & {
|
|
616
|
-
// execute: (
|
|
617
|
-
// args: inferParameters<PARAMETERS>,
|
|
618
|
-
// options: ToolExecutionOptions
|
|
619
|
-
// ) => PromiseLike<RESULT>;
|
|
620
|
-
// } {
|
|
621
|
-
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
622
|
-
// (tool as any).__acceptUserIdAndChatId = true;
|
|
623
|
-
// return tool;
|
|
624
|
-
// }
|
|
625
|
-
|
|
626
|
-
export function promptOrMessagesToCoreMessages(args: {
|
|
627
|
-
system?: string;
|
|
628
|
-
prompt?: string;
|
|
629
|
-
messages?: CoreMessage[] | Omit<UIMessage, "id">[];
|
|
630
|
-
}): CoreMessage[] {
|
|
631
|
-
const messages: CoreMessage[] = [];
|
|
632
|
-
if (args.system) {
|
|
633
|
-
messages.push({ role: "system", content: args.system });
|
|
634
|
-
}
|
|
635
|
-
if (!args.messages) {
|
|
636
|
-
assert(args.prompt, "messages or prompt is required");
|
|
637
|
-
messages.push({ role: "user", content: args.prompt });
|
|
638
|
-
} else if (
|
|
639
|
-
args.messages.some(
|
|
640
|
-
(m) =>
|
|
641
|
-
typeof m === "object" &&
|
|
642
|
-
m !== null &&
|
|
643
|
-
(m.role === "data" || // UI-only role
|
|
644
|
-
"toolInvocations" in m || // UI-specific field
|
|
645
|
-
"parts" in m || // UI-specific field
|
|
646
|
-
"experimental_attachments" in m)
|
|
647
|
-
)
|
|
648
|
-
) {
|
|
649
|
-
messages.push(...convertToCoreMessages(args.messages as UIMessage[]));
|
|
650
|
-
} else {
|
|
651
|
-
messages.push(...coreMessageSchema.array().parse(args.messages));
|
|
652
|
-
}
|
|
653
|
-
assert(messages.length > 0, "Messages must contain at least one message");
|
|
654
|
-
return messages;
|
|
851
|
+
args: ObjectArgs<Parameters<typeof streamObject<T>>[0]>
|
|
852
|
+
): Promise<
|
|
853
|
+
StreamObjectResult<DeepPartial<T>, T, never> & GenerationOutputMetadata
|
|
854
|
+
>;
|
|
655
855
|
}
|
|
656
|
-
|
|
657
|
-
// export function convexValidatorSchema<T>(validator: Validator<unknown>) {
|
|
658
|
-
// return ai.jsonSchema(convexToJsonSchema(validator));
|
|
659
|
-
// }
|