@convex-dev/agent 0.1.10 → 0.1.11
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/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +25 -24
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/mapping.d.ts +1 -0
- package/dist/esm/mapping.d.ts.map +1 -1
- package/dist/esm/mapping.js +2 -2
- package/dist/esm/mapping.js.map +1 -1
- package/dist/esm.tsbuildinfo +1 -1
- package/package.json +23 -53
- package/src/client/index.ts +27 -27
- package/src/mapping.ts +9 -2
- package/dist/commonjs/client/_generated/_ignore.d.ts +0 -1
- package/dist/commonjs/client/_generated/_ignore.d.ts.map +0 -1
- package/dist/commonjs/client/_generated/_ignore.js +0 -3
- package/dist/commonjs/client/_generated/_ignore.js.map +0 -1
- package/dist/commonjs/client/createTool.d.ts +0 -47
- package/dist/commonjs/client/createTool.d.ts.map +0 -1
- package/dist/commonjs/client/createTool.js +0 -49
- package/dist/commonjs/client/createTool.js.map +0 -1
- package/dist/commonjs/client/files.d.ts +0 -56
- package/dist/commonjs/client/files.d.ts.map +0 -1
- package/dist/commonjs/client/files.js +0 -129
- package/dist/commonjs/client/files.js.map +0 -1
- package/dist/commonjs/client/index.d.ts +0 -1355
- package/dist/commonjs/client/index.d.ts.map +0 -1
- package/dist/commonjs/client/index.js +0 -1169
- package/dist/commonjs/client/index.js.map +0 -1
- package/dist/commonjs/client/streaming.d.ts +0 -57
- package/dist/commonjs/client/streaming.d.ts.map +0 -1
- package/dist/commonjs/client/streaming.js +0 -148
- package/dist/commonjs/client/streaming.js.map +0 -1
- package/dist/commonjs/client/types.d.ts +0 -352
- package/dist/commonjs/client/types.d.ts.map +0 -1
- package/dist/commonjs/client/types.js +0 -3
- package/dist/commonjs/client/types.js.map +0 -1
- package/dist/commonjs/component/_generated/api.d.ts +0 -1938
- package/dist/commonjs/component/_generated/api.d.ts.map +0 -1
- package/dist/commonjs/component/_generated/api.js +0 -25
- package/dist/commonjs/component/_generated/api.js.map +0 -1
- package/dist/commonjs/component/_generated/dataModel.d.ts +0 -60
- package/dist/commonjs/component/_generated/server.d.ts +0 -149
- package/dist/commonjs/component/_generated/server.d.ts.map +0 -1
- package/dist/commonjs/component/_generated/server.js +0 -77
- package/dist/commonjs/component/_generated/server.js.map +0 -1
- package/dist/commonjs/component/apiKeys.d.ts +0 -11
- package/dist/commonjs/component/apiKeys.d.ts.map +0 -1
- package/dist/commonjs/component/apiKeys.js +0 -72
- package/dist/commonjs/component/apiKeys.js.map +0 -1
- package/dist/commonjs/component/convex.config.d.ts +0 -3
- package/dist/commonjs/component/convex.config.d.ts.map +0 -1
- package/dist/commonjs/component/convex.config.js +0 -5
- package/dist/commonjs/component/convex.config.js.map +0 -1
- package/dist/commonjs/component/files.d.ts +0 -90
- package/dist/commonjs/component/files.d.ts.map +0 -1
- package/dist/commonjs/component/files.js +0 -157
- package/dist/commonjs/component/files.js.map +0 -1
- package/dist/commonjs/component/messages.d.ts +0 -1479
- package/dist/commonjs/component/messages.d.ts.map +0 -1
- package/dist/commonjs/component/messages.js +0 -483
- package/dist/commonjs/component/messages.js.map +0 -1
- package/dist/commonjs/component/schema.d.ts +0 -4582
- package/dist/commonjs/component/schema.d.ts.map +0 -1
- package/dist/commonjs/component/schema.js +0 -167
- package/dist/commonjs/component/schema.js.map +0 -1
- package/dist/commonjs/component/streams.d.ts +0 -242
- package/dist/commonjs/component/streams.d.ts.map +0 -1
- package/dist/commonjs/component/streams.js +0 -323
- package/dist/commonjs/component/streams.js.map +0 -1
- package/dist/commonjs/component/threads.d.ts +0 -101
- package/dist/commonjs/component/threads.d.ts.map +0 -1
- package/dist/commonjs/component/threads.js +0 -188
- package/dist/commonjs/component/threads.js.map +0 -1
- package/dist/commonjs/component/users.d.ts +0 -52
- package/dist/commonjs/component/users.d.ts.map +0 -1
- package/dist/commonjs/component/users.js +0 -233
- package/dist/commonjs/component/users.js.map +0 -1
- package/dist/commonjs/component/vector/index.d.ts +0 -61
- package/dist/commonjs/component/vector/index.d.ts.map +0 -1
- package/dist/commonjs/component/vector/index.js +0 -153
- package/dist/commonjs/component/vector/index.js.map +0 -1
- package/dist/commonjs/component/vector/tables.d.ts +0 -58
- package/dist/commonjs/component/vector/tables.d.ts.map +0 -1
- package/dist/commonjs/component/vector/tables.js +0 -62
- package/dist/commonjs/component/vector/tables.js.map +0 -1
- package/dist/commonjs/mapping.d.ts +0 -50
- package/dist/commonjs/mapping.d.ts.map +0 -1
- package/dist/commonjs/mapping.js +0 -272
- package/dist/commonjs/mapping.js.map +0 -1
- package/dist/commonjs/package.json +0 -3
- package/dist/commonjs/react/deltas.d.ts +0 -29
- package/dist/commonjs/react/deltas.d.ts.map +0 -1
- package/dist/commonjs/react/deltas.js +0 -274
- package/dist/commonjs/react/deltas.js.map +0 -1
- package/dist/commonjs/react/index.d.ts +0 -95
- package/dist/commonjs/react/index.d.ts.map +0 -1
- package/dist/commonjs/react/index.js +0 -219
- package/dist/commonjs/react/index.js.map +0 -1
- package/dist/commonjs/react/optimisticallySendMessage.d.ts +0 -8
- package/dist/commonjs/react/optimisticallySendMessage.d.ts.map +0 -1
- package/dist/commonjs/react/optimisticallySendMessage.js +0 -43
- package/dist/commonjs/react/optimisticallySendMessage.js.map +0 -1
- package/dist/commonjs/react/toUIMessages.d.ts +0 -13
- package/dist/commonjs/react/toUIMessages.d.ts.map +0 -1
- package/dist/commonjs/react/toUIMessages.js +0 -149
- package/dist/commonjs/react/toUIMessages.js.map +0 -1
- package/dist/commonjs/react/types.d.ts +0 -26
- package/dist/commonjs/react/types.d.ts.map +0 -1
- package/dist/commonjs/react/types.js +0 -3
- package/dist/commonjs/react/types.js.map +0 -1
- package/dist/commonjs/react/useSmoothText.d.ts +0 -20
- package/dist/commonjs/react/useSmoothText.d.ts.map +0 -1
- package/dist/commonjs/react/useSmoothText.js +0 -54
- package/dist/commonjs/react/useSmoothText.js.map +0 -1
- package/dist/commonjs/shared.d.ts +0 -10
- package/dist/commonjs/shared.d.ts.map +0 -1
- package/dist/commonjs/shared.js +0 -35
- package/dist/commonjs/shared.js.map +0 -1
- package/dist/commonjs/validators.d.ts +0 -5716
- package/dist/commonjs/validators.d.ts.map +0 -1
- package/dist/commonjs/validators.js +0 -319
- package/dist/commonjs/validators.js.map +0 -1
- package/dist/commonjs/vitest.config.d.ts +0 -3
- package/dist/commonjs/vitest.config.d.ts.map +0 -1
- package/dist/commonjs/vitest.config.js +0 -9
- package/dist/commonjs/vitest.config.js.map +0 -1
- package/dist/commonjs.tsbuildinfo +0 -1
- package/dist/esm/vitest.config.d.ts +0 -3
- package/dist/esm/vitest.config.d.ts.map +0 -1
- package/dist/esm/vitest.config.js +0 -7
- package/dist/esm/vitest.config.js.map +0 -1
- package/react/package.json +0 -5
- package/validators/package.json +0 -5
|
@@ -1,1169 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Agent = exports.isTool = exports.extractText = exports.createTool = exports.vUserMessage = exports.vUsage = exports.vToolMessage = exports.vSystemMessage = exports.vStreamArgs = exports.vStorageOptions = exports.vProviderMetadata = exports.vPaginationResult = exports.vMessage = exports.vContextOptions = exports.vAssistantMessage = exports.vThreadDoc = exports.vMessageDoc = exports.serializeDataOrUrl = exports.getFile = exports.storeFile = void 0;
|
|
4
|
-
exports.filterOutOrphanedToolMessages = filterOutOrphanedToolMessages;
|
|
5
|
-
const ai_1 = require("ai");
|
|
6
|
-
const convex_helpers_1 = require("convex-helpers");
|
|
7
|
-
const server_1 = require("convex/server");
|
|
8
|
-
const values_1 = require("convex/values");
|
|
9
|
-
const tables_js_1 = require("../component/vector/tables.js");
|
|
10
|
-
const mapping_js_1 = require("../mapping.js");
|
|
11
|
-
const shared_js_1 = require("../shared.js");
|
|
12
|
-
Object.defineProperty(exports, "extractText", { enumerable: true, get: function () { return shared_js_1.extractText; } });
|
|
13
|
-
Object.defineProperty(exports, "isTool", { enumerable: true, get: function () { return shared_js_1.isTool; } });
|
|
14
|
-
const validators_js_1 = require("../validators.js");
|
|
15
|
-
const createTool_js_1 = require("./createTool.js");
|
|
16
|
-
Object.defineProperty(exports, "createTool", { enumerable: true, get: function () { return createTool_js_1.createTool; } });
|
|
17
|
-
const streaming_js_1 = require("./streaming.js");
|
|
18
|
-
var files_js_1 = require("./files.js");
|
|
19
|
-
Object.defineProperty(exports, "storeFile", { enumerable: true, get: function () { return files_js_1.storeFile; } });
|
|
20
|
-
Object.defineProperty(exports, "getFile", { enumerable: true, get: function () { return files_js_1.getFile; } });
|
|
21
|
-
var mapping_js_2 = require("../mapping.js");
|
|
22
|
-
Object.defineProperty(exports, "serializeDataOrUrl", { enumerable: true, get: function () { return mapping_js_2.serializeDataOrUrl; } });
|
|
23
|
-
var schema_js_1 = require("../component/schema.js");
|
|
24
|
-
Object.defineProperty(exports, "vMessageDoc", { enumerable: true, get: function () { return schema_js_1.vMessageDoc; } });
|
|
25
|
-
Object.defineProperty(exports, "vThreadDoc", { enumerable: true, get: function () { return schema_js_1.vThreadDoc; } });
|
|
26
|
-
var validators_js_2 = require("../validators.js");
|
|
27
|
-
Object.defineProperty(exports, "vAssistantMessage", { enumerable: true, get: function () { return validators_js_2.vAssistantMessage; } });
|
|
28
|
-
Object.defineProperty(exports, "vContextOptions", { enumerable: true, get: function () { return validators_js_2.vContextOptions; } });
|
|
29
|
-
Object.defineProperty(exports, "vMessage", { enumerable: true, get: function () { return validators_js_2.vMessage; } });
|
|
30
|
-
Object.defineProperty(exports, "vPaginationResult", { enumerable: true, get: function () { return validators_js_2.vPaginationResult; } });
|
|
31
|
-
Object.defineProperty(exports, "vProviderMetadata", { enumerable: true, get: function () { return validators_js_2.vProviderMetadata; } });
|
|
32
|
-
Object.defineProperty(exports, "vStorageOptions", { enumerable: true, get: function () { return validators_js_2.vStorageOptions; } });
|
|
33
|
-
Object.defineProperty(exports, "vStreamArgs", { enumerable: true, get: function () { return validators_js_2.vStreamArgs; } });
|
|
34
|
-
Object.defineProperty(exports, "vSystemMessage", { enumerable: true, get: function () { return validators_js_2.vSystemMessage; } });
|
|
35
|
-
Object.defineProperty(exports, "vToolMessage", { enumerable: true, get: function () { return validators_js_2.vToolMessage; } });
|
|
36
|
-
Object.defineProperty(exports, "vUsage", { enumerable: true, get: function () { return validators_js_2.vUsage; } });
|
|
37
|
-
Object.defineProperty(exports, "vUserMessage", { enumerable: true, get: function () { return validators_js_2.vUserMessage; } });
|
|
38
|
-
class Agent {
|
|
39
|
-
component;
|
|
40
|
-
options;
|
|
41
|
-
constructor(component, options) {
|
|
42
|
-
this.component = component;
|
|
43
|
-
this.options = options;
|
|
44
|
-
}
|
|
45
|
-
async createThread(ctx, args) {
|
|
46
|
-
const threadDoc = await ctx.runMutation(this.component.threads.createThread, {
|
|
47
|
-
userId: args?.userId,
|
|
48
|
-
title: args?.title,
|
|
49
|
-
summary: args?.summary,
|
|
50
|
-
});
|
|
51
|
-
if (!("runAction" in ctx)) {
|
|
52
|
-
return { threadId: threadDoc._id };
|
|
53
|
-
}
|
|
54
|
-
const { thread } = await this.continueThread(ctx, {
|
|
55
|
-
threadId: threadDoc._id,
|
|
56
|
-
userId: args?.userId,
|
|
57
|
-
usageHandler: args?.usageHandler,
|
|
58
|
-
tools: args?.tools,
|
|
59
|
-
});
|
|
60
|
-
return {
|
|
61
|
-
threadId: threadDoc._id,
|
|
62
|
-
thread,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Continues a thread using this agent. Note: threads can be continued
|
|
67
|
-
* by different agents. This is a convenience around calling the various
|
|
68
|
-
* generate and stream functions with explicit userId and threadId parameters.
|
|
69
|
-
* @param ctx The ctx object passed to the action handler
|
|
70
|
-
* @param { threadId, userId }: the thread and user to associate the messages with.
|
|
71
|
-
* @returns Functions bound to the userId and threadId on a `{thread}` object.
|
|
72
|
-
*/
|
|
73
|
-
async continueThread(ctx, args) {
|
|
74
|
-
return {
|
|
75
|
-
thread: {
|
|
76
|
-
threadId: args.threadId,
|
|
77
|
-
getMetadata: this.getThreadMetadata.bind(this, ctx, {
|
|
78
|
-
threadId: args.threadId,
|
|
79
|
-
}),
|
|
80
|
-
updateMetadata: (patch) => ctx.runMutation(this.component.threads.updateThread, {
|
|
81
|
-
threadId: args.threadId,
|
|
82
|
-
patch,
|
|
83
|
-
}),
|
|
84
|
-
generateText: this.generateText.bind(this, ctx, args),
|
|
85
|
-
streamText: this.streamText.bind(this, ctx, args),
|
|
86
|
-
generateObject: this.generateObject.bind(this, ctx, args),
|
|
87
|
-
streamObject: this.streamObject.bind(this, ctx, args),
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* This behaves like {@link generateText} from the "ai" package except that
|
|
93
|
-
* it add context based on the userId and threadId and saves the input and
|
|
94
|
-
* resulting messages to the thread, if specified.
|
|
95
|
-
* Use {@link continueThread} to get a version of this function already scoped
|
|
96
|
-
* to a thread (and optionally userId).
|
|
97
|
-
* @param ctx The context passed from the action function calling this.
|
|
98
|
-
* @param { userId, threadId }: The user and thread to associate the message with
|
|
99
|
-
* @param args The arguments to the generateText function, along with extra controls
|
|
100
|
-
* for the {@link ContextOptions} and {@link StorageOptions}.
|
|
101
|
-
* @returns The result of the generateText function.
|
|
102
|
-
*/
|
|
103
|
-
async generateText(ctx, { userId: argsUserId, threadId, usageHandler, tools: threadTools, }, args, options) {
|
|
104
|
-
const context = await this._saveMessagesAndFetchContext(ctx, args, {
|
|
105
|
-
userId: argsUserId,
|
|
106
|
-
threadId,
|
|
107
|
-
...options,
|
|
108
|
-
});
|
|
109
|
-
const { args: aiArgs, messageId, userId } = context;
|
|
110
|
-
const toolCtx = { ...ctx, userId, threadId, messageId, agent: this };
|
|
111
|
-
const tools = (0, createTool_js_1.wrapTools)(toolCtx, args.tools ?? threadTools ?? this.options.tools);
|
|
112
|
-
const saveOutputMessages = this._shouldSaveOutputMessages(options?.storageOptions);
|
|
113
|
-
const trackUsage = usageHandler ?? this.options.usageHandler;
|
|
114
|
-
try {
|
|
115
|
-
const result = (await (0, ai_1.generateText)({
|
|
116
|
-
// Can be overridden
|
|
117
|
-
maxSteps: this.options.maxSteps,
|
|
118
|
-
...aiArgs,
|
|
119
|
-
tools,
|
|
120
|
-
onStepFinish: async (step) => {
|
|
121
|
-
if (threadId && messageId && saveOutputMessages) {
|
|
122
|
-
await this.saveStep(ctx, {
|
|
123
|
-
userId,
|
|
124
|
-
threadId,
|
|
125
|
-
promptMessageId: messageId,
|
|
126
|
-
step,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
if (this.options.rawRequestResponseHandler) {
|
|
130
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
131
|
-
userId,
|
|
132
|
-
threadId,
|
|
133
|
-
agentName: this.options.name,
|
|
134
|
-
request: step.request,
|
|
135
|
-
response: step.response,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
if (trackUsage && step.usage) {
|
|
139
|
-
await trackUsage(ctx, {
|
|
140
|
-
userId,
|
|
141
|
-
threadId,
|
|
142
|
-
agentName: this.options.name,
|
|
143
|
-
model: aiArgs.model.modelId,
|
|
144
|
-
provider: aiArgs.model.provider,
|
|
145
|
-
usage: step.usage,
|
|
146
|
-
providerMetadata: step.providerMetadata,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
return args.onStepFinish?.(step);
|
|
150
|
-
},
|
|
151
|
-
}));
|
|
152
|
-
result.messageId = messageId;
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
if (threadId && messageId) {
|
|
157
|
-
console.error("RollbackMessage", messageId);
|
|
158
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
159
|
-
messageId,
|
|
160
|
-
error: error.message,
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
throw error;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* This behaves like {@link streamText} from the "ai" package except that
|
|
168
|
-
* it add context based on the userId and threadId and saves the input and
|
|
169
|
-
* resulting messages to the thread, if specified.
|
|
170
|
-
* Use {@link continueThread} to get a version of this function already scoped
|
|
171
|
-
* to a thread (and optionally userId).
|
|
172
|
-
*/
|
|
173
|
-
async streamText(ctx, { userId: argsUserId, threadId, usageHandler,
|
|
174
|
-
/**
|
|
175
|
-
* @deprecated Pass `tools` in the next parameter instead.
|
|
176
|
-
* This is only intended to pass through thread-default tools.
|
|
177
|
-
*/
|
|
178
|
-
tools: threadTools, },
|
|
179
|
-
/**
|
|
180
|
-
* The arguments to the streamText function, similar to the ai `streamText` function.
|
|
181
|
-
*/
|
|
182
|
-
args,
|
|
183
|
-
/**
|
|
184
|
-
* The {@link ContextOptions} and {@link StorageOptions}
|
|
185
|
-
* options to use for fetching contextual messages and saving input/output messages.
|
|
186
|
-
*/
|
|
187
|
-
options) {
|
|
188
|
-
const context = await this._saveMessagesAndFetchContext(ctx, args, {
|
|
189
|
-
userId: argsUserId,
|
|
190
|
-
threadId,
|
|
191
|
-
...options,
|
|
192
|
-
});
|
|
193
|
-
const { args: aiArgs, messageId, order, stepOrder, userId } = context;
|
|
194
|
-
const toolCtx = { ...ctx, userId, threadId, messageId, agent: this };
|
|
195
|
-
const tools = (0, createTool_js_1.wrapTools)(toolCtx, args.tools ?? threadTools ?? this.options.tools);
|
|
196
|
-
const saveOutputMessages = this._shouldSaveOutputMessages(options?.storageOptions);
|
|
197
|
-
const trackUsage = usageHandler ?? this.options.usageHandler;
|
|
198
|
-
const streamer = threadId && options?.saveStreamDeltas
|
|
199
|
-
? new streaming_js_1.DeltaStreamer(this.component, ctx, options.saveStreamDeltas, {
|
|
200
|
-
threadId,
|
|
201
|
-
userId,
|
|
202
|
-
agentName: this.options.name,
|
|
203
|
-
model: aiArgs.model.modelId,
|
|
204
|
-
provider: aiArgs.model.provider,
|
|
205
|
-
providerOptions: aiArgs.providerOptions,
|
|
206
|
-
order,
|
|
207
|
-
stepOrder,
|
|
208
|
-
abortSignal: aiArgs.abortSignal,
|
|
209
|
-
})
|
|
210
|
-
: undefined;
|
|
211
|
-
const result = (0, ai_1.streamText)({
|
|
212
|
-
// Can be overridden
|
|
213
|
-
maxSteps: this.options.maxSteps,
|
|
214
|
-
...aiArgs,
|
|
215
|
-
tools,
|
|
216
|
-
abortSignal: streamer?.abortController.signal ?? aiArgs.abortSignal,
|
|
217
|
-
experimental_transform: (0, streaming_js_1.mergeTransforms)(options?.saveStreamDeltas, args.experimental_transform),
|
|
218
|
-
onChunk: async (event) => {
|
|
219
|
-
await streamer?.addParts([event.chunk]);
|
|
220
|
-
// console.log("onChunk", chunk);
|
|
221
|
-
return args.onChunk?.(event);
|
|
222
|
-
},
|
|
223
|
-
onError: async (error) => {
|
|
224
|
-
console.error("onError", error);
|
|
225
|
-
if (threadId && messageId && saveOutputMessages) {
|
|
226
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
227
|
-
messageId,
|
|
228
|
-
error: error.error.message,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
return args.onError?.(error);
|
|
232
|
-
},
|
|
233
|
-
onStepFinish: async (step) => {
|
|
234
|
-
// console.log("onStepFinish", step);
|
|
235
|
-
// TODO: compare delta to the output. internally drop the deltas when committing
|
|
236
|
-
if (threadId && messageId) {
|
|
237
|
-
const saved = await this.saveStep(ctx, {
|
|
238
|
-
userId,
|
|
239
|
-
threadId,
|
|
240
|
-
promptMessageId: messageId,
|
|
241
|
-
step,
|
|
242
|
-
});
|
|
243
|
-
// TODO: figure out pending/not
|
|
244
|
-
await streamer?.finish(saved.messages);
|
|
245
|
-
}
|
|
246
|
-
if (this.options.rawRequestResponseHandler) {
|
|
247
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
248
|
-
userId,
|
|
249
|
-
threadId,
|
|
250
|
-
agentName: this.options.name,
|
|
251
|
-
request: step.request,
|
|
252
|
-
response: step.response,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
if (trackUsage && step.usage) {
|
|
256
|
-
await trackUsage(ctx, {
|
|
257
|
-
userId,
|
|
258
|
-
threadId,
|
|
259
|
-
agentName: this.options.name,
|
|
260
|
-
model: aiArgs.model.modelId,
|
|
261
|
-
provider: aiArgs.model.provider,
|
|
262
|
-
usage: step.usage,
|
|
263
|
-
providerMetadata: step.providerMetadata,
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
return args.onStepFinish?.(step);
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
result.messageId = messageId;
|
|
270
|
-
return result;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* This behaves like {@link generateObject} from the "ai" package except that
|
|
274
|
-
* it add context based on the userId and threadId and saves the input and
|
|
275
|
-
* resulting messages to the thread, if specified.
|
|
276
|
-
* Use {@link continueThread} to get a version of this function already scoped
|
|
277
|
-
* to a thread (and optionally userId).
|
|
278
|
-
*/
|
|
279
|
-
async generateObject(ctx, { userId: argsUserId, threadId, usageHandler, },
|
|
280
|
-
/**
|
|
281
|
-
* The arguments to the generateObject function, similar to the ai.generateObject function.
|
|
282
|
-
*/
|
|
283
|
-
args,
|
|
284
|
-
/**
|
|
285
|
-
* The {@link ContextOptions} and {@link StorageOptions}
|
|
286
|
-
* options to use for fetching contextual messages and saving input/output messages.
|
|
287
|
-
*/
|
|
288
|
-
options) {
|
|
289
|
-
const context = await this._saveMessagesAndFetchContext(ctx, args, {
|
|
290
|
-
userId: argsUserId,
|
|
291
|
-
threadId,
|
|
292
|
-
...options,
|
|
293
|
-
});
|
|
294
|
-
const { args: aiArgs, messageId, userId } = context;
|
|
295
|
-
const trackUsage = usageHandler ?? this.options.usageHandler;
|
|
296
|
-
const saveOutputMessages = this._shouldSaveOutputMessages(options?.storageOptions);
|
|
297
|
-
try {
|
|
298
|
-
const result = (await (0, ai_1.generateObject)(
|
|
299
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
300
|
-
aiArgs));
|
|
301
|
-
if (threadId && messageId && saveOutputMessages) {
|
|
302
|
-
await this.saveObject(ctx, {
|
|
303
|
-
threadId,
|
|
304
|
-
promptMessageId: messageId,
|
|
305
|
-
result,
|
|
306
|
-
userId,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
result.messageId = messageId;
|
|
310
|
-
if (this.options.rawRequestResponseHandler) {
|
|
311
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
312
|
-
userId,
|
|
313
|
-
threadId,
|
|
314
|
-
agentName: this.options.name,
|
|
315
|
-
request: result.request,
|
|
316
|
-
response: result.response,
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
if (trackUsage && result.usage) {
|
|
320
|
-
await trackUsage(ctx, {
|
|
321
|
-
userId,
|
|
322
|
-
threadId,
|
|
323
|
-
agentName: this.options.name,
|
|
324
|
-
model: aiArgs.model.modelId,
|
|
325
|
-
provider: aiArgs.model.provider,
|
|
326
|
-
usage: result.usage,
|
|
327
|
-
providerMetadata: result.providerMetadata,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
return result;
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
if (threadId && messageId) {
|
|
334
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
335
|
-
messageId,
|
|
336
|
-
error: error.message,
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
throw error;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* This behaves like `streamObject` from the "ai" package except that
|
|
344
|
-
* it add context based on the userId and threadId and saves the input and
|
|
345
|
-
* resulting messages to the thread, if specified.
|
|
346
|
-
* Use {@link continueThread} to get a version of this function already scoped
|
|
347
|
-
* to a thread (and optionally userId).
|
|
348
|
-
*/
|
|
349
|
-
async streamObject(ctx, { userId: argsUserId, threadId, usageHandler, },
|
|
350
|
-
/**
|
|
351
|
-
* The arguments to the streamObject function, similar to the ai `streamObject` function.
|
|
352
|
-
*/
|
|
353
|
-
args,
|
|
354
|
-
/**
|
|
355
|
-
* The {@link ContextOptions} and {@link StorageOptions}
|
|
356
|
-
* options to use for fetching contextual messages and saving input/output messages.
|
|
357
|
-
*/
|
|
358
|
-
options) {
|
|
359
|
-
// TODO: unify all this shared code between all the generate* and stream* functions
|
|
360
|
-
const context = await this._saveMessagesAndFetchContext(ctx, args, {
|
|
361
|
-
userId: argsUserId,
|
|
362
|
-
threadId,
|
|
363
|
-
...options,
|
|
364
|
-
});
|
|
365
|
-
const { args: aiArgs, messageId, userId } = context;
|
|
366
|
-
const trackUsage = usageHandler ?? this.options.usageHandler;
|
|
367
|
-
const saveOutputMessages = this._shouldSaveOutputMessages(options?.storageOptions);
|
|
368
|
-
const stream = (0, ai_1.streamObject)({
|
|
369
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
370
|
-
...aiArgs,
|
|
371
|
-
onError: async (error) => {
|
|
372
|
-
console.error("onError", error);
|
|
373
|
-
return args.onError?.(error);
|
|
374
|
-
},
|
|
375
|
-
onFinish: async (result) => {
|
|
376
|
-
if (threadId && messageId && saveOutputMessages) {
|
|
377
|
-
await this.saveObject(ctx, {
|
|
378
|
-
userId,
|
|
379
|
-
threadId,
|
|
380
|
-
promptMessageId: messageId,
|
|
381
|
-
result: {
|
|
382
|
-
object: result.object,
|
|
383
|
-
finishReason: "stop",
|
|
384
|
-
usage: result.usage,
|
|
385
|
-
warnings: result.warnings,
|
|
386
|
-
request: await stream.request,
|
|
387
|
-
response: result.response,
|
|
388
|
-
providerMetadata: result.providerMetadata,
|
|
389
|
-
experimental_providerMetadata: result.experimental_providerMetadata,
|
|
390
|
-
logprobs: undefined,
|
|
391
|
-
toJsonResponse: stream.toTextStreamResponse,
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
if (trackUsage && result.usage) {
|
|
396
|
-
await trackUsage(ctx, {
|
|
397
|
-
userId,
|
|
398
|
-
threadId,
|
|
399
|
-
agentName: this.options.name,
|
|
400
|
-
model: aiArgs.model.modelId,
|
|
401
|
-
provider: aiArgs.model.provider,
|
|
402
|
-
usage: result.usage,
|
|
403
|
-
providerMetadata: result.providerMetadata,
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
if (this.options.rawRequestResponseHandler) {
|
|
407
|
-
await this.options.rawRequestResponseHandler(ctx, {
|
|
408
|
-
userId,
|
|
409
|
-
threadId,
|
|
410
|
-
agentName: this.options.name,
|
|
411
|
-
request: await stream.request,
|
|
412
|
-
response: result.response,
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
416
|
-
return args.onFinish?.(result);
|
|
417
|
-
},
|
|
418
|
-
});
|
|
419
|
-
stream.messageId = messageId;
|
|
420
|
-
return stream;
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Save a message to the thread.
|
|
424
|
-
* @param ctx A ctx object from a mutation or action.
|
|
425
|
-
* @param args The message and what to associate it with (user / thread)
|
|
426
|
-
* You can pass extra metadata alongside the message, e.g. associated fileIds.
|
|
427
|
-
* @returns The messageId of the saved message.
|
|
428
|
-
*/
|
|
429
|
-
async saveMessage(ctx, args) {
|
|
430
|
-
const { lastMessageId, messages } = await this.saveMessages(ctx, {
|
|
431
|
-
threadId: args.threadId,
|
|
432
|
-
userId: args.userId,
|
|
433
|
-
messages: args.prompt !== undefined
|
|
434
|
-
? [{ role: "user", content: args.prompt }]
|
|
435
|
-
: [args.message],
|
|
436
|
-
metadata: args.metadata ? [args.metadata] : undefined,
|
|
437
|
-
skipEmbeddings: args.skipEmbeddings,
|
|
438
|
-
});
|
|
439
|
-
return { messageId: lastMessageId, message: messages.at(-1) };
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Explicitly save messages associated with the thread (& user if provided)
|
|
443
|
-
* @param ctx The ctx parameter to a mutation or action.
|
|
444
|
-
* @param args The messages and context to save
|
|
445
|
-
* @returns
|
|
446
|
-
*/
|
|
447
|
-
async saveMessages(ctx, args) {
|
|
448
|
-
let embeddings;
|
|
449
|
-
if (args.skipEmbeddings || !("runAction" in ctx)) {
|
|
450
|
-
embeddings = undefined;
|
|
451
|
-
if (!args.skipEmbeddings && this.options.textEmbedding) {
|
|
452
|
-
console.warn("You're trying to save messages and generate embeddings, but you're in a mutation. " +
|
|
453
|
-
"Pass `skipEmbeddings: true` to skip generating embeddings in the mutation and skip this warning. " +
|
|
454
|
-
"They will be generated lazily when you generate or stream text / objects. " +
|
|
455
|
-
"You can explicitly generate them asynchronously by using the scheduler to run an action later that calls `agent.generateAndSaveEmbeddings`.");
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
embeddings = await this.generateEmbeddings(ctx, {
|
|
460
|
-
userId: args.userId,
|
|
461
|
-
threadId: args.threadId,
|
|
462
|
-
}, args.messages);
|
|
463
|
-
}
|
|
464
|
-
const result = await ctx.runMutation(this.component.messages.addMessages, {
|
|
465
|
-
threadId: args.threadId,
|
|
466
|
-
userId: args.userId,
|
|
467
|
-
agentName: this.options.name,
|
|
468
|
-
promptMessageId: args.promptMessageId,
|
|
469
|
-
embeddings,
|
|
470
|
-
messages: await Promise.all(args.messages.map(async (m, i) => {
|
|
471
|
-
const { message, fileIds } = await (0, mapping_js_1.serializeMessage)(ctx, this.component, m);
|
|
472
|
-
return {
|
|
473
|
-
...args.metadata?.[i],
|
|
474
|
-
message,
|
|
475
|
-
fileIds,
|
|
476
|
-
};
|
|
477
|
-
})),
|
|
478
|
-
failPendingSteps: args.failPendingSteps ?? false,
|
|
479
|
-
pending: args.pending ?? false,
|
|
480
|
-
});
|
|
481
|
-
return {
|
|
482
|
-
lastMessageId: result.messages.at(-1)._id,
|
|
483
|
-
messages: result.messages,
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* List messages from a thread.
|
|
488
|
-
* @param ctx A ctx object from a query, mutation, or action.
|
|
489
|
-
* @param args.threadId The thread to list messages from.
|
|
490
|
-
* @param args.paginationOpts Pagination options (e.g. via usePaginatedQuery).
|
|
491
|
-
* @param args.excludeToolMessages Whether to exclude tool messages.
|
|
492
|
-
* False by default.
|
|
493
|
-
* @param args.statuses What statuses to include. All by default.
|
|
494
|
-
* @returns The MessageDoc's in a format compatible with usePaginatedQuery.
|
|
495
|
-
*/
|
|
496
|
-
async listMessages(ctx, args) {
|
|
497
|
-
if (args.paginationOpts.numItems === 0) {
|
|
498
|
-
return {
|
|
499
|
-
page: [],
|
|
500
|
-
isDone: true,
|
|
501
|
-
continueCursor: args.paginationOpts.cursor ?? "",
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
return ctx.runQuery(this.component.messages.listMessagesByThreadId, {
|
|
505
|
-
order: "desc",
|
|
506
|
-
...args,
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* A function that handles fetching stream deltas, used with the React hooks
|
|
511
|
-
* `useThreadMessages` or `useStreamingThreadMessages`.
|
|
512
|
-
* @param ctx A ctx object from a query, mutation, or action.
|
|
513
|
-
* @param args.threadId The thread to sync streams for.
|
|
514
|
-
* @param args.streamArgs The stream arguments with per-stream cursors.
|
|
515
|
-
* @returns The deltas for each stream from their existing cursor.
|
|
516
|
-
*/
|
|
517
|
-
async syncStreams(ctx, args) {
|
|
518
|
-
if (!args.streamArgs)
|
|
519
|
-
return undefined;
|
|
520
|
-
if (args.streamArgs.kind === "list") {
|
|
521
|
-
return {
|
|
522
|
-
kind: "list",
|
|
523
|
-
messages: await ctx.runQuery(this.component.streams.list, {
|
|
524
|
-
threadId: args.threadId,
|
|
525
|
-
}),
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
else {
|
|
529
|
-
return {
|
|
530
|
-
kind: "deltas",
|
|
531
|
-
deltas: await ctx.runQuery(this.component.streams.listDeltas, {
|
|
532
|
-
threadId: args.threadId,
|
|
533
|
-
cursors: args.streamArgs.cursors,
|
|
534
|
-
}),
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Fetch the context messages for a thread.
|
|
540
|
-
* @param ctx Either a query, mutation, or action ctx.
|
|
541
|
-
* If it is not an action context, you can't do text or
|
|
542
|
-
* vector search.
|
|
543
|
-
* @param args The associated thread, user, message
|
|
544
|
-
* @returns
|
|
545
|
-
*/
|
|
546
|
-
async fetchContextMessages(ctx, args) {
|
|
547
|
-
(0, convex_helpers_1.assert)(args.userId || args.threadId, "Specify userId or threadId");
|
|
548
|
-
// Fetch the latest messages from the thread
|
|
549
|
-
let included;
|
|
550
|
-
const opts = this._mergedContextOptions(args.contextOptions);
|
|
551
|
-
const contextMessages = [];
|
|
552
|
-
if (args.threadId &&
|
|
553
|
-
(opts.recentMessages !== 0 || args.upToAndIncludingMessageId)) {
|
|
554
|
-
const { page } = await ctx.runQuery(this.component.messages.listMessagesByThreadId, {
|
|
555
|
-
threadId: args.threadId,
|
|
556
|
-
excludeToolMessages: opts.excludeToolMessages,
|
|
557
|
-
paginationOpts: {
|
|
558
|
-
numItems: opts.recentMessages ?? shared_js_1.DEFAULT_RECENT_MESSAGES,
|
|
559
|
-
cursor: null,
|
|
560
|
-
},
|
|
561
|
-
upToAndIncludingMessageId: args.upToAndIncludingMessageId,
|
|
562
|
-
order: "desc",
|
|
563
|
-
statuses: ["success"],
|
|
564
|
-
});
|
|
565
|
-
included = new Set(page.map((m) => m._id));
|
|
566
|
-
contextMessages.push(
|
|
567
|
-
// Reverse since we fetched in descending order
|
|
568
|
-
...page.reverse());
|
|
569
|
-
}
|
|
570
|
-
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
571
|
-
const targetMessage = contextMessages.find((m) => m._id === args.upToAndIncludingMessageId)?.message;
|
|
572
|
-
const messagesToSearch = targetMessage
|
|
573
|
-
? [targetMessage, ...args.messages]
|
|
574
|
-
: args.messages;
|
|
575
|
-
if (!("runAction" in ctx)) {
|
|
576
|
-
throw new Error("searchUserMessages only works in an action");
|
|
577
|
-
}
|
|
578
|
-
const searchMessages = await ctx.runAction(this.component.messages.searchMessages, {
|
|
579
|
-
searchAllMessagesForUserId: opts?.searchOtherThreads
|
|
580
|
-
? args.userId ??
|
|
581
|
-
(args.threadId &&
|
|
582
|
-
(await ctx.runQuery(this.component.threads.getThread, {
|
|
583
|
-
threadId: args.threadId,
|
|
584
|
-
}))?.userId)
|
|
585
|
-
: undefined,
|
|
586
|
-
threadId: args.threadId,
|
|
587
|
-
beforeMessageId: args.upToAndIncludingMessageId,
|
|
588
|
-
...(await this._searchOptionsWithEmbeddingAndDefaults(ctx, { userId: args.userId, threadId: args.threadId }, opts, messagesToSearch)),
|
|
589
|
-
});
|
|
590
|
-
// TODO: track what messages we used for context
|
|
591
|
-
contextMessages.unshift(...searchMessages.filter((m) => !included?.has(m._id)));
|
|
592
|
-
}
|
|
593
|
-
// Ensure we don't include tool messages without a corresponding tool call
|
|
594
|
-
return filterOutOrphanedToolMessages(contextMessages.sort((a, b) =>
|
|
595
|
-
// Sort the raw MessageDocs by order and stepOrder
|
|
596
|
-
a.order === b.order ? a.stepOrder - b.stepOrder : a.order - b.order));
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Get the metadata for a thread.
|
|
600
|
-
* @param ctx A ctx object from a query, mutation, or action.
|
|
601
|
-
* @param args.threadId The thread to get the metadata for.
|
|
602
|
-
* @returns The metadata for the thread.
|
|
603
|
-
*/
|
|
604
|
-
async getThreadMetadata(ctx, args) {
|
|
605
|
-
const thread = await ctx.runQuery(this.component.threads.getThread, {
|
|
606
|
-
threadId: args.threadId,
|
|
607
|
-
});
|
|
608
|
-
if (!thread) {
|
|
609
|
-
throw new Error("Thread not found");
|
|
610
|
-
}
|
|
611
|
-
return thread;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Update the metadata for a thread.
|
|
615
|
-
* @param ctx A ctx object from a mutation or action.
|
|
616
|
-
* @param args.threadId The thread to update the metadata for.
|
|
617
|
-
* @param args.patch The patch to apply to the thread.
|
|
618
|
-
* @returns The updated thread metadata.
|
|
619
|
-
*/
|
|
620
|
-
async updateThreadMetadata(ctx, args) {
|
|
621
|
-
const thread = await ctx.runMutation(this.component.threads.updateThread, args);
|
|
622
|
-
return thread;
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Get the embeddings for a set of messages.
|
|
626
|
-
* @param messages The messages to get the embeddings for.
|
|
627
|
-
* @returns The embeddings for the messages.
|
|
628
|
-
*/
|
|
629
|
-
async generateEmbeddings(ctx, { userId, threadId, }, messages) {
|
|
630
|
-
if (!this.options.textEmbedding) {
|
|
631
|
-
return undefined;
|
|
632
|
-
}
|
|
633
|
-
let embeddings;
|
|
634
|
-
const messageTexts = messages.map((m) => !(0, shared_js_1.isTool)(m) && (0, shared_js_1.extractText)(m));
|
|
635
|
-
// Find the indexes of the messages that have text.
|
|
636
|
-
const textIndexes = messageTexts
|
|
637
|
-
.map((t, i) => (t ? i : undefined))
|
|
638
|
-
.filter((i) => i !== undefined);
|
|
639
|
-
if (textIndexes.length === 0) {
|
|
640
|
-
return undefined;
|
|
641
|
-
}
|
|
642
|
-
// Then embed those messages.
|
|
643
|
-
const textEmbeddings = await this.doEmbed(ctx, {
|
|
644
|
-
userId,
|
|
645
|
-
threadId,
|
|
646
|
-
values: messageTexts.filter((t) => !!t),
|
|
647
|
-
});
|
|
648
|
-
// TODO: record usage of embeddings
|
|
649
|
-
// Then assemble the embeddings into a single array with nulls for the messages without text.
|
|
650
|
-
const embeddingsOrNull = Array(messages.length).fill(null);
|
|
651
|
-
textIndexes.forEach((i, j) => {
|
|
652
|
-
embeddingsOrNull[i] = textEmbeddings.embeddings[j];
|
|
653
|
-
});
|
|
654
|
-
if (textEmbeddings.embeddings.length > 0) {
|
|
655
|
-
const dimension = textEmbeddings.embeddings[0].length;
|
|
656
|
-
(0, tables_js_1.validateVectorDimension)(dimension);
|
|
657
|
-
embeddings = {
|
|
658
|
-
vectors: embeddingsOrNull,
|
|
659
|
-
dimension,
|
|
660
|
-
model: this.options.textEmbedding.modelId,
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
return embeddings;
|
|
664
|
-
}
|
|
665
|
-
/**
|
|
666
|
-
* Generate embeddings for a set of messages, and save them to the database.
|
|
667
|
-
* It will not generate or save embeddings for messages that already have an
|
|
668
|
-
* embedding.
|
|
669
|
-
* @param ctx The ctx parameter to an action.
|
|
670
|
-
* @param args The messageIds to generate embeddings for.
|
|
671
|
-
*/
|
|
672
|
-
async generateAndSaveEmbeddings(ctx, args) {
|
|
673
|
-
const messages = (await ctx.runQuery(this.component.messages.getMessagesByIds, {
|
|
674
|
-
messageIds: args.messageIds,
|
|
675
|
-
})).filter((m) => m !== null);
|
|
676
|
-
if (messages.length !== args.messageIds.length) {
|
|
677
|
-
throw new Error("Some messages were not found: " +
|
|
678
|
-
args.messageIds
|
|
679
|
-
.filter((id) => !messages.some((m) => m?._id === id))
|
|
680
|
-
.join(", "));
|
|
681
|
-
}
|
|
682
|
-
if (messages.some((m) => !m.message)) {
|
|
683
|
-
throw new Error("Some messages don't have a message: " +
|
|
684
|
-
args.messageIds
|
|
685
|
-
.map((id, i) => (!messages[i].message ? id : undefined))
|
|
686
|
-
.filter((id) => id !== undefined)
|
|
687
|
-
.join(", "));
|
|
688
|
-
}
|
|
689
|
-
const messagesMissingEmbeddings = messages.filter((m) => !m.embeddingId);
|
|
690
|
-
if (messagesMissingEmbeddings.length === 0) {
|
|
691
|
-
return;
|
|
692
|
-
}
|
|
693
|
-
const embeddings = await this.generateEmbeddings(ctx, {
|
|
694
|
-
userId: messagesMissingEmbeddings[0].userId,
|
|
695
|
-
threadId: messagesMissingEmbeddings[0].threadId,
|
|
696
|
-
}, messagesMissingEmbeddings.map((m) => m.message));
|
|
697
|
-
if (!embeddings) {
|
|
698
|
-
if (!this.options.textEmbedding) {
|
|
699
|
-
throw new Error("No embeddings were generated for the messages. You must pass a textEmbedding model to the agent constructor.");
|
|
700
|
-
}
|
|
701
|
-
throw new Error("No embeddings were generated for these messages: " +
|
|
702
|
-
messagesMissingEmbeddings.map((m) => m._id).join(", "));
|
|
703
|
-
}
|
|
704
|
-
await ctx.runMutation(this.component.vector.index.insertBatch, {
|
|
705
|
-
vectorDimension: embeddings.dimension,
|
|
706
|
-
vectors: messagesMissingEmbeddings
|
|
707
|
-
.map((m, i) => ({
|
|
708
|
-
messageId: m._id,
|
|
709
|
-
model: embeddings.model,
|
|
710
|
-
table: "messages",
|
|
711
|
-
userId: m.userId,
|
|
712
|
-
threadId: m.threadId,
|
|
713
|
-
vector: embeddings.vectors[i],
|
|
714
|
-
}))
|
|
715
|
-
.filter((v) => v.vector !== null),
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Explicitly save a "step" created by the AI SDK.
|
|
720
|
-
* @param ctx The ctx argument to a mutation or action.
|
|
721
|
-
* @param args The Step generated by the AI SDK.
|
|
722
|
-
*/
|
|
723
|
-
async saveStep(ctx, args) {
|
|
724
|
-
const messages = await (0, mapping_js_1.serializeNewMessagesInStep)(ctx, this.component, args.step, {
|
|
725
|
-
provider: args.provider ?? this.options.chat.provider,
|
|
726
|
-
model: args.model ?? this.options.chat.modelId,
|
|
727
|
-
});
|
|
728
|
-
const embeddings = await this.generateEmbeddings(ctx, { userId: args.userId, threadId: args.threadId }, messages.map((m) => m.message));
|
|
729
|
-
const saved = await ctx.runMutation(this.component.messages.addMessages, {
|
|
730
|
-
userId: args.userId,
|
|
731
|
-
threadId: args.threadId,
|
|
732
|
-
agentName: this.options.name,
|
|
733
|
-
promptMessageId: args.promptMessageId,
|
|
734
|
-
messages,
|
|
735
|
-
embeddings,
|
|
736
|
-
failPendingSteps: false,
|
|
737
|
-
});
|
|
738
|
-
return saved;
|
|
739
|
-
}
|
|
740
|
-
/**
|
|
741
|
-
* Manually save the result of a generateObject call to the thread.
|
|
742
|
-
* This happens automatically when using {@link generateObject} or {@link streamObject}
|
|
743
|
-
* from the `thread` object created by {@link continueThread} or {@link createThread}.
|
|
744
|
-
* @param ctx The context passed from the mutation or action function calling this.
|
|
745
|
-
* @param args The arguments to the saveObject function.
|
|
746
|
-
*/
|
|
747
|
-
async saveObject(ctx, args) {
|
|
748
|
-
const { messages } = await (0, mapping_js_1.serializeObjectResult)(ctx, this.component, args.result, {
|
|
749
|
-
model: this.options.chat.modelId,
|
|
750
|
-
provider: this.options.chat.provider,
|
|
751
|
-
});
|
|
752
|
-
const embeddings = await this.generateEmbeddings(ctx, { userId: args.userId, threadId: args.threadId }, messages.map((m) => m.message));
|
|
753
|
-
await ctx.runMutation(this.component.messages.addMessages, {
|
|
754
|
-
userId: args.userId,
|
|
755
|
-
threadId: args.threadId,
|
|
756
|
-
promptMessageId: args.promptMessageId,
|
|
757
|
-
failPendingSteps: false,
|
|
758
|
-
messages,
|
|
759
|
-
embeddings,
|
|
760
|
-
agentName: this.options.name,
|
|
761
|
-
pending: false,
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Commit or rollback a message that was pending.
|
|
766
|
-
* This is done automatically when saving messages by default.
|
|
767
|
-
* If creating pending messages, you can call this when the full "transaction" is done.
|
|
768
|
-
* @param ctx The ctx argument to your mutation or action.
|
|
769
|
-
* @param args What message to save. Generally the parent message sent into
|
|
770
|
-
* the generateText call.
|
|
771
|
-
*/
|
|
772
|
-
async completeMessage(ctx, args) {
|
|
773
|
-
const result = args.result;
|
|
774
|
-
if (result.kind === "success") {
|
|
775
|
-
await ctx.runMutation(this.component.messages.commitMessage, {
|
|
776
|
-
messageId: args.messageId,
|
|
777
|
-
});
|
|
778
|
-
}
|
|
779
|
-
else {
|
|
780
|
-
await ctx.runMutation(this.component.messages.rollbackMessage, {
|
|
781
|
-
messageId: args.messageId,
|
|
782
|
-
error: result.error,
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
async _saveMessagesAndFetchContext(ctx, args, { userId: argsUserId, threadId, contextOptions, storageOptions, }) {
|
|
787
|
-
contextOptions ||= this.options.contextOptions;
|
|
788
|
-
storageOptions ||= this.options.storageOptions;
|
|
789
|
-
// If only a messageId is provided, this will be empty.
|
|
790
|
-
const messages = args.promptMessageId
|
|
791
|
-
? []
|
|
792
|
-
: (0, mapping_js_1.promptOrMessagesToCoreMessages)(args);
|
|
793
|
-
const userId = argsUserId ??
|
|
794
|
-
(threadId &&
|
|
795
|
-
(await ctx.runQuery(this.component.threads.getThread, { threadId }))
|
|
796
|
-
?.userId);
|
|
797
|
-
(0, convex_helpers_1.assert)(!args.promptMessageId || !(args.prompt || args.messages), "you can't specify a prompt or message if you specify a promptMessageId");
|
|
798
|
-
// If only a messageId is provided, this will add that message to the end.
|
|
799
|
-
const contextMessages = await this.fetchContextMessages(ctx, {
|
|
800
|
-
userId,
|
|
801
|
-
threadId,
|
|
802
|
-
upToAndIncludingMessageId: args.promptMessageId,
|
|
803
|
-
messages,
|
|
804
|
-
contextOptions,
|
|
805
|
-
});
|
|
806
|
-
// Lazily generate embeddings for the prompt message, if it doesn't have
|
|
807
|
-
// embeddings yet. This can happen if the message was saved in a mutation
|
|
808
|
-
// where the LLM is not available.
|
|
809
|
-
if (args.promptMessageId &&
|
|
810
|
-
!contextMessages.at(-1)?.embeddingId &&
|
|
811
|
-
this.options.textEmbedding) {
|
|
812
|
-
await this.generateAndSaveEmbeddings(ctx, {
|
|
813
|
-
messageIds: [args.promptMessageId],
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
let messageId = args.promptMessageId;
|
|
817
|
-
let order = args.promptMessageId
|
|
818
|
-
? contextMessages.at(-1)?.order
|
|
819
|
-
: undefined;
|
|
820
|
-
let stepOrder = args.promptMessageId
|
|
821
|
-
? contextMessages.at(-1)?.stepOrder
|
|
822
|
-
: undefined;
|
|
823
|
-
if (threadId &&
|
|
824
|
-
messages.length &&
|
|
825
|
-
storageOptions?.saveMessages !== "none" &&
|
|
826
|
-
storageOptions?.saveAnyInputMessages !== false) {
|
|
827
|
-
const saveAll = storageOptions?.saveMessages === "all";
|
|
828
|
-
const coreMessages = saveAll ? messages : messages.slice(-1);
|
|
829
|
-
const saved = await this.saveMessages(ctx, {
|
|
830
|
-
threadId,
|
|
831
|
-
userId,
|
|
832
|
-
messages: coreMessages,
|
|
833
|
-
metadata: coreMessages.map((_, i) => i === coreMessages.length - 1 ? { id: args.id } : {}),
|
|
834
|
-
pending: true,
|
|
835
|
-
failPendingSteps: true,
|
|
836
|
-
});
|
|
837
|
-
messageId = saved.lastMessageId;
|
|
838
|
-
order = saved.messages.at(-1)?.order;
|
|
839
|
-
stepOrder = saved.messages.at(-1)?.stepOrder;
|
|
840
|
-
}
|
|
841
|
-
let processedMessages = [
|
|
842
|
-
...contextMessages.map((m) => (0, mapping_js_1.deserializeMessage)(m.message)),
|
|
843
|
-
...messages,
|
|
844
|
-
];
|
|
845
|
-
// Process messages to inline localhost files (if not, file urls pointing to localhost will be sent to LLM providers)
|
|
846
|
-
if (process.env.CONVEX_CLOUD_URL?.startsWith("http://127.0.0.1")) {
|
|
847
|
-
processedMessages = await this._inlineMessagesFiles(processedMessages);
|
|
848
|
-
}
|
|
849
|
-
const { prompt: _, model, ...rest } = args;
|
|
850
|
-
return {
|
|
851
|
-
args: {
|
|
852
|
-
...rest,
|
|
853
|
-
maxRetries: args.maxRetries ?? this.options.maxRetries,
|
|
854
|
-
model: model ?? this.options.chat,
|
|
855
|
-
system: args.system ?? this.options.instructions,
|
|
856
|
-
messages: processedMessages,
|
|
857
|
-
},
|
|
858
|
-
userId,
|
|
859
|
-
messageId,
|
|
860
|
-
order,
|
|
861
|
-
stepOrder,
|
|
862
|
-
};
|
|
863
|
-
}
|
|
864
|
-
_shouldSaveOutputMessages(storageOpts) {
|
|
865
|
-
const opts = storageOpts ?? this.options.storageOptions;
|
|
866
|
-
return opts?.saveOutputMessages !== false && opts?.saveMessages !== "none";
|
|
867
|
-
}
|
|
868
|
-
_mergedContextOptions(opts) {
|
|
869
|
-
const searchOptions = {
|
|
870
|
-
...this.options.contextOptions?.searchOptions,
|
|
871
|
-
...opts?.searchOptions,
|
|
872
|
-
};
|
|
873
|
-
return {
|
|
874
|
-
...this.options.contextOptions,
|
|
875
|
-
...opts,
|
|
876
|
-
searchOptions: searchOptions.limit
|
|
877
|
-
? searchOptions
|
|
878
|
-
: undefined,
|
|
879
|
-
};
|
|
880
|
-
}
|
|
881
|
-
async _searchOptionsWithEmbeddingAndDefaults(ctx, { userId, threadId }, contextOptions, messages) {
|
|
882
|
-
(0, convex_helpers_1.assert)(contextOptions.searchOptions?.textSearch ||
|
|
883
|
-
contextOptions.searchOptions?.vectorSearch, "searchOptions is required");
|
|
884
|
-
(0, convex_helpers_1.assert)(messages.length > 0, "Core messages cannot be empty");
|
|
885
|
-
const text = (0, shared_js_1.extractText)(messages.at(-1));
|
|
886
|
-
const search = {
|
|
887
|
-
limit: contextOptions.searchOptions?.limit ?? 10,
|
|
888
|
-
messageRange: {
|
|
889
|
-
...shared_js_1.DEFAULT_MESSAGE_RANGE,
|
|
890
|
-
...contextOptions.searchOptions?.messageRange,
|
|
891
|
-
},
|
|
892
|
-
text: (0, shared_js_1.extractText)(messages.at(-1)),
|
|
893
|
-
};
|
|
894
|
-
if (contextOptions.searchOptions?.vectorSearch &&
|
|
895
|
-
text &&
|
|
896
|
-
this.options.textEmbedding) {
|
|
897
|
-
search.vector = (await this.doEmbed(ctx, {
|
|
898
|
-
threadId,
|
|
899
|
-
userId,
|
|
900
|
-
values: [text],
|
|
901
|
-
})).embeddings[0];
|
|
902
|
-
search.vectorModel = this.options.textEmbedding.modelId;
|
|
903
|
-
}
|
|
904
|
-
return search;
|
|
905
|
-
}
|
|
906
|
-
async doEmbed(ctx, options) {
|
|
907
|
-
const embedding = this.options.textEmbedding;
|
|
908
|
-
(0, convex_helpers_1.assert)(embedding, "textEmbedding is required");
|
|
909
|
-
const result = await embedding.doEmbed({
|
|
910
|
-
values: options.values,
|
|
911
|
-
abortSignal: options.abortSignal,
|
|
912
|
-
headers: options.headers,
|
|
913
|
-
});
|
|
914
|
-
if (this.options.usageHandler && result.usage) {
|
|
915
|
-
await this.options.usageHandler(ctx, {
|
|
916
|
-
userId: options.userId,
|
|
917
|
-
threadId: options.threadId,
|
|
918
|
-
agentName: this.options.name,
|
|
919
|
-
model: embedding.modelId,
|
|
920
|
-
provider: embedding.provider,
|
|
921
|
-
providerMetadata: result.rawResponse
|
|
922
|
-
? { [embedding.provider]: result.rawResponse }
|
|
923
|
-
: undefined,
|
|
924
|
-
usage: {
|
|
925
|
-
promptTokens: result.usage.tokens,
|
|
926
|
-
completionTokens: 0,
|
|
927
|
-
totalTokens: result.usage.tokens,
|
|
928
|
-
},
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
return { embeddings: result.embeddings };
|
|
932
|
-
}
|
|
933
|
-
/**
|
|
934
|
-
* Process messages to inline file and image URLs that point to localhost
|
|
935
|
-
* by converting them to base64. This solves the problem of LLMs not being
|
|
936
|
-
* able to access localhost URLs.
|
|
937
|
-
*/
|
|
938
|
-
async _inlineMessagesFiles(messages) {
|
|
939
|
-
// Process each message to convert localhost URLs to base64
|
|
940
|
-
return Promise.all(messages.map(async (message) => {
|
|
941
|
-
if (message.role !== "user" ||
|
|
942
|
-
typeof message.content === "string" ||
|
|
943
|
-
!Array.isArray(message.content)) {
|
|
944
|
-
return message;
|
|
945
|
-
}
|
|
946
|
-
const processedContent = await Promise.all(message.content.map(async (part) => {
|
|
947
|
-
if (part.type === "image" && part.image instanceof URL) {
|
|
948
|
-
if (this._isLocalhostUrl(part.image)) {
|
|
949
|
-
const imageData = await this._downloadFile(part.image);
|
|
950
|
-
return {
|
|
951
|
-
...part,
|
|
952
|
-
image: imageData,
|
|
953
|
-
};
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
// Handle file parts
|
|
957
|
-
if (part.type === "file" && part.data instanceof URL) {
|
|
958
|
-
if (this._isLocalhostUrl(part.data)) {
|
|
959
|
-
const fileData = await this._downloadFile(part.data);
|
|
960
|
-
return {
|
|
961
|
-
...part,
|
|
962
|
-
data: fileData,
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
return part;
|
|
967
|
-
}));
|
|
968
|
-
return {
|
|
969
|
-
...message,
|
|
970
|
-
content: processedContent,
|
|
971
|
-
};
|
|
972
|
-
}));
|
|
973
|
-
}
|
|
974
|
-
/**
|
|
975
|
-
* Check if a URL points to localhost
|
|
976
|
-
*/
|
|
977
|
-
_isLocalhostUrl(url) {
|
|
978
|
-
return (url.hostname === "localhost" ||
|
|
979
|
-
url.hostname === "127.0.0.1" ||
|
|
980
|
-
url.hostname === "::1" ||
|
|
981
|
-
url.hostname === "0.0.0.0");
|
|
982
|
-
}
|
|
983
|
-
/**
|
|
984
|
-
* Download a file from a URL
|
|
985
|
-
*/
|
|
986
|
-
async _downloadFile(url) {
|
|
987
|
-
// Fetch the file
|
|
988
|
-
const response = await fetch(url);
|
|
989
|
-
if (!response.ok) {
|
|
990
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
991
|
-
}
|
|
992
|
-
return await response.arrayBuffer();
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* WORKFLOW UTILITIES
|
|
996
|
-
*/
|
|
997
|
-
/**
|
|
998
|
-
* Create a mutation that creates a thread so you can call it from a Workflow.
|
|
999
|
-
* e.g.
|
|
1000
|
-
* ```ts
|
|
1001
|
-
* // in convex/foo.ts
|
|
1002
|
-
* export const createThread = weatherAgent.createThreadMutation();
|
|
1003
|
-
*
|
|
1004
|
-
* const workflow = new WorkflowManager(components.workflow);
|
|
1005
|
-
* export const myWorkflow = workflow.define({
|
|
1006
|
-
* args: {},
|
|
1007
|
-
* handler: async (step) => {
|
|
1008
|
-
* const { threadId } = await step.runMutation(internal.foo.createThread);
|
|
1009
|
-
* // use the threadId to generate text, object, etc.
|
|
1010
|
-
* },
|
|
1011
|
-
* });
|
|
1012
|
-
* ```
|
|
1013
|
-
* @returns A mutation that creates a thread.
|
|
1014
|
-
*/
|
|
1015
|
-
createThreadMutation() {
|
|
1016
|
-
return (0, server_1.internalMutationGeneric)({
|
|
1017
|
-
args: {
|
|
1018
|
-
userId: values_1.v.optional(values_1.v.string()),
|
|
1019
|
-
title: values_1.v.optional(values_1.v.string()),
|
|
1020
|
-
summary: values_1.v.optional(values_1.v.string()),
|
|
1021
|
-
},
|
|
1022
|
-
handler: async (ctx, args) => {
|
|
1023
|
-
const { threadId } = await this.createThread(ctx, args);
|
|
1024
|
-
return { threadId };
|
|
1025
|
-
},
|
|
1026
|
-
});
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Create an action out of this agent so you can call it from workflows or other actions
|
|
1030
|
-
* without a wrapping function.
|
|
1031
|
-
* @param spec Configuration for the agent acting as an action, including
|
|
1032
|
-
* {@link ContextOptions}, {@link StorageOptions}, and maxSteps.
|
|
1033
|
-
*/
|
|
1034
|
-
asTextAction(spec) {
|
|
1035
|
-
const maxSteps = spec?.maxSteps ?? this.options.maxSteps;
|
|
1036
|
-
return (0, server_1.internalActionGeneric)({
|
|
1037
|
-
args: validators_js_1.vTextArgs,
|
|
1038
|
-
handler: async (ctx, args) => {
|
|
1039
|
-
const { contextOptions, storageOptions, ...rest } = args;
|
|
1040
|
-
const stream = args.stream === true ? spec?.stream || true : spec?.stream ?? false;
|
|
1041
|
-
const targetArgs = { userId: args.userId, threadId: args.threadId };
|
|
1042
|
-
const llmArgs = { maxSteps, ...rest };
|
|
1043
|
-
const opts = {
|
|
1044
|
-
contextOptions: contextOptions ??
|
|
1045
|
-
spec?.contextOptions ??
|
|
1046
|
-
this.options.contextOptions,
|
|
1047
|
-
storageOptions: storageOptions ??
|
|
1048
|
-
spec?.storageOptions ??
|
|
1049
|
-
this.options.storageOptions,
|
|
1050
|
-
saveStreamDeltas: stream,
|
|
1051
|
-
};
|
|
1052
|
-
if (stream) {
|
|
1053
|
-
const result = await this.streamText(ctx, targetArgs, llmArgs, opts);
|
|
1054
|
-
await result.consumeStream();
|
|
1055
|
-
return {
|
|
1056
|
-
text: await result.text,
|
|
1057
|
-
finishReason: await result.finishReason,
|
|
1058
|
-
messageId: result.messageId,
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
else {
|
|
1062
|
-
const { text, messageId, finishReason } = await this.generateText(ctx, targetArgs, llmArgs, opts);
|
|
1063
|
-
return { text, messageId, finishReason };
|
|
1064
|
-
}
|
|
1065
|
-
},
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
/**
|
|
1069
|
-
* Create an action that generates an object out of this agent so you can call
|
|
1070
|
-
* it from workflows or other actions without a wrapping function.
|
|
1071
|
-
* @param spec Configuration for the agent acting as an action, including
|
|
1072
|
-
* the normal parameters to {@link generateObject}, plus {@link ContextOptions}
|
|
1073
|
-
* and maxSteps.
|
|
1074
|
-
*/
|
|
1075
|
-
asObjectAction(spec, options) {
|
|
1076
|
-
const maxSteps = spec?.maxSteps ?? this.options.maxSteps;
|
|
1077
|
-
return (0, server_1.internalActionGeneric)({
|
|
1078
|
-
args: validators_js_1.vSafeObjectArgs,
|
|
1079
|
-
handler: async (ctx, args) => {
|
|
1080
|
-
const { contextOptions, storageOptions, ...rest } = args;
|
|
1081
|
-
const value = await this.generateObject(ctx, { userId: args.userId, threadId: args.threadId }, {
|
|
1082
|
-
...spec,
|
|
1083
|
-
maxSteps,
|
|
1084
|
-
...rest,
|
|
1085
|
-
}, {
|
|
1086
|
-
contextOptions: contextOptions ??
|
|
1087
|
-
options?.contextOptions ??
|
|
1088
|
-
this.options.contextOptions,
|
|
1089
|
-
storageOptions: storageOptions ??
|
|
1090
|
-
options?.storageOptions ??
|
|
1091
|
-
this.options.storageOptions,
|
|
1092
|
-
});
|
|
1093
|
-
return { object: value.object };
|
|
1094
|
-
},
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
/**
|
|
1098
|
-
* Save messages to the thread.
|
|
1099
|
-
* Useful as a step in Workflows, e.g.
|
|
1100
|
-
* ```ts
|
|
1101
|
-
* const saveMessages = agent.asSaveMessagesMutation();
|
|
1102
|
-
*
|
|
1103
|
-
* const myWorkflow = workflow.define({
|
|
1104
|
-
* args: {...},
|
|
1105
|
-
* handler: async (step, args) => {
|
|
1106
|
-
* // do things to create (but not save)messages
|
|
1107
|
-
* const { messageIds } = await step.runMutation(internal.foo.saveMessages, {
|
|
1108
|
-
* threadId: args.threadId,
|
|
1109
|
-
* messages: args.messages,
|
|
1110
|
-
* });
|
|
1111
|
-
* // ...
|
|
1112
|
-
* },
|
|
1113
|
-
* })
|
|
1114
|
-
* ```
|
|
1115
|
-
* @returns A mutation that can be used to save messages to the thread.
|
|
1116
|
-
*/
|
|
1117
|
-
asSaveMessagesMutation() {
|
|
1118
|
-
return (0, server_1.internalMutationGeneric)({
|
|
1119
|
-
args: {
|
|
1120
|
-
threadId: values_1.v.string(),
|
|
1121
|
-
userId: values_1.v.optional(values_1.v.string()),
|
|
1122
|
-
promptMessageId: values_1.v.optional(values_1.v.string()),
|
|
1123
|
-
messages: values_1.v.array(validators_js_1.vMessageWithMetadata),
|
|
1124
|
-
pending: values_1.v.optional(values_1.v.boolean()),
|
|
1125
|
-
failPendingSteps: values_1.v.optional(values_1.v.boolean()),
|
|
1126
|
-
},
|
|
1127
|
-
handler: async (ctx, args) => {
|
|
1128
|
-
const { lastMessageId, messages } = await this.saveMessages(ctx, {
|
|
1129
|
-
...args,
|
|
1130
|
-
messages: args.messages.map((m) => m.message),
|
|
1131
|
-
metadata: args.messages.map(({ message: _, ...m }) => m),
|
|
1132
|
-
});
|
|
1133
|
-
return {
|
|
1134
|
-
lastMessageId,
|
|
1135
|
-
messageIds: messages.map((m) => m._id),
|
|
1136
|
-
};
|
|
1137
|
-
},
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
exports.Agent = Agent;
|
|
1142
|
-
function filterOutOrphanedToolMessages(docs) {
|
|
1143
|
-
const toolCallIds = new Set();
|
|
1144
|
-
const result = [];
|
|
1145
|
-
for (const doc of docs) {
|
|
1146
|
-
if (doc.message?.role === "assistant" &&
|
|
1147
|
-
Array.isArray(doc.message.content)) {
|
|
1148
|
-
for (const content of doc.message.content) {
|
|
1149
|
-
if (content.type === "tool-call") {
|
|
1150
|
-
toolCallIds.add(content.toolCallId);
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
result.push(doc);
|
|
1154
|
-
}
|
|
1155
|
-
else if (doc.message?.role === "tool") {
|
|
1156
|
-
if (doc.message.content.every((c) => toolCallIds.has(c.toolCallId))) {
|
|
1157
|
-
result.push(doc);
|
|
1158
|
-
}
|
|
1159
|
-
else {
|
|
1160
|
-
console.debug("Filtering out orphaned tool message", doc);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
else {
|
|
1164
|
-
result.push(doc);
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
return result;
|
|
1168
|
-
}
|
|
1169
|
-
//# sourceMappingURL=index.js.map
|