@convex-dev/agent 0.5.0-alpha.1 → 0.6.0-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/MIGRATION.md +153 -0
- package/README.md +32 -27
- package/dist/UIMessages.d.ts +46 -0
- package/dist/UIMessages.d.ts.map +1 -0
- package/dist/UIMessages.js +546 -0
- package/dist/UIMessages.js.map +1 -0
- package/dist/client/createTool.d.ts +126 -27
- package/dist/client/createTool.d.ts.map +1 -1
- package/dist/client/createTool.js +67 -12
- package/dist/client/createTool.js.map +1 -1
- package/dist/client/defaultComponent.d.ts +11 -0
- package/dist/client/defaultComponent.d.ts.map +1 -0
- package/dist/client/defaultComponent.js +7 -0
- package/dist/client/defaultComponent.js.map +1 -0
- package/dist/client/definePlaygroundAPI.d.ts +1335 -204
- package/dist/client/definePlaygroundAPI.d.ts.map +1 -1
- package/dist/client/definePlaygroundAPI.js +52 -28
- package/dist/client/definePlaygroundAPI.js.map +1 -1
- package/dist/client/files.d.ts +20 -7
- package/dist/client/files.d.ts.map +1 -1
- package/dist/client/files.js +68 -11
- package/dist/client/files.js.map +1 -1
- package/dist/client/index.d.ts +1116 -978
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +332 -747
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +461 -0
- package/dist/client/messages.d.ts.map +1 -0
- package/dist/client/messages.js +106 -0
- package/dist/client/messages.js.map +1 -0
- package/dist/client/mockModel.d.ts +42 -0
- package/dist/client/mockModel.d.ts.map +1 -0
- package/dist/client/mockModel.js +182 -0
- package/dist/client/mockModel.js.map +1 -0
- package/dist/client/saveInputMessages.d.ts +20 -0
- package/dist/client/saveInputMessages.d.ts.map +1 -0
- package/dist/client/saveInputMessages.js +58 -0
- package/dist/client/saveInputMessages.js.map +1 -0
- package/dist/client/search.d.ts +350 -39
- package/dist/client/search.d.ts.map +1 -1
- package/dist/client/search.js +350 -39
- package/dist/client/search.js.map +1 -1
- package/dist/client/start.d.ts +84 -0
- package/dist/client/start.d.ts.map +1 -0
- package/dist/client/start.js +185 -0
- package/dist/client/start.js.map +1 -0
- package/dist/client/streamText.d.ts +46 -0
- package/dist/client/streamText.d.ts.map +1 -0
- package/dist/client/streamText.js +117 -0
- package/dist/client/streamText.js.map +1 -0
- package/dist/client/streaming.d.ts +3716 -32
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +161 -59
- package/dist/client/streaming.js.map +1 -1
- package/dist/client/threads.d.ts +46 -0
- package/dist/client/threads.d.ts.map +1 -0
- package/dist/client/threads.js +49 -0
- package/dist/client/threads.js.map +1 -0
- package/dist/client/types.d.ts +266 -128
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/utils.d.ts +4 -0
- package/dist/client/utils.d.ts.map +1 -0
- package/dist/client/utils.js +21 -0
- package/dist/client/utils.js.map +1 -0
- package/dist/component/_generated/api.d.ts +24 -2178
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js +10 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +3120 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +4 -18
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +10 -38
- package/dist/component/_generated/server.d.ts.map +1 -1
- package/dist/component/_generated/server.js +9 -5
- package/dist/component/_generated/server.js.map +1 -1
- package/dist/component/files.d.ts +16 -10
- package/dist/component/files.d.ts.map +1 -1
- package/dist/component/files.js +10 -2
- package/dist/component/files.js.map +1 -1
- package/dist/component/messages.d.ts +2578 -366
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +397 -154
- package/dist/component/messages.js.map +1 -1
- package/dist/component/schema.d.ts +5697 -3584
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +18 -41
- package/dist/component/schema.js.map +1 -1
- package/dist/component/streams.d.ts +39 -339
- package/dist/component/streams.d.ts.map +1 -1
- package/dist/component/streams.js +114 -73
- package/dist/component/streams.js.map +1 -1
- package/dist/component/threads.d.ts +13 -13
- package/dist/component/users.d.ts +7 -7
- package/dist/component/vector/index.d.ts +1 -1
- package/dist/component/vector/index.d.ts.map +1 -1
- package/dist/component/vector/index.js +1 -3
- package/dist/component/vector/index.js.map +1 -1
- package/dist/deltas.d.ts +43 -0
- package/dist/deltas.d.ts.map +1 -0
- package/dist/deltas.js +446 -0
- package/dist/deltas.js.map +1 -0
- package/dist/mapping.d.ts +38 -20
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +365 -97
- package/dist/mapping.js.map +1 -1
- package/dist/react/SmoothText.d.ts +5 -0
- package/dist/react/SmoothText.d.ts.map +1 -0
- package/dist/react/SmoothText.js +6 -0
- package/dist/react/SmoothText.js.map +1 -0
- package/dist/react/index.d.ts +5 -77
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +6 -160
- package/dist/react/index.js.map +1 -1
- package/dist/react/optimisticallySendMessage.d.ts +36 -3
- package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
- package/dist/react/optimisticallySendMessage.js +35 -9
- package/dist/react/optimisticallySendMessage.js.map +1 -1
- package/dist/react/types.d.ts +4 -18
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/useDeltaStreams.d.ts +10 -0
- package/dist/react/useDeltaStreams.d.ts.map +1 -0
- package/dist/react/useDeltaStreams.js +106 -0
- package/dist/react/useDeltaStreams.js.map +1 -0
- package/dist/react/useSmoothText.d.ts +13 -12
- package/dist/react/useSmoothText.d.ts.map +1 -1
- package/dist/react/useSmoothText.js +32 -15
- package/dist/react/useSmoothText.js.map +1 -1
- package/dist/react/useStreamingUIMessages.d.ts +22 -0
- package/dist/react/useStreamingUIMessages.d.ts.map +1 -0
- package/dist/react/useStreamingUIMessages.js +92 -0
- package/dist/react/useStreamingUIMessages.js.map +1 -0
- package/dist/react/useThreadMessages.d.ts +104 -0
- package/dist/react/useThreadMessages.d.ts.map +1 -0
- package/dist/react/useThreadMessages.js +148 -0
- package/dist/react/useThreadMessages.js.map +1 -0
- package/dist/react/useUIMessages.d.ts +96 -0
- package/dist/react/useUIMessages.d.ts.map +1 -0
- package/dist/react/useUIMessages.js +108 -0
- package/dist/react/useUIMessages.js.map +1 -0
- package/dist/shared.d.ts +20 -4
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +45 -8
- package/dist/shared.js.map +1 -1
- package/dist/validators.d.ts +22981 -5666
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +245 -137
- package/dist/validators.js.map +1 -1
- package/package.json +101 -51
- package/src/UIMessages.combineUIMessages.test.ts +239 -0
- package/src/UIMessages.test.ts +273 -0
- package/src/UIMessages.ts +739 -0
- package/src/client/approval.test.ts +350 -0
- package/src/client/createTool.ts +291 -76
- package/src/client/defaultComponent.ts +17 -0
- package/src/client/definePlaygroundAPI.ts +67 -31
- package/src/client/files.ts +100 -20
- package/src/client/index.test.ts +40 -85
- package/src/client/index.ts +638 -1289
- package/src/client/messages.ts +237 -0
- package/src/client/mockModel.ts +252 -0
- package/src/client/saveInputMessages.test.ts +583 -0
- package/src/client/saveInputMessages.ts +101 -0
- package/src/client/search.test.ts +1207 -0
- package/src/client/search.ts +581 -70
- package/src/client/start.ts +327 -0
- package/src/client/streamText.ts +187 -0
- package/src/client/streaming.test.ts +186 -0
- package/src/client/streaming.ts +241 -97
- package/src/client/threads.ts +83 -0
- package/src/client/types.ts +370 -219
- package/src/client/utils.ts +27 -0
- package/src/component/_generated/api.ts +64 -0
- package/src/component/_generated/component.ts +4902 -0
- package/src/component/_generated/{server.d.ts → server.ts} +33 -21
- package/src/component/files.ts +11 -2
- package/src/component/messages.test.ts +195 -51
- package/src/component/messages.ts +500 -201
- package/src/component/schema.ts +20 -46
- package/src/component/setup.test.ts +7 -0
- package/src/component/streams.ts +184 -83
- package/src/component/users.test.ts +0 -1
- package/src/component/vector/index.ts +1 -3
- package/src/deltas.test.ts +626 -0
- package/src/deltas.ts +569 -0
- package/src/fromUIMessages.test.ts +497 -0
- package/src/mapping.test.ts +180 -6
- package/src/mapping.ts +479 -162
- package/src/react/SmoothText.tsx +9 -0
- package/src/react/index.ts +10 -230
- package/src/react/optimisticallySendMessage.ts +55 -12
- package/src/react/types.ts +6 -39
- package/src/react/useDeltaStreams.ts +160 -0
- package/src/react/useSmoothText.ts +56 -36
- package/src/react/useStreamingUIMessages.ts +143 -0
- package/src/react/useThreadMessages.ts +262 -0
- package/src/react/useUIMessages.test.ts +255 -0
- package/src/react/useUIMessages.ts +195 -0
- package/src/shared.ts +88 -12
- package/src/test.ts +18 -0
- package/src/toUIMessages.test.ts +1269 -0
- package/src/validators.test.ts +18 -19
- package/src/validators.ts +325 -185
- package/dist/client/_generated/_ignore.d.ts +0 -1
- package/dist/client/_generated/_ignore.d.ts.map +0 -1
- package/dist/client/_generated/_ignore.js +0 -3
- package/dist/client/_generated/_ignore.js.map +0 -1
- package/dist/client/listMessages.d.ts +0 -22
- package/dist/client/listMessages.d.ts.map +0 -1
- package/dist/client/listMessages.js +0 -25
- package/dist/client/listMessages.js.map +0 -1
- package/dist/package.json +0 -3
- package/dist/react/deltas.d.ts +0 -26
- package/dist/react/deltas.d.ts.map +0 -1
- package/dist/react/deltas.js +0 -384
- package/dist/react/deltas.js.map +0 -1
- package/dist/react/toUIMessages.d.ts +0 -15
- package/dist/react/toUIMessages.d.ts.map +0 -1
- package/dist/react/toUIMessages.js +0 -211
- package/dist/react/toUIMessages.js.map +0 -1
- package/src/client/listMessages.ts +0 -38
- package/src/component/_generated/api.d.ts +0 -2202
- package/src/component/_generated/api.js +0 -23
- package/src/component/_generated/server.js +0 -90
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/src/react/deltas.test.ts +0 -315
- package/src/react/deltas.ts +0 -478
- package/src/react/toUIMessages.test.ts +0 -420
- package/src/react/toUIMessages.ts +0 -253
- package/src/vitest.config.ts +0 -7
- /package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +0 -0
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import type {
|
|
12
12
|
ActionBuilder,
|
|
13
|
-
AnyComponents,
|
|
14
13
|
HttpActionBuilder,
|
|
15
14
|
MutationBuilder,
|
|
16
15
|
QueryBuilder,
|
|
@@ -19,15 +18,18 @@ import {
|
|
|
19
18
|
GenericQueryCtx,
|
|
20
19
|
GenericDatabaseReader,
|
|
21
20
|
GenericDatabaseWriter,
|
|
22
|
-
|
|
21
|
+
} from "convex/server";
|
|
22
|
+
import {
|
|
23
|
+
actionGeneric,
|
|
24
|
+
httpActionGeneric,
|
|
25
|
+
queryGeneric,
|
|
26
|
+
mutationGeneric,
|
|
27
|
+
internalActionGeneric,
|
|
28
|
+
internalMutationGeneric,
|
|
29
|
+
internalQueryGeneric,
|
|
23
30
|
} from "convex/server";
|
|
24
31
|
import type { DataModel } from "./dataModel.js";
|
|
25
32
|
|
|
26
|
-
type GenericCtx =
|
|
27
|
-
| GenericActionCtx<DataModel>
|
|
28
|
-
| GenericMutationCtx<DataModel>
|
|
29
|
-
| GenericQueryCtx<DataModel>;
|
|
30
|
-
|
|
31
33
|
/**
|
|
32
34
|
* Define a query in this Convex app's public API.
|
|
33
35
|
*
|
|
@@ -36,7 +38,7 @@ type GenericCtx =
|
|
|
36
38
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
37
39
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
38
40
|
*/
|
|
39
|
-
export
|
|
41
|
+
export const query: QueryBuilder<DataModel, "public"> = queryGeneric;
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Define a query that is only accessible from other Convex functions (but not from the client).
|
|
@@ -46,7 +48,8 @@ export declare const query: QueryBuilder<DataModel, "public">;
|
|
|
46
48
|
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
|
47
49
|
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
|
48
50
|
*/
|
|
49
|
-
export
|
|
51
|
+
export const internalQuery: QueryBuilder<DataModel, "internal"> =
|
|
52
|
+
internalQueryGeneric;
|
|
50
53
|
|
|
51
54
|
/**
|
|
52
55
|
* Define a mutation in this Convex app's public API.
|
|
@@ -56,7 +59,7 @@ export declare const internalQuery: QueryBuilder<DataModel, "internal">;
|
|
|
56
59
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
57
60
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
58
61
|
*/
|
|
59
|
-
export
|
|
62
|
+
export const mutation: MutationBuilder<DataModel, "public"> = mutationGeneric;
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
|
@@ -66,7 +69,8 @@ export declare const mutation: MutationBuilder<DataModel, "public">;
|
|
|
66
69
|
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
|
67
70
|
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
|
68
71
|
*/
|
|
69
|
-
export
|
|
72
|
+
export const internalMutation: MutationBuilder<DataModel, "internal"> =
|
|
73
|
+
internalMutationGeneric;
|
|
70
74
|
|
|
71
75
|
/**
|
|
72
76
|
* Define an action in this Convex app's public API.
|
|
@@ -79,7 +83,7 @@ export declare const internalMutation: MutationBuilder<DataModel, "internal">;
|
|
|
79
83
|
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
|
80
84
|
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
|
81
85
|
*/
|
|
82
|
-
export
|
|
86
|
+
export const action: ActionBuilder<DataModel, "public"> = actionGeneric;
|
|
83
87
|
|
|
84
88
|
/**
|
|
85
89
|
* Define an action that is only accessible from other Convex functions (but not from the client).
|
|
@@ -87,19 +91,26 @@ export declare const action: ActionBuilder<DataModel, "public">;
|
|
|
87
91
|
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
|
88
92
|
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
|
89
93
|
*/
|
|
90
|
-
export
|
|
94
|
+
export const internalAction: ActionBuilder<DataModel, "internal"> =
|
|
95
|
+
internalActionGeneric;
|
|
91
96
|
|
|
92
97
|
/**
|
|
93
98
|
* Define an HTTP action.
|
|
94
99
|
*
|
|
95
|
-
*
|
|
96
|
-
* deployment if the requests matches the path and method where
|
|
97
|
-
* is routed. Be sure to route your
|
|
100
|
+
* The wrapped function will be used to respond to HTTP requests received
|
|
101
|
+
* by a Convex deployment if the requests matches the path and method where
|
|
102
|
+
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
|
98
103
|
*
|
|
99
|
-
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
|
104
|
+
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
|
105
|
+
* and a Fetch API `Request` object as its second.
|
|
100
106
|
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
|
101
107
|
*/
|
|
102
|
-
export
|
|
108
|
+
export const httpAction: HttpActionBuilder = httpActionGeneric;
|
|
109
|
+
|
|
110
|
+
type GenericCtx =
|
|
111
|
+
| GenericActionCtx<DataModel>
|
|
112
|
+
| GenericMutationCtx<DataModel>
|
|
113
|
+
| GenericQueryCtx<DataModel>;
|
|
103
114
|
|
|
104
115
|
/**
|
|
105
116
|
* A set of services for use within Convex query functions.
|
|
@@ -107,8 +118,7 @@ export declare const httpAction: HttpActionBuilder;
|
|
|
107
118
|
* The query context is passed as the first argument to any Convex query
|
|
108
119
|
* function run on the server.
|
|
109
120
|
*
|
|
110
|
-
*
|
|
111
|
-
* read-only.
|
|
121
|
+
* If you're using code generation, use the `QueryCtx` type in `convex/_generated/server.d.ts` instead.
|
|
112
122
|
*/
|
|
113
123
|
export type QueryCtx = GenericQueryCtx<DataModel>;
|
|
114
124
|
|
|
@@ -117,6 +127,8 @@ export type QueryCtx = GenericQueryCtx<DataModel>;
|
|
|
117
127
|
*
|
|
118
128
|
* The mutation context is passed as the first argument to any Convex mutation
|
|
119
129
|
* function run on the server.
|
|
130
|
+
*
|
|
131
|
+
* If you're using code generation, use the `MutationCtx` type in `convex/_generated/server.d.ts` instead.
|
|
120
132
|
*/
|
|
121
133
|
export type MutationCtx = GenericMutationCtx<DataModel>;
|
|
122
134
|
|
package/src/component/files.ts
CHANGED
|
@@ -9,7 +9,9 @@ const addFileArgs = v.object({
|
|
|
9
9
|
storageId: v.string(),
|
|
10
10
|
hash: v.string(),
|
|
11
11
|
filename: v.optional(v.string()),
|
|
12
|
-
|
|
12
|
+
mediaType: v.optional(v.string()),
|
|
13
|
+
/** @deprecated Use `mediaType` instead. */
|
|
14
|
+
mimeType: v.optional(v.string()),
|
|
13
15
|
});
|
|
14
16
|
|
|
15
17
|
export const addFile = mutation({
|
|
@@ -25,6 +27,9 @@ export async function addFileHandler(
|
|
|
25
27
|
ctx: MutationCtx,
|
|
26
28
|
args: Infer<typeof addFileArgs>,
|
|
27
29
|
) {
|
|
30
|
+
// Support both mediaType (preferred) and mimeType (deprecated)
|
|
31
|
+
const mediaType = args.mediaType ?? args.mimeType;
|
|
32
|
+
|
|
28
33
|
const existingFile = await ctx.db
|
|
29
34
|
.query("files")
|
|
30
35
|
.withIndex("hash", (q) => q.eq("hash", args.hash))
|
|
@@ -42,7 +47,11 @@ export async function addFileHandler(
|
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
const fileId = await ctx.db.insert("files", {
|
|
45
|
-
|
|
50
|
+
storageId: args.storageId,
|
|
51
|
+
hash: args.hash,
|
|
52
|
+
filename: args.filename,
|
|
53
|
+
mediaType,
|
|
54
|
+
mimeType: args.mimeType, // Keep for backwards compatibility
|
|
46
55
|
// We start out with it unused - when it's saved in a message we increment.
|
|
47
56
|
refcount: 0,
|
|
48
57
|
lastTouchedAt: Date.now(),
|
|
@@ -6,11 +6,11 @@ import { api } from "./_generated/api.js";
|
|
|
6
6
|
import type { Id } from "./_generated/dataModel.js";
|
|
7
7
|
import { getMaxMessage } from "./messages.js";
|
|
8
8
|
import schema from "./schema.js";
|
|
9
|
-
import { modules } from "./setup.test.js";
|
|
9
|
+
import { initConvexTest, modules } from "./setup.test.js";
|
|
10
10
|
|
|
11
11
|
describe("agent", () => {
|
|
12
12
|
test("getMaxMessage works for threads", async () => {
|
|
13
|
-
const t =
|
|
13
|
+
const t = initConvexTest();
|
|
14
14
|
const thread = await t.mutation(api.threads.createThread, {
|
|
15
15
|
userId: "test",
|
|
16
16
|
});
|
|
@@ -30,6 +30,29 @@ describe("agent", () => {
|
|
|
30
30
|
stepOrder: 1,
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
|
+
test("getMaxMessage works for a specific order", async () => {
|
|
34
|
+
const t = convexTest(schema, modules);
|
|
35
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
36
|
+
userId: "test",
|
|
37
|
+
});
|
|
38
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
39
|
+
threadId: thread._id as Id<"threads">,
|
|
40
|
+
messages: [
|
|
41
|
+
{ message: { role: "user", content: "hello" } },
|
|
42
|
+
{ message: { role: "assistant", content: "step 1" } },
|
|
43
|
+
{ message: { role: "user", content: "hello2" } },
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
const maxMessage = await t.run(async (ctx) => {
|
|
47
|
+
return await getMaxMessage(ctx, thread._id as Id<"threads">, 0);
|
|
48
|
+
});
|
|
49
|
+
expect(maxMessage).toMatchObject({
|
|
50
|
+
_id: messages.at(1)!._id,
|
|
51
|
+
order: 0,
|
|
52
|
+
stepOrder: 1,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
33
56
|
test("getMaxMessages works when there are tools involved", async () => {
|
|
34
57
|
const t = convexTest(schema, modules);
|
|
35
58
|
const thread = await t.mutation(api.threads.createThread, {
|
|
@@ -45,7 +68,7 @@ describe("agent", () => {
|
|
|
45
68
|
content: [
|
|
46
69
|
{
|
|
47
70
|
type: "tool-call",
|
|
48
|
-
|
|
71
|
+
input: { a: 1 },
|
|
49
72
|
toolCallId: "1",
|
|
50
73
|
toolName: "tool",
|
|
51
74
|
},
|
|
@@ -78,7 +101,7 @@ describe("agent", () => {
|
|
|
78
101
|
});
|
|
79
102
|
});
|
|
80
103
|
|
|
81
|
-
test("ordering is incremented on subsequent calls to addMessages", async () => {
|
|
104
|
+
test("ordering is incremented on subsequent calls to addMessages for user messages", async () => {
|
|
82
105
|
const t = convexTest(schema, modules);
|
|
83
106
|
const thread = await t.mutation(api.threads.createThread, {
|
|
84
107
|
userId: "test",
|
|
@@ -109,7 +132,38 @@ describe("agent", () => {
|
|
|
109
132
|
});
|
|
110
133
|
});
|
|
111
134
|
|
|
112
|
-
test("
|
|
135
|
+
test("ordering is incremented on subsequent calls to addMessages for assistant messages", async () => {
|
|
136
|
+
const t = convexTest(schema, modules);
|
|
137
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
138
|
+
userId: "test",
|
|
139
|
+
});
|
|
140
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
141
|
+
threadId: thread._id as Id<"threads">,
|
|
142
|
+
messages: [{ message: { role: "user", content: "hello" } }],
|
|
143
|
+
});
|
|
144
|
+
const maxMessage = await t.run(async (ctx) => {
|
|
145
|
+
return await getMaxMessage(ctx, thread._id as Id<"threads">);
|
|
146
|
+
});
|
|
147
|
+
expect(maxMessage).toMatchObject({
|
|
148
|
+
_id: messages.at(-1)!._id,
|
|
149
|
+
order: 0,
|
|
150
|
+
stepOrder: 0,
|
|
151
|
+
});
|
|
152
|
+
const { messages: messages2 } = await t.mutation(api.messages.addMessages, {
|
|
153
|
+
threadId: thread._id as Id<"threads">,
|
|
154
|
+
messages: [{ message: { role: "assistant", content: "hello" } }],
|
|
155
|
+
});
|
|
156
|
+
const maxMessage2 = await t.run(async (ctx) => {
|
|
157
|
+
return await getMaxMessage(ctx, thread._id as Id<"threads">);
|
|
158
|
+
});
|
|
159
|
+
expect(maxMessage2).toMatchObject({
|
|
160
|
+
_id: messages2.at(-1)!._id,
|
|
161
|
+
order: 0,
|
|
162
|
+
stepOrder: 1,
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("order is incremented for user messages on to addMessages for the same promptMessageId", async () => {
|
|
113
167
|
const t = convexTest(schema, modules);
|
|
114
168
|
const thread = await t.mutation(api.threads.createThread, {
|
|
115
169
|
userId: "test",
|
|
@@ -135,6 +189,39 @@ describe("agent", () => {
|
|
|
135
189
|
const maxMessage2 = await t.run(async (ctx) => {
|
|
136
190
|
return await getMaxMessage(ctx, thread._id as Id<"threads">);
|
|
137
191
|
});
|
|
192
|
+
expect(maxMessage2).toMatchObject({
|
|
193
|
+
_id: messages2.at(-1)!._id,
|
|
194
|
+
order: 1,
|
|
195
|
+
stepOrder: 0,
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("sub order is incremented on subsequent calls to addMessages for the same promptMessageId", async () => {
|
|
200
|
+
const t = convexTest(schema, modules);
|
|
201
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
202
|
+
userId: "test",
|
|
203
|
+
});
|
|
204
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
205
|
+
threadId: thread._id as Id<"threads">,
|
|
206
|
+
messages: [{ message: { role: "user", content: "hello" } }],
|
|
207
|
+
});
|
|
208
|
+
const maxMessage = await t.run(async (ctx) => {
|
|
209
|
+
return await getMaxMessage(ctx, thread._id as Id<"threads">);
|
|
210
|
+
});
|
|
211
|
+
expect(maxMessage).toMatchObject({
|
|
212
|
+
_id: messages.at(-1)!._id,
|
|
213
|
+
order: 0,
|
|
214
|
+
stepOrder: 0,
|
|
215
|
+
});
|
|
216
|
+
const { messages: messages2 } = await t.mutation(api.messages.addMessages, {
|
|
217
|
+
threadId: thread._id as Id<"threads">,
|
|
218
|
+
messages: [{ message: { role: "assistant", content: "hello" } }],
|
|
219
|
+
agentName: "test",
|
|
220
|
+
promptMessageId: messages.at(-1)!._id as Id<"messages">,
|
|
221
|
+
});
|
|
222
|
+
const maxMessage2 = await t.run(async (ctx) => {
|
|
223
|
+
return await getMaxMessage(ctx, thread._id as Id<"threads">);
|
|
224
|
+
});
|
|
138
225
|
expect(maxMessage2).toMatchObject({
|
|
139
226
|
_id: messages2.at(-1)!._id,
|
|
140
227
|
order: 0,
|
|
@@ -142,6 +229,83 @@ describe("agent", () => {
|
|
|
142
229
|
});
|
|
143
230
|
});
|
|
144
231
|
|
|
232
|
+
test("adding multiple messages at a promptMessageId skips later messages", async () => {
|
|
233
|
+
const t = convexTest(schema, modules);
|
|
234
|
+
const thread = await t.mutation(api.threads.createThread, {
|
|
235
|
+
userId: "test",
|
|
236
|
+
});
|
|
237
|
+
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
238
|
+
threadId: thread._id as Id<"threads">,
|
|
239
|
+
messages: [{ message: { role: "user", content: "hello" } }],
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const { messages: messages2 } = await t.mutation(api.messages.addMessages, {
|
|
243
|
+
threadId: thread._id as Id<"threads">,
|
|
244
|
+
messages: [
|
|
245
|
+
{ message: { role: "user", content: "hello2" } },
|
|
246
|
+
{ message: { role: "assistant", content: "hello" } },
|
|
247
|
+
],
|
|
248
|
+
agentName: "test",
|
|
249
|
+
});
|
|
250
|
+
expect(messages2.length).toBe(2);
|
|
251
|
+
|
|
252
|
+
const { messages: messages3 } = await t.mutation(api.messages.addMessages, {
|
|
253
|
+
threadId: thread._id as Id<"threads">,
|
|
254
|
+
messages: [
|
|
255
|
+
{
|
|
256
|
+
message: {
|
|
257
|
+
role: "assistant",
|
|
258
|
+
content: [
|
|
259
|
+
{
|
|
260
|
+
type: "tool-call",
|
|
261
|
+
input: { a: 1 },
|
|
262
|
+
toolCallId: "1",
|
|
263
|
+
toolName: "tool",
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
message: {
|
|
270
|
+
role: "tool",
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: "tool-result",
|
|
274
|
+
toolName: "tool",
|
|
275
|
+
result: "foo",
|
|
276
|
+
toolCallId: "1",
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
{ message: { role: "user", content: "bye" } },
|
|
282
|
+
],
|
|
283
|
+
agentName: "test",
|
|
284
|
+
promptMessageId: messages.at(-1)!._id as Id<"messages">,
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
expect(messages3.length).toBe(3);
|
|
288
|
+
|
|
289
|
+
const allMessages = await t.query(api.messages.listMessagesByThreadId, {
|
|
290
|
+
threadId: thread._id as Id<"threads">,
|
|
291
|
+
order: "asc",
|
|
292
|
+
});
|
|
293
|
+
expect(allMessages.page).toHaveLength(6);
|
|
294
|
+
expect(allMessages.page.map((m) => m.order)).toEqual([0, 0, 0, 1, 1, 2]);
|
|
295
|
+
expect(allMessages.page.map((m) => m.stepOrder)).toEqual([
|
|
296
|
+
0, 1, 2, 0, 1, 0,
|
|
297
|
+
]);
|
|
298
|
+
expect(allMessages.page[0]!.message!.role).toBe("user");
|
|
299
|
+
expect(allMessages.page[0]!.message!.content).toBe("hello");
|
|
300
|
+
expect(allMessages.page[1]!.message!.role).toBe("assistant");
|
|
301
|
+
expect(allMessages.page[2]!.message!.role).toBe("tool");
|
|
302
|
+
expect(allMessages.page[3]!.message!.role).toBe("user");
|
|
303
|
+
expect(allMessages.page[3]!.message!.content).toBe("hello2");
|
|
304
|
+
expect(allMessages.page[4]!.message!.role).toBe("assistant");
|
|
305
|
+
expect(allMessages.page[5]!.message!.role).toBe("user");
|
|
306
|
+
expect(allMessages.page[5]!.message!.content).toBe("bye");
|
|
307
|
+
});
|
|
308
|
+
|
|
145
309
|
test("updateMessage updates message content", async () => {
|
|
146
310
|
const t = convexTest(schema, modules);
|
|
147
311
|
const thread = await t.mutation(api.threads.createThread, {
|
|
@@ -155,9 +319,7 @@ describe("agent", () => {
|
|
|
155
319
|
|
|
156
320
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
157
321
|
messageId,
|
|
158
|
-
patch: {
|
|
159
|
-
message: { role: "user", content: "updated content" },
|
|
160
|
-
},
|
|
322
|
+
patch: { message: { role: "user", content: "updated content" } },
|
|
161
323
|
});
|
|
162
324
|
|
|
163
325
|
expect(updatedMessage.message).toEqual({
|
|
@@ -173,8 +335,9 @@ describe("agent", () => {
|
|
|
173
335
|
});
|
|
174
336
|
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
175
337
|
threadId: thread._id as Id<"threads">,
|
|
176
|
-
messages: [
|
|
177
|
-
|
|
338
|
+
messages: [
|
|
339
|
+
{ message: { role: "assistant", content: "hello" }, status: "pending" },
|
|
340
|
+
],
|
|
178
341
|
});
|
|
179
342
|
const messageId = messages[0]._id as Id<"messages">;
|
|
180
343
|
|
|
@@ -184,9 +347,7 @@ describe("agent", () => {
|
|
|
184
347
|
// Update to success
|
|
185
348
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
186
349
|
messageId,
|
|
187
|
-
patch: {
|
|
188
|
-
status: "success",
|
|
189
|
-
},
|
|
350
|
+
patch: { status: "success" },
|
|
190
351
|
});
|
|
191
352
|
|
|
192
353
|
expect(updatedMessage.status).toBe("success");
|
|
@@ -199,17 +360,15 @@ describe("agent", () => {
|
|
|
199
360
|
});
|
|
200
361
|
const { messages } = await t.mutation(api.messages.addMessages, {
|
|
201
362
|
threadId: thread._id as Id<"threads">,
|
|
202
|
-
messages: [
|
|
203
|
-
|
|
363
|
+
messages: [
|
|
364
|
+
{ message: { role: "assistant", content: "hello" }, status: "pending" },
|
|
365
|
+
],
|
|
204
366
|
});
|
|
205
367
|
const messageId = messages[0]._id as Id<"messages">;
|
|
206
368
|
|
|
207
369
|
const updatedMessage = await t.mutation(api.messages.updateMessage, {
|
|
208
370
|
messageId,
|
|
209
|
-
patch: {
|
|
210
|
-
status: "failed",
|
|
211
|
-
error: "Something went wrong",
|
|
212
|
-
},
|
|
371
|
+
patch: { status: "failed", error: "Something went wrong" },
|
|
213
372
|
});
|
|
214
373
|
|
|
215
374
|
expect(updatedMessage.status).toBe("failed");
|
|
@@ -230,7 +389,7 @@ describe("agent", () => {
|
|
|
230
389
|
content: [
|
|
231
390
|
{
|
|
232
391
|
type: "tool-call",
|
|
233
|
-
|
|
392
|
+
input: { a: 1 },
|
|
234
393
|
toolCallId: "1",
|
|
235
394
|
toolName: "tool",
|
|
236
395
|
},
|
|
@@ -249,7 +408,7 @@ describe("agent", () => {
|
|
|
249
408
|
content: [
|
|
250
409
|
{
|
|
251
410
|
type: "tool-call",
|
|
252
|
-
|
|
411
|
+
input: { a: 2, b: 3 },
|
|
253
412
|
toolCallId: "1",
|
|
254
413
|
toolName: "tool",
|
|
255
414
|
},
|
|
@@ -263,7 +422,7 @@ describe("agent", () => {
|
|
|
263
422
|
content: [
|
|
264
423
|
{
|
|
265
424
|
type: "tool-call",
|
|
266
|
-
|
|
425
|
+
input: { a: 2, b: 3 },
|
|
267
426
|
toolCallId: "1",
|
|
268
427
|
toolName: "tool",
|
|
269
428
|
},
|
|
@@ -277,9 +436,7 @@ describe("agent", () => {
|
|
|
277
436
|
await expect(
|
|
278
437
|
t.mutation(api.messages.updateMessage, {
|
|
279
438
|
messageId: "invalidId" as Id<"messages">,
|
|
280
|
-
patch: {
|
|
281
|
-
message: { role: "user", content: "test" },
|
|
282
|
-
},
|
|
439
|
+
patch: { message: { role: "user", content: "test" } },
|
|
283
440
|
}),
|
|
284
441
|
).rejects.toThrow();
|
|
285
442
|
});
|
|
@@ -308,10 +465,7 @@ describe("agent", () => {
|
|
|
308
465
|
// Verify messages are actually deleted
|
|
309
466
|
const remainingMessages = await t.query(
|
|
310
467
|
api.messages.listMessagesByThreadId,
|
|
311
|
-
{
|
|
312
|
-
threadId: thread._id as Id<"threads">,
|
|
313
|
-
order: "asc",
|
|
314
|
-
},
|
|
468
|
+
{ threadId: thread._id as Id<"threads">, order: "asc" },
|
|
315
469
|
);
|
|
316
470
|
expect(remainingMessages.page).toHaveLength(1);
|
|
317
471
|
expect(remainingMessages.page[0]._id).toBe(messageIds[1]);
|
|
@@ -343,10 +497,7 @@ describe("agent", () => {
|
|
|
343
497
|
// Verify the valid message was deleted
|
|
344
498
|
const remainingMessages = await t.query(
|
|
345
499
|
api.messages.listMessagesByThreadId,
|
|
346
|
-
{
|
|
347
|
-
threadId: thread._id as Id<"threads">,
|
|
348
|
-
order: "asc",
|
|
349
|
-
},
|
|
500
|
+
{ threadId: thread._id as Id<"threads">, order: "asc" },
|
|
350
501
|
);
|
|
351
502
|
expect(remainingMessages.page).toHaveLength(0);
|
|
352
503
|
});
|
|
@@ -385,24 +536,23 @@ describe("agent", () => {
|
|
|
385
536
|
const result = await t.mutation(api.messages.deleteByOrder, {
|
|
386
537
|
threadId: thread._id as Id<"threads">,
|
|
387
538
|
startOrder: 0,
|
|
388
|
-
endOrder:
|
|
539
|
+
endOrder: 2,
|
|
389
540
|
});
|
|
390
541
|
|
|
391
542
|
expect(result.isDone).toBe(true);
|
|
392
|
-
expect(result.lastOrder).toBe(
|
|
543
|
+
expect(result.lastOrder).toBe(1);
|
|
393
544
|
expect(result.lastStepOrder).toBe(1);
|
|
394
545
|
|
|
395
|
-
// Verify only messages from order 0 were deleted
|
|
546
|
+
// Verify only messages from order 0 & 1 were deleted
|
|
396
547
|
const remainingMessages = await t.query(
|
|
397
548
|
api.messages.listMessagesByThreadId,
|
|
398
|
-
{
|
|
399
|
-
threadId: thread._id as Id<"threads">,
|
|
400
|
-
order: "asc",
|
|
401
|
-
},
|
|
549
|
+
{ threadId: thread._id as Id<"threads">, order: "asc" },
|
|
402
550
|
);
|
|
403
551
|
|
|
404
|
-
expect(remainingMessages.page).toHaveLength(
|
|
405
|
-
expect(remainingMessages.page.
|
|
552
|
+
expect(remainingMessages.page).toHaveLength(1); // Should have messages from order 2
|
|
553
|
+
expect(remainingMessages.page[0].message!.content).toBe(
|
|
554
|
+
"message order 2, step 0",
|
|
555
|
+
);
|
|
406
556
|
});
|
|
407
557
|
|
|
408
558
|
test("deleteByOrder handles step order boundaries correctly", async () => {
|
|
@@ -417,7 +567,7 @@ describe("agent", () => {
|
|
|
417
567
|
messages: [
|
|
418
568
|
{ message: { role: "user", content: "step 0" } },
|
|
419
569
|
{ message: { role: "assistant", content: "step 1" } },
|
|
420
|
-
{ message: { role: "
|
|
570
|
+
{ message: { role: "assistant", content: "step 2" } },
|
|
421
571
|
{ message: { role: "assistant", content: "step 3" } },
|
|
422
572
|
],
|
|
423
573
|
});
|
|
@@ -438,10 +588,7 @@ describe("agent", () => {
|
|
|
438
588
|
// Verify only step 1 and 2 were deleted (step 3 is excluded by upperBoundInclusive: false)
|
|
439
589
|
const remainingMessages = await t.query(
|
|
440
590
|
api.messages.listMessagesByThreadId,
|
|
441
|
-
{
|
|
442
|
-
threadId: thread._id as Id<"threads">,
|
|
443
|
-
order: "asc",
|
|
444
|
-
},
|
|
591
|
+
{ threadId: thread._id as Id<"threads">, order: "asc" },
|
|
445
592
|
);
|
|
446
593
|
|
|
447
594
|
expect(remainingMessages.page).toHaveLength(2);
|
|
@@ -501,10 +648,7 @@ describe("agent", () => {
|
|
|
501
648
|
// Verify original message is still there
|
|
502
649
|
const remainingMessages = await t.query(
|
|
503
650
|
api.messages.listMessagesByThreadId,
|
|
504
|
-
{
|
|
505
|
-
threadId: thread._id as Id<"threads">,
|
|
506
|
-
order: "asc",
|
|
507
|
-
},
|
|
651
|
+
{ threadId: thread._id as Id<"threads">, order: "asc" },
|
|
508
652
|
);
|
|
509
653
|
expect(remainingMessages.page).toHaveLength(1);
|
|
510
654
|
});
|