@convex-dev/agent 0.1.15-alpha.0 → 0.1.15-alpha.1
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/index.d.ts +494 -173
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +119 -166
- 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/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 +4 -3
- package/src/client/index.ts +245 -268
- 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/validators.ts +2 -10
package/src/client/index.ts
CHANGED
|
@@ -34,22 +34,17 @@ import {
|
|
|
34
34
|
serializeNewMessagesInStep,
|
|
35
35
|
serializeObjectResult,
|
|
36
36
|
} from "../mapping.js";
|
|
37
|
-
import {
|
|
38
|
-
DEFAULT_MESSAGE_RANGE,
|
|
39
|
-
DEFAULT_RECENT_MESSAGES,
|
|
40
|
-
extractText,
|
|
41
|
-
isTool,
|
|
42
|
-
} from "../shared.js";
|
|
37
|
+
import { extractText, isTool } from "../shared.js";
|
|
43
38
|
import {
|
|
44
39
|
type MessageWithMetadata,
|
|
45
40
|
type MessageStatus,
|
|
46
41
|
type ProviderMetadata,
|
|
47
|
-
type SearchOptions,
|
|
48
42
|
type StreamArgs,
|
|
49
43
|
type Usage,
|
|
50
44
|
vMessageWithMetadata,
|
|
51
45
|
vSafeObjectArgs,
|
|
52
46
|
vTextArgs,
|
|
47
|
+
type MessageEmbeddings,
|
|
53
48
|
} from "../validators.js";
|
|
54
49
|
import { createTool, wrapTools } from "./createTool.js";
|
|
55
50
|
import {
|
|
@@ -77,6 +72,9 @@ import type {
|
|
|
77
72
|
UsageHandler,
|
|
78
73
|
} from "./types.js";
|
|
79
74
|
import type { threadFieldsSupportingPatch } from "../component/threads.js";
|
|
75
|
+
import { listMessages } from "./listMessages.js";
|
|
76
|
+
import { syncStreams } from "./streaming.js";
|
|
77
|
+
import { fetchContextMessages } from "./search.js";
|
|
80
78
|
|
|
81
79
|
export { storeFile, getFile } from "./files.js";
|
|
82
80
|
export { serializeDataOrUrl } from "../mapping.js";
|
|
@@ -95,12 +93,21 @@ export {
|
|
|
95
93
|
vUserMessage,
|
|
96
94
|
} from "../validators.js";
|
|
97
95
|
export type { ToolCtx } from "./createTool.js";
|
|
98
|
-
export {
|
|
96
|
+
export { filterOutOrphanedToolMessages } from "./search.js";
|
|
97
|
+
export {
|
|
98
|
+
createTool,
|
|
99
|
+
extractText,
|
|
100
|
+
fetchContextMessages,
|
|
101
|
+
isTool,
|
|
102
|
+
listMessages,
|
|
103
|
+
syncStreams,
|
|
104
|
+
};
|
|
99
105
|
export type {
|
|
100
106
|
AgentComponent,
|
|
101
107
|
ContextOptions,
|
|
102
108
|
MessageDoc,
|
|
103
109
|
ProviderMetadata,
|
|
110
|
+
RawRequestResponseHandler,
|
|
104
111
|
StorageOptions,
|
|
105
112
|
StreamArgs,
|
|
106
113
|
SyncStreamsReturnValue,
|
|
@@ -276,25 +283,18 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
276
283
|
threadId: string;
|
|
277
284
|
thread?: Thread<ThreadTools extends undefined ? AgentTools : ThreadTools>;
|
|
278
285
|
}> {
|
|
279
|
-
const
|
|
280
|
-
this.component.threads.createThread,
|
|
281
|
-
{
|
|
282
|
-
userId: args?.userId,
|
|
283
|
-
title: args?.title,
|
|
284
|
-
summary: args?.summary,
|
|
285
|
-
}
|
|
286
|
-
);
|
|
286
|
+
const threadId = await createThread(ctx, this.component, args);
|
|
287
287
|
if (!("runAction" in ctx)) {
|
|
288
|
-
return { threadId
|
|
288
|
+
return { threadId };
|
|
289
289
|
}
|
|
290
290
|
const { thread } = await this.continueThread(ctx, {
|
|
291
|
-
threadId
|
|
291
|
+
threadId,
|
|
292
292
|
userId: args?.userId,
|
|
293
293
|
usageHandler: args?.usageHandler,
|
|
294
294
|
tools: args?.tools,
|
|
295
295
|
});
|
|
296
296
|
return {
|
|
297
|
-
threadId
|
|
297
|
+
threadId,
|
|
298
298
|
thread,
|
|
299
299
|
};
|
|
300
300
|
}
|
|
@@ -833,14 +833,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
833
833
|
*/
|
|
834
834
|
async saveMessage(
|
|
835
835
|
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">;
|
|
836
|
+
args: SaveMessageArgs & {
|
|
844
837
|
/**
|
|
845
838
|
* If true, it will not generate embeddings for the message.
|
|
846
839
|
* Useful if you're saving messages in a mutation where you can't run `fetch`.
|
|
@@ -848,22 +841,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
848
841
|
* action later that calls `agent.generateAndSaveEmbeddings`.
|
|
849
842
|
*/
|
|
850
843
|
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
|
-
)
|
|
844
|
+
}
|
|
867
845
|
) {
|
|
868
846
|
const { lastMessageId, messages } = await this.saveMessages(ctx, {
|
|
869
847
|
threadId: args.threadId,
|
|
@@ -880,40 +858,15 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
880
858
|
|
|
881
859
|
/**
|
|
882
860
|
* Explicitly save messages associated with the thread (& user if provided)
|
|
861
|
+
* If you have an embedding model set, it will also generate embeddings for
|
|
862
|
+
* the messages.
|
|
883
863
|
* @param ctx The ctx parameter to a mutation or action.
|
|
884
864
|
* @param args The messages and context to save
|
|
885
865
|
* @returns
|
|
886
866
|
*/
|
|
887
867
|
async saveMessages(
|
|
888
868
|
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;
|
|
869
|
+
args: SaveMessagesArgs & {
|
|
917
870
|
/**
|
|
918
871
|
* Skip generating embeddings for the messages. Useful if you're
|
|
919
872
|
* saving messages in a mutation where you can't run `fetch`.
|
|
@@ -933,9 +886,12 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
933
886
|
model: string;
|
|
934
887
|
}
|
|
935
888
|
| undefined;
|
|
936
|
-
|
|
889
|
+
const { skipEmbeddings, ...rest } = args;
|
|
890
|
+
if (args.embeddings) {
|
|
891
|
+
embeddings = args.embeddings;
|
|
892
|
+
} else if (skipEmbeddings || !("runAction" in ctx)) {
|
|
937
893
|
embeddings = undefined;
|
|
938
|
-
if (!
|
|
894
|
+
if (!skipEmbeddings && this.options.textEmbedding) {
|
|
939
895
|
console.warn(
|
|
940
896
|
"You're trying to save messages and generate embeddings, but you're in a mutation. " +
|
|
941
897
|
"Pass `skipEmbeddings: true` to skip generating embeddings in the mutation and skip this warning. " +
|
|
@@ -953,33 +909,11 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
953
909
|
args.messages
|
|
954
910
|
);
|
|
955
911
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
userId: args.userId,
|
|
912
|
+
return saveMessages(ctx, this.component, {
|
|
913
|
+
...rest,
|
|
959
914
|
agentName: this.options.name,
|
|
960
|
-
promptMessageId: args.promptMessageId,
|
|
961
915
|
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
916
|
});
|
|
979
|
-
return {
|
|
980
|
-
lastMessageId: result.messages.at(-1)!._id,
|
|
981
|
-
messages: result.messages,
|
|
982
|
-
};
|
|
983
917
|
}
|
|
984
918
|
|
|
985
919
|
/**
|
|
@@ -1001,17 +935,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1001
935
|
statuses?: MessageStatus[];
|
|
1002
936
|
}
|
|
1003
937
|
): 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
|
-
});
|
|
938
|
+
return listMessages(ctx, this.component, args);
|
|
1015
939
|
}
|
|
1016
940
|
|
|
1017
941
|
/**
|
|
@@ -1031,25 +955,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1031
955
|
includeStatuses?: ("streaming" | "finished" | "aborted")[];
|
|
1032
956
|
}
|
|
1033
957
|
): 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
|
-
}
|
|
958
|
+
return syncStreams(ctx, this.component, args);
|
|
1053
959
|
}
|
|
1054
960
|
|
|
1055
961
|
/**
|
|
@@ -1076,76 +982,28 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1076
982
|
}
|
|
1077
983
|
): Promise<MessageDoc[]> {
|
|
1078
984
|
assert(args.userId || args.threadId, "Specify userId or threadId");
|
|
1079
|
-
// Fetch the latest messages from the thread
|
|
1080
|
-
let included: Set<string> | undefined;
|
|
1081
985
|
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
|
-
);
|
|
986
|
+
return fetchContextMessages(ctx, this.component, {
|
|
987
|
+
...args,
|
|
988
|
+
contextOptions: opts,
|
|
989
|
+
getEmbedding: async (text) => {
|
|
990
|
+
assert("runAction" in ctx);
|
|
991
|
+
assert(
|
|
992
|
+
this.options.textEmbedding,
|
|
993
|
+
"A textEmbedding model is required to be set on the Agent that you're doing vector search with"
|
|
994
|
+
);
|
|
995
|
+
return {
|
|
996
|
+
vector: (
|
|
997
|
+
await this.doEmbed(ctx, {
|
|
998
|
+
userId: args.userId,
|
|
999
|
+
threadId: args.threadId,
|
|
1000
|
+
values: [text],
|
|
1001
|
+
})
|
|
1002
|
+
).embeddings[0],
|
|
1003
|
+
vectorModel: this.options.textEmbedding.modelId,
|
|
1004
|
+
};
|
|
1005
|
+
},
|
|
1006
|
+
});
|
|
1149
1007
|
}
|
|
1150
1008
|
|
|
1151
1009
|
/**
|
|
@@ -1158,13 +1016,7 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1158
1016
|
ctx: RunQueryCtx,
|
|
1159
1017
|
args: { threadId: string }
|
|
1160
1018
|
): Promise<ThreadDoc> {
|
|
1161
|
-
|
|
1162
|
-
threadId: args.threadId,
|
|
1163
|
-
});
|
|
1164
|
-
if (!thread) {
|
|
1165
|
-
throw new Error("Thread not found");
|
|
1166
|
-
}
|
|
1167
|
-
return thread;
|
|
1019
|
+
return getThreadMetadata(ctx, this.component, args);
|
|
1168
1020
|
}
|
|
1169
1021
|
|
|
1170
1022
|
/**
|
|
@@ -1769,49 +1621,11 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1769
1621
|
...this.options.contextOptions,
|
|
1770
1622
|
...opts,
|
|
1771
1623
|
searchOptions: searchOptions.limit
|
|
1772
|
-
? (searchOptions as
|
|
1624
|
+
? (searchOptions as ContextOptions["searchOptions"])
|
|
1773
1625
|
: undefined,
|
|
1774
1626
|
};
|
|
1775
1627
|
}
|
|
1776
1628
|
|
|
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
1629
|
async doEmbed(
|
|
1816
1630
|
ctx: RunActionCtx,
|
|
1817
1631
|
options: {
|
|
@@ -1823,7 +1637,10 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
1823
1637
|
}
|
|
1824
1638
|
): Promise<{ embeddings: number[][] }> {
|
|
1825
1639
|
const embedding = this.options.textEmbedding;
|
|
1826
|
-
assert(
|
|
1640
|
+
assert(
|
|
1641
|
+
embedding,
|
|
1642
|
+
"a textEmbedding model is required to be set on the Agent that you're doing vector search with"
|
|
1643
|
+
);
|
|
1827
1644
|
const result = await embedding.doEmbed({
|
|
1828
1645
|
values: options.values,
|
|
1829
1646
|
abortSignal: options.abortSignal,
|
|
@@ -2124,31 +1941,191 @@ export class Agent<AgentTools extends ToolSet = ToolSet> {
|
|
|
2124
1941
|
}
|
|
2125
1942
|
}
|
|
2126
1943
|
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
result.push(doc);
|
|
2144
|
-
} else {
|
|
2145
|
-
console.debug("Filtering out orphaned tool message", doc);
|
|
2146
|
-
}
|
|
2147
|
-
} else {
|
|
2148
|
-
result.push(doc);
|
|
2149
|
-
}
|
|
1944
|
+
type CoreMessageMaybeWithId = CoreMessage & { id?: string | undefined };
|
|
1945
|
+
|
|
1946
|
+
/**
|
|
1947
|
+
* Create a thread to store messages with an Agent.
|
|
1948
|
+
* @param ctx The context from a mutation or action.
|
|
1949
|
+
* @param component The Agent component, usually `components.agent`.
|
|
1950
|
+
* @param args The associated thread metadata.
|
|
1951
|
+
* @returns The id of the created thread.
|
|
1952
|
+
*/
|
|
1953
|
+
export async function createThread(
|
|
1954
|
+
ctx: RunMutationCtx,
|
|
1955
|
+
component: AgentComponent,
|
|
1956
|
+
args?: {
|
|
1957
|
+
userId?: string;
|
|
1958
|
+
title?: string;
|
|
1959
|
+
summary?: string;
|
|
2150
1960
|
}
|
|
2151
|
-
|
|
1961
|
+
) {
|
|
1962
|
+
const { _id: threadId } = await ctx.runMutation(
|
|
1963
|
+
component.threads.createThread,
|
|
1964
|
+
{ userId: args?.userId, title: args?.title, summary: args?.summary }
|
|
1965
|
+
);
|
|
1966
|
+
return threadId;
|
|
2152
1967
|
}
|
|
2153
1968
|
|
|
2154
|
-
|
|
1969
|
+
/**
|
|
1970
|
+
* Get the metadata for a thread.
|
|
1971
|
+
* @param ctx A ctx object from a query, mutation, or action.
|
|
1972
|
+
* @param args.threadId The thread to get the metadata for.
|
|
1973
|
+
* @returns The metadata for the thread.
|
|
1974
|
+
*/
|
|
1975
|
+
export async function getThreadMetadata(
|
|
1976
|
+
ctx: RunQueryCtx,
|
|
1977
|
+
component: AgentComponent,
|
|
1978
|
+
args: { threadId: string }
|
|
1979
|
+
): Promise<ThreadDoc> {
|
|
1980
|
+
const thread = await ctx.runQuery(component.threads.getThread, {
|
|
1981
|
+
threadId: args.threadId,
|
|
1982
|
+
});
|
|
1983
|
+
if (!thread) {
|
|
1984
|
+
throw new Error("Thread not found");
|
|
1985
|
+
}
|
|
1986
|
+
return thread;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
type SaveMessagesArgs = {
|
|
1990
|
+
threadId: string;
|
|
1991
|
+
userId?: string;
|
|
1992
|
+
/**
|
|
1993
|
+
* The message that these messages are in response to. They will be
|
|
1994
|
+
* the same "order" as this message, at increasing stepOrder(s).
|
|
1995
|
+
*/
|
|
1996
|
+
promptMessageId?: string;
|
|
1997
|
+
/**
|
|
1998
|
+
* The messages to save.
|
|
1999
|
+
*/
|
|
2000
|
+
messages: CoreMessageMaybeWithId[];
|
|
2001
|
+
/**
|
|
2002
|
+
* Metadata to save with the messages. Each element corresponds to the
|
|
2003
|
+
* message at the same index.
|
|
2004
|
+
*/
|
|
2005
|
+
metadata?: Omit<MessageWithMetadata, "message">[];
|
|
2006
|
+
/**
|
|
2007
|
+
* If false, it will "commit" the messages immediately.
|
|
2008
|
+
* If true, it will mark them as pending until the final step has finished.
|
|
2009
|
+
* Defaults to false.
|
|
2010
|
+
*/
|
|
2011
|
+
pending?: boolean;
|
|
2012
|
+
/**
|
|
2013
|
+
* If true, it will fail any pending steps.
|
|
2014
|
+
* Defaults to false.
|
|
2015
|
+
*/
|
|
2016
|
+
failPendingSteps?: boolean;
|
|
2017
|
+
/**
|
|
2018
|
+
* The embeddings to save with the messages.
|
|
2019
|
+
*/
|
|
2020
|
+
embeddings?: MessageEmbeddings;
|
|
2021
|
+
};
|
|
2022
|
+
|
|
2023
|
+
/**
|
|
2024
|
+
* Explicitly save messages associated with the thread (& user if provided)
|
|
2025
|
+
*/
|
|
2026
|
+
export async function saveMessages(
|
|
2027
|
+
ctx: RunMutationCtx,
|
|
2028
|
+
component: AgentComponent,
|
|
2029
|
+
args: SaveMessagesArgs & {
|
|
2030
|
+
/**
|
|
2031
|
+
* The agent name to associate with the messages.
|
|
2032
|
+
*/
|
|
2033
|
+
agentName?: string;
|
|
2034
|
+
}
|
|
2035
|
+
) {
|
|
2036
|
+
const result = await ctx.runMutation(component.messages.addMessages, {
|
|
2037
|
+
threadId: args.threadId,
|
|
2038
|
+
userId: args.userId,
|
|
2039
|
+
agentName: args.agentName,
|
|
2040
|
+
promptMessageId: args.promptMessageId,
|
|
2041
|
+
embeddings: args.embeddings,
|
|
2042
|
+
messages: await Promise.all(
|
|
2043
|
+
args.messages.map(async (m, i) => {
|
|
2044
|
+
const { message, fileIds } = await serializeMessage(ctx, component, m);
|
|
2045
|
+
return {
|
|
2046
|
+
...args.metadata?.[i],
|
|
2047
|
+
message,
|
|
2048
|
+
fileIds,
|
|
2049
|
+
} as MessageWithMetadata;
|
|
2050
|
+
})
|
|
2051
|
+
),
|
|
2052
|
+
failPendingSteps: args.failPendingSteps ?? false,
|
|
2053
|
+
pending: args.pending ?? false,
|
|
2054
|
+
});
|
|
2055
|
+
return {
|
|
2056
|
+
lastMessageId: result.messages.at(-1)!._id,
|
|
2057
|
+
messages: result.messages,
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
type SaveMessageArgs = {
|
|
2062
|
+
threadId: string;
|
|
2063
|
+
userId?: string;
|
|
2064
|
+
/**
|
|
2065
|
+
* Metadata to save with the messages. Each element corresponds to the
|
|
2066
|
+
* message at the same index.
|
|
2067
|
+
*/
|
|
2068
|
+
metadata?: Omit<MessageWithMetadata, "message">;
|
|
2069
|
+
/**
|
|
2070
|
+
* The embedding to save with the message.
|
|
2071
|
+
*/
|
|
2072
|
+
embedding?: {
|
|
2073
|
+
vector: number[];
|
|
2074
|
+
model: string;
|
|
2075
|
+
};
|
|
2076
|
+
} & (
|
|
2077
|
+
| {
|
|
2078
|
+
prompt?: undefined;
|
|
2079
|
+
/**
|
|
2080
|
+
* The message to save.
|
|
2081
|
+
*/
|
|
2082
|
+
message: CoreMessage;
|
|
2083
|
+
}
|
|
2084
|
+
| {
|
|
2085
|
+
/*
|
|
2086
|
+
* The prompt to save with the message.
|
|
2087
|
+
*/
|
|
2088
|
+
prompt: string;
|
|
2089
|
+
message?: undefined;
|
|
2090
|
+
}
|
|
2091
|
+
);
|
|
2092
|
+
|
|
2093
|
+
/**
|
|
2094
|
+
* Save a message to the thread.
|
|
2095
|
+
* @param ctx A ctx object from a mutation or action.
|
|
2096
|
+
* @param args The message and what to associate it with (user / thread)
|
|
2097
|
+
* You can pass extra metadata alongside the message, e.g. associated fileIds.
|
|
2098
|
+
* @returns The messageId of the saved message.
|
|
2099
|
+
*/
|
|
2100
|
+
export async function saveMessage(
|
|
2101
|
+
ctx: RunMutationCtx,
|
|
2102
|
+
component: AgentComponent,
|
|
2103
|
+
args: SaveMessageArgs & {
|
|
2104
|
+
/**
|
|
2105
|
+
* The agent name to associate with the message.
|
|
2106
|
+
*/
|
|
2107
|
+
agentName?: string;
|
|
2108
|
+
}
|
|
2109
|
+
) {
|
|
2110
|
+
let embeddings: MessageEmbeddings | undefined;
|
|
2111
|
+
if (args.embedding) {
|
|
2112
|
+
const dimension = args.embedding.vector.length;
|
|
2113
|
+
validateVectorDimension(dimension);
|
|
2114
|
+
embeddings = {
|
|
2115
|
+
model: args.embedding.model,
|
|
2116
|
+
dimension,
|
|
2117
|
+
vectors: [args.embedding.vector],
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
const { lastMessageId, messages } = await saveMessages(ctx, component, {
|
|
2121
|
+
threadId: args.threadId,
|
|
2122
|
+
userId: args.userId,
|
|
2123
|
+
messages:
|
|
2124
|
+
args.prompt !== undefined
|
|
2125
|
+
? [{ role: "user", content: args.prompt }]
|
|
2126
|
+
: [args.message],
|
|
2127
|
+
metadata: args.metadata ? [args.metadata] : undefined,
|
|
2128
|
+
embeddings,
|
|
2129
|
+
});
|
|
2130
|
+
return { messageId: lastMessageId, message: messages.at(-1)! };
|
|
2131
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { PaginationOptions, PaginationResult } from "convex/server";
|
|
2
|
+
import type { AgentComponent, RunQueryCtx } from "./types.js";
|
|
3
|
+
import type { MessageStatus } from "../validators.js";
|
|
4
|
+
import type { MessageDoc } from "../component/schema.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* List messages from a thread.
|
|
8
|
+
* @param ctx A ctx object from a query, mutation, or action.
|
|
9
|
+
* @param component The agent component, usually `components.agent`.
|
|
10
|
+
* @param args.threadId The thread to list messages from.
|
|
11
|
+
* @param args.paginationOpts Pagination options (e.g. via usePaginatedQuery).
|
|
12
|
+
* @param args.excludeToolMessages Whether to exclude tool messages.
|
|
13
|
+
* False by default.
|
|
14
|
+
* @param args.statuses What statuses to include. All by default.
|
|
15
|
+
* @returns The MessageDoc's in a format compatible with usePaginatedQuery.
|
|
16
|
+
*/
|
|
17
|
+
export async function listMessages(
|
|
18
|
+
ctx: RunQueryCtx,
|
|
19
|
+
component: AgentComponent,
|
|
20
|
+
args: {
|
|
21
|
+
threadId: string;
|
|
22
|
+
paginationOpts: PaginationOptions;
|
|
23
|
+
excludeToolMessages?: boolean;
|
|
24
|
+
statuses?: MessageStatus[];
|
|
25
|
+
}
|
|
26
|
+
): Promise<PaginationResult<MessageDoc>> {
|
|
27
|
+
if (args.paginationOpts.numItems === 0) {
|
|
28
|
+
return {
|
|
29
|
+
page: [],
|
|
30
|
+
isDone: true,
|
|
31
|
+
continueCursor: args.paginationOpts.cursor ?? "",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return ctx.runQuery(component.messages.listMessagesByThreadId, {
|
|
35
|
+
order: "desc",
|
|
36
|
+
...args,
|
|
37
|
+
});
|
|
38
|
+
}
|