@convex-dev/agent 0.1.15-alpha.0 → 0.1.15-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -12
- package/dist/client/index.d.ts +494 -173
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +148 -170
- package/dist/client/index.js.map +1 -1
- package/dist/client/listMessages.d.ts +22 -0
- package/dist/client/listMessages.d.ts.map +1 -0
- package/dist/client/listMessages.js +25 -0
- package/dist/client/listMessages.js.map +1 -0
- package/dist/client/search.d.ts +162 -0
- package/dist/client/search.d.ts.map +1 -0
- package/dist/client/search.js +113 -0
- package/dist/client/search.js.map +1 -0
- package/dist/client/streaming.d.ts +17 -3
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +32 -0
- package/dist/client/streaming.js.map +1 -1
- package/dist/client/types.d.ts +5 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/component/_generated/api.d.ts +2 -2
- package/dist/component/messages.d.ts +3 -3
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +12 -7
- package/dist/component/messages.js.map +1 -1
- package/dist/component/vector/index.js +3 -3
- package/dist/component/vector/index.js.map +1 -1
- package/dist/react/optimisticallySendMessage.d.ts +1 -0
- package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
- package/dist/react/optimisticallySendMessage.js +8 -1
- package/dist/react/optimisticallySendMessage.js.map +1 -1
- package/dist/react/toUIMessages.d.ts +1 -0
- package/dist/react/toUIMessages.d.ts.map +1 -1
- package/dist/react/toUIMessages.js +2 -0
- package/dist/react/toUIMessages.js.map +1 -1
- package/dist/validators.d.ts +41 -52
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +1 -8
- package/dist/validators.js.map +1 -1
- package/package.json +6 -4
- package/src/client/index.ts +283 -274
- package/src/client/listMessages.ts +38 -0
- package/src/client/search.ts +172 -0
- package/src/client/streaming.ts +49 -2
- package/src/client/types.ts +5 -1
- package/src/component/_generated/api.d.ts +2 -2
- package/src/component/messages.ts +13 -7
- package/src/component/vector/index.ts +4 -4
- package/src/react/optimisticallySendMessage.ts +11 -1
- package/src/react/toUIMessages.ts +3 -0
- package/src/validators.ts +2 -10
package/src/client/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EmbeddingModelV1, LanguageModelV1 } from "@ai-sdk/provider";
|
|
2
2
|
import type {
|
|
3
|
+
AssistantContent,
|
|
3
4
|
CoreMessage,
|
|
4
5
|
DeepPartial,
|
|
5
6
|
FilePart,
|
|
@@ -10,6 +11,7 @@ import type {
|
|
|
10
11
|
StreamObjectResult,
|
|
11
12
|
StreamTextResult,
|
|
12
13
|
ToolSet,
|
|
14
|
+
UserContent,
|
|
13
15
|
} from "ai";
|
|
14
16
|
import { generateObject, generateText, streamObject, streamText } from "ai";
|
|
15
17
|
import { assert } from "convex-helpers";
|
|
@@ -34,22 +36,17 @@ import {
|
|
|
34
36
|
serializeNewMessagesInStep,
|
|
35
37
|
serializeObjectResult,
|
|
36
38
|
} from "../mapping.js";
|
|
37
|
-
import {
|
|
38
|
-
DEFAULT_MESSAGE_RANGE,
|
|
39
|
-
DEFAULT_RECENT_MESSAGES,
|
|
40
|
-
extractText,
|
|
41
|
-
isTool,
|
|
42
|
-
} from "../shared.js";
|
|
39
|
+
import { extractText, isTool } from "../shared.js";
|
|
43
40
|
import {
|
|
44
41
|
type MessageWithMetadata,
|
|
45
42
|
type MessageStatus,
|
|
46
43
|
type ProviderMetadata,
|
|
47
|
-
type SearchOptions,
|
|
48
44
|
type StreamArgs,
|
|
49
45
|
type Usage,
|
|
50
46
|
vMessageWithMetadata,
|
|
51
47
|
vSafeObjectArgs,
|
|
52
48
|
vTextArgs,
|
|
49
|
+
type MessageEmbeddings,
|
|
53
50
|
} from "../validators.js";
|
|
54
51
|
import { createTool, wrapTools } from "./createTool.js";
|
|
55
52
|
import {
|
|
@@ -77,6 +74,9 @@ import type {
|
|
|
77
74
|
UsageHandler,
|
|
78
75
|
} from "./types.js";
|
|
79
76
|
import type { threadFieldsSupportingPatch } from "../component/threads.js";
|
|
77
|
+
import { listMessages } from "./listMessages.js";
|
|
78
|
+
import { syncStreams } from "./streaming.js";
|
|
79
|
+
import { fetchContextMessages } from "./search.js";
|
|
80
80
|
|
|
81
81
|
export { storeFile, getFile } from "./files.js";
|
|
82
82
|
export { serializeDataOrUrl } from "../mapping.js";
|
|
@@ -95,12 +95,21 @@ export {
|
|
|
95
95
|
vUserMessage,
|
|
96
96
|
} from "../validators.js";
|
|
97
97
|
export type { ToolCtx } from "./createTool.js";
|
|
98
|
-
export {
|
|
98
|
+
export { filterOutOrphanedToolMessages } from "./search.js";
|
|
99
|
+
export {
|
|
100
|
+
createTool,
|
|
101
|
+
extractText,
|
|
102
|
+
fetchContextMessages,
|
|
103
|
+
isTool,
|
|
104
|
+
listMessages,
|
|
105
|
+
syncStreams,
|
|
106
|
+
};
|
|
99
107
|
export type {
|
|
100
108
|
AgentComponent,
|
|
101
109
|
ContextOptions,
|
|
102
110
|
MessageDoc,
|
|
103
111
|
ProviderMetadata,
|
|
112
|
+
RawRequestResponseHandler,
|
|
104
113
|
StorageOptions,
|
|
105
114
|
StreamArgs,
|
|
106
115
|
SyncStreamsReturnValue,
|
|
@@ -276,25 +285,18 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
276
285
|
threadId: string;
|
|
277
286
|
thread?: Thread<ThreadTools extends undefined ? AgentTools : ThreadTools>;
|
|
278
287
|
}> {
|
|
279
|
-
const
|
|
280
|
-
this.component.threads.createThread,
|
|
281
|
-
{
|
|
282
|
-
userId: args?.userId,
|
|
283
|
-
title: args?.title,
|
|
284
|
-
summary: args?.summary,
|
|
285
|
-
}
|
|
286
|
-
);
|
|
288
|
+
const threadId = await createThread(ctx, this.component, args);
|
|
287
289
|
if (!("runAction" in ctx)) {
|
|
288
|
-
return { threadId
|
|
290
|
+
return { threadId };
|
|
289
291
|
}
|
|
290
292
|
const { thread } = await this.continueThread(ctx, {
|
|
291
|
-
threadId
|
|
293
|
+
threadId,
|
|
292
294
|
userId: args?.userId,
|
|
293
295
|
usageHandler: args?.usageHandler,
|
|
294
296
|
tools: args?.tools,
|
|
295
297
|
});
|
|
296
298
|
return {
|
|
297
|
-
threadId
|
|
299
|
+
threadId,
|
|
298
300
|
thread,
|
|
299
301
|
};
|
|
300
302
|
}
|
|
@@ -833,14 +835,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
833
835
|
*/
|
|
834
836
|
async saveMessage(
|
|
835
837
|
ctx: RunMutationCtx,
|
|
836
|
-
args: {
|
|
837
|
-
threadId: string;
|
|
838
|
-
userId?: string;
|
|
839
|
-
/**
|
|
840
|
-
* Metadata to save with the messages. Each element corresponds to the
|
|
841
|
-
* message at the same index.
|
|
842
|
-
*/
|
|
843
|
-
metadata?: Omit<MessageWithMetadata, "message">;
|
|
838
|
+
args: SaveMessageArgs & {
|
|
844
839
|
/**
|
|
845
840
|
* If true, it will not generate embeddings for the message.
|
|
846
841
|
* Useful if you're saving messages in a mutation where you can't run `fetch`.
|
|
@@ -848,26 +843,17 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
848
843
|
* action later that calls `agent.generateAndSaveEmbeddings`.
|
|
849
844
|
*/
|
|
850
845
|
skipEmbeddings?: boolean;
|
|
851
|
-
}
|
|
852
|
-
| {
|
|
853
|
-
prompt?: undefined;
|
|
854
|
-
/**
|
|
855
|
-
* The message to save.
|
|
856
|
-
*/
|
|
857
|
-
message: CoreMessage;
|
|
858
|
-
}
|
|
859
|
-
| {
|
|
860
|
-
/*
|
|
861
|
-
* The prompt to save with the message.
|
|
862
|
-
*/
|
|
863
|
-
prompt: string;
|
|
864
|
-
message?: undefined;
|
|
865
|
-
}
|
|
866
|
-
)
|
|
846
|
+
}
|
|
867
847
|
) {
|
|
868
848
|
const { lastMessageId, messages } = await this.saveMessages(ctx, {
|
|
869
849
|
threadId: args.threadId,
|
|
870
850
|
userId: args.userId,
|
|
851
|
+
embeddings: args.embedding
|
|
852
|
+
? {
|
|
853
|
+
model: args.embedding.model,
|
|
854
|
+
vectors: [args.embedding.vector],
|
|
855
|
+
}
|
|
856
|
+
: undefined,
|
|
871
857
|
messages:
|
|
872
858
|
args.prompt !== undefined
|
|
873
859
|
? [{ role: "user", content: args.prompt }]
|
|
@@ -880,40 +866,15 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
880
866
|
|
|
881
867
|
/**
|
|
882
868
|
* Explicitly save messages associated with the thread (& user if provided)
|
|
869
|
+
* If you have an embedding model set, it will also generate embeddings for
|
|
870
|
+
* the messages.
|
|
883
871
|
* @param ctx The ctx parameter to a mutation or action.
|
|
884
872
|
* @param args The messages and context to save
|
|
885
873
|
* @returns
|
|
886
874
|
*/
|
|
887
875
|
async saveMessages(
|
|
888
876
|
ctx: RunMutationCtx | RunActionCtx,
|
|
889
|
-
args: {
|
|
890
|
-
threadId: string;
|
|
891
|
-
userId?: string;
|
|
892
|
-
/**
|
|
893
|
-
* The message that these messages are in response to. They will be
|
|
894
|
-
* the same "order" as this message, at increasing stepOrder(s).
|
|
895
|
-
*/
|
|
896
|
-
promptMessageId?: string;
|
|
897
|
-
/**
|
|
898
|
-
* The messages to save.
|
|
899
|
-
*/
|
|
900
|
-
messages: CoreMessageMaybeWithId[];
|
|
901
|
-
/**
|
|
902
|
-
* Metadata to save with the messages. Each element corresponds to the
|
|
903
|
-
* message at the same index.
|
|
904
|
-
*/
|
|
905
|
-
metadata?: Omit<MessageWithMetadata, "message">[];
|
|
906
|
-
/**
|
|
907
|
-
* If false, it will "commit" the messages immediately.
|
|
908
|
-
* If true, it will mark them as pending until the final step has finished.
|
|
909
|
-
* Defaults to false.
|
|
910
|
-
*/
|
|
911
|
-
pending?: boolean;
|
|
912
|
-
/**
|
|
913
|
-
* If true, it will fail any pending steps.
|
|
914
|
-
* Defaults to false.
|
|
915
|
-
*/
|
|
916
|
-
failPendingSteps?: boolean;
|
|
877
|
+
args: SaveMessagesArgs & {
|
|
917
878
|
/**
|
|
918
879
|
* Skip generating embeddings for the messages. Useful if you're
|
|
919
880
|
* saving messages in a mutation where you can't run `fetch`.
|
|
@@ -929,13 +890,15 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
929
890
|
let embeddings:
|
|
930
891
|
| {
|
|
931
892
|
vectors: (number[] | null)[];
|
|
932
|
-
dimension: VectorDimension;
|
|
933
893
|
model: string;
|
|
934
894
|
}
|
|
935
895
|
| undefined;
|
|
936
|
-
|
|
896
|
+
const { skipEmbeddings, ...rest } = args;
|
|
897
|
+
if (args.embeddings) {
|
|
898
|
+
embeddings = args.embeddings;
|
|
899
|
+
} else if (skipEmbeddings || !("runAction" in ctx)) {
|
|
937
900
|
embeddings = undefined;
|
|
938
|
-
if (!
|
|
901
|
+
if (!skipEmbeddings && this.options.textEmbedding) {
|
|
939
902
|
console.warn(
|
|
940
903
|
"You're trying to save messages and generate embeddings, but you're in a mutation. " +
|
|
941
904
|
"Pass `skipEmbeddings: true` to skip generating embeddings in the mutation and skip this warning. " +
|
|
@@ -953,33 +916,11 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
953
916
|
args.messages
|
|
954
917
|
);
|
|
955
918
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
userId: args.userId,
|
|
919
|
+
return saveMessages(ctx, this.component, {
|
|
920
|
+
...rest,
|
|
959
921
|
agentName: this.options.name,
|
|
960
|
-
promptMessageId: args.promptMessageId,
|
|
961
922
|
embeddings,
|
|
962
|
-
messages: await Promise.all(
|
|
963
|
-
args.messages.map(async (m, i) => {
|
|
964
|
-
const { message, fileIds } = await serializeMessage(
|
|
965
|
-
ctx,
|
|
966
|
-
this.component,
|
|
967
|
-
m
|
|
968
|
-
);
|
|
969
|
-
return {
|
|
970
|
-
...args.metadata?.[i],
|
|
971
|
-
message,
|
|
972
|
-
fileIds,
|
|
973
|
-
} as MessageWithMetadata;
|
|
974
|
-
})
|
|
975
|
-
),
|
|
976
|
-
failPendingSteps: args.failPendingSteps ?? false,
|
|
977
|
-
pending: args.pending ?? false,
|
|
978
923
|
});
|
|
979
|
-
return {
|
|
980
|
-
lastMessageId: result.messages.at(-1)!._id,
|
|
981
|
-
messages: result.messages,
|
|
982
|
-
};
|
|
983
924
|
}
|
|
984
925
|
|
|
985
926
|
/**
|
|
@@ -1001,17 +942,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1001
942
|
statuses?: MessageStatus[];
|
|
1002
943
|
}
|
|
1003
944
|
): Promise<PaginationResult<MessageDoc>> {
|
|
1004
|
-
|
|
1005
|
-
return {
|
|
1006
|
-
page: [],
|
|
1007
|
-
isDone: true,
|
|
1008
|
-
continueCursor: args.paginationOpts.cursor ?? "",
|
|
1009
|
-
};
|
|
1010
|
-
}
|
|
1011
|
-
return ctx.runQuery(this.component.messages.listMessagesByThreadId, {
|
|
1012
|
-
order: "desc",
|
|
1013
|
-
...args,
|
|
1014
|
-
});
|
|
945
|
+
return listMessages(ctx, this.component, args);
|
|
1015
946
|
}
|
|
1016
947
|
|
|
1017
948
|
/**
|
|
@@ -1031,25 +962,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1031
962
|
includeStatuses?: ("streaming" | "finished" | "aborted")[];
|
|
1032
963
|
}
|
|
1033
964
|
): Promise<SyncStreamsReturnValue | undefined> {
|
|
1034
|
-
|
|
1035
|
-
if (args.streamArgs.kind === "list") {
|
|
1036
|
-
return {
|
|
1037
|
-
kind: "list",
|
|
1038
|
-
messages: await ctx.runQuery(this.component.streams.list, {
|
|
1039
|
-
threadId: args.threadId,
|
|
1040
|
-
startOrder: args.streamArgs.startOrder,
|
|
1041
|
-
statuses: args.includeStatuses,
|
|
1042
|
-
}),
|
|
1043
|
-
};
|
|
1044
|
-
} else {
|
|
1045
|
-
return {
|
|
1046
|
-
kind: "deltas",
|
|
1047
|
-
deltas: await ctx.runQuery(this.component.streams.listDeltas, {
|
|
1048
|
-
threadId: args.threadId,
|
|
1049
|
-
cursors: args.streamArgs.cursors,
|
|
1050
|
-
}),
|
|
1051
|
-
};
|
|
1052
|
-
}
|
|
965
|
+
return syncStreams(ctx, this.component, args);
|
|
1053
966
|
}
|
|
1054
967
|
|
|
1055
968
|
/**
|
|
@@ -1076,76 +989,28 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1076
989
|
}
|
|
1077
990
|
): Promise<MessageDoc[]> {
|
|
1078
991
|
assert(args.userId || args.threadId, "Specify userId or threadId");
|
|
1079
|
-
// Fetch the latest messages from the thread
|
|
1080
|
-
let included: Set<string> | undefined;
|
|
1081
992
|
const opts = this._mergedContextOptions(args.contextOptions);
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
// Reverse since we fetched in descending order
|
|
1104
|
-
...page.reverse()
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
if (opts.searchOptions?.textSearch || opts.searchOptions?.vectorSearch) {
|
|
1108
|
-
const targetMessage = contextMessages.find(
|
|
1109
|
-
(m) => m._id === args.upToAndIncludingMessageId
|
|
1110
|
-
)?.message;
|
|
1111
|
-
const messagesToSearch = targetMessage ? [targetMessage] : args.messages;
|
|
1112
|
-
if (!("runAction" in ctx)) {
|
|
1113
|
-
throw new Error("searchUserMessages only works in an action");
|
|
1114
|
-
}
|
|
1115
|
-
const searchMessages = await ctx.runAction(
|
|
1116
|
-
this.component.messages.searchMessages,
|
|
1117
|
-
{
|
|
1118
|
-
searchAllMessagesForUserId: opts?.searchOtherThreads
|
|
1119
|
-
? args.userId ??
|
|
1120
|
-
(args.threadId &&
|
|
1121
|
-
(
|
|
1122
|
-
await ctx.runQuery(this.component.threads.getThread, {
|
|
1123
|
-
threadId: args.threadId,
|
|
1124
|
-
})
|
|
1125
|
-
)?.userId)
|
|
1126
|
-
: undefined,
|
|
1127
|
-
threadId: args.threadId,
|
|
1128
|
-
beforeMessageId: args.upToAndIncludingMessageId,
|
|
1129
|
-
...(await this._searchOptionsWithEmbeddingAndDefaults(
|
|
1130
|
-
ctx,
|
|
1131
|
-
{ userId: args.userId, threadId: args.threadId },
|
|
1132
|
-
opts,
|
|
1133
|
-
messagesToSearch
|
|
1134
|
-
)),
|
|
1135
|
-
}
|
|
1136
|
-
);
|
|
1137
|
-
// TODO: track what messages we used for context
|
|
1138
|
-
contextMessages.unshift(
|
|
1139
|
-
...searchMessages.filter((m) => !included?.has(m._id))
|
|
1140
|
-
);
|
|
1141
|
-
}
|
|
1142
|
-
// Ensure we don't include tool messages without a corresponding tool call
|
|
1143
|
-
return filterOutOrphanedToolMessages(
|
|
1144
|
-
contextMessages.sort((a, b) =>
|
|
1145
|
-
// Sort the raw MessageDocs by order and stepOrder
|
|
1146
|
-
a.order === b.order ? a.stepOrder - b.stepOrder : a.order - b.order
|
|
1147
|
-
)
|
|
1148
|
-
);
|
|
993
|
+
return fetchContextMessages(ctx, this.component, {
|
|
994
|
+
...args,
|
|
995
|
+
contextOptions: opts,
|
|
996
|
+
getEmbedding: async (text) => {
|
|
997
|
+
assert("runAction" in ctx);
|
|
998
|
+
assert(
|
|
999
|
+
this.options.textEmbedding,
|
|
1000
|
+
"A textEmbedding model is required to be set on the Agent that you're doing vector search with"
|
|
1001
|
+
);
|
|
1002
|
+
return {
|
|
1003
|
+
vector: (
|
|
1004
|
+
await this.doEmbed(ctx, {
|
|
1005
|
+
userId: args.userId,
|
|
1006
|
+
threadId: args.threadId,
|
|
1007
|
+
values: [text],
|
|
1008
|
+
})
|
|
1009
|
+
).embeddings[0],
|
|
1010
|
+
vectorModel: this.options.textEmbedding.modelId,
|
|
1011
|
+
};
|
|
1012
|
+
},
|
|
1013
|
+
});
|
|
1149
1014
|
}
|
|
1150
1015
|
|
|
1151
1016
|
/**
|
|
@@ -1158,13 +1023,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1158
1023
|
ctx: RunQueryCtx,
|
|
1159
1024
|
args: { threadId: string }
|
|
1160
1025
|
): Promise<ThreadDoc> {
|
|
1161
|
-
|
|
1162
|
-
threadId: args.threadId,
|
|
1163
|
-
});
|
|
1164
|
-
if (!thread) {
|
|
1165
|
-
throw new Error("Thread not found");
|
|
1166
|
-
}
|
|
1167
|
-
return thread;
|
|
1026
|
+
return getThreadMetadata(ctx, this.component, args);
|
|
1168
1027
|
}
|
|
1169
1028
|
|
|
1170
1029
|
/**
|
|
@@ -1769,49 +1628,11 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1769
1628
|
...this.options.contextOptions,
|
|
1770
1629
|
...opts,
|
|
1771
1630
|
searchOptions: searchOptions.limit
|
|
1772
|
-
? (searchOptions as
|
|
1631
|
+
? (searchOptions as ContextOptions["searchOptions"])
|
|
1773
1632
|
: undefined,
|
|
1774
1633
|
};
|
|
1775
1634
|
}
|
|
1776
1635
|
|
|
1777
|
-
async _searchOptionsWithEmbeddingAndDefaults(
|
|
1778
|
-
ctx: RunActionCtx,
|
|
1779
|
-
{ userId, threadId }: { userId?: string; threadId?: string },
|
|
1780
|
-
contextOptions: ContextOptions,
|
|
1781
|
-
messages: CoreMessage[]
|
|
1782
|
-
): Promise<SearchOptions> {
|
|
1783
|
-
assert(
|
|
1784
|
-
contextOptions.searchOptions?.textSearch ||
|
|
1785
|
-
contextOptions.searchOptions?.vectorSearch,
|
|
1786
|
-
"searchOptions is required"
|
|
1787
|
-
);
|
|
1788
|
-
assert(messages.length > 0, "Core messages cannot be empty");
|
|
1789
|
-
const text = extractText(messages.at(-1)!);
|
|
1790
|
-
const search: SearchOptions = {
|
|
1791
|
-
limit: contextOptions.searchOptions?.limit ?? 10,
|
|
1792
|
-
messageRange: {
|
|
1793
|
-
...DEFAULT_MESSAGE_RANGE,
|
|
1794
|
-
...contextOptions.searchOptions?.messageRange,
|
|
1795
|
-
},
|
|
1796
|
-
text: extractText(messages.at(-1)!),
|
|
1797
|
-
};
|
|
1798
|
-
if (
|
|
1799
|
-
contextOptions.searchOptions?.vectorSearch &&
|
|
1800
|
-
text &&
|
|
1801
|
-
this.options.textEmbedding
|
|
1802
|
-
) {
|
|
1803
|
-
search.vector = (
|
|
1804
|
-
await this.doEmbed(ctx, {
|
|
1805
|
-
threadId,
|
|
1806
|
-
userId,
|
|
1807
|
-
values: [text],
|
|
1808
|
-
})
|
|
1809
|
-
).embeddings[0];
|
|
1810
|
-
search.vectorModel = this.options.textEmbedding.modelId;
|
|
1811
|
-
}
|
|
1812
|
-
return search;
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
1636
|
async doEmbed(
|
|
1816
1637
|
ctx: RunActionCtx,
|
|
1817
1638
|
options: {
|
|
@@ -1823,7 +1644,10 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1823
1644
|
}
|
|
1824
1645
|
): Promise<{ embeddings: number[][] }> {
|
|
1825
1646
|
const embedding = this.options.textEmbedding;
|
|
1826
|
-
assert(
|
|
1647
|
+
assert(
|
|
1648
|
+
embedding,
|
|
1649
|
+
"a textEmbedding model is required to be set on the Agent that you're doing vector search with"
|
|
1650
|
+
);
|
|
1827
1651
|
const result = await embedding.doEmbed({
|
|
1828
1652
|
values: options.values,
|
|
1829
1653
|
abortSignal: options.abortSignal,
|
|
@@ -1861,7 +1685,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1861
1685
|
return Promise.all(
|
|
1862
1686
|
messages.map(async (message): Promise<CoreMessage> => {
|
|
1863
1687
|
if (
|
|
1864
|
-
message.role !== "user" ||
|
|
1688
|
+
(message.role !== "user" && message.role !== "assistant") ||
|
|
1865
1689
|
typeof message.content === "string" ||
|
|
1866
1690
|
!Array.isArray(message.content)
|
|
1867
1691
|
) {
|
|
@@ -1871,6 +1695,10 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1871
1695
|
const processedContent = await Promise.all(
|
|
1872
1696
|
message.content.map(async (part) => {
|
|
1873
1697
|
if (part.type === "image" && part.image instanceof URL) {
|
|
1698
|
+
assert(
|
|
1699
|
+
message.role === "user",
|
|
1700
|
+
"Images can only be in user messages"
|
|
1701
|
+
);
|
|
1874
1702
|
if (this._isLocalhostUrl(part.image)) {
|
|
1875
1703
|
const imageData = await this._downloadFile(part.image);
|
|
1876
1704
|
return {
|
|
@@ -1894,11 +1722,17 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1894
1722
|
return part;
|
|
1895
1723
|
})
|
|
1896
1724
|
);
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1725
|
+
if (message.role === "user") {
|
|
1726
|
+
return {
|
|
1727
|
+
...message,
|
|
1728
|
+
content: processedContent as UserContent,
|
|
1729
|
+
};
|
|
1730
|
+
} else {
|
|
1731
|
+
return {
|
|
1732
|
+
...message,
|
|
1733
|
+
content: processedContent as AssistantContent,
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1902
1736
|
})
|
|
1903
1737
|
);
|
|
1904
1738
|
}
|
|
@@ -2124,31 +1958,206 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
2124
1958
|
}
|
|
2125
1959
|
}
|
|
2126
1960
|
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
1961
|
+
type CoreMessageMaybeWithId = CoreMessage & { id?: string | undefined };
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* Create a thread to store messages with an Agent.
|
|
1965
|
+
* @param ctx The context from a mutation or action.
|
|
1966
|
+
* @param component The Agent component, usually `components.agent`.
|
|
1967
|
+
* @param args The associated thread metadata.
|
|
1968
|
+
* @returns The id of the created thread.
|
|
1969
|
+
*/
|
|
1970
|
+
export async function createThread(
|
|
1971
|
+
ctx: RunMutationCtx,
|
|
1972
|
+
component: AgentComponent,
|
|
1973
|
+
args?: {
|
|
1974
|
+
userId?: string;
|
|
1975
|
+
title?: string;
|
|
1976
|
+
summary?: string;
|
|
1977
|
+
}
|
|
1978
|
+
) {
|
|
1979
|
+
const { _id: threadId } = await ctx.runMutation(
|
|
1980
|
+
component.threads.createThread,
|
|
1981
|
+
{ userId: args?.userId, title: args?.title, summary: args?.summary }
|
|
1982
|
+
);
|
|
1983
|
+
return threadId;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
/**
|
|
1987
|
+
* Get the metadata for a thread.
|
|
1988
|
+
* @param ctx A ctx object from a query, mutation, or action.
|
|
1989
|
+
* @param args.threadId The thread to get the metadata for.
|
|
1990
|
+
* @returns The metadata for the thread.
|
|
1991
|
+
*/
|
|
1992
|
+
export async function getThreadMetadata(
|
|
1993
|
+
ctx: RunQueryCtx,
|
|
1994
|
+
component: AgentComponent,
|
|
1995
|
+
args: { threadId: string }
|
|
1996
|
+
): Promise<ThreadDoc> {
|
|
1997
|
+
const thread = await ctx.runQuery(component.threads.getThread, {
|
|
1998
|
+
threadId: args.threadId,
|
|
1999
|
+
});
|
|
2000
|
+
if (!thread) {
|
|
2001
|
+
throw new Error("Thread not found");
|
|
2002
|
+
}
|
|
2003
|
+
return thread;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
type SaveMessagesArgs = {
|
|
2007
|
+
threadId: string;
|
|
2008
|
+
userId?: string;
|
|
2009
|
+
/**
|
|
2010
|
+
* The message that these messages are in response to. They will be
|
|
2011
|
+
* the same "order" as this message, at increasing stepOrder(s).
|
|
2012
|
+
*/
|
|
2013
|
+
promptMessageId?: string;
|
|
2014
|
+
/**
|
|
2015
|
+
* The messages to save.
|
|
2016
|
+
*/
|
|
2017
|
+
messages: CoreMessageMaybeWithId[];
|
|
2018
|
+
/**
|
|
2019
|
+
* Metadata to save with the messages. Each element corresponds to the
|
|
2020
|
+
* message at the same index.
|
|
2021
|
+
*/
|
|
2022
|
+
metadata?: Omit<MessageWithMetadata, "message">[];
|
|
2023
|
+
/**
|
|
2024
|
+
* If false, it will "commit" the messages immediately.
|
|
2025
|
+
* If true, it will mark them as pending until the final step has finished.
|
|
2026
|
+
* Defaults to false.
|
|
2027
|
+
*/
|
|
2028
|
+
pending?: boolean;
|
|
2029
|
+
/**
|
|
2030
|
+
* If true, it will fail any pending steps.
|
|
2031
|
+
* Defaults to false.
|
|
2032
|
+
*/
|
|
2033
|
+
failPendingSteps?: boolean;
|
|
2034
|
+
/**
|
|
2035
|
+
* The embeddings to save with the messages.
|
|
2036
|
+
*/
|
|
2037
|
+
embeddings?: Omit<MessageEmbeddings, "dimension">;
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
/**
|
|
2041
|
+
* Explicitly save messages associated with the thread (& user if provided)
|
|
2042
|
+
*/
|
|
2043
|
+
export async function saveMessages(
|
|
2044
|
+
ctx: RunMutationCtx,
|
|
2045
|
+
component: AgentComponent,
|
|
2046
|
+
args: SaveMessagesArgs & {
|
|
2047
|
+
/**
|
|
2048
|
+
* The agent name to associate with the messages.
|
|
2049
|
+
*/
|
|
2050
|
+
agentName?: string;
|
|
2051
|
+
}
|
|
2052
|
+
) {
|
|
2053
|
+
let embeddings: MessageEmbeddings | undefined;
|
|
2054
|
+
if (args.embeddings) {
|
|
2055
|
+
const dimension = args.embeddings.vectors.find((v) => v !== null)?.length;
|
|
2056
|
+
if (dimension) {
|
|
2057
|
+
validateVectorDimension(dimension);
|
|
2058
|
+
embeddings = {
|
|
2059
|
+
model: args.embeddings.model,
|
|
2060
|
+
dimension,
|
|
2061
|
+
vectors: args.embeddings.vectors,
|
|
2062
|
+
};
|
|
2149
2063
|
}
|
|
2150
2064
|
}
|
|
2151
|
-
|
|
2065
|
+
const result = await ctx.runMutation(component.messages.addMessages, {
|
|
2066
|
+
threadId: args.threadId,
|
|
2067
|
+
userId: args.userId,
|
|
2068
|
+
agentName: args.agentName,
|
|
2069
|
+
promptMessageId: args.promptMessageId,
|
|
2070
|
+
embeddings,
|
|
2071
|
+
messages: await Promise.all(
|
|
2072
|
+
args.messages.map(async (m, i) => {
|
|
2073
|
+
const { message, fileIds } = await serializeMessage(ctx, component, m);
|
|
2074
|
+
return {
|
|
2075
|
+
...args.metadata?.[i],
|
|
2076
|
+
message,
|
|
2077
|
+
fileIds,
|
|
2078
|
+
} as MessageWithMetadata;
|
|
2079
|
+
})
|
|
2080
|
+
),
|
|
2081
|
+
failPendingSteps: args.failPendingSteps ?? false,
|
|
2082
|
+
pending: args.pending ?? false,
|
|
2083
|
+
});
|
|
2084
|
+
return {
|
|
2085
|
+
lastMessageId: result.messages.at(-1)!._id,
|
|
2086
|
+
messages: result.messages,
|
|
2087
|
+
};
|
|
2152
2088
|
}
|
|
2153
2089
|
|
|
2154
|
-
type
|
|
2090
|
+
type SaveMessageArgs = {
|
|
2091
|
+
threadId: string;
|
|
2092
|
+
userId?: string;
|
|
2093
|
+
/**
|
|
2094
|
+
* Metadata to save with the messages. Each element corresponds to the
|
|
2095
|
+
* message at the same index.
|
|
2096
|
+
*/
|
|
2097
|
+
metadata?: Omit<MessageWithMetadata, "message">;
|
|
2098
|
+
/**
|
|
2099
|
+
* The embedding to save with the message.
|
|
2100
|
+
*/
|
|
2101
|
+
embedding?: {
|
|
2102
|
+
vector: number[];
|
|
2103
|
+
model: string;
|
|
2104
|
+
};
|
|
2105
|
+
} & (
|
|
2106
|
+
| {
|
|
2107
|
+
prompt?: undefined;
|
|
2108
|
+
/**
|
|
2109
|
+
* The message to save.
|
|
2110
|
+
*/
|
|
2111
|
+
message: CoreMessage;
|
|
2112
|
+
}
|
|
2113
|
+
| {
|
|
2114
|
+
/*
|
|
2115
|
+
* The prompt to save with the message.
|
|
2116
|
+
*/
|
|
2117
|
+
prompt: string;
|
|
2118
|
+
message?: undefined;
|
|
2119
|
+
}
|
|
2120
|
+
);
|
|
2121
|
+
|
|
2122
|
+
/**
|
|
2123
|
+
* Save a message to the thread.
|
|
2124
|
+
* @param ctx A ctx object from a mutation or action.
|
|
2125
|
+
* @param args The message and what to associate it with (user / thread)
|
|
2126
|
+
* You can pass extra metadata alongside the message, e.g. associated fileIds.
|
|
2127
|
+
* @returns The messageId of the saved message.
|
|
2128
|
+
*/
|
|
2129
|
+
export async function saveMessage(
|
|
2130
|
+
ctx: RunMutationCtx,
|
|
2131
|
+
component: AgentComponent,
|
|
2132
|
+
args: SaveMessageArgs & {
|
|
2133
|
+
/**
|
|
2134
|
+
* The agent name to associate with the message.
|
|
2135
|
+
*/
|
|
2136
|
+
agentName?: string;
|
|
2137
|
+
}
|
|
2138
|
+
) {
|
|
2139
|
+
let embeddings:
|
|
2140
|
+
| {
|
|
2141
|
+
vectors: number[][];
|
|
2142
|
+
model: string;
|
|
2143
|
+
}
|
|
2144
|
+
| undefined;
|
|
2145
|
+
if (args.embedding && args.embedding.vector) {
|
|
2146
|
+
embeddings = {
|
|
2147
|
+
model: args.embedding.model,
|
|
2148
|
+
vectors: [args.embedding.vector],
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
const { lastMessageId, messages } = await saveMessages(ctx, component, {
|
|
2152
|
+
threadId: args.threadId,
|
|
2153
|
+
userId: args.userId,
|
|
2154
|
+
agentName: args.agentName,
|
|
2155
|
+
messages:
|
|
2156
|
+
args.prompt !== undefined
|
|
2157
|
+
? [{ role: "user", content: args.prompt }]
|
|
2158
|
+
: [args.message],
|
|
2159
|
+
metadata: args.metadata ? [args.metadata] : undefined,
|
|
2160
|
+
embeddings,
|
|
2161
|
+
});
|
|
2162
|
+
return { messageId: lastMessageId, message: messages.at(-1)! };
|
|
2163
|
+
}
|