@convex-dev/agent 0.1.18 → 0.2.0
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/dist/client/createTool.d.ts +30 -11
- package/dist/client/createTool.d.ts.map +1 -1
- package/dist/client/createTool.js +24 -10
- package/dist/client/createTool.js.map +1 -1
- package/dist/client/defaultComponent.d.ts +11 -0
- package/dist/client/defaultComponent.d.ts.map +1 -0
- package/dist/client/defaultComponent.js +7 -0
- package/dist/client/defaultComponent.js.map +1 -0
- package/dist/client/definePlaygroundAPI.d.ts +68 -23
- package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/client/definePlaygroundAPI.js +7 -20
- package/dist/client/definePlaygroundAPI.js.map +1 -1
- package/dist/client/files.d.ts +14 -4
- package/dist/client/files.d.ts.map +1 -1
- package/dist/client/files.js +66 -11
- package/dist/client/files.js.map +1 -1
- package/dist/client/index.d.ts +323 -780
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +445 -543
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +256 -0
- package/dist/client/messages.d.ts.map +1 -0
- package/dist/client/messages.js +97 -0
- package/dist/client/messages.js.map +1 -0
- package/dist/client/search.d.ts +35 -12
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/search.js +21 -4
- package/dist/client/search.js.map +1 -1
- package/dist/client/streaming.d.ts +21 -21
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +35 -40
- package/dist/client/streaming.js.map +1 -1
- package/dist/client/threads.d.ts +46 -0
- package/dist/client/threads.d.ts.map +1 -0
- package/dist/client/threads.js +49 -0
- package/dist/client/threads.js.map +1 -0
- package/dist/client/types.d.ts +159 -75
- package/dist/client/types.d.ts.map +1 -1
- package/dist/component/_generated/api.d.ts +261 -209
- package/dist/component/messages.d.ts +314 -105
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +141 -83
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +631 -870
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +11 -16
- package/dist/component/schema.js.map +1 -1
- package/dist/component/streams.d.ts +29 -149
- package/dist/component/streams.d.ts.map +1 -1
- package/dist/component/streams.js +104 -60
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts +4 -4
- package/dist/component/users.d.ts +3 -3
- package/dist/mapping.d.ts +15 -16
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +208 -62
- package/dist/mapping.js.map +1 -1
- package/dist/parts.d.ts +3 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +34 -0
- package/dist/parts.js.map +1 -0
- package/dist/react/SmoothText.d.ts +5 -0
- package/dist/react/SmoothText.d.ts.map +1 -0
- package/dist/react/SmoothText.js +6 -0
- package/dist/react/SmoothText.js.map +1 -0
- package/dist/react/deltas.d.ts +3 -5
- package/dist/react/deltas.d.ts.map +1 -1
- package/dist/react/deltas.js +89 -53
- package/dist/react/deltas.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +31 -11
- package/dist/react/index.js.map +1 -1
- package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
- package/dist/react/optimisticallySendMessage.js +2 -8
- package/dist/react/optimisticallySendMessage.js.map +1 -1
- package/dist/react/toUIMessages.d.ts +5 -4
- package/dist/react/toUIMessages.d.ts.map +1 -1
- package/dist/react/toUIMessages.js +103 -40
- package/dist/react/toUIMessages.js.map +1 -1
- package/dist/react/useSmoothText.d.ts +13 -12
- package/dist/react/useSmoothText.d.ts.map +1 -1
- package/dist/react/useSmoothText.js +1 -1
- package/dist/react/useSmoothText.js.map +1 -1
- package/dist/validators.d.ts +751 -1464
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +39 -80
- package/dist/validators.js.map +1 -1
- package/package.json +34 -30
- package/src/client/createTool.ts +66 -40
- package/src/client/defaultComponent.ts +17 -0
- package/src/client/definePlaygroundAPI.ts +17 -31
- package/src/client/files.ts +94 -17
- package/src/client/index.test.ts +28 -38
- package/src/client/index.ts +785 -977
- package/src/client/messages.ts +205 -0
- package/src/client/search.ts +37 -10
- package/src/client/streaming.ts +53 -56
- package/src/client/threads.ts +78 -0
- package/src/client/types.ts +239 -131
- package/src/component/_generated/api.d.ts +261 -209
- package/src/component/messages.test.ts +182 -40
- package/src/component/messages.ts +165 -108
- package/src/component/schema.ts +11 -17
- package/src/component/streams.ts +180 -69
- package/src/mapping.ts +253 -96
- package/src/parts.ts +39 -0
- package/src/react/SmoothText.tsx +9 -0
- package/src/react/deltas.test.ts +38 -42
- package/src/react/deltas.ts +116 -65
- package/src/react/index.ts +35 -13
- package/src/react/optimisticallySendMessage.ts +2 -8
- package/src/react/toUIMessages.test.ts +154 -36
- package/src/react/toUIMessages.ts +136 -57
- package/src/react/useSmoothText.ts +14 -15
- package/src/validators.test.ts +1 -117
- package/src/validators.ts +57 -107
- package/dist/client/listMessages.d.ts +0 -22
- package/dist/client/listMessages.d.ts.map +0 -1
- package/dist/client/listMessages.js +0 -25
- package/dist/client/listMessages.js.map +0 -1
- package/src/client/listMessages.ts +0 -38
package/src/client/index.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
import type { EmbeddingModelV1, LanguageModelV1 } from "@ai-sdk/provider";
|
|
2
1
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
FlexibleSchema,
|
|
3
|
+
IdGenerator,
|
|
4
|
+
InferSchema,
|
|
5
|
+
} from "@ai-sdk/provider-utils";
|
|
6
|
+
import type {
|
|
7
|
+
CallSettings,
|
|
8
|
+
EmbeddingModel,
|
|
7
9
|
GenerateObjectResult,
|
|
8
10
|
GenerateTextResult,
|
|
9
|
-
|
|
11
|
+
LanguageModel,
|
|
12
|
+
ModelMessage,
|
|
10
13
|
StepResult,
|
|
11
|
-
|
|
14
|
+
StopCondition,
|
|
12
15
|
StreamTextResult,
|
|
16
|
+
ToolChoice,
|
|
13
17
|
ToolSet,
|
|
14
|
-
UserContent,
|
|
15
18
|
} from "ai";
|
|
16
19
|
import {
|
|
17
20
|
embedMany,
|
|
18
21
|
generateObject,
|
|
19
22
|
generateText,
|
|
23
|
+
stepCountIs,
|
|
20
24
|
streamObject,
|
|
21
25
|
streamText,
|
|
22
26
|
} from "ai";
|
|
@@ -24,13 +28,12 @@ import { assert, omit, pick } from "convex-helpers";
|
|
|
24
28
|
import {
|
|
25
29
|
internalActionGeneric,
|
|
26
30
|
internalMutationGeneric,
|
|
27
|
-
type GenericActionCtx,
|
|
28
31
|
type GenericDataModel,
|
|
29
32
|
type PaginationOptions,
|
|
30
33
|
type PaginationResult,
|
|
31
34
|
type WithoutSystemFields,
|
|
32
35
|
} from "convex/server";
|
|
33
|
-
import { v } from "convex/values";
|
|
36
|
+
import { convexToJson, v, type Value } from "convex/values";
|
|
34
37
|
import type { MessageDoc, ThreadDoc } from "../component/schema.js";
|
|
35
38
|
import type { threadFieldsSupportingPatch } from "../component/threads.js";
|
|
36
39
|
import {
|
|
@@ -38,57 +41,77 @@ import {
|
|
|
38
41
|
type VectorDimension,
|
|
39
42
|
} from "../component/vector/tables.js";
|
|
40
43
|
import {
|
|
41
|
-
type AIMessageWithoutId,
|
|
42
44
|
deserializeMessage,
|
|
43
|
-
promptOrMessagesToCoreMessages,
|
|
44
45
|
serializeMessage,
|
|
45
46
|
serializeNewMessagesInStep,
|
|
46
47
|
serializeObjectResult,
|
|
47
48
|
} from "../mapping.js";
|
|
48
49
|
import { extractText, isTool } from "../shared.js";
|
|
49
50
|
import {
|
|
50
|
-
|
|
51
|
+
vMessageEmbeddings,
|
|
52
|
+
vMessageWithMetadata,
|
|
53
|
+
vSafeObjectArgs,
|
|
54
|
+
vTextArgs,
|
|
55
|
+
type Message,
|
|
51
56
|
type MessageStatus,
|
|
52
57
|
type MessageWithMetadata,
|
|
53
58
|
type ProviderMetadata,
|
|
54
59
|
type StreamArgs,
|
|
55
60
|
type Usage,
|
|
56
|
-
vMessageWithMetadata,
|
|
57
|
-
vSafeObjectArgs,
|
|
58
|
-
vTextArgs,
|
|
59
61
|
} from "../validators.js";
|
|
60
|
-
import { createTool, wrapTools } from "./createTool.js";
|
|
61
|
-
import {
|
|
62
|
-
|
|
62
|
+
import { createTool, wrapTools, type ToolCtx } from "./createTool.js";
|
|
63
|
+
import {
|
|
64
|
+
listMessages,
|
|
65
|
+
saveMessages,
|
|
66
|
+
type SaveMessageArgs,
|
|
67
|
+
type SaveMessagesArgs,
|
|
68
|
+
} from "./messages.js";
|
|
69
|
+
import {
|
|
70
|
+
fetchContextMessages,
|
|
71
|
+
getModelName,
|
|
72
|
+
getProviderName,
|
|
73
|
+
} from "./search.js";
|
|
63
74
|
import {
|
|
64
75
|
DeltaStreamer,
|
|
65
76
|
mergeTransforms,
|
|
66
|
-
type StreamingOptions,
|
|
67
77
|
syncStreams,
|
|
78
|
+
type StreamingOptions,
|
|
68
79
|
} from "./streaming.js";
|
|
80
|
+
import { createThread, getThreadMetadata } from "./threads.js";
|
|
69
81
|
import type {
|
|
70
82
|
ActionCtx,
|
|
71
83
|
AgentComponent,
|
|
72
84
|
ContextOptions,
|
|
85
|
+
DefaultObjectSchema,
|
|
73
86
|
GenerationOutputMetadata,
|
|
87
|
+
MaybeCustomCtx,
|
|
88
|
+
GenerateObjectArgs,
|
|
89
|
+
ObjectMode,
|
|
90
|
+
ObjectSchema,
|
|
74
91
|
Options,
|
|
75
|
-
OurObjectArgs,
|
|
76
|
-
OurStreamObjectArgs,
|
|
77
92
|
RawRequestResponseHandler,
|
|
78
93
|
RunActionCtx,
|
|
79
94
|
RunMutationCtx,
|
|
80
95
|
RunQueryCtx,
|
|
81
96
|
StorageOptions,
|
|
82
97
|
StreamingTextArgs,
|
|
98
|
+
StreamObjectArgs,
|
|
83
99
|
SyncStreamsReturnValue,
|
|
84
100
|
TextArgs,
|
|
85
101
|
Thread,
|
|
86
102
|
UsageHandler,
|
|
87
103
|
UserActionCtx,
|
|
88
104
|
} from "./types.js";
|
|
105
|
+
import { inlineMessagesFiles } from "./files.js";
|
|
106
|
+
import type { DataModel } from "../component/_generated/dataModel.js";
|
|
89
107
|
|
|
108
|
+
export { stepCountIs } from "ai";
|
|
90
109
|
export { vMessageDoc, vThreadDoc } from "../component/schema.js";
|
|
91
|
-
export {
|
|
110
|
+
export {
|
|
111
|
+
deserializeMessage,
|
|
112
|
+
serializeDataOrUrl,
|
|
113
|
+
serializeMessage,
|
|
114
|
+
} from "../mapping.js";
|
|
92
115
|
// NOTE: these are also exported via @convex-dev/agent/validators
|
|
93
116
|
// a future version may put them all here or move these over there
|
|
94
117
|
export {
|
|
@@ -105,22 +128,26 @@ export {
|
|
|
105
128
|
vUserMessage,
|
|
106
129
|
} from "../validators.js";
|
|
107
130
|
export type { ToolCtx } from "./createTool.js";
|
|
108
|
-
export { getFile, storeFile } from "./files.js";
|
|
109
|
-
export { filterOutOrphanedToolMessages } from "./search.js";
|
|
110
|
-
export { abortStream, listStreams } from "./streaming.js";
|
|
111
|
-
export {
|
|
112
|
-
createTool,
|
|
113
|
-
extractText,
|
|
114
|
-
fetchContextMessages,
|
|
115
|
-
isTool,
|
|
116
|
-
listMessages,
|
|
117
|
-
syncStreams,
|
|
118
|
-
};
|
|
119
131
|
export {
|
|
120
132
|
definePlaygroundAPI,
|
|
121
|
-
type PlaygroundAPI,
|
|
122
133
|
type AgentsFn,
|
|
134
|
+
type PlaygroundAPI,
|
|
123
135
|
} from "./definePlaygroundAPI.js";
|
|
136
|
+
export { getFile, storeFile } from "./files.js";
|
|
137
|
+
export {
|
|
138
|
+
listMessages,
|
|
139
|
+
saveMessage,
|
|
140
|
+
saveMessages,
|
|
141
|
+
type SaveMessageArgs,
|
|
142
|
+
type SaveMessagesArgs,
|
|
143
|
+
} from "./messages.js";
|
|
144
|
+
export {
|
|
145
|
+
fetchContextMessages,
|
|
146
|
+
filterOutOrphanedToolMessages,
|
|
147
|
+
} from "./search.js";
|
|
148
|
+
export { abortStream, listStreams, syncStreams } from "./streaming.js";
|
|
149
|
+
export { createThread, getThreadMetadata } from "./threads.js";
|
|
150
|
+
export { createTool, extractText, isTool };
|
|
124
151
|
export type {
|
|
125
152
|
AgentComponent,
|
|
126
153
|
ContextOptions,
|
|
@@ -136,6 +163,55 @@ export type {
|
|
|
136
163
|
UsageHandler,
|
|
137
164
|
};
|
|
138
165
|
|
|
166
|
+
export type Config = {
|
|
167
|
+
/**
|
|
168
|
+
* The LLM model to use for generating / streaming text and objects.
|
|
169
|
+
* e.g.
|
|
170
|
+
* import { openai } from "@ai-sdk/openai"
|
|
171
|
+
* const myAgent = new Agent(components.agent, {
|
|
172
|
+
* languageModel: openai.chat("gpt-4o-mini"),
|
|
173
|
+
*/
|
|
174
|
+
languageModel?: LanguageModel;
|
|
175
|
+
/**
|
|
176
|
+
* The model to use for text embeddings. Optional.
|
|
177
|
+
* If specified, it will use this for generating vector embeddings
|
|
178
|
+
* of chats, and can opt-in to doing vector search for automatic context
|
|
179
|
+
* on generateText, etc.
|
|
180
|
+
* e.g.
|
|
181
|
+
* import { openai } from "@ai-sdk/openai"
|
|
182
|
+
* const myAgent = new Agent(components.agent, {
|
|
183
|
+
* ...
|
|
184
|
+
* textEmbeddingModel: openai.embedding("text-embedding-3-small")
|
|
185
|
+
*/
|
|
186
|
+
textEmbeddingModel?: EmbeddingModel<string>;
|
|
187
|
+
/**
|
|
188
|
+
* Options to determine what messages are included as context in message
|
|
189
|
+
* generation. To disable any messages automatically being added, pass:
|
|
190
|
+
* { recentMessages: 0 }
|
|
191
|
+
*/
|
|
192
|
+
contextOptions?: ContextOptions;
|
|
193
|
+
/**
|
|
194
|
+
* Determines whether messages are automatically stored when passed as
|
|
195
|
+
* arguments or generated.
|
|
196
|
+
*/
|
|
197
|
+
storageOptions?: StorageOptions;
|
|
198
|
+
/**
|
|
199
|
+
* The default settings to use for the LLM calls.
|
|
200
|
+
* This can be overridden at each generate/stream callsite on a per-field
|
|
201
|
+
* basis. To clear a default setting, you'll need to pass `undefined`.
|
|
202
|
+
*/
|
|
203
|
+
callSettings?: CallSettings;
|
|
204
|
+
/**
|
|
205
|
+
* The usage handler to use for this agent.
|
|
206
|
+
*/
|
|
207
|
+
usageHandler?: UsageHandler;
|
|
208
|
+
/**
|
|
209
|
+
* Called for each LLM request/response, so you can do things like
|
|
210
|
+
* log the raw request body or response headers to a table, or logs.
|
|
211
|
+
*/
|
|
212
|
+
rawRequestResponseHandler?: RawRequestResponseHandler;
|
|
213
|
+
};
|
|
214
|
+
|
|
139
215
|
export class Agent<
|
|
140
216
|
/**
|
|
141
217
|
* You can require that all `ctx` args to generateText & streamText
|
|
@@ -162,7 +238,7 @@ export class Agent<
|
|
|
162
238
|
> {
|
|
163
239
|
constructor(
|
|
164
240
|
public component: AgentComponent,
|
|
165
|
-
public options: {
|
|
241
|
+
public options: Config & {
|
|
166
242
|
/**
|
|
167
243
|
* The name for the agent. This will be attributed on each message
|
|
168
244
|
* created by this agent.
|
|
@@ -173,20 +249,9 @@ export class Agent<
|
|
|
173
249
|
* e.g.
|
|
174
250
|
* import { openai } from "@ai-sdk/openai"
|
|
175
251
|
* const myAgent = new Agent(components.agent, {
|
|
176
|
-
*
|
|
177
|
-
*/
|
|
178
|
-
chat: LanguageModelV1;
|
|
179
|
-
/**
|
|
180
|
-
* The model to use for text embeddings. Optional.
|
|
181
|
-
* If specified, it will use this for generating vector embeddings
|
|
182
|
-
* of chats, and can opt-in to doing vector search for automatic context
|
|
183
|
-
* on generateText, etc.
|
|
184
|
-
* e.g.
|
|
185
|
-
* import { openai } from "@ai-sdk/openai"
|
|
186
|
-
* const myAgent = new Agent(components.agent, {
|
|
187
|
-
* textEmbedding: openai.embedding("text-embedding-3-small")
|
|
252
|
+
* languageModel: openai.chat("gpt-4o-mini"),
|
|
188
253
|
*/
|
|
189
|
-
|
|
254
|
+
languageModel: LanguageModel;
|
|
190
255
|
/**
|
|
191
256
|
* The default system prompt to put in each request.
|
|
192
257
|
* Override per-prompt by passing the "system" parameter.
|
|
@@ -199,36 +264,15 @@ export class Agent<
|
|
|
199
264
|
* (import { createTool } from "@convex-dev/agent")
|
|
200
265
|
*/
|
|
201
266
|
tools?: AgentTools;
|
|
202
|
-
/**
|
|
203
|
-
* Options to determine what messages are included as context in message
|
|
204
|
-
* generation. To disable any messages automatically being added, pass:
|
|
205
|
-
* { recentMessages: 0 }
|
|
206
|
-
*/
|
|
207
|
-
contextOptions?: ContextOptions;
|
|
208
|
-
/**
|
|
209
|
-
* Determines whether messages are automatically stored when passed as
|
|
210
|
-
* arguments or generated.
|
|
211
|
-
*/
|
|
212
|
-
storageOptions?: StorageOptions;
|
|
213
267
|
/**
|
|
214
268
|
* When generating or streaming text with tools available, this
|
|
215
|
-
* determines
|
|
216
|
-
*/
|
|
217
|
-
maxSteps?: number;
|
|
218
|
-
/**
|
|
219
|
-
* The maximum number of calls to make to an LLM in case it fails.
|
|
220
|
-
* This can be overridden at each generate/stream callsite.
|
|
269
|
+
* determines when to stop. Defaults to stepCountIs(1).
|
|
221
270
|
*/
|
|
222
|
-
|
|
271
|
+
stopWhen?: StopCondition<AgentTools> | Array<StopCondition<AgentTools>>;
|
|
223
272
|
/**
|
|
224
|
-
*
|
|
273
|
+
* @deprecated Use `languageEmbeddingModel` instead.
|
|
225
274
|
*/
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Called for each LLM request/response, so you can do things like
|
|
229
|
-
* log the raw request body or response headers to a table, or logs.
|
|
230
|
-
*/
|
|
231
|
-
rawRequestResponseHandler?: RawRequestResponseHandler;
|
|
275
|
+
chat?: LanguageModel;
|
|
232
276
|
},
|
|
233
277
|
) {}
|
|
234
278
|
|
|
@@ -242,7 +286,7 @@ export class Agent<
|
|
|
242
286
|
* @param args The thread metadata.
|
|
243
287
|
* @returns The threadId of the new thread and the thread object.
|
|
244
288
|
*/
|
|
245
|
-
async createThread
|
|
289
|
+
async createThread(
|
|
246
290
|
ctx: RunActionCtx & CustomCtx,
|
|
247
291
|
args?: {
|
|
248
292
|
/**
|
|
@@ -258,21 +302,8 @@ export class Agent<
|
|
|
258
302
|
* The summary of the thread. Not currently used for anything.
|
|
259
303
|
*/
|
|
260
304
|
summary?: string;
|
|
261
|
-
/**
|
|
262
|
-
* The usage handler to use for this thread. Overrides any handler
|
|
263
|
-
* set in the agent constructor.
|
|
264
|
-
*/
|
|
265
|
-
usageHandler?: UsageHandler;
|
|
266
|
-
/**
|
|
267
|
-
* The tools to use for this thread.
|
|
268
|
-
* Overrides any tools passed in the agent constructor.
|
|
269
|
-
*/
|
|
270
|
-
tools?: ThreadTools;
|
|
271
305
|
},
|
|
272
|
-
): Promise<{
|
|
273
|
-
threadId: string;
|
|
274
|
-
thread: Thread<ThreadTools extends undefined ? AgentTools : ThreadTools>;
|
|
275
|
-
}>;
|
|
306
|
+
): Promise<{ threadId: string; thread: Thread<AgentTools> }>;
|
|
276
307
|
/**
|
|
277
308
|
* Start a new thread with the agent. This will have a fresh history, though if
|
|
278
309
|
* you pass in a userId you can have it search across other threads for relevant
|
|
@@ -282,7 +313,7 @@ export class Agent<
|
|
|
282
313
|
* @param args The thread metadata.
|
|
283
314
|
* @returns The threadId of the new thread.
|
|
284
315
|
*/
|
|
285
|
-
async createThread
|
|
316
|
+
async createThread(
|
|
286
317
|
ctx: RunMutationCtx,
|
|
287
318
|
args?: {
|
|
288
319
|
/**
|
|
@@ -298,33 +329,12 @@ export class Agent<
|
|
|
298
329
|
* The summary of the thread. Not currently used for anything.
|
|
299
330
|
*/
|
|
300
331
|
summary?: string;
|
|
301
|
-
/**
|
|
302
|
-
* The usage handler to use for this thread. Overrides any handler
|
|
303
|
-
* set in the agent constructor.
|
|
304
|
-
*/
|
|
305
|
-
usageHandler?: UsageHandler;
|
|
306
|
-
/**
|
|
307
|
-
* The tools to use for this thread.
|
|
308
|
-
* Overrides any tools passed in the agent constructor.
|
|
309
|
-
*/
|
|
310
|
-
tools?: ThreadTools;
|
|
311
332
|
},
|
|
312
|
-
): Promise<{
|
|
313
|
-
|
|
314
|
-
}>;
|
|
315
|
-
async createThread<ThreadTools extends ToolSet | undefined = undefined>(
|
|
333
|
+
): Promise<{ threadId: string }>;
|
|
334
|
+
async createThread(
|
|
316
335
|
ctx: (ActionCtx & CustomCtx) | RunMutationCtx,
|
|
317
|
-
args?: {
|
|
318
|
-
|
|
319
|
-
title?: string;
|
|
320
|
-
summary?: string;
|
|
321
|
-
usageHandler?: UsageHandler;
|
|
322
|
-
tools?: ThreadTools;
|
|
323
|
-
},
|
|
324
|
-
): Promise<{
|
|
325
|
-
threadId: string;
|
|
326
|
-
thread?: Thread<ThreadTools extends undefined ? AgentTools : ThreadTools>;
|
|
327
|
-
}> {
|
|
336
|
+
args?: { userId: string | null; title?: string; summary?: string },
|
|
337
|
+
): Promise<{ threadId: string; thread?: Thread<AgentTools> }> {
|
|
328
338
|
const threadId = await createThread(ctx, this.component, args);
|
|
329
339
|
if (!("runAction" in ctx) || "workflowId" in ctx) {
|
|
330
340
|
return { threadId };
|
|
@@ -332,13 +342,8 @@ export class Agent<
|
|
|
332
342
|
const { thread } = await this.continueThread(ctx, {
|
|
333
343
|
threadId,
|
|
334
344
|
userId: args?.userId,
|
|
335
|
-
usageHandler: args?.usageHandler,
|
|
336
|
-
tools: args?.tools,
|
|
337
345
|
});
|
|
338
|
-
return {
|
|
339
|
-
threadId,
|
|
340
|
-
thread,
|
|
341
|
-
};
|
|
346
|
+
return { threadId, thread };
|
|
342
347
|
}
|
|
343
348
|
|
|
344
349
|
/**
|
|
@@ -349,7 +354,7 @@ export class Agent<
|
|
|
349
354
|
* @param { threadId, userId }: the thread and user to associate the messages with.
|
|
350
355
|
* @returns Functions bound to the userId and threadId on a `{thread}` object.
|
|
351
356
|
*/
|
|
352
|
-
async continueThread
|
|
357
|
+
async continueThread(
|
|
353
358
|
ctx: ActionCtx & CustomCtx,
|
|
354
359
|
args: {
|
|
355
360
|
/**
|
|
@@ -361,20 +366,8 @@ export class Agent<
|
|
|
361
366
|
* relevant messages from the same user as context for the LLM calls.
|
|
362
367
|
*/
|
|
363
368
|
userId?: string | null;
|
|
364
|
-
/**
|
|
365
|
-
* The usage handler to use for this thread. Overrides any handler
|
|
366
|
-
* set in the agent constructor.
|
|
367
|
-
*/
|
|
368
|
-
usageHandler?: UsageHandler;
|
|
369
|
-
/**
|
|
370
|
-
* The tools to use for this thread.
|
|
371
|
-
* Overrides any tools passed in the agent constructor.
|
|
372
|
-
*/
|
|
373
|
-
tools?: ThreadTools;
|
|
374
369
|
},
|
|
375
|
-
): Promise<{
|
|
376
|
-
thread: Thread<ThreadTools extends undefined ? AgentTools : ThreadTools>;
|
|
377
|
-
}> {
|
|
370
|
+
): Promise<{ thread: Thread<AgentTools> }> {
|
|
378
371
|
return {
|
|
379
372
|
thread: {
|
|
380
373
|
threadId: args.threadId,
|
|
@@ -390,32 +383,251 @@ export class Agent<
|
|
|
390
383
|
streamText: this.streamText.bind(this, ctx, args),
|
|
391
384
|
generateObject: this.generateObject.bind(this, ctx, args),
|
|
392
385
|
streamObject: this.streamObject.bind(this, ctx, args),
|
|
393
|
-
} as Thread<
|
|
386
|
+
} as Thread<AgentTools>,
|
|
394
387
|
};
|
|
395
388
|
}
|
|
396
389
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
390
|
+
async start<TOOLS extends ToolSet | undefined, T>(
|
|
391
|
+
ctx: ActionCtx & CustomCtx,
|
|
392
|
+
/**
|
|
393
|
+
* These are the arguments you'll pass to the LLM call such as
|
|
394
|
+
* `generateText` or `streamText`. This function will look up the context
|
|
395
|
+
* and provide functions to save the steps, abort the generation, and more.
|
|
396
|
+
* The type of the arguments returned infers from the type of the arguments
|
|
397
|
+
* you pass here.
|
|
398
|
+
*/
|
|
399
|
+
args: T & {
|
|
400
|
+
/**
|
|
401
|
+
* If provided, this message will be used as the "prompt" for the LLM call,
|
|
402
|
+
* instead of the prompt or messages.
|
|
403
|
+
* This is useful if you want to first save a user message, then use it as
|
|
404
|
+
* the prompt for the LLM call in another call.
|
|
405
|
+
*/
|
|
406
|
+
promptMessageId?: string;
|
|
407
|
+
/**
|
|
408
|
+
* The model to use for the LLM calls. This will override the model specified
|
|
409
|
+
* in the Agent constructor.
|
|
410
|
+
*/
|
|
411
|
+
model?: LanguageModel;
|
|
412
|
+
/**
|
|
413
|
+
* The tools to use for the tool calls. This will override tools specified
|
|
414
|
+
* in the Agent constructor or createThread / continueThread.
|
|
415
|
+
*/
|
|
416
|
+
tools?: TOOLS;
|
|
417
|
+
/**
|
|
418
|
+
* The single prompt message to use for the LLM call. This will be the
|
|
419
|
+
* last message in the context. If it's a string, it will be a user role.
|
|
420
|
+
*/
|
|
421
|
+
prompt?: string | (ModelMessage | Message)[];
|
|
422
|
+
/**
|
|
423
|
+
* If provided alongside prompt, the ordering will be:
|
|
424
|
+
* 1. system prompt
|
|
425
|
+
* 2. search context
|
|
426
|
+
* 3. recent messages
|
|
427
|
+
* 4. these messages
|
|
428
|
+
* 5. prompt messages, including those already on the same `order` as
|
|
429
|
+
* the promptMessageId message, if provided.
|
|
430
|
+
*/
|
|
431
|
+
messages?: (ModelMessage | Message)[];
|
|
432
|
+
/**
|
|
433
|
+
* This will be the first message in the context, and overrides the
|
|
434
|
+
* agent's instructions.
|
|
435
|
+
*/
|
|
436
|
+
system?: string;
|
|
437
|
+
/**
|
|
438
|
+
* The abort signal to be passed to the LLM call. If triggered, it will
|
|
439
|
+
* mark the pending message as failed. If the generation is asynchronously
|
|
440
|
+
* aborted, it will trigger this signal when detected.
|
|
441
|
+
*/
|
|
442
|
+
abortSignal?: AbortSignal;
|
|
443
|
+
// We optimistically override the generateId function to use the pending
|
|
444
|
+
// message id.
|
|
445
|
+
_internal?: { generateId?: IdGenerator };
|
|
412
446
|
},
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
447
|
+
options?: Options & { userId?: string | null; threadId?: string },
|
|
448
|
+
): Promise<{
|
|
449
|
+
args: T & {
|
|
450
|
+
system?: string;
|
|
451
|
+
model: LanguageModel;
|
|
452
|
+
messages: ModelMessage[];
|
|
453
|
+
// abortSignal?: AbortSignal;
|
|
454
|
+
tools?: TOOLS extends undefined ? AgentTools : TOOLS;
|
|
455
|
+
} & CallSettings;
|
|
456
|
+
order: number;
|
|
457
|
+
stepOrder: number;
|
|
458
|
+
userId: string | undefined;
|
|
459
|
+
promptMessageId: string | undefined;
|
|
460
|
+
updateModel: (model: LanguageModel | undefined) => void;
|
|
461
|
+
save: <TOOLS extends ToolSet>(
|
|
462
|
+
toSave:
|
|
463
|
+
| { step: StepResult<TOOLS> }
|
|
464
|
+
| { object: GenerateObjectResult<unknown> },
|
|
465
|
+
createPendingMessage?: boolean,
|
|
466
|
+
) => Promise<void>;
|
|
467
|
+
fail: (reason: string) => Promise<void>;
|
|
468
|
+
getSavedMessages: () => MessageDoc[];
|
|
469
|
+
}> {
|
|
470
|
+
const { threadId, ...opts } = { ...this.options, ...options };
|
|
471
|
+
const context = await this._saveMessagesAndFetchContext(ctx, args, {
|
|
472
|
+
userId: options?.userId,
|
|
473
|
+
threadId: options?.threadId,
|
|
474
|
+
...opts,
|
|
418
475
|
});
|
|
476
|
+
let pendingMessageId = context.pendingMessageId;
|
|
477
|
+
// TODO: extract pending message if one exists
|
|
478
|
+
const { args: aiArgs, promptMessageId, order, stepOrder, userId } = context;
|
|
479
|
+
const messages = context.savedMessages ?? [];
|
|
480
|
+
if (pendingMessageId) {
|
|
481
|
+
if (!aiArgs._internal?.generateId) {
|
|
482
|
+
aiArgs._internal = {
|
|
483
|
+
...aiArgs._internal,
|
|
484
|
+
generateId: () => pendingMessageId ?? crypto.randomUUID(),
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const toolCtx = {
|
|
489
|
+
...(ctx as UserActionCtx & CustomCtx),
|
|
490
|
+
userId,
|
|
491
|
+
threadId,
|
|
492
|
+
promptMessageId,
|
|
493
|
+
agent: this,
|
|
494
|
+
} satisfies ToolCtx;
|
|
495
|
+
type Tools = TOOLS extends undefined ? AgentTools : TOOLS;
|
|
496
|
+
const tools = wrapTools(toolCtx, args.tools ?? this.options.tools) as Tools;
|
|
497
|
+
const saveOutput = opts.storageOptions?.saveMessages !== "none";
|
|
498
|
+
const fail = async (reason: string) => {
|
|
499
|
+
if (threadId && promptMessageId) {
|
|
500
|
+
console.error("RollbackMessage", promptMessageId, reason);
|
|
501
|
+
}
|
|
502
|
+
if (pendingMessageId) {
|
|
503
|
+
await ctx.runMutation(this.component.messages.finalizeMessage, {
|
|
504
|
+
messageId: pendingMessageId,
|
|
505
|
+
result: { status: "failed", error: reason },
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
let activeModel = aiArgs.model;
|
|
510
|
+
if (aiArgs.abortSignal) {
|
|
511
|
+
const abortSignal = aiArgs.abortSignal;
|
|
512
|
+
aiArgs.abortSignal.addEventListener(
|
|
513
|
+
"abort",
|
|
514
|
+
async () => {
|
|
515
|
+
await fail(abortSignal.reason ?? "Aborted");
|
|
516
|
+
},
|
|
517
|
+
{ once: true },
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
args: {
|
|
522
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
523
|
+
stopWhen: (args as any).stopWhen ?? this.options.stopWhen,
|
|
524
|
+
...aiArgs,
|
|
525
|
+
tools,
|
|
526
|
+
// abortSignal: abortController.signal,
|
|
527
|
+
},
|
|
528
|
+
order: order ?? 0,
|
|
529
|
+
stepOrder: stepOrder ?? 0,
|
|
530
|
+
userId,
|
|
531
|
+
promptMessageId,
|
|
532
|
+
getSavedMessages: () => messages,
|
|
533
|
+
updateModel: (model: LanguageModel | undefined) => {
|
|
534
|
+
if (model) {
|
|
535
|
+
activeModel = model;
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
fail,
|
|
539
|
+
save: async <TOOLS extends ToolSet>(
|
|
540
|
+
toSave:
|
|
541
|
+
| { step: StepResult<TOOLS> }
|
|
542
|
+
| { object: GenerateObjectResult<unknown> },
|
|
543
|
+
createPendingMessage?: boolean,
|
|
544
|
+
) => {
|
|
545
|
+
if (threadId && promptMessageId && saveOutput) {
|
|
546
|
+
const metadata = {
|
|
547
|
+
// TODO: get up to date one when user selects mid-generation
|
|
548
|
+
model: getModelName(activeModel),
|
|
549
|
+
provider: getProviderName(activeModel),
|
|
550
|
+
};
|
|
551
|
+
const serialized =
|
|
552
|
+
"object" in toSave
|
|
553
|
+
? await serializeObjectResult(
|
|
554
|
+
ctx,
|
|
555
|
+
this.component,
|
|
556
|
+
toSave.object,
|
|
557
|
+
metadata,
|
|
558
|
+
)
|
|
559
|
+
: await serializeNewMessagesInStep(
|
|
560
|
+
ctx,
|
|
561
|
+
this.component,
|
|
562
|
+
toSave.step,
|
|
563
|
+
metadata,
|
|
564
|
+
);
|
|
565
|
+
const embeddings = await this.generateEmbeddings(
|
|
566
|
+
ctx,
|
|
567
|
+
{ userId, threadId },
|
|
568
|
+
serialized.messages.map((m) => m.message),
|
|
569
|
+
);
|
|
570
|
+
if (createPendingMessage) {
|
|
571
|
+
serialized.messages.push({
|
|
572
|
+
message: { role: "assistant", content: [] },
|
|
573
|
+
status: "pending",
|
|
574
|
+
});
|
|
575
|
+
embeddings?.vectors.push(null);
|
|
576
|
+
}
|
|
577
|
+
const saved = await ctx.runMutation(
|
|
578
|
+
this.component.messages.addMessages,
|
|
579
|
+
{
|
|
580
|
+
userId,
|
|
581
|
+
threadId,
|
|
582
|
+
agentName: this.options.name,
|
|
583
|
+
promptMessageId,
|
|
584
|
+
pendingMessageId,
|
|
585
|
+
messages: serialized.messages,
|
|
586
|
+
embeddings,
|
|
587
|
+
failPendingSteps: false,
|
|
588
|
+
},
|
|
589
|
+
);
|
|
590
|
+
const lastMessage = saved.messages.at(-1)!;
|
|
591
|
+
if (createPendingMessage) {
|
|
592
|
+
if (lastMessage.status === "failed") {
|
|
593
|
+
pendingMessageId = undefined;
|
|
594
|
+
messages.push(...saved.messages);
|
|
595
|
+
await fail(
|
|
596
|
+
lastMessage.error ??
|
|
597
|
+
"Aborting - the pending message was marked as failed",
|
|
598
|
+
);
|
|
599
|
+
} else {
|
|
600
|
+
pendingMessageId = lastMessage._id;
|
|
601
|
+
messages.push(...saved.messages.slice(0, -1));
|
|
602
|
+
}
|
|
603
|
+
} else {
|
|
604
|
+
pendingMessageId = undefined;
|
|
605
|
+
messages.push(...saved.messages);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const output = "object" in toSave ? toSave.object : toSave.step;
|
|
609
|
+
if (this.options.rawRequestResponseHandler) {
|
|
610
|
+
await this.options.rawRequestResponseHandler(ctx, {
|
|
611
|
+
userId,
|
|
612
|
+
threadId,
|
|
613
|
+
agentName: this.options.name,
|
|
614
|
+
request: output.request,
|
|
615
|
+
response: output.response,
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (opts.usageHandler && output.usage) {
|
|
619
|
+
await opts.usageHandler(ctx, {
|
|
620
|
+
userId,
|
|
621
|
+
threadId,
|
|
622
|
+
agentName: this.options.name,
|
|
623
|
+
model: getModelName(activeModel),
|
|
624
|
+
provider: getProviderName(activeModel),
|
|
625
|
+
usage: output.usage,
|
|
626
|
+
providerMetadata: output.providerMetadata,
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
};
|
|
419
631
|
}
|
|
420
632
|
|
|
421
633
|
/**
|
|
@@ -426,7 +638,7 @@ export class Agent<
|
|
|
426
638
|
* to a thread (and optionally userId).
|
|
427
639
|
* @param ctx The context passed from the action function calling this.
|
|
428
640
|
* @param { userId, threadId }: The user and thread to associate the message with
|
|
429
|
-
* @param
|
|
641
|
+
* @param generateTextArgs The arguments to the generateText function, along with extra controls
|
|
430
642
|
* for the {@link ContextOptions} and {@link StorageOptions}.
|
|
431
643
|
* @returns The result of the generateText function.
|
|
432
644
|
*/
|
|
@@ -436,102 +648,44 @@ export class Agent<
|
|
|
436
648
|
OUTPUT_PARTIAL = never,
|
|
437
649
|
>(
|
|
438
650
|
ctx: ActionCtx & CustomCtx,
|
|
439
|
-
{
|
|
440
|
-
|
|
441
|
-
threadId,
|
|
442
|
-
tools: threadTools,
|
|
443
|
-
...usageHandler
|
|
444
|
-
}: {
|
|
445
|
-
userId?: string | null;
|
|
446
|
-
threadId?: string;
|
|
447
|
-
/**
|
|
448
|
-
* The usage handler to use for this thread. Overrides any handler
|
|
449
|
-
* set in the agent constructor.
|
|
450
|
-
*/
|
|
451
|
-
usageHandler?: UsageHandler;
|
|
452
|
-
/** Note: to get better type inference, pass tools in the next arg */
|
|
453
|
-
tools?: ToolSet;
|
|
454
|
-
},
|
|
455
|
-
args: TextArgs<AgentTools, TOOLS, OUTPUT, OUTPUT_PARTIAL>,
|
|
651
|
+
threadOpts: { userId?: string | null; threadId?: string },
|
|
652
|
+
generateTextArgs: TextArgs<AgentTools, TOOLS, OUTPUT, OUTPUT_PARTIAL>,
|
|
456
653
|
options?: Options,
|
|
457
654
|
): Promise<
|
|
458
655
|
GenerateTextResult<TOOLS extends undefined ? AgentTools : TOOLS, OUTPUT> &
|
|
459
656
|
GenerationOutputMetadata
|
|
460
657
|
> {
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const
|
|
469
|
-
...(ctx as UserActionCtx & CustomCtx),
|
|
470
|
-
userId,
|
|
471
|
-
threadId,
|
|
472
|
-
messageId,
|
|
473
|
-
agent: this,
|
|
474
|
-
};
|
|
475
|
-
const tools = wrapTools(
|
|
476
|
-
toolCtx,
|
|
477
|
-
args.tools ?? threadTools ?? this.options.tools,
|
|
478
|
-
) as TOOLS extends undefined ? AgentTools : TOOLS;
|
|
479
|
-
const saveOutput = opts.storageOptions?.saveMessages !== "none";
|
|
658
|
+
const { args, promptMessageId, order, ...call } = await this.start(
|
|
659
|
+
ctx,
|
|
660
|
+
generateTextArgs,
|
|
661
|
+
{ ...threadOpts, ...options },
|
|
662
|
+
);
|
|
663
|
+
|
|
664
|
+
type Tools = TOOLS extends undefined ? AgentTools : TOOLS;
|
|
665
|
+
const steps: StepResult<Tools>[] = [];
|
|
480
666
|
try {
|
|
481
|
-
const result = (await generateText({
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
667
|
+
const result = (await generateText<Tools, OUTPUT, OUTPUT_PARTIAL>({
|
|
668
|
+
...args,
|
|
669
|
+
prepareStep: async (options) => {
|
|
670
|
+
const result = await generateTextArgs.prepareStep?.(options);
|
|
671
|
+
call.updateModel(result?.model ?? options.model);
|
|
672
|
+
return result;
|
|
673
|
+
},
|
|
486
674
|
onStepFinish: async (step) => {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
threadId,
|
|
491
|
-
promptMessageId: messageId,
|
|
492
|
-
model: aiArgs.model.modelId,
|
|
493
|
-
provider: aiArgs.model.provider,
|
|
494
|
-
step,
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
if (this.options.rawRequestResponseHandler) {
|
|
498
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
499
|
-
userId,
|
|
500
|
-
threadId,
|
|
501
|
-
agentName: this.options.name,
|
|
502
|
-
request: step.request,
|
|
503
|
-
response: step.response,
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
if (opts.usageHandler && step.usage) {
|
|
507
|
-
await opts.usageHandler(ctx, {
|
|
508
|
-
userId,
|
|
509
|
-
threadId,
|
|
510
|
-
agentName: this.options.name,
|
|
511
|
-
model: aiArgs.model.modelId,
|
|
512
|
-
provider: aiArgs.model.provider,
|
|
513
|
-
usage: step.usage,
|
|
514
|
-
providerMetadata: step.providerMetadata,
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
return args.onStepFinish?.(step);
|
|
675
|
+
steps.push(step);
|
|
676
|
+
await call.save({ step }, await willContinue(steps, args.stopWhen));
|
|
677
|
+
return generateTextArgs.onStepFinish?.(step);
|
|
518
678
|
},
|
|
519
|
-
})) as GenerateTextResult<
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
return result;
|
|
679
|
+
})) as GenerateTextResult<Tools, OUTPUT>;
|
|
680
|
+
const metadata: GenerationOutputMetadata = {
|
|
681
|
+
promptMessageId,
|
|
682
|
+
order,
|
|
683
|
+
savedMessages: call.getSavedMessages(),
|
|
684
|
+
messageId: promptMessageId,
|
|
685
|
+
};
|
|
686
|
+
return Object.assign(result, metadata);
|
|
527
687
|
} catch (error) {
|
|
528
|
-
|
|
529
|
-
console.error("RollbackMessage", messageId);
|
|
530
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
531
|
-
messageId,
|
|
532
|
-
error: (error as Error).message,
|
|
533
|
-
});
|
|
534
|
-
}
|
|
688
|
+
await call.fail(errorToString(error));
|
|
535
689
|
throw error;
|
|
536
690
|
}
|
|
537
691
|
}
|
|
@@ -549,22 +703,16 @@ export class Agent<
|
|
|
549
703
|
PARTIAL_OUTPUT = never,
|
|
550
704
|
>(
|
|
551
705
|
ctx: ActionCtx & CustomCtx,
|
|
552
|
-
{
|
|
553
|
-
userId: argsUserId,
|
|
554
|
-
threadId,
|
|
555
|
-
/** Note: to get better type inference, pass tools in the next arg */
|
|
556
|
-
tools: threadTools,
|
|
557
|
-
...usageHandler
|
|
558
|
-
}: {
|
|
559
|
-
userId?: string | null;
|
|
560
|
-
threadId?: string;
|
|
561
|
-
usageHandler?: UsageHandler;
|
|
562
|
-
tools?: ToolSet;
|
|
563
|
-
},
|
|
706
|
+
threadOpts: { userId?: string | null; threadId?: string },
|
|
564
707
|
/**
|
|
565
708
|
* The arguments to the streamText function, similar to the ai `streamText` function.
|
|
566
709
|
*/
|
|
567
|
-
|
|
710
|
+
streamTextArgs: StreamingTextArgs<
|
|
711
|
+
AgentTools,
|
|
712
|
+
TOOLS,
|
|
713
|
+
OUTPUT,
|
|
714
|
+
PARTIAL_OUTPUT
|
|
715
|
+
>,
|
|
568
716
|
/**
|
|
569
717
|
* The {@link ContextOptions} and {@link StorageOptions}
|
|
570
718
|
* options to use for fetching contextual messages and saving input/output messages.
|
|
@@ -589,109 +737,80 @@ export class Agent<
|
|
|
589
737
|
> &
|
|
590
738
|
GenerationOutputMetadata
|
|
591
739
|
> {
|
|
592
|
-
const
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
...(ctx as UserActionCtx & CustomCtx),
|
|
601
|
-
userId,
|
|
602
|
-
threadId,
|
|
603
|
-
messageId,
|
|
604
|
-
agent: this,
|
|
605
|
-
};
|
|
606
|
-
const tools = wrapTools(
|
|
607
|
-
toolCtx,
|
|
608
|
-
args.tools ?? threadTools ?? this.options.tools,
|
|
609
|
-
) as TOOLS extends undefined ? AgentTools : TOOLS;
|
|
610
|
-
const saveOutput = opts.storageOptions?.saveMessages !== "none";
|
|
740
|
+
const { threadId } = threadOpts;
|
|
741
|
+
const { args, userId, order, stepOrder, promptMessageId, ...call } =
|
|
742
|
+
await this.start(ctx, streamTextArgs, { ...threadOpts, ...options });
|
|
743
|
+
|
|
744
|
+
type Tools = TOOLS extends undefined ? AgentTools : TOOLS;
|
|
745
|
+
const steps: StepResult<Tools>[] = [];
|
|
746
|
+
|
|
747
|
+
const opts = { ...this.options, ...options };
|
|
611
748
|
const streamer =
|
|
612
749
|
threadId && opts.saveStreamDeltas
|
|
613
750
|
? new DeltaStreamer(this.component, ctx, opts.saveStreamDeltas, {
|
|
614
751
|
threadId,
|
|
615
752
|
userId,
|
|
616
753
|
agentName: this.options.name,
|
|
617
|
-
model:
|
|
618
|
-
provider:
|
|
619
|
-
providerOptions:
|
|
754
|
+
model: getModelName(args.model),
|
|
755
|
+
provider: getProviderName(args.model),
|
|
756
|
+
providerOptions: args.providerOptions,
|
|
620
757
|
order,
|
|
621
758
|
stepOrder,
|
|
622
|
-
abortSignal:
|
|
759
|
+
abortSignal: args.abortSignal,
|
|
623
760
|
})
|
|
624
761
|
: undefined;
|
|
625
762
|
|
|
626
763
|
const result = streamText({
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
tools,
|
|
631
|
-
abortSignal: streamer?.abortController.signal ?? aiArgs.abortSignal,
|
|
764
|
+
...args,
|
|
765
|
+
abortSignal: streamer?.abortController.signal ?? args.abortSignal,
|
|
766
|
+
// TODO: this is probably why reasoning isn't streaming
|
|
632
767
|
experimental_transform: mergeTransforms(
|
|
633
768
|
options?.saveStreamDeltas,
|
|
634
|
-
|
|
769
|
+
streamTextArgs.experimental_transform,
|
|
635
770
|
),
|
|
636
771
|
onChunk: async (event) => {
|
|
637
772
|
await streamer?.addParts([event.chunk]);
|
|
638
773
|
// console.log("onChunk", chunk);
|
|
639
|
-
return
|
|
774
|
+
return streamTextArgs.onChunk?.(event);
|
|
640
775
|
},
|
|
641
776
|
onError: async (error) => {
|
|
642
777
|
console.error("onError", error);
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
778
|
+
await call.fail(errorToString(error.error));
|
|
779
|
+
await streamer?.fail(errorToString(error.error));
|
|
780
|
+
return streamTextArgs.onError?.(error);
|
|
781
|
+
},
|
|
782
|
+
// onFinish: async (event) => {
|
|
783
|
+
// return streamTextArgs.onFinish?.(event);
|
|
784
|
+
// },
|
|
785
|
+
prepareStep: async (options) => {
|
|
786
|
+
const result = await streamTextArgs.prepareStep?.(options);
|
|
787
|
+
if (result) {
|
|
788
|
+
const model = result.model ?? options.model;
|
|
789
|
+
call.updateModel(model);
|
|
790
|
+
return result;
|
|
648
791
|
}
|
|
649
|
-
|
|
650
|
-
return args.onError?.(error);
|
|
792
|
+
return undefined;
|
|
651
793
|
},
|
|
652
794
|
onStepFinish: async (step) => {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
model: aiArgs.model.modelId,
|
|
659
|
-
provider: aiArgs.model.provider,
|
|
660
|
-
promptMessageId: messageId,
|
|
661
|
-
step,
|
|
662
|
-
});
|
|
663
|
-
await streamer?.finish(saved.messages);
|
|
664
|
-
}
|
|
665
|
-
if (this.options.rawRequestResponseHandler) {
|
|
666
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
667
|
-
userId,
|
|
668
|
-
threadId,
|
|
669
|
-
agentName: this.options.name,
|
|
670
|
-
request: step.request,
|
|
671
|
-
response: step.response,
|
|
672
|
-
});
|
|
673
|
-
}
|
|
674
|
-
if (opts.usageHandler && step.usage) {
|
|
675
|
-
await opts.usageHandler(ctx, {
|
|
676
|
-
userId,
|
|
677
|
-
threadId,
|
|
678
|
-
agentName: this.options.name,
|
|
679
|
-
model: aiArgs.model.modelId,
|
|
680
|
-
provider: aiArgs.model.provider,
|
|
681
|
-
usage: step.usage,
|
|
682
|
-
providerMetadata: step.providerMetadata,
|
|
683
|
-
});
|
|
795
|
+
steps.push(step);
|
|
796
|
+
const createPendingMessage = await willContinue(steps, args.stopWhen);
|
|
797
|
+
await call.save({ step }, createPendingMessage);
|
|
798
|
+
if (!createPendingMessage) {
|
|
799
|
+
await streamer?.finish();
|
|
684
800
|
}
|
|
685
801
|
return args.onStepFinish?.(step);
|
|
686
802
|
},
|
|
687
803
|
}) as StreamTextResult<
|
|
688
804
|
TOOLS extends undefined ? AgentTools : TOOLS,
|
|
689
805
|
PARTIAL_OUTPUT
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
806
|
+
>;
|
|
807
|
+
const metadata: GenerationOutputMetadata = {
|
|
808
|
+
promptMessageId,
|
|
809
|
+
order,
|
|
810
|
+
savedMessages: call.getSavedMessages(),
|
|
811
|
+
messageId: promptMessageId,
|
|
812
|
+
};
|
|
813
|
+
return Object.assign(result, metadata);
|
|
695
814
|
}
|
|
696
815
|
|
|
697
816
|
/**
|
|
@@ -701,81 +820,45 @@ export class Agent<
|
|
|
701
820
|
* Use {@link continueThread} to get a version of this function already scoped
|
|
702
821
|
* to a thread (and optionally userId).
|
|
703
822
|
*/
|
|
704
|
-
async generateObject<
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
},
|
|
823
|
+
async generateObject<
|
|
824
|
+
SCHEMA extends ObjectSchema = DefaultObjectSchema,
|
|
825
|
+
OUTPUT extends ObjectMode = InferSchema<SCHEMA> extends string
|
|
826
|
+
? "enum"
|
|
827
|
+
: "object",
|
|
828
|
+
RESULT = OUTPUT extends "array"
|
|
829
|
+
? Array<InferSchema<SCHEMA>>
|
|
830
|
+
: InferSchema<SCHEMA>,
|
|
831
|
+
>(
|
|
832
|
+
ctx: ActionCtx & CustomCtx,
|
|
833
|
+
threadOpts: { userId?: string | null; threadId?: string },
|
|
715
834
|
/**
|
|
716
835
|
* The arguments to the generateObject function, similar to the ai.generateObject function.
|
|
717
836
|
*/
|
|
718
|
-
|
|
837
|
+
generateObjectArgs: GenerateObjectArgs<SCHEMA, OUTPUT, RESULT>,
|
|
719
838
|
/**
|
|
720
839
|
* The {@link ContextOptions} and {@link StorageOptions}
|
|
721
840
|
* options to use for fetching contextual messages and saving input/output messages.
|
|
722
841
|
*/
|
|
723
842
|
options?: Options,
|
|
724
|
-
): Promise<GenerateObjectResult<
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
threadId,
|
|
729
|
-
...opts,
|
|
730
|
-
});
|
|
731
|
-
const { args: aiArgs, messageId, order, userId } = context;
|
|
732
|
-
const saveOutput = opts.storageOptions?.saveMessages !== "none";
|
|
843
|
+
): Promise<GenerateObjectResult<RESULT> & GenerationOutputMetadata> {
|
|
844
|
+
const { args, promptMessageId, order, fail, save, getSavedMessages } =
|
|
845
|
+
await this.start(ctx, generateObjectArgs, { ...threadOpts, ...options });
|
|
846
|
+
|
|
733
847
|
try {
|
|
734
848
|
const result = (await generateObject(
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
)) as GenerateObjectResult<T> & GenerationOutputMetadata;
|
|
849
|
+
args,
|
|
850
|
+
)) as GenerateObjectResult<RESULT>;
|
|
738
851
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
result.messageId = messageId;
|
|
750
|
-
result.order = order;
|
|
751
|
-
if (this.options.rawRequestResponseHandler) {
|
|
752
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
753
|
-
userId,
|
|
754
|
-
threadId,
|
|
755
|
-
agentName: this.options.name,
|
|
756
|
-
request: result.request,
|
|
757
|
-
response: result.response,
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
if (opts.usageHandler && result.usage) {
|
|
761
|
-
await opts.usageHandler(ctx, {
|
|
762
|
-
userId,
|
|
763
|
-
threadId,
|
|
764
|
-
agentName: this.options.name,
|
|
765
|
-
model: aiArgs.model.modelId,
|
|
766
|
-
provider: aiArgs.model.provider,
|
|
767
|
-
usage: result.usage,
|
|
768
|
-
providerMetadata: result.providerMetadata,
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
return result;
|
|
852
|
+
await save({ object: result });
|
|
853
|
+
const metadata: GenerationOutputMetadata = {
|
|
854
|
+
promptMessageId,
|
|
855
|
+
order,
|
|
856
|
+
savedMessages: getSavedMessages(),
|
|
857
|
+
messageId: promptMessageId,
|
|
858
|
+
};
|
|
859
|
+
return Object.assign(result, metadata);
|
|
772
860
|
} catch (error) {
|
|
773
|
-
|
|
774
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
775
|
-
messageId,
|
|
776
|
-
error: (error as Error).message,
|
|
777
|
-
});
|
|
778
|
-
}
|
|
861
|
+
await fail(errorToString(error));
|
|
779
862
|
throw error;
|
|
780
863
|
}
|
|
781
864
|
}
|
|
@@ -787,96 +870,83 @@ export class Agent<
|
|
|
787
870
|
* Use {@link continueThread} to get a version of this function already scoped
|
|
788
871
|
* to a thread (and optionally userId).
|
|
789
872
|
*/
|
|
790
|
-
async streamObject<
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
},
|
|
873
|
+
async streamObject<
|
|
874
|
+
SCHEMA extends ObjectSchema = DefaultObjectSchema,
|
|
875
|
+
OUTPUT extends ObjectMode = InferSchema<SCHEMA> extends string
|
|
876
|
+
? "enum"
|
|
877
|
+
: "object",
|
|
878
|
+
RESULT = OUTPUT extends "array"
|
|
879
|
+
? Array<InferSchema<SCHEMA>>
|
|
880
|
+
: InferSchema<SCHEMA>,
|
|
881
|
+
>(
|
|
882
|
+
ctx: ActionCtx & CustomCtx,
|
|
883
|
+
threadOpts: { userId?: string | null; threadId?: string },
|
|
801
884
|
/**
|
|
802
885
|
* The arguments to the streamObject function, similar to the ai `streamObject` function.
|
|
803
886
|
*/
|
|
804
|
-
|
|
887
|
+
streamObjectArgs: StreamObjectArgs<SCHEMA, OUTPUT, RESULT> & {
|
|
888
|
+
/**
|
|
889
|
+
* If provided, this message will be used as the "prompt" for the LLM call,
|
|
890
|
+
* instead of the prompt or messages.
|
|
891
|
+
* This is useful if you want to first save a user message, then use it as
|
|
892
|
+
* the prompt for the LLM call in another call.
|
|
893
|
+
*/
|
|
894
|
+
promptMessageId?: string;
|
|
895
|
+
/**
|
|
896
|
+
* The model to use for the LLM calls. This will override the model specified
|
|
897
|
+
* in the Agent constructor.
|
|
898
|
+
*/
|
|
899
|
+
model?: LanguageModel;
|
|
900
|
+
/**
|
|
901
|
+
* The tools to use for the tool calls. This will override tools specified
|
|
902
|
+
* in the Agent constructor or createThread / continueThread.
|
|
903
|
+
*/
|
|
904
|
+
},
|
|
805
905
|
/**
|
|
806
906
|
* The {@link ContextOptions} and {@link StorageOptions}
|
|
807
907
|
* options to use for fetching contextual messages and saving input/output messages.
|
|
808
908
|
*/
|
|
809
909
|
options?: Options,
|
|
810
910
|
): Promise<
|
|
811
|
-
|
|
911
|
+
ReturnType<typeof streamObject<SCHEMA, OUTPUT, RESULT>> &
|
|
912
|
+
GenerationOutputMetadata
|
|
812
913
|
> {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
threadId,
|
|
818
|
-
...opts,
|
|
819
|
-
});
|
|
820
|
-
const { args: aiArgs, messageId, order, userId } = context;
|
|
821
|
-
const saveOutput = opts.storageOptions?.saveMessages !== "none";
|
|
822
|
-
const stream = streamObject<T>({
|
|
914
|
+
const { args, promptMessageId, order, fail, save, getSavedMessages } =
|
|
915
|
+
await this.start(ctx, streamObjectArgs, { ...threadOpts, ...options });
|
|
916
|
+
|
|
917
|
+
const stream = streamObject<SCHEMA, OUTPUT, RESULT>({
|
|
823
918
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
824
|
-
...(
|
|
919
|
+
...(args as any),
|
|
825
920
|
onError: async (error) => {
|
|
826
|
-
console.error("onError", error);
|
|
921
|
+
console.error(" streamObject onError", error);
|
|
922
|
+
// TODO: content that we have so far
|
|
923
|
+
// content: stream.fullStream.
|
|
924
|
+
await fail(errorToString(error.error));
|
|
827
925
|
return args.onError?.(error);
|
|
828
926
|
},
|
|
829
927
|
onFinish: async (result) => {
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
promptMessageId: messageId,
|
|
835
|
-
result: {
|
|
836
|
-
object: result.object,
|
|
837
|
-
finishReason: "stop",
|
|
838
|
-
usage: result.usage,
|
|
839
|
-
warnings: result.warnings,
|
|
840
|
-
request: await stream.request,
|
|
841
|
-
response: result.response,
|
|
842
|
-
providerMetadata: result.providerMetadata,
|
|
843
|
-
experimental_providerMetadata:
|
|
844
|
-
result.experimental_providerMetadata,
|
|
845
|
-
logprobs: undefined,
|
|
846
|
-
toJsonResponse: stream.toTextStreamResponse,
|
|
847
|
-
},
|
|
848
|
-
model: aiArgs.model.modelId,
|
|
849
|
-
provider: aiArgs.model.provider,
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
if (opts.usageHandler && result.usage) {
|
|
853
|
-
await opts.usageHandler(ctx, {
|
|
854
|
-
userId,
|
|
855
|
-
threadId,
|
|
856
|
-
agentName: this.options.name,
|
|
857
|
-
model: aiArgs.model.modelId,
|
|
858
|
-
provider: aiArgs.model.provider,
|
|
928
|
+
await save({
|
|
929
|
+
object: {
|
|
930
|
+
object: result.object,
|
|
931
|
+
finishReason: result.error ? "error" : "stop",
|
|
859
932
|
usage: result.usage,
|
|
860
|
-
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
if (this.options.rawRequestResponseHandler) {
|
|
864
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
865
|
-
userId,
|
|
866
|
-
threadId,
|
|
867
|
-
agentName: this.options.name,
|
|
933
|
+
warnings: result.warnings,
|
|
868
934
|
request: await stream.request,
|
|
869
935
|
response: result.response,
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
936
|
+
providerMetadata: result.providerMetadata,
|
|
937
|
+
toJsonResponse: stream.toTextStreamResponse,
|
|
938
|
+
},
|
|
939
|
+
});
|
|
940
|
+
return args.onFinish?.(result);
|
|
874
941
|
},
|
|
875
|
-
})
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
942
|
+
});
|
|
943
|
+
const metadata: GenerationOutputMetadata = {
|
|
944
|
+
promptMessageId,
|
|
945
|
+
order,
|
|
946
|
+
savedMessages: getSavedMessages(),
|
|
947
|
+
messageId: promptMessageId,
|
|
948
|
+
};
|
|
949
|
+
return Object.assign(stream, metadata);
|
|
880
950
|
}
|
|
881
951
|
|
|
882
952
|
/**
|
|
@@ -898,14 +968,11 @@ export class Agent<
|
|
|
898
968
|
skipEmbeddings?: boolean;
|
|
899
969
|
},
|
|
900
970
|
) {
|
|
901
|
-
const {
|
|
971
|
+
const { messages } = await this.saveMessages(ctx, {
|
|
902
972
|
threadId: args.threadId,
|
|
903
973
|
userId: args.userId,
|
|
904
974
|
embeddings: args.embedding
|
|
905
|
-
? {
|
|
906
|
-
model: args.embedding.model,
|
|
907
|
-
vectors: [args.embedding.vector],
|
|
908
|
-
}
|
|
975
|
+
? { model: args.embedding.model, vectors: [args.embedding.vector] }
|
|
909
976
|
: undefined,
|
|
910
977
|
messages:
|
|
911
978
|
args.prompt !== undefined
|
|
@@ -913,8 +980,10 @@ export class Agent<
|
|
|
913
980
|
: [args.message],
|
|
914
981
|
metadata: args.metadata ? [args.metadata] : undefined,
|
|
915
982
|
skipEmbeddings: args.skipEmbeddings,
|
|
983
|
+
pendingMessageId: args.pendingMessageId,
|
|
916
984
|
});
|
|
917
|
-
|
|
985
|
+
const message = messages.at(-1)!;
|
|
986
|
+
return { messageId: message._id, message };
|
|
918
987
|
}
|
|
919
988
|
|
|
920
989
|
/**
|
|
@@ -936,20 +1005,12 @@ export class Agent<
|
|
|
936
1005
|
*/
|
|
937
1006
|
skipEmbeddings?: boolean;
|
|
938
1007
|
},
|
|
939
|
-
): Promise<{
|
|
940
|
-
|
|
941
|
-
messages: MessageDoc[];
|
|
942
|
-
}> {
|
|
943
|
-
let embeddings:
|
|
944
|
-
| {
|
|
945
|
-
vectors: (number[] | null)[];
|
|
946
|
-
model: string;
|
|
947
|
-
}
|
|
948
|
-
| undefined;
|
|
1008
|
+
): Promise<{ messages: MessageDoc[] }> {
|
|
1009
|
+
let embeddings: { vectors: (number[] | null)[]; model: string } | undefined;
|
|
949
1010
|
const { skipEmbeddings, ...rest } = args;
|
|
950
1011
|
if (args.embeddings) {
|
|
951
1012
|
embeddings = args.embeddings;
|
|
952
|
-
} else if (!skipEmbeddings && this.options.
|
|
1013
|
+
} else if (!skipEmbeddings && this.options.textEmbeddingModel) {
|
|
953
1014
|
if (!("runAction" in ctx)) {
|
|
954
1015
|
console.warn(
|
|
955
1016
|
"You're trying to save messages and generate embeddings, but you're in a mutation. " +
|
|
@@ -967,10 +1028,7 @@ export class Agent<
|
|
|
967
1028
|
} else {
|
|
968
1029
|
embeddings = await this.generateEmbeddings(
|
|
969
1030
|
ctx,
|
|
970
|
-
{
|
|
971
|
-
userId: args.userId ?? undefined,
|
|
972
|
-
threadId: args.threadId,
|
|
973
|
-
},
|
|
1031
|
+
{ userId: args.userId ?? undefined, threadId: args.threadId },
|
|
974
1032
|
args.messages,
|
|
975
1033
|
);
|
|
976
1034
|
}
|
|
@@ -1037,7 +1095,7 @@ export class Agent<
|
|
|
1037
1095
|
args: {
|
|
1038
1096
|
userId: string | undefined;
|
|
1039
1097
|
threadId: string | undefined;
|
|
1040
|
-
messages:
|
|
1098
|
+
messages: (ModelMessage | Message)[];
|
|
1041
1099
|
/**
|
|
1042
1100
|
* If provided, it will search for messages up to and including this message.
|
|
1043
1101
|
* Note: if this is far in the past, text and vector search results may be more
|
|
@@ -1058,8 +1116,8 @@ export class Agent<
|
|
|
1058
1116
|
getEmbedding: async (text) => {
|
|
1059
1117
|
assert("runAction" in ctx);
|
|
1060
1118
|
assert(
|
|
1061
|
-
this.options.
|
|
1062
|
-
"A
|
|
1119
|
+
this.options.textEmbeddingModel,
|
|
1120
|
+
"A textEmbeddingModel is required to be set on the Agent that you're doing vector search with",
|
|
1063
1121
|
);
|
|
1064
1122
|
return {
|
|
1065
1123
|
embedding: (
|
|
@@ -1069,7 +1127,7 @@ export class Agent<
|
|
|
1069
1127
|
values: [text],
|
|
1070
1128
|
})
|
|
1071
1129
|
).embeddings[0],
|
|
1072
|
-
|
|
1130
|
+
textEmbeddingModel: this.options.textEmbeddingModel,
|
|
1073
1131
|
};
|
|
1074
1132
|
},
|
|
1075
1133
|
});
|
|
@@ -1121,13 +1179,10 @@ export class Agent<
|
|
|
1121
1179
|
{
|
|
1122
1180
|
userId,
|
|
1123
1181
|
threadId,
|
|
1124
|
-
}: {
|
|
1125
|
-
|
|
1126
|
-
threadId: string | undefined;
|
|
1127
|
-
},
|
|
1128
|
-
messages: CoreMessage[],
|
|
1182
|
+
}: { userId: string | undefined; threadId: string | undefined },
|
|
1183
|
+
messages: (ModelMessage | Message)[],
|
|
1129
1184
|
) {
|
|
1130
|
-
if (!this.options.
|
|
1185
|
+
if (!this.options.textEmbeddingModel) {
|
|
1131
1186
|
return undefined;
|
|
1132
1187
|
}
|
|
1133
1188
|
let embeddings:
|
|
@@ -1145,13 +1200,13 @@ export class Agent<
|
|
|
1145
1200
|
if (textIndexes.length === 0) {
|
|
1146
1201
|
return undefined;
|
|
1147
1202
|
}
|
|
1203
|
+
const values = messageTexts.filter((t): t is string => !!t);
|
|
1148
1204
|
// Then embed those messages.
|
|
1149
1205
|
const textEmbeddings = await this.doEmbed(ctx, {
|
|
1150
1206
|
userId,
|
|
1151
1207
|
threadId,
|
|
1152
|
-
values
|
|
1208
|
+
values,
|
|
1153
1209
|
});
|
|
1154
|
-
// TODO: record usage of embeddings
|
|
1155
1210
|
// Then assemble the embeddings into a single array with nulls for the messages without text.
|
|
1156
1211
|
const embeddingsOrNull = Array(messages.length).fill(null);
|
|
1157
1212
|
textIndexes.forEach((i, j) => {
|
|
@@ -1160,11 +1215,8 @@ export class Agent<
|
|
|
1160
1215
|
if (textEmbeddings.embeddings.length > 0) {
|
|
1161
1216
|
const dimension = textEmbeddings.embeddings[0].length;
|
|
1162
1217
|
validateVectorDimension(dimension);
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
dimension,
|
|
1166
|
-
model: this.options.textEmbedding.modelId,
|
|
1167
|
-
};
|
|
1218
|
+
const model = getModelName(this.options.textEmbeddingModel);
|
|
1219
|
+
embeddings = { vectors: embeddingsOrNull, dimension, model };
|
|
1168
1220
|
}
|
|
1169
1221
|
return embeddings;
|
|
1170
1222
|
}
|
|
@@ -1178,9 +1230,7 @@ export class Agent<
|
|
|
1178
1230
|
*/
|
|
1179
1231
|
async generateAndSaveEmbeddings(
|
|
1180
1232
|
ctx: RunActionCtx,
|
|
1181
|
-
args: {
|
|
1182
|
-
messageIds: string[];
|
|
1183
|
-
},
|
|
1233
|
+
args: { messageIds: string[] },
|
|
1184
1234
|
) {
|
|
1185
1235
|
const messages = (
|
|
1186
1236
|
await ctx.runQuery(this.component.messages.getMessagesByIds, {
|
|
@@ -1218,12 +1268,12 @@ export class Agent<
|
|
|
1218
1268
|
userId: messagesMissingEmbeddings[0]!.userId,
|
|
1219
1269
|
threadId: messagesMissingEmbeddings[0]!.threadId,
|
|
1220
1270
|
},
|
|
1221
|
-
messagesMissingEmbeddings.map((m) => m!.message!),
|
|
1271
|
+
messagesMissingEmbeddings.map((m) => deserializeMessage(m!.message!)),
|
|
1222
1272
|
);
|
|
1223
1273
|
if (!embeddings) {
|
|
1224
|
-
if (!this.options.
|
|
1274
|
+
if (!this.options.textEmbeddingModel) {
|
|
1225
1275
|
throw new Error(
|
|
1226
|
-
"No embeddings were generated for the messages. You must pass a
|
|
1276
|
+
"No embeddings were generated for the messages. You must pass a textEmbeddingModel to the agent constructor.",
|
|
1227
1277
|
);
|
|
1228
1278
|
}
|
|
1229
1279
|
throw new Error(
|
|
@@ -1278,14 +1328,14 @@ export class Agent<
|
|
|
1278
1328
|
*/
|
|
1279
1329
|
provider?: string;
|
|
1280
1330
|
},
|
|
1281
|
-
): Promise<{ messages: MessageDoc[]
|
|
1282
|
-
const messages = await serializeNewMessagesInStep(
|
|
1331
|
+
): Promise<{ messages: MessageDoc[] }> {
|
|
1332
|
+
const { messages } = await serializeNewMessagesInStep(
|
|
1283
1333
|
ctx,
|
|
1284
1334
|
this.component,
|
|
1285
1335
|
args.step,
|
|
1286
1336
|
{
|
|
1287
|
-
provider: args.provider ?? this.options.
|
|
1288
|
-
model: args.model ?? this.options.
|
|
1337
|
+
provider: args.provider ?? getProviderName(this.options.languageModel),
|
|
1338
|
+
model: args.model ?? getModelName(this.options.languageModel),
|
|
1289
1339
|
},
|
|
1290
1340
|
);
|
|
1291
1341
|
const embeddings = await this.generateEmbeddings(
|
|
@@ -1293,7 +1343,7 @@ export class Agent<
|
|
|
1293
1343
|
{ userId: args.userId, threadId: args.threadId },
|
|
1294
1344
|
messages.map((m) => m.message),
|
|
1295
1345
|
);
|
|
1296
|
-
|
|
1346
|
+
return ctx.runMutation(this.component.messages.addMessages, {
|
|
1297
1347
|
userId: args.userId,
|
|
1298
1348
|
threadId: args.threadId,
|
|
1299
1349
|
agentName: this.options.name,
|
|
@@ -1302,7 +1352,6 @@ export class Agent<
|
|
|
1302
1352
|
embeddings,
|
|
1303
1353
|
failPendingSteps: false,
|
|
1304
1354
|
});
|
|
1305
|
-
return saved;
|
|
1306
1355
|
}
|
|
1307
1356
|
|
|
1308
1357
|
/**
|
|
@@ -1323,14 +1372,20 @@ export class Agent<
|
|
|
1323
1372
|
result: GenerateObjectResult<unknown>;
|
|
1324
1373
|
metadata?: Omit<MessageWithMetadata, "message">;
|
|
1325
1374
|
},
|
|
1326
|
-
): Promise<
|
|
1375
|
+
): Promise<{ messages: MessageDoc[] }> {
|
|
1327
1376
|
const { messages } = await serializeObjectResult(
|
|
1328
1377
|
ctx,
|
|
1329
1378
|
this.component,
|
|
1330
1379
|
args.result,
|
|
1331
1380
|
{
|
|
1332
|
-
model:
|
|
1333
|
-
|
|
1381
|
+
model:
|
|
1382
|
+
args.model ??
|
|
1383
|
+
args.metadata?.model ??
|
|
1384
|
+
getModelName(this.options.languageModel),
|
|
1385
|
+
provider:
|
|
1386
|
+
args.provider ??
|
|
1387
|
+
args.metadata?.provider ??
|
|
1388
|
+
getProviderName(this.options.languageModel),
|
|
1334
1389
|
},
|
|
1335
1390
|
);
|
|
1336
1391
|
const embeddings = await this.generateEmbeddings(
|
|
@@ -1339,7 +1394,7 @@ export class Agent<
|
|
|
1339
1394
|
messages.map((m) => m.message),
|
|
1340
1395
|
);
|
|
1341
1396
|
|
|
1342
|
-
|
|
1397
|
+
return ctx.runMutation(this.component.messages.addMessages, {
|
|
1343
1398
|
userId: args.userId,
|
|
1344
1399
|
threadId: args.threadId,
|
|
1345
1400
|
promptMessageId: args.promptMessageId,
|
|
@@ -1347,7 +1402,6 @@ export class Agent<
|
|
|
1347
1402
|
messages,
|
|
1348
1403
|
embeddings,
|
|
1349
1404
|
agentName: this.options.name,
|
|
1350
|
-
pending: false,
|
|
1351
1405
|
});
|
|
1352
1406
|
}
|
|
1353
1407
|
|
|
@@ -1359,25 +1413,17 @@ export class Agent<
|
|
|
1359
1413
|
* @param args What message to save. Generally the parent message sent into
|
|
1360
1414
|
* the generateText call.
|
|
1361
1415
|
*/
|
|
1362
|
-
async
|
|
1416
|
+
async finalizeMessage(
|
|
1363
1417
|
ctx: RunMutationCtx,
|
|
1364
1418
|
args: {
|
|
1365
|
-
threadId: string;
|
|
1366
1419
|
messageId: string;
|
|
1367
|
-
result: {
|
|
1420
|
+
result: { status: "failed"; error: string } | { status: "success" };
|
|
1368
1421
|
},
|
|
1369
1422
|
): Promise<void> {
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
});
|
|
1375
|
-
} else {
|
|
1376
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
1377
|
-
messageId: args.messageId,
|
|
1378
|
-
error: result.error,
|
|
1379
|
-
});
|
|
1380
|
-
}
|
|
1423
|
+
await ctx.runMutation(this.component.messages.finalizeMessage, {
|
|
1424
|
+
messageId: args.messageId,
|
|
1425
|
+
result: args.result,
|
|
1426
|
+
});
|
|
1381
1427
|
}
|
|
1382
1428
|
|
|
1383
1429
|
/**
|
|
@@ -1392,7 +1438,7 @@ export class Agent<
|
|
|
1392
1438
|
messageId: string;
|
|
1393
1439
|
patch: {
|
|
1394
1440
|
/** The message to replace the existing message. */
|
|
1395
|
-
message:
|
|
1441
|
+
message: ModelMessage | Message;
|
|
1396
1442
|
/** The status to set on the message. */
|
|
1397
1443
|
status: "success" | "error";
|
|
1398
1444
|
/** The error message to set on the message. */
|
|
@@ -1437,9 +1483,7 @@ export class Agent<
|
|
|
1437
1483
|
*/
|
|
1438
1484
|
async deleteMessages(
|
|
1439
1485
|
ctx: RunMutationCtx,
|
|
1440
|
-
args: {
|
|
1441
|
-
messageIds: string[];
|
|
1442
|
-
},
|
|
1486
|
+
args: { messageIds: string[] },
|
|
1443
1487
|
): Promise<void> {
|
|
1444
1488
|
await ctx.runMutation(this.component.messages.deleteByIds, args);
|
|
1445
1489
|
}
|
|
@@ -1452,9 +1496,7 @@ export class Agent<
|
|
|
1452
1496
|
*/
|
|
1453
1497
|
async deleteMessage(
|
|
1454
1498
|
ctx: RunMutationCtx,
|
|
1455
|
-
args: {
|
|
1456
|
-
messageId: string;
|
|
1457
|
-
},
|
|
1499
|
+
args: { messageId: string },
|
|
1458
1500
|
): Promise<void> {
|
|
1459
1501
|
await ctx.runMutation(this.component.messages.deleteByIds, {
|
|
1460
1502
|
messageIds: [args.messageId],
|
|
@@ -1526,10 +1568,7 @@ export class Agent<
|
|
|
1526
1568
|
*/
|
|
1527
1569
|
async deleteThreadAsync(
|
|
1528
1570
|
ctx: RunMutationCtx,
|
|
1529
|
-
args: {
|
|
1530
|
-
threadId: string;
|
|
1531
|
-
pageSize?: number;
|
|
1532
|
-
},
|
|
1571
|
+
args: { threadId: string; pageSize?: number },
|
|
1533
1572
|
): Promise<void> {
|
|
1534
1573
|
await ctx.runMutation(this.component.threads.deleteAllForThreadIdAsync, {
|
|
1535
1574
|
threadId: args.threadId,
|
|
@@ -1546,10 +1585,7 @@ export class Agent<
|
|
|
1546
1585
|
*/
|
|
1547
1586
|
async deleteThreadSync(
|
|
1548
1587
|
ctx: RunActionCtx,
|
|
1549
|
-
args: {
|
|
1550
|
-
threadId: string;
|
|
1551
|
-
pageSize?: number;
|
|
1552
|
-
},
|
|
1588
|
+
args: { threadId: string; pageSize?: number },
|
|
1553
1589
|
): Promise<void> {
|
|
1554
1590
|
await ctx.runAction(this.component.threads.deleteAllForThreadIdSync, {
|
|
1555
1591
|
threadId: args.threadId,
|
|
@@ -1559,13 +1595,12 @@ export class Agent<
|
|
|
1559
1595
|
|
|
1560
1596
|
async _saveMessagesAndFetchContext<
|
|
1561
1597
|
T extends {
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
messages?: CoreMessage[] | AIMessageWithoutId[];
|
|
1598
|
+
prompt?: string | (ModelMessage | Message)[];
|
|
1599
|
+
messages?: (ModelMessage | Message)[];
|
|
1565
1600
|
system?: string;
|
|
1566
1601
|
promptMessageId?: string;
|
|
1567
|
-
|
|
1568
|
-
|
|
1602
|
+
pendingMessageId?: string;
|
|
1603
|
+
model?: LanguageModel;
|
|
1569
1604
|
},
|
|
1570
1605
|
>(
|
|
1571
1606
|
ctx: RunActionCtx,
|
|
@@ -1576,23 +1611,32 @@ export class Agent<
|
|
|
1576
1611
|
contextOptions,
|
|
1577
1612
|
storageOptions,
|
|
1578
1613
|
}: {
|
|
1579
|
-
userId: string | undefined;
|
|
1614
|
+
userId: string | null | undefined;
|
|
1580
1615
|
threadId: string | undefined;
|
|
1581
1616
|
} & Options,
|
|
1582
1617
|
): Promise<{
|
|
1583
|
-
args: T
|
|
1618
|
+
args: Extract<T, { model: LanguageModel; messages: ModelMessage[] }> &
|
|
1619
|
+
CallSettings;
|
|
1584
1620
|
userId: string | undefined;
|
|
1585
|
-
|
|
1621
|
+
promptMessageId: string | undefined;
|
|
1622
|
+
pendingMessageId: string | undefined;
|
|
1586
1623
|
order: number | undefined;
|
|
1587
1624
|
stepOrder: number | undefined;
|
|
1625
|
+
savedMessages: MessageDoc[] | undefined;
|
|
1588
1626
|
}> {
|
|
1589
1627
|
// If only a promptMessageId is provided, this will be empty.
|
|
1590
|
-
const messages =
|
|
1628
|
+
const messages = args.messages ?? [];
|
|
1629
|
+
const prompt: (ModelMessage | Message)[] = !args.prompt
|
|
1630
|
+
? []
|
|
1631
|
+
: Array.isArray(args.prompt)
|
|
1632
|
+
? args.prompt
|
|
1633
|
+
: [{ role: "user", content: args.prompt }];
|
|
1591
1634
|
const userId =
|
|
1592
1635
|
argsUserId ??
|
|
1593
1636
|
(threadId &&
|
|
1594
1637
|
(await ctx.runQuery(this.component.threads.getThread, { threadId }))
|
|
1595
|
-
?.userId)
|
|
1638
|
+
?.userId) ??
|
|
1639
|
+
undefined;
|
|
1596
1640
|
// If only a messageId is provided, this will add that message to the end.
|
|
1597
1641
|
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
1598
1642
|
userId,
|
|
@@ -1603,74 +1647,111 @@ export class Agent<
|
|
|
1603
1647
|
});
|
|
1604
1648
|
// If it was a promptMessageId, pop it off context messages
|
|
1605
1649
|
// and add to the end of messages.
|
|
1606
|
-
|
|
1650
|
+
const promptMessageIndex = args.promptMessageId
|
|
1651
|
+
? contextMessages.findIndex((m) => m._id === args.promptMessageId)
|
|
1652
|
+
: -1;
|
|
1607
1653
|
const promptMessage =
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
? contextMessages.pop()
|
|
1654
|
+
promptMessageIndex !== -1
|
|
1655
|
+
? contextMessages.splice(promptMessageIndex, 1)[0]
|
|
1611
1656
|
: undefined;
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
// the prompt to stand in for the promptMessageId message.
|
|
1615
|
-
promptMessage.message = { role: "user", content: args.prompt };
|
|
1616
|
-
}
|
|
1617
|
-
let messageId = promptMessage?._id;
|
|
1657
|
+
|
|
1658
|
+
let promptMessageId = promptMessage?._id;
|
|
1618
1659
|
let order = promptMessage?.order;
|
|
1619
1660
|
let stepOrder = promptMessage?.stepOrder;
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1661
|
+
let savedMessages = undefined;
|
|
1662
|
+
let pendingMessageId = undefined;
|
|
1663
|
+
if (threadId && storageOptions?.saveMessages !== "none") {
|
|
1664
|
+
let saved: { messages: MessageDoc[] };
|
|
1665
|
+
if (
|
|
1666
|
+
messages.length + prompt.length &&
|
|
1667
|
+
// If it was a promptMessageId, we don't want to save it again.
|
|
1668
|
+
(!args.promptMessageId || storageOptions?.saveMessages === "all")
|
|
1669
|
+
) {
|
|
1670
|
+
const saveAll = storageOptions?.saveMessages === "all";
|
|
1671
|
+
const coreMessages = [...messages, ...prompt];
|
|
1672
|
+
const toSave = saveAll ? coreMessages : coreMessages.slice(-1);
|
|
1673
|
+
const metadata = Array.from({ length: toSave.length }, () => ({}));
|
|
1674
|
+
saved = await this.saveMessages(ctx, {
|
|
1675
|
+
threadId,
|
|
1676
|
+
userId,
|
|
1677
|
+
messages: [...toSave, { role: "assistant", content: [] }],
|
|
1678
|
+
metadata: [...metadata, { status: "pending" }],
|
|
1679
|
+
failPendingSteps: true,
|
|
1680
|
+
pendingMessageId: args.pendingMessageId,
|
|
1681
|
+
});
|
|
1682
|
+
promptMessageId = saved.messages.at(-2)!._id;
|
|
1683
|
+
} else {
|
|
1684
|
+
saved = await this.saveMessages(ctx, {
|
|
1685
|
+
threadId,
|
|
1686
|
+
userId,
|
|
1687
|
+
messages: [{ role: "assistant", content: [] }],
|
|
1688
|
+
metadata: [{ status: "pending" }],
|
|
1689
|
+
failPendingSteps: true,
|
|
1690
|
+
pendingMessageId: args.pendingMessageId,
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
pendingMessageId = saved.messages.at(-1)!._id;
|
|
1694
|
+
order = saved.messages.at(-1)!.order;
|
|
1695
|
+
stepOrder = saved.messages.at(-1)!.stepOrder;
|
|
1696
|
+
// Don't return the pending message
|
|
1697
|
+
savedMessages = saved.messages.slice(0, -1);
|
|
1641
1698
|
}
|
|
1699
|
+
|
|
1642
1700
|
if (promptMessage?.message) {
|
|
1643
|
-
|
|
1644
|
-
|
|
1701
|
+
if (!args.prompt) {
|
|
1702
|
+
// If they override the prompt, we skip the existing prompt message.
|
|
1703
|
+
messages.push(deserializeMessage(promptMessage.message));
|
|
1704
|
+
}
|
|
1645
1705
|
// Lazily generate embeddings for the prompt message, if it doesn't have
|
|
1646
1706
|
// embeddings yet. This can happen if the message was saved in a mutation
|
|
1647
1707
|
// where the LLM is not available.
|
|
1648
|
-
if (!promptMessage.embeddingId && this.options.
|
|
1708
|
+
if (!promptMessage.embeddingId && this.options.textEmbeddingModel) {
|
|
1649
1709
|
await this._generateAndSaveEmbeddings(ctx, [promptMessage]);
|
|
1650
1710
|
}
|
|
1651
1711
|
}
|
|
1652
1712
|
|
|
1713
|
+
const prePrompt = contextMessages.map((m) =>
|
|
1714
|
+
deserializeMessage(m.message!),
|
|
1715
|
+
);
|
|
1716
|
+
let existingResponses: ModelMessage[] = [];
|
|
1717
|
+
if (promptMessageIndex !== -1) {
|
|
1718
|
+
// pull any messages that already responded to the prompt off
|
|
1719
|
+
// and add them after the prompt
|
|
1720
|
+
existingResponses = prePrompt.splice(promptMessageIndex);
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1653
1723
|
let processedMessages = [
|
|
1654
|
-
...
|
|
1724
|
+
...prePrompt,
|
|
1655
1725
|
...messages,
|
|
1726
|
+
...prompt,
|
|
1727
|
+
...existingResponses,
|
|
1656
1728
|
];
|
|
1729
|
+
if (promptMessageIndex === -1) {
|
|
1730
|
+
processedMessages.push(...prompt);
|
|
1731
|
+
} else {
|
|
1732
|
+
// We add the prompt where the prompt message was
|
|
1733
|
+
processedMessages.splice(promptMessageIndex, 0, ...prompt);
|
|
1734
|
+
}
|
|
1657
1735
|
|
|
1658
1736
|
// Process messages to inline localhost files (if not, file urls pointing to localhost will be sent to LLM providers)
|
|
1659
1737
|
if (process.env.CONVEX_CLOUD_URL?.startsWith("http://127.0.0.1")) {
|
|
1660
|
-
processedMessages = await
|
|
1738
|
+
processedMessages = await inlineMessagesFiles(processedMessages);
|
|
1661
1739
|
}
|
|
1662
1740
|
|
|
1663
1741
|
const { prompt: _, model, ...rest } = args;
|
|
1664
1742
|
return {
|
|
1665
1743
|
args: {
|
|
1744
|
+
...this.options.callSettings,
|
|
1666
1745
|
...rest,
|
|
1667
|
-
|
|
1668
|
-
model: model ?? this.options.chat,
|
|
1746
|
+
model: model ?? this.options.languageModel,
|
|
1669
1747
|
system: args.system ?? this.options.instructions,
|
|
1670
1748
|
messages: processedMessages,
|
|
1671
|
-
} as T
|
|
1749
|
+
} as Extract<T, { model: LanguageModel; messages: ModelMessage[] }> &
|
|
1750
|
+
CallSettings,
|
|
1672
1751
|
userId,
|
|
1673
|
-
|
|
1752
|
+
promptMessageId,
|
|
1753
|
+
pendingMessageId,
|
|
1754
|
+
savedMessages,
|
|
1674
1755
|
order,
|
|
1675
1756
|
stepOrder,
|
|
1676
1757
|
};
|
|
@@ -1686,29 +1767,29 @@ export class Agent<
|
|
|
1686
1767
|
headers?: Record<string, string>;
|
|
1687
1768
|
},
|
|
1688
1769
|
): Promise<{ embeddings: number[][] }> {
|
|
1689
|
-
const embeddingModel = this.options.
|
|
1770
|
+
const embeddingModel = this.options.textEmbeddingModel;
|
|
1690
1771
|
assert(
|
|
1691
1772
|
embeddingModel,
|
|
1692
|
-
"a
|
|
1773
|
+
"a textEmbeddingModel is required to be set on the Agent that you're doing vector search with",
|
|
1693
1774
|
);
|
|
1694
1775
|
const result = await embedMany({
|
|
1776
|
+
...this.options.callSettings,
|
|
1695
1777
|
model: embeddingModel,
|
|
1696
1778
|
values: options.values,
|
|
1697
1779
|
abortSignal: options.abortSignal,
|
|
1698
1780
|
headers: options.headers,
|
|
1699
|
-
maxRetries: this.options.maxRetries,
|
|
1700
1781
|
});
|
|
1701
1782
|
if (this.options.usageHandler && result.usage) {
|
|
1702
1783
|
await this.options.usageHandler(ctx, {
|
|
1703
1784
|
userId: options.userId,
|
|
1704
1785
|
threadId: options.threadId,
|
|
1705
1786
|
agentName: this.options.name,
|
|
1706
|
-
model: embeddingModel
|
|
1707
|
-
provider: embeddingModel
|
|
1787
|
+
model: getModelName(embeddingModel),
|
|
1788
|
+
provider: getProviderName(embeddingModel),
|
|
1708
1789
|
providerMetadata: undefined,
|
|
1709
1790
|
usage: {
|
|
1710
|
-
|
|
1711
|
-
|
|
1791
|
+
inputTokens: result.usage.tokens,
|
|
1792
|
+
outputTokens: 0,
|
|
1712
1793
|
totalTokens: result.usage.tokens,
|
|
1713
1794
|
},
|
|
1714
1795
|
});
|
|
@@ -1716,95 +1797,6 @@ export class Agent<
|
|
|
1716
1797
|
return { embeddings: result.embeddings };
|
|
1717
1798
|
}
|
|
1718
1799
|
|
|
1719
|
-
/**
|
|
1720
|
-
* Process messages to inline file and image URLs that point to localhost
|
|
1721
|
-
* by converting them to base64. This solves the problem of LLMs not being
|
|
1722
|
-
* able to access localhost URLs.
|
|
1723
|
-
*/
|
|
1724
|
-
private async _inlineMessagesFiles(
|
|
1725
|
-
messages: CoreMessage[],
|
|
1726
|
-
): Promise<CoreMessage[]> {
|
|
1727
|
-
// Process each message to convert localhost URLs to base64
|
|
1728
|
-
return Promise.all(
|
|
1729
|
-
messages.map(async (message): Promise<CoreMessage> => {
|
|
1730
|
-
if (
|
|
1731
|
-
(message.role !== "user" && message.role !== "assistant") ||
|
|
1732
|
-
typeof message.content === "string" ||
|
|
1733
|
-
!Array.isArray(message.content)
|
|
1734
|
-
) {
|
|
1735
|
-
return message;
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
const processedContent = await Promise.all(
|
|
1739
|
-
message.content.map(async (part) => {
|
|
1740
|
-
if (part.type === "image" && part.image instanceof URL) {
|
|
1741
|
-
assert(
|
|
1742
|
-
message.role === "user",
|
|
1743
|
-
"Images can only be in user messages",
|
|
1744
|
-
);
|
|
1745
|
-
if (this._isLocalhostUrl(part.image)) {
|
|
1746
|
-
const imageData = await this._downloadFile(part.image);
|
|
1747
|
-
return {
|
|
1748
|
-
...part,
|
|
1749
|
-
image: imageData,
|
|
1750
|
-
} as ImagePart;
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
// Handle file parts
|
|
1755
|
-
if (part.type === "file" && part.data instanceof URL) {
|
|
1756
|
-
if (this._isLocalhostUrl(part.data)) {
|
|
1757
|
-
const fileData = await this._downloadFile(part.data);
|
|
1758
|
-
return {
|
|
1759
|
-
...part,
|
|
1760
|
-
data: fileData,
|
|
1761
|
-
} as FilePart;
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
return part;
|
|
1766
|
-
}),
|
|
1767
|
-
);
|
|
1768
|
-
if (message.role === "user") {
|
|
1769
|
-
return {
|
|
1770
|
-
...message,
|
|
1771
|
-
content: processedContent as UserContent,
|
|
1772
|
-
};
|
|
1773
|
-
} else {
|
|
1774
|
-
return {
|
|
1775
|
-
...message,
|
|
1776
|
-
content: processedContent as AssistantContent,
|
|
1777
|
-
};
|
|
1778
|
-
}
|
|
1779
|
-
}),
|
|
1780
|
-
);
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
/**
|
|
1784
|
-
* Check if a URL points to localhost
|
|
1785
|
-
*/
|
|
1786
|
-
private _isLocalhostUrl(url: URL): boolean {
|
|
1787
|
-
return (
|
|
1788
|
-
url.hostname === "localhost" ||
|
|
1789
|
-
url.hostname === "127.0.0.1" ||
|
|
1790
|
-
url.hostname === "::1" ||
|
|
1791
|
-
url.hostname === "0.0.0.0"
|
|
1792
|
-
);
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
/**
|
|
1796
|
-
* Download a file from a URL
|
|
1797
|
-
*/
|
|
1798
|
-
private async _downloadFile(url: URL): Promise<ArrayBuffer> {
|
|
1799
|
-
// Fetch the file
|
|
1800
|
-
const response = await fetch(url);
|
|
1801
|
-
if (!response.ok) {
|
|
1802
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1805
|
-
return await response.arrayBuffer();
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1808
1800
|
/**
|
|
1809
1801
|
* WORKFLOW UTILITIES
|
|
1810
1802
|
*/
|
|
@@ -1845,26 +1837,10 @@ export class Agent<
|
|
|
1845
1837
|
* Create an action out of this agent so you can call it from workflows or other actions
|
|
1846
1838
|
* without a wrapping function.
|
|
1847
1839
|
* @param spec Configuration for the agent acting as an action, including
|
|
1848
|
-
* {@link ContextOptions}, {@link StorageOptions}, and
|
|
1840
|
+
* {@link ContextOptions}, {@link StorageOptions}, and {@link stopWhen}.
|
|
1849
1841
|
*/
|
|
1850
1842
|
asTextAction<DataModel extends GenericDataModel>(
|
|
1851
|
-
spec
|
|
1852
|
-
/**
|
|
1853
|
-
* The maximum number of steps to take in this action.
|
|
1854
|
-
* Defaults to the {@link Agent.maxSteps} option.
|
|
1855
|
-
*/
|
|
1856
|
-
maxSteps?: number;
|
|
1857
|
-
/**
|
|
1858
|
-
* The {@link ContextOptions} to use for fetching contextual messages and
|
|
1859
|
-
* saving input/output messages.
|
|
1860
|
-
* Defaults to the {@link Agent.contextOptions} option.
|
|
1861
|
-
*/
|
|
1862
|
-
contextOptions?: ContextOptions;
|
|
1863
|
-
/**
|
|
1864
|
-
* The {@link StorageOptions} to use for saving input/output messages.
|
|
1865
|
-
* Defaults to the {@link Agent.storageOptions} option.
|
|
1866
|
-
*/
|
|
1867
|
-
storageOptions?: StorageOptions;
|
|
1843
|
+
spec: MaybeCustomCtx<CustomCtx, DataModel, AgentTools> & {
|
|
1868
1844
|
/**
|
|
1869
1845
|
* Whether to stream the text.
|
|
1870
1846
|
* If false, it will generate the text in a single call. (default)
|
|
@@ -1873,49 +1849,36 @@ export class Agent<
|
|
|
1873
1849
|
* defaults if you pass true.
|
|
1874
1850
|
*/
|
|
1875
1851
|
stream?: boolean | StreamingOptions;
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
* ```ts
|
|
1884
|
-
* const myAgent = new Agent<{ orgId: string }>(...);
|
|
1885
|
-
* const myAction = myAgent.asTextAction({
|
|
1886
|
-
* customCtx: (ctx: ActionCtx, target, llmArgs) => {
|
|
1887
|
-
* const orgId = await lookupOrgId(ctx, target.threadId);
|
|
1888
|
-
* return { orgId };
|
|
1889
|
-
* },
|
|
1890
|
-
* });
|
|
1891
|
-
* ```
|
|
1892
|
-
* Then, in your tools, you can
|
|
1893
|
-
*/
|
|
1894
|
-
customCtx: (
|
|
1895
|
-
ctx: GenericActionCtx<DataModel>,
|
|
1896
|
-
target: {
|
|
1897
|
-
userId?: string | undefined;
|
|
1898
|
-
threadId?: string | undefined;
|
|
1899
|
-
},
|
|
1900
|
-
llmArgs: TextArgs<AgentTools>,
|
|
1901
|
-
) => CustomCtx;
|
|
1902
|
-
}
|
|
1903
|
-
: { customCtx?: never }),
|
|
1852
|
+
/**
|
|
1853
|
+
* When to stop generating text.
|
|
1854
|
+
* Defaults to the {@link Agent["options"].stopWhen} option.
|
|
1855
|
+
*/
|
|
1856
|
+
stopWhen?: StopCondition<AgentTools> | Array<StopCondition<AgentTools>>;
|
|
1857
|
+
} & Options,
|
|
1858
|
+
overrides?: CallSettings,
|
|
1904
1859
|
) {
|
|
1905
|
-
const maxSteps = spec?.maxSteps ?? this.options.maxSteps;
|
|
1906
1860
|
return internalActionGeneric({
|
|
1907
1861
|
args: vTextArgs,
|
|
1908
1862
|
handler: async (ctx_, args) => {
|
|
1909
1863
|
const stream =
|
|
1910
|
-
args.stream === true ? spec?.stream || true : spec?.stream ?? false;
|
|
1864
|
+
args.stream === true ? spec?.stream || true : (spec?.stream ?? false);
|
|
1911
1865
|
const targetArgs = { userId: args.userId, threadId: args.threadId };
|
|
1912
1866
|
const llmArgs = {
|
|
1913
|
-
|
|
1867
|
+
stopWhen: spec?.stopWhen ?? this.options.stopWhen,
|
|
1868
|
+
...overrides,
|
|
1914
1869
|
...omit(args, ["storageOptions", "contextOptions"]),
|
|
1915
|
-
|
|
1870
|
+
messages: args.messages?.map(deserializeMessage),
|
|
1871
|
+
prompt: Array.isArray(args.prompt)
|
|
1872
|
+
? args.prompt.map(deserializeMessage)
|
|
1873
|
+
: args.prompt,
|
|
1874
|
+
toolChoice: args.toolChoice as ToolChoice<AgentTools>,
|
|
1875
|
+
} satisfies StreamingTextArgs<AgentTools>;
|
|
1876
|
+
if (args.maxSteps) {
|
|
1877
|
+
llmArgs.stopWhen = stepCountIs(args.maxSteps);
|
|
1878
|
+
}
|
|
1916
1879
|
const opts = {
|
|
1917
1880
|
...this.options,
|
|
1918
|
-
...
|
|
1881
|
+
...pick(spec, ["contextOptions", "storageOptions"]),
|
|
1919
1882
|
...pick(args, ["contextOptions", "storageOptions"]),
|
|
1920
1883
|
saveStreamDeltas: stream,
|
|
1921
1884
|
};
|
|
@@ -1925,23 +1888,37 @@ export class Agent<
|
|
|
1925
1888
|
: ctx_
|
|
1926
1889
|
) as UserActionCtx & CustomCtx;
|
|
1927
1890
|
if (stream) {
|
|
1928
|
-
|
|
1891
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1892
|
+
const result = await this.streamText<any>(
|
|
1893
|
+
ctx,
|
|
1894
|
+
targetArgs,
|
|
1895
|
+
llmArgs,
|
|
1896
|
+
opts,
|
|
1897
|
+
);
|
|
1929
1898
|
await result.consumeStream();
|
|
1930
1899
|
return {
|
|
1931
1900
|
text: await result.text,
|
|
1932
|
-
|
|
1901
|
+
promptMessageId: result.promptMessageId,
|
|
1933
1902
|
order: result.order,
|
|
1934
1903
|
finishReason: await result.finishReason,
|
|
1935
1904
|
warnings: result.warnings,
|
|
1905
|
+
savedMessageIds: result.savedMessages?.map((m) => m._id) ?? [],
|
|
1936
1906
|
};
|
|
1937
1907
|
} else {
|
|
1938
|
-
|
|
1908
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1909
|
+
const res = await this.generateText<any>(
|
|
1910
|
+
ctx,
|
|
1911
|
+
targetArgs,
|
|
1912
|
+
llmArgs,
|
|
1913
|
+
opts,
|
|
1914
|
+
);
|
|
1939
1915
|
return {
|
|
1940
1916
|
text: res.text,
|
|
1941
|
-
|
|
1917
|
+
promptMessageId: res.promptMessageId,
|
|
1942
1918
|
order: res.order,
|
|
1943
1919
|
finishReason: res.finishReason,
|
|
1944
1920
|
warnings: res.warnings,
|
|
1921
|
+
savedMessageIds: res.savedMessages?.map((m) => m._id) ?? [],
|
|
1945
1922
|
};
|
|
1946
1923
|
}
|
|
1947
1924
|
},
|
|
@@ -1952,36 +1929,47 @@ export class Agent<
|
|
|
1952
1929
|
* it from workflows or other actions without a wrapping function.
|
|
1953
1930
|
* @param spec Configuration for the agent acting as an action, including
|
|
1954
1931
|
* the normal parameters to {@link generateObject}, plus {@link ContextOptions}
|
|
1955
|
-
* and
|
|
1932
|
+
* and stopWhen.
|
|
1956
1933
|
*/
|
|
1957
1934
|
asObjectAction<T>(
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1935
|
+
objectArgs: Omit<
|
|
1936
|
+
Parameters<typeof generateObject<FlexibleSchema<T>>>[0],
|
|
1937
|
+
"model"
|
|
1938
|
+
>,
|
|
1939
|
+
options?: Options & MaybeCustomCtx<CustomCtx, DataModel, AgentTools>,
|
|
1963
1940
|
) {
|
|
1964
|
-
const maxSteps = spec?.maxSteps ?? this.options.maxSteps;
|
|
1965
1941
|
return internalActionGeneric({
|
|
1966
1942
|
args: vSafeObjectArgs,
|
|
1967
|
-
handler: async (
|
|
1968
|
-
const
|
|
1969
|
-
const
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1943
|
+
handler: async (ctx_, args) => {
|
|
1944
|
+
const { userId, threadId, callSettings, ...rest } = args;
|
|
1945
|
+
const overrides = pick(rest, ["contextOptions", "storageOptions"]);
|
|
1946
|
+
const targetArgs = { userId, threadId };
|
|
1947
|
+
const llmArgs = {
|
|
1948
|
+
...objectArgs,
|
|
1949
|
+
...callSettings,
|
|
1950
|
+
...omit(rest, ["storageOptions", "contextOptions"]),
|
|
1951
|
+
messages: args.messages?.map(deserializeMessage),
|
|
1952
|
+
prompt: Array.isArray(args.prompt)
|
|
1953
|
+
? args.prompt.map(deserializeMessage)
|
|
1954
|
+
: args.prompt,
|
|
1955
|
+
} as Omit<Parameters<typeof generateObject>[0], "model">;
|
|
1956
|
+
const ctx = (
|
|
1957
|
+
options?.customCtx
|
|
1958
|
+
? { ...ctx_, ...options.customCtx(ctx_, targetArgs, llmArgs) }
|
|
1959
|
+
: ctx_
|
|
1960
|
+
) as UserActionCtx & CustomCtx;
|
|
1961
|
+
const value = await this.generateObject(ctx, targetArgs, llmArgs, {
|
|
1962
|
+
...this.options,
|
|
1963
|
+
...options,
|
|
1964
|
+
...overrides,
|
|
1965
|
+
});
|
|
1979
1966
|
return {
|
|
1980
|
-
object: value.object as T,
|
|
1981
|
-
|
|
1967
|
+
object: convexToJson(value.object as Value) as T,
|
|
1968
|
+
promptMessageId: value.promptMessageId,
|
|
1982
1969
|
order: value.order,
|
|
1983
1970
|
finishReason: value.finishReason,
|
|
1984
1971
|
warnings: value.warnings,
|
|
1972
|
+
savedMessageIds: value.savedMessages?.map((m) => m._id) ?? [],
|
|
1985
1973
|
};
|
|
1986
1974
|
},
|
|
1987
1975
|
});
|
|
@@ -2014,228 +2002,48 @@ export class Agent<
|
|
|
2014
2002
|
userId: v.optional(v.string()),
|
|
2015
2003
|
promptMessageId: v.optional(v.string()),
|
|
2016
2004
|
messages: v.array(vMessageWithMetadata),
|
|
2017
|
-
pending: v.optional(v.boolean()),
|
|
2018
2005
|
failPendingSteps: v.optional(v.boolean()),
|
|
2006
|
+
embeddings: v.optional(vMessageEmbeddings),
|
|
2019
2007
|
},
|
|
2020
2008
|
handler: async (ctx, args) => {
|
|
2021
|
-
const {
|
|
2009
|
+
const { messages } = await this.saveMessages(ctx, {
|
|
2022
2010
|
...args,
|
|
2023
|
-
messages: args.messages.map((m) => m.message),
|
|
2011
|
+
messages: args.messages.map((m) => deserializeMessage(m.message)),
|
|
2024
2012
|
metadata: args.messages.map(({ message: _, ...m }) => m),
|
|
2013
|
+
skipEmbeddings: true,
|
|
2025
2014
|
});
|
|
2026
2015
|
return {
|
|
2027
|
-
lastMessageId,
|
|
2028
|
-
|
|
2016
|
+
lastMessageId: messages.at(-1)!._id,
|
|
2017
|
+
messages: messages.map((m) => pick(m, ["_id", "order", "stepOrder"])),
|
|
2029
2018
|
};
|
|
2030
2019
|
},
|
|
2031
2020
|
});
|
|
2032
2021
|
}
|
|
2033
2022
|
}
|
|
2034
2023
|
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
},
|
|
2052
|
-
) {
|
|
2053
|
-
const { _id: threadId } = await ctx.runMutation(
|
|
2054
|
-
component.threads.createThread,
|
|
2055
|
-
{
|
|
2056
|
-
userId: args?.userId ?? undefined,
|
|
2057
|
-
title: args?.title,
|
|
2058
|
-
summary: args?.summary,
|
|
2059
|
-
},
|
|
2060
|
-
);
|
|
2061
|
-
return threadId;
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
/**
|
|
2065
|
-
* Get the metadata for a thread.
|
|
2066
|
-
* @param ctx A ctx object from a query, mutation, or action.
|
|
2067
|
-
* @param args.threadId The thread to get the metadata for.
|
|
2068
|
-
* @returns The metadata for the thread.
|
|
2069
|
-
*/
|
|
2070
|
-
export async function getThreadMetadata(
|
|
2071
|
-
ctx: RunQueryCtx,
|
|
2072
|
-
component: AgentComponent,
|
|
2073
|
-
args: { threadId: string },
|
|
2074
|
-
): Promise<ThreadDoc> {
|
|
2075
|
-
const thread = await ctx.runQuery(component.threads.getThread, {
|
|
2076
|
-
threadId: args.threadId,
|
|
2077
|
-
});
|
|
2078
|
-
if (!thread) {
|
|
2079
|
-
throw new Error("Thread not found");
|
|
2080
|
-
}
|
|
2081
|
-
return thread;
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
type SaveMessagesArgs = {
|
|
2085
|
-
threadId: string;
|
|
2086
|
-
userId?: string | null;
|
|
2087
|
-
/**
|
|
2088
|
-
* The message that these messages are in response to. They will be
|
|
2089
|
-
* the same "order" as this message, at increasing stepOrder(s).
|
|
2090
|
-
*/
|
|
2091
|
-
promptMessageId?: string;
|
|
2092
|
-
/**
|
|
2093
|
-
* The messages to save.
|
|
2094
|
-
*/
|
|
2095
|
-
messages: CoreMessageMaybeWithId[];
|
|
2096
|
-
/**
|
|
2097
|
-
* Metadata to save with the messages. Each element corresponds to the
|
|
2098
|
-
* message at the same index.
|
|
2099
|
-
*/
|
|
2100
|
-
metadata?: Omit<MessageWithMetadata, "message">[];
|
|
2101
|
-
/**
|
|
2102
|
-
* If false, it will "commit" the messages immediately.
|
|
2103
|
-
* If true, it will mark them as pending until the final step has finished.
|
|
2104
|
-
* Defaults to false.
|
|
2105
|
-
*/
|
|
2106
|
-
pending?: boolean;
|
|
2107
|
-
/**
|
|
2108
|
-
* If true, it will fail any pending steps.
|
|
2109
|
-
* Defaults to false.
|
|
2110
|
-
*/
|
|
2111
|
-
failPendingSteps?: boolean;
|
|
2112
|
-
/**
|
|
2113
|
-
* The embeddings to save with the messages.
|
|
2114
|
-
*/
|
|
2115
|
-
embeddings?: Omit<MessageEmbeddings, "dimension">;
|
|
2116
|
-
};
|
|
2117
|
-
|
|
2118
|
-
/**
|
|
2119
|
-
* Explicitly save messages associated with the thread (& user if provided)
|
|
2120
|
-
*/
|
|
2121
|
-
export async function saveMessages(
|
|
2122
|
-
ctx: RunMutationCtx,
|
|
2123
|
-
component: AgentComponent,
|
|
2124
|
-
args: SaveMessagesArgs & {
|
|
2125
|
-
/**
|
|
2126
|
-
* The agent name to associate with the messages.
|
|
2127
|
-
*/
|
|
2128
|
-
agentName?: string;
|
|
2129
|
-
},
|
|
2130
|
-
) {
|
|
2131
|
-
let embeddings: MessageEmbeddings | undefined;
|
|
2132
|
-
if (args.embeddings) {
|
|
2133
|
-
const dimension = args.embeddings.vectors.find((v) => v !== null)?.length;
|
|
2134
|
-
if (dimension) {
|
|
2135
|
-
validateVectorDimension(dimension);
|
|
2136
|
-
embeddings = {
|
|
2137
|
-
model: args.embeddings.model,
|
|
2138
|
-
dimension,
|
|
2139
|
-
vectors: args.embeddings.vectors,
|
|
2140
|
-
};
|
|
2141
|
-
}
|
|
2024
|
+
async function willContinue(
|
|
2025
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2026
|
+
steps: StepResult<any>[],
|
|
2027
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2028
|
+
stopWhen: StopCondition<any> | Array<StopCondition<any>> | undefined,
|
|
2029
|
+
): Promise<boolean> {
|
|
2030
|
+
const step = steps.at(-1)!;
|
|
2031
|
+
// we aren't doing another round after a tool result
|
|
2032
|
+
// TODO: whether to handle continuing after too much context used..
|
|
2033
|
+
if (step.finishReason !== "tool-calls") return false;
|
|
2034
|
+
// we don't have a tool result, so we'll wait for more
|
|
2035
|
+
if (step.toolCalls.length > step.toolResults.length) return false;
|
|
2036
|
+
if (Array.isArray(stopWhen)) {
|
|
2037
|
+
return (await Promise.all(stopWhen.map(async (s) => s({ steps })))).every(
|
|
2038
|
+
(stop) => !stop,
|
|
2039
|
+
);
|
|
2142
2040
|
}
|
|
2143
|
-
|
|
2144
|
-
threadId: args.threadId,
|
|
2145
|
-
userId: args.userId ?? undefined,
|
|
2146
|
-
agentName: args.agentName,
|
|
2147
|
-
promptMessageId: args.promptMessageId,
|
|
2148
|
-
embeddings,
|
|
2149
|
-
messages: await Promise.all(
|
|
2150
|
-
args.messages.map(async (m, i) => {
|
|
2151
|
-
const { message, fileIds } = await serializeMessage(ctx, component, m);
|
|
2152
|
-
return {
|
|
2153
|
-
...args.metadata?.[i],
|
|
2154
|
-
message,
|
|
2155
|
-
fileIds,
|
|
2156
|
-
} as MessageWithMetadata;
|
|
2157
|
-
}),
|
|
2158
|
-
),
|
|
2159
|
-
failPendingSteps: args.failPendingSteps ?? false,
|
|
2160
|
-
pending: args.pending ?? false,
|
|
2161
|
-
});
|
|
2162
|
-
return {
|
|
2163
|
-
lastMessageId: result.messages.at(-1)!._id,
|
|
2164
|
-
messages: result.messages,
|
|
2165
|
-
};
|
|
2041
|
+
return !(await stopWhen?.({ steps }));
|
|
2166
2042
|
}
|
|
2167
2043
|
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
/**
|
|
2172
|
-
* Metadata to save with the messages. Each element corresponds to the
|
|
2173
|
-
* message at the same index.
|
|
2174
|
-
*/
|
|
2175
|
-
metadata?: Omit<MessageWithMetadata, "message">;
|
|
2176
|
-
/**
|
|
2177
|
-
* The embedding to save with the message.
|
|
2178
|
-
*/
|
|
2179
|
-
embedding?: {
|
|
2180
|
-
vector: number[];
|
|
2181
|
-
model: string;
|
|
2182
|
-
};
|
|
2183
|
-
} & (
|
|
2184
|
-
| {
|
|
2185
|
-
prompt?: undefined;
|
|
2186
|
-
/**
|
|
2187
|
-
* The message to save.
|
|
2188
|
-
*/
|
|
2189
|
-
message: CoreMessage;
|
|
2190
|
-
}
|
|
2191
|
-
| {
|
|
2192
|
-
/*
|
|
2193
|
-
* The prompt to save with the message.
|
|
2194
|
-
*/
|
|
2195
|
-
prompt: string;
|
|
2196
|
-
message?: undefined;
|
|
2197
|
-
}
|
|
2198
|
-
);
|
|
2199
|
-
|
|
2200
|
-
/**
|
|
2201
|
-
* Save a message to the thread.
|
|
2202
|
-
* @param ctx A ctx object from a mutation or action.
|
|
2203
|
-
* @param args The message and what to associate it with (user / thread)
|
|
2204
|
-
* You can pass extra metadata alongside the message, e.g. associated fileIds.
|
|
2205
|
-
* @returns The messageId of the saved message.
|
|
2206
|
-
*/
|
|
2207
|
-
export async function saveMessage(
|
|
2208
|
-
ctx: RunMutationCtx,
|
|
2209
|
-
component: AgentComponent,
|
|
2210
|
-
args: SaveMessageArgs & {
|
|
2211
|
-
/**
|
|
2212
|
-
* The agent name to associate with the message.
|
|
2213
|
-
*/
|
|
2214
|
-
agentName?: string;
|
|
2215
|
-
},
|
|
2216
|
-
) {
|
|
2217
|
-
let embeddings:
|
|
2218
|
-
| {
|
|
2219
|
-
vectors: number[][];
|
|
2220
|
-
model: string;
|
|
2221
|
-
}
|
|
2222
|
-
| undefined;
|
|
2223
|
-
if (args.embedding && args.embedding.vector) {
|
|
2224
|
-
embeddings = {
|
|
2225
|
-
model: args.embedding.model,
|
|
2226
|
-
vectors: [args.embedding.vector],
|
|
2227
|
-
};
|
|
2044
|
+
function errorToString(error: unknown): string {
|
|
2045
|
+
if (error instanceof Error) {
|
|
2046
|
+
return error.message;
|
|
2228
2047
|
}
|
|
2229
|
-
|
|
2230
|
-
threadId: args.threadId,
|
|
2231
|
-
userId: args.userId ?? undefined,
|
|
2232
|
-
agentName: args.agentName,
|
|
2233
|
-
messages:
|
|
2234
|
-
args.prompt !== undefined
|
|
2235
|
-
? [{ role: "user", content: args.prompt }]
|
|
2236
|
-
: [args.message],
|
|
2237
|
-
metadata: args.metadata ? [args.metadata] : undefined,
|
|
2238
|
-
embeddings,
|
|
2239
|
-
});
|
|
2240
|
-
return { messageId: lastMessageId, message: messages.at(-1)! };
|
|
2048
|
+
return String(error);
|
|
2241
2049
|
}
|