@convex-dev/agent 0.5.0-alpha.1 → 0.6.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +129 -27
- package/dist/client/createTool.d.ts.map +1 -1
- package/dist/client/createTool.js +66 -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 +1323 -192
- 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 +1056 -965
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +242 -748
- 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 +175 -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 +346 -35
- 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 +171 -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 +93 -0
- package/dist/client/streamText.js.map +1 -0
- package/dist/client/streaming.d.ts +3705 -32
- package/dist/client/streaming.d.ts.map +1 -1
- package/dist/client/streaming.js +141 -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 +265 -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 +3119 -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 +2553 -342
- package/dist/component/messages.d.ts.map +1 -1
- package/dist/component/messages.js +387 -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 +35 -335
- 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 +16 -16
- package/dist/component/users.d.ts +4 -4
- 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 +447 -0
- package/dist/deltas.js.map +1 -0
- package/dist/mapping.d.ts +20 -20
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +313 -96
- 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 +101 -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 +98 -50
- package/src/UIMessages.combineUIMessages.test.ts +239 -0
- package/src/UIMessages.test.ts +273 -0
- package/src/UIMessages.ts +739 -0
- package/src/client/createTool.ts +293 -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 +520 -1290
- package/src/client/messages.ts +237 -0
- package/src/client/mockModel.ts +245 -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 +577 -70
- package/src/client/start.ts +310 -0
- package/src/client/streamText.ts +163 -0
- package/src/client/streaming.test.ts +186 -0
- package/src/client/streaming.ts +219 -97
- package/src/client/threads.ts +83 -0
- package/src/client/types.ts +368 -219
- package/src/client/utils.ts +27 -0
- package/src/component/_generated/api.ts +64 -0
- package/src/component/_generated/component.ts +4913 -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 +490 -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 +570 -0
- package/src/fromUIMessages.test.ts +497 -0
- package/src/mapping.test.ts +103 -6
- package/src/mapping.ts +422 -161
- 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 +154 -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
package/src/component/schema.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineSchema, defineTable } from "convex/server";
|
|
2
|
-
import {
|
|
2
|
+
import { v } from "convex/values";
|
|
3
3
|
import {
|
|
4
4
|
vThreadStatus,
|
|
5
5
|
vMessage,
|
|
@@ -11,11 +11,9 @@ import {
|
|
|
11
11
|
vProviderOptions,
|
|
12
12
|
vProviderMetadata,
|
|
13
13
|
vReasoningDetails,
|
|
14
|
-
vTextStreamPart,
|
|
15
14
|
} from "../validators.js";
|
|
16
15
|
import { typedV } from "convex-helpers/validators";
|
|
17
16
|
import vectorTables, { vVectorId } from "./vector/tables.js";
|
|
18
|
-
import { omit } from "convex-helpers";
|
|
19
17
|
|
|
20
18
|
export const schema = defineSchema({
|
|
21
19
|
threads: defineTable({
|
|
@@ -29,12 +27,8 @@ export const schema = defineSchema({
|
|
|
29
27
|
order: /*DEPRECATED*/ v.optional(v.number()),
|
|
30
28
|
})
|
|
31
29
|
.index("userId", ["userId"])
|
|
32
|
-
.searchIndex("title", {
|
|
33
|
-
searchField: "title",
|
|
34
|
-
filterFields: ["userId"],
|
|
35
|
-
}),
|
|
30
|
+
.searchIndex("title", { searchField: "title", filterFields: ["userId"] }),
|
|
36
31
|
messages: defineTable({
|
|
37
|
-
id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
|
|
38
32
|
userId: v.optional(v.string()), // useful for searching across threads
|
|
39
33
|
threadId: v.id("threads"),
|
|
40
34
|
order: v.number(),
|
|
@@ -60,11 +54,13 @@ export const schema = defineSchema({
|
|
|
60
54
|
usage: v.optional(vUsage),
|
|
61
55
|
providerMetadata: v.optional(vProviderMetadata), // Received from model
|
|
62
56
|
sources: v.optional(v.array(vSource)),
|
|
63
|
-
reasoning: v.optional(v.string()),
|
|
64
|
-
reasoningDetails: v.optional(vReasoningDetails),
|
|
65
57
|
warnings: v.optional(v.array(vLanguageModelCallWarning)),
|
|
66
58
|
finishReason: v.optional(vFinishReason),
|
|
59
|
+
// Likely deprecated soon
|
|
60
|
+
reasoning: v.optional(v.string()),
|
|
61
|
+
reasoningDetails: v.optional(vReasoningDetails),
|
|
67
62
|
// DEPRECATED
|
|
63
|
+
id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
|
|
68
64
|
parentMessageId: v.optional(v.id("messages")),
|
|
69
65
|
stepId: v.optional(v.string()),
|
|
70
66
|
files: v.optional(v.array(v.any())),
|
|
@@ -95,6 +91,12 @@ export const schema = defineSchema({
|
|
|
95
91
|
model: v.optional(v.string()),
|
|
96
92
|
provider: v.optional(v.string()),
|
|
97
93
|
providerOptions: v.optional(vProviderOptions), // Sent to model
|
|
94
|
+
// The data format for the deltas. By default, we use UIMessageChunks.
|
|
95
|
+
// This format dictates how the messages are materialized for capturing
|
|
96
|
+
// partial messages during failure, as well as on the client side.
|
|
97
|
+
format: v.optional(
|
|
98
|
+
v.union(v.literal("UIMessageChunk"), v.literal("TextStreamPart")),
|
|
99
|
+
),
|
|
98
100
|
|
|
99
101
|
threadId: v.id("threads"),
|
|
100
102
|
order: v.number(),
|
|
@@ -115,10 +117,7 @@ export const schema = defineSchema({
|
|
|
115
117
|
endedAt: v.number(),
|
|
116
118
|
cleanupFnId: v.optional(v.id("_scheduled_functions")),
|
|
117
119
|
}),
|
|
118
|
-
v.object({
|
|
119
|
-
kind: v.literal("aborted"),
|
|
120
|
-
reason: v.string(),
|
|
121
|
-
}),
|
|
120
|
+
v.object({ kind: v.literal("aborted"), reason: v.string() }),
|
|
122
121
|
),
|
|
123
122
|
})
|
|
124
123
|
// There should only be one per "order" index
|
|
@@ -135,7 +134,7 @@ export const schema = defineSchema({
|
|
|
135
134
|
// the indexes work like: 0 <first> 1 <second> 2 <third> 3 ...
|
|
136
135
|
start: v.number(), // inclusive
|
|
137
136
|
end: v.number(), // exclusive
|
|
138
|
-
parts: v.array(
|
|
137
|
+
parts: v.array(v.any()),
|
|
139
138
|
}).index("streamId_start_end", ["streamId", "start", "end"]),
|
|
140
139
|
|
|
141
140
|
memories: defineTable({
|
|
@@ -150,7 +149,9 @@ export const schema = defineSchema({
|
|
|
150
149
|
|
|
151
150
|
files: defineTable({
|
|
152
151
|
storageId: v.string(),
|
|
153
|
-
|
|
152
|
+
mediaType: v.optional(v.string()),
|
|
153
|
+
/** @deprecated Use `mediaType` instead. */
|
|
154
|
+
mimeType: v.optional(v.string()),
|
|
154
155
|
filename: v.optional(v.string()),
|
|
155
156
|
hash: v.string(),
|
|
156
157
|
refcount: v.number(),
|
|
@@ -162,39 +163,12 @@ export const schema = defineSchema({
|
|
|
162
163
|
// To authenticate playground usage
|
|
163
164
|
// Delete a key to invalidate it
|
|
164
165
|
// Provide a name to easily identify it / invalidate by name
|
|
165
|
-
apiKeys: defineTable({
|
|
166
|
-
name
|
|
167
|
-
|
|
166
|
+
apiKeys: defineTable({ name: v.optional(v.string()) }).index("name", [
|
|
167
|
+
"name",
|
|
168
|
+
]),
|
|
168
169
|
});
|
|
169
170
|
|
|
170
171
|
export const vv = typedV(schema);
|
|
171
172
|
export { vv as v };
|
|
172
173
|
|
|
173
|
-
// Public
|
|
174
|
-
export const vThreadDoc = v.object({
|
|
175
|
-
_id: v.string(),
|
|
176
|
-
_creationTime: v.number(),
|
|
177
|
-
userId: v.optional(v.string()), // Unset for anonymous
|
|
178
|
-
title: v.optional(v.string()),
|
|
179
|
-
summary: v.optional(v.string()),
|
|
180
|
-
status: vThreadStatus,
|
|
181
|
-
});
|
|
182
|
-
export type ThreadDoc = Infer<typeof vThreadDoc>;
|
|
183
|
-
|
|
184
|
-
export const vMessageDoc = v.object({
|
|
185
|
-
_id: v.string(),
|
|
186
|
-
_creationTime: v.number(),
|
|
187
|
-
...omit(schema.tables.messages.validator.fields, [
|
|
188
|
-
"parentMessageId",
|
|
189
|
-
"stepId",
|
|
190
|
-
"files",
|
|
191
|
-
]),
|
|
192
|
-
// Overwrite all the types that have a v.id validator
|
|
193
|
-
// Outside of the component, they are strings
|
|
194
|
-
threadId: v.string(),
|
|
195
|
-
embeddingId: v.optional(v.string()),
|
|
196
|
-
fileIds: v.optional(v.array(v.string())),
|
|
197
|
-
});
|
|
198
|
-
export type MessageDoc = Infer<typeof vMessageDoc>;
|
|
199
|
-
|
|
200
174
|
export default schema;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/// <reference types="vite/client" />
|
|
2
|
+
import { convexTest } from "convex-test";
|
|
2
3
|
import { test } from "vitest";
|
|
4
|
+
import schema from "./schema.js";
|
|
3
5
|
export const modules = import.meta.glob("./**/*.*s");
|
|
4
6
|
|
|
7
|
+
export function initConvexTest() {
|
|
8
|
+
const t = convexTest(schema, modules);
|
|
9
|
+
return t;
|
|
10
|
+
}
|
|
11
|
+
|
|
5
12
|
test("setup", () => {});
|
package/src/component/streams.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { omit, pick } from "convex-helpers";
|
|
2
2
|
import { v } from "convex/values";
|
|
3
3
|
import {
|
|
4
|
+
type MessageWithMetadataInternal,
|
|
4
5
|
type StreamDelta,
|
|
6
|
+
type StreamMessage,
|
|
5
7
|
vStreamDelta,
|
|
6
8
|
vStreamMessage,
|
|
7
9
|
} from "../validators.js";
|
|
@@ -18,6 +20,9 @@ import schema from "./schema.js";
|
|
|
18
20
|
import { stream } from "convex-helpers/server/stream";
|
|
19
21
|
import { mergedStream } from "convex-helpers/server/stream";
|
|
20
22
|
import { paginator } from "convex-helpers/server/pagination";
|
|
23
|
+
import type { WithoutSystemFields } from "convex/server";
|
|
24
|
+
import { deriveUIMessagesFromDeltas } from "../deltas.js";
|
|
25
|
+
import { fromUIMessages } from "../UIMessages.js";
|
|
21
26
|
|
|
22
27
|
const SECOND = 1000;
|
|
23
28
|
const MINUTE = 60 * SECOND;
|
|
@@ -33,13 +38,16 @@ export const addDelta = mutation({
|
|
|
33
38
|
args: deltaValidator,
|
|
34
39
|
returns: v.boolean(),
|
|
35
40
|
handler: async (ctx, args) => {
|
|
36
|
-
await ctx.db.insert("streamDeltas", args);
|
|
37
|
-
await heartbeatStream(ctx, { streamId: args.streamId });
|
|
38
41
|
const stream = await ctx.db.get(args.streamId);
|
|
39
|
-
if (stream
|
|
40
|
-
console.warn(
|
|
42
|
+
if (!stream) {
|
|
43
|
+
console.warn("Stream not found", args.streamId);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (stream.state.kind !== "streaming") {
|
|
41
47
|
return false;
|
|
42
48
|
}
|
|
49
|
+
await ctx.db.insert("streamDeltas", args);
|
|
50
|
+
await heartbeatStream(ctx, { streamId: args.streamId });
|
|
43
51
|
return true;
|
|
44
52
|
},
|
|
45
53
|
});
|
|
@@ -48,10 +56,7 @@ export const listDeltas = query({
|
|
|
48
56
|
args: {
|
|
49
57
|
threadId: v.id("threads"),
|
|
50
58
|
cursors: v.array(
|
|
51
|
-
v.object({
|
|
52
|
-
streamId: v.id("streamingMessages"),
|
|
53
|
-
cursor: v.number(),
|
|
54
|
-
}),
|
|
59
|
+
v.object({ streamId: v.id("streamingMessages"), cursor: v.number() }),
|
|
55
60
|
),
|
|
56
61
|
},
|
|
57
62
|
returns: v.array(vStreamDelta),
|
|
@@ -85,10 +90,8 @@ export const create = mutation({
|
|
|
85
90
|
args: omit(schema.tables.streamingMessages.validator.fields, ["state"]),
|
|
86
91
|
returns: v.id("streamingMessages"),
|
|
87
92
|
handler: async (ctx, args) => {
|
|
88
|
-
const state = {
|
|
89
|
-
|
|
90
|
-
lastHeartbeat: Date.now(),
|
|
91
|
-
};
|
|
93
|
+
const state = { kind: "streaming" as const, lastHeartbeat: Date.now() };
|
|
94
|
+
// TODO: enforce order/stepOrder uniqueness?
|
|
92
95
|
const streamId = await ctx.db.insert("streamingMessages", {
|
|
93
96
|
...args,
|
|
94
97
|
state,
|
|
@@ -135,28 +138,29 @@ export const list = query({
|
|
|
135
138
|
["order", "stepOrder"],
|
|
136
139
|
).take(100);
|
|
137
140
|
|
|
138
|
-
return messages.map((m) => (
|
|
139
|
-
streamId: m._id,
|
|
140
|
-
status: m.state.kind,
|
|
141
|
-
...pick(m, [
|
|
142
|
-
"order",
|
|
143
|
-
"stepOrder",
|
|
144
|
-
"userId",
|
|
145
|
-
"agentName",
|
|
146
|
-
"model",
|
|
147
|
-
"provider",
|
|
148
|
-
"providerOptions",
|
|
149
|
-
]),
|
|
150
|
-
}));
|
|
141
|
+
return messages.map((m) => publicStreamMessage(m));
|
|
151
142
|
},
|
|
152
143
|
});
|
|
153
144
|
|
|
145
|
+
function publicStreamMessage(m: Doc<"streamingMessages">): StreamMessage {
|
|
146
|
+
return {
|
|
147
|
+
streamId: m._id,
|
|
148
|
+
status: m.state.kind,
|
|
149
|
+
...pick(m, [
|
|
150
|
+
"format",
|
|
151
|
+
"order",
|
|
152
|
+
"stepOrder",
|
|
153
|
+
"userId",
|
|
154
|
+
"agentName",
|
|
155
|
+
"model",
|
|
156
|
+
"provider",
|
|
157
|
+
"providerOptions",
|
|
158
|
+
]),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
154
162
|
export const abortByOrder = mutation({
|
|
155
|
-
args: {
|
|
156
|
-
threadId: v.id("threads"),
|
|
157
|
-
order: v.number(),
|
|
158
|
-
reason: v.string(),
|
|
159
|
-
},
|
|
163
|
+
args: { threadId: v.id("threads"), order: v.number(), reason: v.string() },
|
|
160
164
|
returns: v.boolean(),
|
|
161
165
|
handler: async (ctx, args) => {
|
|
162
166
|
const streams = await ctx.db
|
|
@@ -169,10 +173,7 @@ export const abortByOrder = mutation({
|
|
|
169
173
|
)
|
|
170
174
|
.take(100);
|
|
171
175
|
for (const stream of streams) {
|
|
172
|
-
await abortById(ctx, {
|
|
173
|
-
streamId: stream._id,
|
|
174
|
-
reason: args.reason,
|
|
175
|
-
});
|
|
176
|
+
await abortById(ctx, { streamId: stream._id, reason: args.reason });
|
|
176
177
|
}
|
|
177
178
|
return streams.length > 0;
|
|
178
179
|
},
|
|
@@ -182,6 +183,7 @@ export const abort = mutation({
|
|
|
182
183
|
args: {
|
|
183
184
|
streamId: v.id("streamingMessages"),
|
|
184
185
|
reason: v.string(),
|
|
186
|
+
finalDelta: v.optional(deltaValidator),
|
|
185
187
|
},
|
|
186
188
|
returns: v.boolean(),
|
|
187
189
|
handler: abortById,
|
|
@@ -189,16 +191,20 @@ export const abort = mutation({
|
|
|
189
191
|
|
|
190
192
|
async function abortById(
|
|
191
193
|
ctx: MutationCtx,
|
|
192
|
-
args: {
|
|
194
|
+
args: {
|
|
195
|
+
streamId: Id<"streamingMessages">;
|
|
196
|
+
reason: string;
|
|
197
|
+
finalDelta?: WithoutSystemFields<Doc<"streamDeltas">>;
|
|
198
|
+
},
|
|
193
199
|
) {
|
|
194
200
|
const stream = await ctx.db.get(args.streamId);
|
|
195
201
|
if (!stream) {
|
|
196
202
|
throw new Error(`Stream not found: ${args.streamId}`);
|
|
197
203
|
}
|
|
204
|
+
if (args.finalDelta) {
|
|
205
|
+
await ctx.db.insert("streamDeltas", args.finalDelta);
|
|
206
|
+
}
|
|
198
207
|
if (stream.state.kind !== "streaming") {
|
|
199
|
-
console.warn(
|
|
200
|
-
`Stream trying to abort but not currently streaming (${stream.state.kind}): ${args.streamId}`,
|
|
201
|
-
);
|
|
202
208
|
return false;
|
|
203
209
|
}
|
|
204
210
|
await cleanupTimeoutFn(ctx, stream);
|
|
@@ -220,49 +226,65 @@ async function cleanupTimeoutFn(
|
|
|
220
226
|
}
|
|
221
227
|
}
|
|
222
228
|
|
|
229
|
+
// No longer used from the DeltaStreamer
|
|
223
230
|
export const finish = mutation({
|
|
224
231
|
args: {
|
|
225
232
|
streamId: v.id("streamingMessages"),
|
|
226
233
|
finalDelta: v.optional(deltaValidator),
|
|
227
234
|
},
|
|
228
235
|
returns: v.null(),
|
|
229
|
-
handler:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (stream.state.kind !== "streaming") {
|
|
238
|
-
console.warn(
|
|
239
|
-
`Stream trying to finish but not currently streaming: ${args.streamId}`,
|
|
240
|
-
);
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
await cleanupTimeoutFn(ctx, stream);
|
|
244
|
-
const cleanupFnId = await ctx.scheduler.runAfter(
|
|
245
|
-
DELETE_STREAM_DELAY,
|
|
246
|
-
api.streams.deleteStreamAsync,
|
|
247
|
-
{ streamId: args.streamId },
|
|
248
|
-
);
|
|
249
|
-
await ctx.db.patch(args.streamId, {
|
|
250
|
-
state: { kind: "finished", endedAt: Date.now(), cleanupFnId },
|
|
251
|
-
});
|
|
236
|
+
handler: finishHandler,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
export async function finishHandler(
|
|
240
|
+
ctx: MutationCtx,
|
|
241
|
+
args: {
|
|
242
|
+
streamId: Id<"streamingMessages">;
|
|
243
|
+
finalDelta?: WithoutSystemFields<Doc<"streamDeltas">>;
|
|
252
244
|
},
|
|
245
|
+
) {
|
|
246
|
+
if (args.finalDelta) {
|
|
247
|
+
await ctx.db.insert("streamDeltas", args.finalDelta);
|
|
248
|
+
}
|
|
249
|
+
const stream = await ctx.db.get(args.streamId);
|
|
250
|
+
if (!stream) {
|
|
251
|
+
throw new Error(`Stream not found: ${args.streamId}`);
|
|
252
|
+
}
|
|
253
|
+
if (stream.state.kind !== "streaming") {
|
|
254
|
+
console.warn(
|
|
255
|
+
`Stream trying to finish ${args.streamId} but is ${stream.state.kind}`,
|
|
256
|
+
);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
await cleanupTimeoutFn(ctx, stream);
|
|
260
|
+
const cleanupFnId = await ctx.scheduler.runAfter(
|
|
261
|
+
DELETE_STREAM_DELAY,
|
|
262
|
+
api.streams.deleteStreamAsync,
|
|
263
|
+
{ streamId: args.streamId },
|
|
264
|
+
);
|
|
265
|
+
await ctx.db.patch(args.streamId, {
|
|
266
|
+
state: { kind: "finished", endedAt: Date.now(), cleanupFnId },
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// TODO: use this heartbeat while streaming, every 30 seconds or so,
|
|
271
|
+
// then reduce the timeout to 60 seconds.
|
|
272
|
+
export const heartbeat = mutation({
|
|
273
|
+
args: { streamId: v.id("streamingMessages") },
|
|
274
|
+
returns: v.null(),
|
|
275
|
+
handler: heartbeatStream,
|
|
253
276
|
});
|
|
254
277
|
|
|
255
278
|
async function heartbeatStream(
|
|
256
279
|
ctx: MutationCtx,
|
|
257
280
|
args: { streamId: Id<"streamingMessages"> },
|
|
258
|
-
) {
|
|
281
|
+
): Promise<void> {
|
|
259
282
|
const stream = await ctx.db.get(args.streamId);
|
|
260
283
|
if (!stream) {
|
|
261
284
|
console.warn("Stream not found", args.streamId);
|
|
262
285
|
return;
|
|
263
286
|
}
|
|
264
287
|
if (stream.state.kind !== "streaming") {
|
|
265
|
-
console.warn("Stream is not streaming", args.streamId);
|
|
266
288
|
return;
|
|
267
289
|
}
|
|
268
290
|
if (Date.now() - stream.state.lastHeartbeat < TIMEOUT_INTERVAL / 4) {
|
|
@@ -286,11 +308,7 @@ async function heartbeatStream(
|
|
|
286
308
|
{ streamId: args.streamId },
|
|
287
309
|
);
|
|
288
310
|
await ctx.db.patch(args.streamId, {
|
|
289
|
-
state: {
|
|
290
|
-
kind: "streaming",
|
|
291
|
-
lastHeartbeat: Date.now(),
|
|
292
|
-
timeoutFnId,
|
|
293
|
-
},
|
|
311
|
+
state: { kind: "streaming", lastHeartbeat: Date.now(), timeoutFnId },
|
|
294
312
|
});
|
|
295
313
|
}
|
|
296
314
|
|
|
@@ -304,10 +322,7 @@ export const timeoutStream = internalMutation({
|
|
|
304
322
|
return;
|
|
305
323
|
}
|
|
306
324
|
await ctx.db.patch(args.streamId, {
|
|
307
|
-
state: {
|
|
308
|
-
kind: "aborted",
|
|
309
|
-
reason: "timeout",
|
|
310
|
-
},
|
|
325
|
+
state: { kind: "aborted", reason: "timeout" },
|
|
311
326
|
});
|
|
312
327
|
},
|
|
313
328
|
});
|
|
@@ -362,11 +377,7 @@ export async function deleteStreamsPageForThreadId(
|
|
|
362
377
|
"stepOrder",
|
|
363
378
|
]).first();
|
|
364
379
|
if (!streamMessage) {
|
|
365
|
-
return {
|
|
366
|
-
isDone: true,
|
|
367
|
-
streamOrder: undefined,
|
|
368
|
-
deltaCursor: undefined,
|
|
369
|
-
};
|
|
380
|
+
return { isDone: true, streamOrder: undefined, deltaCursor: undefined };
|
|
370
381
|
}
|
|
371
382
|
const result = await deletePageForStreamId(ctx, {
|
|
372
383
|
streamId: streamMessage._id,
|
|
@@ -375,11 +386,7 @@ export async function deleteStreamsPageForThreadId(
|
|
|
375
386
|
if (result.isDone) {
|
|
376
387
|
deltaCursor = undefined;
|
|
377
388
|
}
|
|
378
|
-
return {
|
|
379
|
-
isDone: false,
|
|
380
|
-
streamOrder: streamMessage.order,
|
|
381
|
-
deltaCursor,
|
|
382
|
-
};
|
|
389
|
+
return { isDone: false, streamOrder: streamMessage.order, deltaCursor };
|
|
383
390
|
}
|
|
384
391
|
|
|
385
392
|
export const deleteStreamsPageForThreadIdMutation = internalMutation({
|
|
@@ -407,7 +414,14 @@ export const deleteAllStreamsForThreadIdAsync = mutation({
|
|
|
407
414
|
streamOrder: v.optional(v.number()),
|
|
408
415
|
deltaCursor: v.optional(v.string()),
|
|
409
416
|
}),
|
|
410
|
-
handler: async (
|
|
417
|
+
handler: async (
|
|
418
|
+
ctx,
|
|
419
|
+
args,
|
|
420
|
+
): Promise<{
|
|
421
|
+
isDone: boolean;
|
|
422
|
+
streamOrder?: number;
|
|
423
|
+
deltaCursor?: string;
|
|
424
|
+
}> => {
|
|
411
425
|
const result = await deleteStreamsPageForThreadId(ctx, args);
|
|
412
426
|
if (!result.isDone) {
|
|
413
427
|
await ctx.scheduler.runAfter(
|
|
@@ -474,3 +488,90 @@ export const deleteAllStreamsForThreadIdSync = action({
|
|
|
474
488
|
}
|
|
475
489
|
},
|
|
476
490
|
});
|
|
491
|
+
|
|
492
|
+
export async function getStreamingMessages(
|
|
493
|
+
ctx: MutationCtx,
|
|
494
|
+
threadId: Id<"threads">,
|
|
495
|
+
order: number,
|
|
496
|
+
stepOrder: number,
|
|
497
|
+
): Promise<Doc<"streamingMessages">[]> {
|
|
498
|
+
return mergedStream(
|
|
499
|
+
(["aborted", "streaming", "finished"] as const).map((state) =>
|
|
500
|
+
stream(ctx.db, schema)
|
|
501
|
+
.query("streamingMessages")
|
|
502
|
+
.withIndex("threadId_state_order_stepOrder", (q) =>
|
|
503
|
+
q
|
|
504
|
+
.eq("threadId", threadId)
|
|
505
|
+
.eq("state.kind", state)
|
|
506
|
+
.eq("order", order)
|
|
507
|
+
.lte("stepOrder", stepOrder),
|
|
508
|
+
)
|
|
509
|
+
.order("desc"),
|
|
510
|
+
),
|
|
511
|
+
["stepOrder"],
|
|
512
|
+
).take(10);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
export async function getStreamingMessagesWithMetadata(
|
|
516
|
+
ctx: MutationCtx,
|
|
517
|
+
{
|
|
518
|
+
threadId,
|
|
519
|
+
order,
|
|
520
|
+
stepOrder,
|
|
521
|
+
}: { threadId: Id<"threads">; order: number; stepOrder: number },
|
|
522
|
+
metadata: { status: "success" | "failed"; error?: string },
|
|
523
|
+
): Promise<MessageWithMetadataInternal[]> {
|
|
524
|
+
// See if there are any streaming messages for this order
|
|
525
|
+
const streamingMessages = await getStreamingMessages(
|
|
526
|
+
ctx,
|
|
527
|
+
threadId,
|
|
528
|
+
order,
|
|
529
|
+
stepOrder,
|
|
530
|
+
);
|
|
531
|
+
const messages = (
|
|
532
|
+
await Promise.all(
|
|
533
|
+
streamingMessages.map(async (streamingMessage) => {
|
|
534
|
+
const deltas = await ctx.db
|
|
535
|
+
.query("streamDeltas")
|
|
536
|
+
.withIndex("streamId_start_end", (q) =>
|
|
537
|
+
q.eq("streamId", streamingMessage._id),
|
|
538
|
+
)
|
|
539
|
+
.take(1000);
|
|
540
|
+
const uiMessages = await deriveUIMessagesFromDeltas(
|
|
541
|
+
threadId,
|
|
542
|
+
[publicStreamMessage(streamingMessage)],
|
|
543
|
+
deltas,
|
|
544
|
+
);
|
|
545
|
+
// We don't save messages that have already been saved
|
|
546
|
+
const numToSkip = stepOrder - streamingMessage.stepOrder;
|
|
547
|
+
const messages = await Promise.all(
|
|
548
|
+
(await fromUIMessages(uiMessages, streamingMessage))
|
|
549
|
+
.slice(numToSkip)
|
|
550
|
+
.filter((m) => m.message !== undefined)
|
|
551
|
+
.map(async (msg) => {
|
|
552
|
+
return {
|
|
553
|
+
...pick(msg, [
|
|
554
|
+
"message",
|
|
555
|
+
"fileIds",
|
|
556
|
+
"status",
|
|
557
|
+
"finishReason",
|
|
558
|
+
"model",
|
|
559
|
+
"provider",
|
|
560
|
+
"providerMetadata",
|
|
561
|
+
"sources",
|
|
562
|
+
"reasoning",
|
|
563
|
+
"reasoningDetails",
|
|
564
|
+
"usage",
|
|
565
|
+
"warnings",
|
|
566
|
+
"error",
|
|
567
|
+
]),
|
|
568
|
+
...metadata,
|
|
569
|
+
} as MessageWithMetadataInternal;
|
|
570
|
+
}),
|
|
571
|
+
);
|
|
572
|
+
return messages;
|
|
573
|
+
}),
|
|
574
|
+
)
|
|
575
|
+
).flat();
|
|
576
|
+
return messages;
|
|
577
|
+
}
|
|
@@ -35,11 +35,9 @@ export const paginate = query({
|
|
|
35
35
|
const tableName = getVectorTableName(args.vectorDimension);
|
|
36
36
|
const vectors = await paginator(ctx.db, schema)
|
|
37
37
|
.query(tableName)
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
38
|
.withIndex("model_table_threadId" as any, (q) =>
|
|
40
39
|
args.table
|
|
41
|
-
?
|
|
42
|
-
(q.eq("model", args.targetModel) as any).eq("table", args.table)
|
|
40
|
+
? (q.eq("model", args.targetModel) as any).eq("table", args.table)
|
|
43
41
|
: q.eq("model", args.targetModel),
|
|
44
42
|
)
|
|
45
43
|
.paginate({
|