@convex-dev/agent 0.1.9-alpha.9 → 0.1.9
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 +1 -0
- package/dist/commonjs/client/index.d.ts +0 -1
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +0 -2
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/client/streaming.d.ts.map +1 -1
- package/dist/commonjs/client/streaming.js +1 -7
- package/dist/commonjs/client/streaming.js.map +1 -1
- package/dist/commonjs/component/_generated/api.d.ts +1 -12
- package/dist/commonjs/component/schema.d.ts +26 -26
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +2 -2
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/streams.d.ts +3 -10
- package/dist/commonjs/component/streams.d.ts.map +1 -1
- package/dist/commonjs/component/streams.js +20 -47
- package/dist/commonjs/component/streams.js.map +1 -1
- package/dist/commonjs/react/deltas.d.ts.map +1 -1
- package/dist/commonjs/react/deltas.js +2 -2
- package/dist/commonjs/react/deltas.js.map +1 -1
- package/dist/commonjs/react/index.d.ts +2 -4
- package/dist/commonjs/react/index.d.ts.map +1 -1
- package/dist/commonjs/react/index.js +8 -21
- package/dist/commonjs/react/index.js.map +1 -1
- package/dist/commonjs/react/optimisticallySendMessage.js +1 -1
- package/dist/commonjs/react/optimisticallySendMessage.js.map +1 -1
- package/dist/commonjs/validators.d.ts +3 -8
- package/dist/commonjs/validators.d.ts.map +1 -1
- package/dist/commonjs/validators.js +0 -2
- package/dist/commonjs/validators.js.map +1 -1
- package/dist/commonjs.tsbuildinfo +1 -1
- package/dist/esm/client/index.d.ts +0 -1
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +0 -2
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/streaming.d.ts.map +1 -1
- package/dist/esm/client/streaming.js +1 -7
- package/dist/esm/client/streaming.js.map +1 -1
- package/dist/esm/component/_generated/api.d.ts +1 -12
- package/dist/esm/component/schema.d.ts +26 -26
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +2 -2
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/streams.d.ts +3 -10
- package/dist/esm/component/streams.d.ts.map +1 -1
- package/dist/esm/component/streams.js +20 -47
- package/dist/esm/component/streams.js.map +1 -1
- package/dist/esm/react/deltas.d.ts.map +1 -1
- package/dist/esm/react/deltas.js +2 -2
- package/dist/esm/react/deltas.js.map +1 -1
- package/dist/esm/react/index.d.ts +2 -4
- package/dist/esm/react/index.d.ts.map +1 -1
- package/dist/esm/react/index.js +8 -21
- package/dist/esm/react/index.js.map +1 -1
- package/dist/esm/react/optimisticallySendMessage.js +1 -1
- package/dist/esm/react/optimisticallySendMessage.js.map +1 -1
- package/dist/esm/validators.d.ts +3 -8
- package/dist/esm/validators.d.ts.map +1 -1
- package/dist/esm/validators.js +0 -2
- package/dist/esm/validators.js.map +1 -1
- package/dist/esm.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +0 -4
- package/src/client/streaming.ts +1 -7
- package/src/component/_generated/api.d.ts +1 -12
- package/src/component/schema.ts +2 -2
- package/src/component/streams.ts +36 -81
- package/src/react/deltas.ts +2 -4
- package/src/react/index.ts +10 -22
- package/src/react/optimisticallySendMessage.ts +1 -1
- package/src/validators.ts +0 -6
package/src/component/streams.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
vStreamMessage,
|
|
7
7
|
} from "../validators.js";
|
|
8
8
|
import { api, internal } from "./_generated/api.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type { Id } from "./_generated/dataModel.js";
|
|
10
10
|
import {
|
|
11
11
|
internalMutation,
|
|
12
12
|
mutation,
|
|
@@ -19,10 +19,13 @@ import { stream } from "convex-helpers/server/stream";
|
|
|
19
19
|
import { mergedStream } from "convex-helpers/server/stream";
|
|
20
20
|
import { paginator } from "convex-helpers/server/pagination";
|
|
21
21
|
|
|
22
|
+
const SECOND = 1000;
|
|
23
|
+
const MINUTE = 60 * SECOND;
|
|
24
|
+
|
|
22
25
|
const MAX_DELTAS_PER_REQUEST = 1000;
|
|
23
26
|
const MAX_DELTAS_PER_STREAM = 100;
|
|
24
|
-
const TIMEOUT_INTERVAL =
|
|
25
|
-
const DELETE_STREAM_DELAY =
|
|
27
|
+
const TIMEOUT_INTERVAL = 10 * MINUTE;
|
|
28
|
+
const DELETE_STREAM_DELAY = MINUTE * 5; // 5 minutes
|
|
26
29
|
|
|
27
30
|
const deltaValidator = schema.tables.streamDeltas.validator;
|
|
28
31
|
|
|
@@ -103,87 +106,33 @@ export const create = mutation({
|
|
|
103
106
|
export const list = query({
|
|
104
107
|
args: {
|
|
105
108
|
threadId: v.id("threads"),
|
|
106
|
-
startOrder: v.optional(v.number()),
|
|
107
|
-
statuses: v.optional(
|
|
108
|
-
v.array(
|
|
109
|
-
v.union(
|
|
110
|
-
v.literal("streaming"),
|
|
111
|
-
v.literal("finished"),
|
|
112
|
-
v.literal("aborted")
|
|
113
|
-
)
|
|
114
|
-
)
|
|
115
|
-
),
|
|
116
109
|
},
|
|
117
110
|
returns: v.array(vStreamMessage),
|
|
118
111
|
handler: async (ctx, args) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"order",
|
|
140
|
-
"stepOrder",
|
|
141
|
-
"userId",
|
|
142
|
-
"agentName",
|
|
143
|
-
"model",
|
|
144
|
-
"provider",
|
|
145
|
-
"providerOptions",
|
|
146
|
-
]),
|
|
147
|
-
}));
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
export const abort = mutation({
|
|
152
|
-
args: {
|
|
153
|
-
streamId: v.id("streamingMessages"),
|
|
154
|
-
reason: v.string(),
|
|
155
|
-
},
|
|
156
|
-
returns: v.null(),
|
|
157
|
-
handler: async (ctx, args) => {
|
|
158
|
-
const stream = await ctx.db.get(args.streamId);
|
|
159
|
-
if (!stream) {
|
|
160
|
-
throw new Error(`Stream not found: ${args.streamId}`);
|
|
161
|
-
}
|
|
162
|
-
if (stream.state.kind !== "streaming") {
|
|
163
|
-
console.warn(
|
|
164
|
-
`Stream trying to abort but not currently streaming (${stream.state.kind}): ${args.streamId}`
|
|
112
|
+
return ctx.db
|
|
113
|
+
.query("streamingMessages")
|
|
114
|
+
.withIndex("threadId_state_order_stepOrder", (q) =>
|
|
115
|
+
q.eq("threadId", args.threadId).eq("state.kind", "streaming")
|
|
116
|
+
)
|
|
117
|
+
.order("desc")
|
|
118
|
+
.take(100)
|
|
119
|
+
.then((msgs) =>
|
|
120
|
+
msgs.map((m) => ({
|
|
121
|
+
streamId: m._id,
|
|
122
|
+
...pick(m, [
|
|
123
|
+
"order",
|
|
124
|
+
"stepOrder",
|
|
125
|
+
"userId",
|
|
126
|
+
"agentName",
|
|
127
|
+
"model",
|
|
128
|
+
"provider",
|
|
129
|
+
"providerOptions",
|
|
130
|
+
]),
|
|
131
|
+
}))
|
|
165
132
|
);
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
await cleanupTimeoutFn(ctx, stream);
|
|
169
|
-
await ctx.db.patch(args.streamId, {
|
|
170
|
-
state: { kind: "aborted", reason: args.reason },
|
|
171
|
-
});
|
|
172
133
|
},
|
|
173
134
|
});
|
|
174
135
|
|
|
175
|
-
async function cleanupTimeoutFn(
|
|
176
|
-
ctx: MutationCtx,
|
|
177
|
-
stream: Doc<"streamingMessages">
|
|
178
|
-
) {
|
|
179
|
-
if (stream.state.kind === "streaming" && stream.state.timeoutFnId) {
|
|
180
|
-
const timeoutFn = await ctx.db.system.get(stream.state.timeoutFnId);
|
|
181
|
-
if (timeoutFn?.state.kind === "pending") {
|
|
182
|
-
await ctx.scheduler.cancel(stream.state.timeoutFnId);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
136
|
export const finish = mutation({
|
|
188
137
|
args: {
|
|
189
138
|
streamId: v.id("streamingMessages"),
|
|
@@ -204,7 +153,12 @@ export const finish = mutation({
|
|
|
204
153
|
);
|
|
205
154
|
return;
|
|
206
155
|
}
|
|
207
|
-
|
|
156
|
+
if (stream.state.timeoutFnId) {
|
|
157
|
+
const timeoutFn = await ctx.db.system.get(stream.state.timeoutFnId);
|
|
158
|
+
if (timeoutFn?.state.kind === "pending") {
|
|
159
|
+
await ctx.scheduler.cancel(stream.state.timeoutFnId);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
208
162
|
await ctx.db.patch(args.streamId, {
|
|
209
163
|
state: { kind: "finished", endedAt: Date.now() },
|
|
210
164
|
});
|
|
@@ -288,6 +242,9 @@ async function deletePageForStreamId(
|
|
|
288
242
|
cursor: args.cursor ?? null,
|
|
289
243
|
});
|
|
290
244
|
await Promise.all(deltas.page.map((d) => ctx.db.delete(d._id)));
|
|
245
|
+
if (deltas.isDone) {
|
|
246
|
+
await ctx.db.delete(args.streamId);
|
|
247
|
+
}
|
|
291
248
|
return deltas;
|
|
292
249
|
}
|
|
293
250
|
|
|
@@ -327,13 +284,12 @@ export async function deleteStreamsPageForThreadId(
|
|
|
327
284
|
cursor: deltaCursor,
|
|
328
285
|
});
|
|
329
286
|
if (result.isDone) {
|
|
330
|
-
await ctx.db.delete(streamMessage._id);
|
|
331
287
|
deltaCursor = undefined;
|
|
332
288
|
}
|
|
333
289
|
return {
|
|
334
290
|
isDone: false,
|
|
335
291
|
streamOrder: streamMessage.order,
|
|
336
|
-
deltaCursor
|
|
292
|
+
deltaCursor,
|
|
337
293
|
};
|
|
338
294
|
}
|
|
339
295
|
|
|
@@ -392,7 +348,6 @@ export const deleteStreamSync = mutation({
|
|
|
392
348
|
cursor: deltas.continueCursor,
|
|
393
349
|
});
|
|
394
350
|
}
|
|
395
|
-
await ctx.db.delete(args.streamId);
|
|
396
351
|
},
|
|
397
352
|
});
|
|
398
353
|
|
package/src/react/deltas.ts
CHANGED
|
@@ -256,14 +256,12 @@ export function createStreamingMessage(
|
|
|
256
256
|
): MessageDoc {
|
|
257
257
|
const { streamId, ...rest } = message;
|
|
258
258
|
const metadata: MessageDoc = {
|
|
259
|
-
...rest,
|
|
260
259
|
_id: `${streamId}-${index}`,
|
|
261
260
|
_creationTime: Date.now(),
|
|
262
|
-
status:
|
|
263
|
-
{ streaming: "pending", finished: "success", aborted: "failed" } as const
|
|
264
|
-
)[message.status],
|
|
261
|
+
status: "pending",
|
|
265
262
|
threadId,
|
|
266
263
|
tool: false,
|
|
264
|
+
...rest,
|
|
267
265
|
};
|
|
268
266
|
switch (part.type) {
|
|
269
267
|
case "text-delta":
|
package/src/react/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import type { ErrorMessage } from "convex-helpers";
|
|
3
3
|
import {
|
|
4
4
|
type PaginatedQueryArgs,
|
|
5
5
|
type UsePaginatedQueryResult,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "convex/react";
|
|
8
8
|
import { usePaginatedQuery } from "convex-helpers/react";
|
|
9
9
|
import type { FunctionArgs } from "convex/server";
|
|
10
|
-
import { useMemo,
|
|
10
|
+
import { useMemo, useState } from "react";
|
|
11
11
|
import type { MessageDoc } from "../client/index.js";
|
|
12
12
|
import type { SyncStreamsReturnValue } from "../client/types.js";
|
|
13
13
|
import type { StreamArgs } from "../validators.js";
|
|
@@ -103,11 +103,7 @@ export function useThreadMessages<
|
|
|
103
103
|
ThreadMessagesArgs<Query>,
|
|
104
104
|
ThreadMessagesResult<Query>
|
|
105
105
|
>,
|
|
106
|
-
!options.stream
|
|
107
|
-
args === "skip" ||
|
|
108
|
-
paginated.status === "LoadingFirstPage"
|
|
109
|
-
? "skip"
|
|
110
|
-
: { ...args, startOrder: paginated.results.at(-1)?.order }
|
|
106
|
+
!options.stream ? "skip" : args
|
|
111
107
|
);
|
|
112
108
|
|
|
113
109
|
const merged = useMemo(() => {
|
|
@@ -154,7 +150,7 @@ export function useStreamingThreadMessages<
|
|
|
154
150
|
Query extends ThreadStreamQuery<any, any>,
|
|
155
151
|
>(
|
|
156
152
|
query: Query,
|
|
157
|
-
args:
|
|
153
|
+
args: ThreadMessagesArgs<Query> | "skip"
|
|
158
154
|
): Array<ThreadMessagesResult<Query>> | undefined {
|
|
159
155
|
// Invariant: streamMessages[streamId] is comprised of all deltas up to the
|
|
160
156
|
// cursor. There can be multiple messages in the same stream, e.g. for tool
|
|
@@ -162,23 +158,15 @@ export function useStreamingThreadMessages<
|
|
|
162
158
|
const [streams, setStreams] = useState<
|
|
163
159
|
Array<{ streamId: string; cursor: number; messages: MessageDoc[] }>
|
|
164
160
|
>([]);
|
|
165
|
-
const startOrderRef = useRef<number>(0);
|
|
166
|
-
const queryArgs = args === "skip" ? args : omit(args, ["startOrder"]);
|
|
167
|
-
if (args !== "skip" && !startOrderRef.current && args.startOrder) {
|
|
168
|
-
startOrderRef.current = args.startOrder;
|
|
169
|
-
}
|
|
170
161
|
// Get all the active streams
|
|
171
162
|
const streamList = useQuery(
|
|
172
163
|
query,
|
|
173
|
-
|
|
174
|
-
?
|
|
164
|
+
args === "skip"
|
|
165
|
+
? args
|
|
175
166
|
: ({
|
|
176
|
-
...
|
|
167
|
+
...args,
|
|
177
168
|
paginationOpts: { cursor: null, numItems: 0 },
|
|
178
|
-
streamArgs: {
|
|
179
|
-
kind: "list",
|
|
180
|
-
startOrder: startOrderRef.current,
|
|
181
|
-
} as StreamArgs,
|
|
169
|
+
streamArgs: { kind: "list" } as StreamArgs,
|
|
182
170
|
} as FunctionArgs<Query>)
|
|
183
171
|
) as
|
|
184
172
|
| { streams: Extract<SyncStreamsReturnValue, { kind: "list" }> }
|
|
@@ -198,10 +186,10 @@ export function useStreamingThreadMessages<
|
|
|
198
186
|
// Get the deltas for all the active streams, if any.
|
|
199
187
|
const cursorQuery = useQuery(
|
|
200
188
|
query,
|
|
201
|
-
|
|
189
|
+
args === "skip" || !streamList
|
|
202
190
|
? ("skip" as const)
|
|
203
191
|
: ({
|
|
204
|
-
...
|
|
192
|
+
...args,
|
|
205
193
|
paginationOpts: { cursor: null, numItems: 0 },
|
|
206
194
|
streamArgs: { kind: "deltas", cursors } as StreamArgs,
|
|
207
195
|
} as FunctionArgs<Query>)
|
|
@@ -11,7 +11,7 @@ export function optimisticallySendMessage(
|
|
|
11
11
|
) => void {
|
|
12
12
|
return (store, args) => {
|
|
13
13
|
const queries = store.getAllQueries(query);
|
|
14
|
-
let maxOrder =
|
|
14
|
+
let maxOrder = 0;
|
|
15
15
|
let maxStepOrder = 0;
|
|
16
16
|
for (const q of queries) {
|
|
17
17
|
if (q.args?.threadId !== args.threadId) continue;
|
package/src/validators.ts
CHANGED
|
@@ -460,7 +460,6 @@ export const vStreamArgs = v.optional(
|
|
|
460
460
|
v.union(
|
|
461
461
|
v.object({
|
|
462
462
|
kind: v.literal("list"),
|
|
463
|
-
startOrder: v.optional(v.number()),
|
|
464
463
|
}),
|
|
465
464
|
v.object({
|
|
466
465
|
kind: v.literal("deltas"),
|
|
@@ -472,11 +471,6 @@ export type StreamArgs = Infer<typeof vStreamArgs>;
|
|
|
472
471
|
|
|
473
472
|
export const vStreamMessage = v.object({
|
|
474
473
|
streamId: v.string(),
|
|
475
|
-
status: v.union(
|
|
476
|
-
v.literal("streaming"),
|
|
477
|
-
v.literal("finished"),
|
|
478
|
-
v.literal("aborted")
|
|
479
|
-
),
|
|
480
474
|
order: v.number(),
|
|
481
475
|
stepOrder: v.number(),
|
|
482
476
|
// metadata
|