@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.
Files changed (71) hide show
  1. package/README.md +1 -0
  2. package/dist/commonjs/client/index.d.ts +0 -1
  3. package/dist/commonjs/client/index.d.ts.map +1 -1
  4. package/dist/commonjs/client/index.js +0 -2
  5. package/dist/commonjs/client/index.js.map +1 -1
  6. package/dist/commonjs/client/streaming.d.ts.map +1 -1
  7. package/dist/commonjs/client/streaming.js +1 -7
  8. package/dist/commonjs/client/streaming.js.map +1 -1
  9. package/dist/commonjs/component/_generated/api.d.ts +1 -12
  10. package/dist/commonjs/component/schema.d.ts +26 -26
  11. package/dist/commonjs/component/schema.d.ts.map +1 -1
  12. package/dist/commonjs/component/schema.js +2 -2
  13. package/dist/commonjs/component/schema.js.map +1 -1
  14. package/dist/commonjs/component/streams.d.ts +3 -10
  15. package/dist/commonjs/component/streams.d.ts.map +1 -1
  16. package/dist/commonjs/component/streams.js +20 -47
  17. package/dist/commonjs/component/streams.js.map +1 -1
  18. package/dist/commonjs/react/deltas.d.ts.map +1 -1
  19. package/dist/commonjs/react/deltas.js +2 -2
  20. package/dist/commonjs/react/deltas.js.map +1 -1
  21. package/dist/commonjs/react/index.d.ts +2 -4
  22. package/dist/commonjs/react/index.d.ts.map +1 -1
  23. package/dist/commonjs/react/index.js +8 -21
  24. package/dist/commonjs/react/index.js.map +1 -1
  25. package/dist/commonjs/react/optimisticallySendMessage.js +1 -1
  26. package/dist/commonjs/react/optimisticallySendMessage.js.map +1 -1
  27. package/dist/commonjs/validators.d.ts +3 -8
  28. package/dist/commonjs/validators.d.ts.map +1 -1
  29. package/dist/commonjs/validators.js +0 -2
  30. package/dist/commonjs/validators.js.map +1 -1
  31. package/dist/commonjs.tsbuildinfo +1 -1
  32. package/dist/esm/client/index.d.ts +0 -1
  33. package/dist/esm/client/index.d.ts.map +1 -1
  34. package/dist/esm/client/index.js +0 -2
  35. package/dist/esm/client/index.js.map +1 -1
  36. package/dist/esm/client/streaming.d.ts.map +1 -1
  37. package/dist/esm/client/streaming.js +1 -7
  38. package/dist/esm/client/streaming.js.map +1 -1
  39. package/dist/esm/component/_generated/api.d.ts +1 -12
  40. package/dist/esm/component/schema.d.ts +26 -26
  41. package/dist/esm/component/schema.d.ts.map +1 -1
  42. package/dist/esm/component/schema.js +2 -2
  43. package/dist/esm/component/schema.js.map +1 -1
  44. package/dist/esm/component/streams.d.ts +3 -10
  45. package/dist/esm/component/streams.d.ts.map +1 -1
  46. package/dist/esm/component/streams.js +20 -47
  47. package/dist/esm/component/streams.js.map +1 -1
  48. package/dist/esm/react/deltas.d.ts.map +1 -1
  49. package/dist/esm/react/deltas.js +2 -2
  50. package/dist/esm/react/deltas.js.map +1 -1
  51. package/dist/esm/react/index.d.ts +2 -4
  52. package/dist/esm/react/index.d.ts.map +1 -1
  53. package/dist/esm/react/index.js +8 -21
  54. package/dist/esm/react/index.js.map +1 -1
  55. package/dist/esm/react/optimisticallySendMessage.js +1 -1
  56. package/dist/esm/react/optimisticallySendMessage.js.map +1 -1
  57. package/dist/esm/validators.d.ts +3 -8
  58. package/dist/esm/validators.d.ts.map +1 -1
  59. package/dist/esm/validators.js +0 -2
  60. package/dist/esm/validators.js.map +1 -1
  61. package/dist/esm.tsbuildinfo +1 -1
  62. package/package.json +1 -1
  63. package/src/client/index.ts +0 -4
  64. package/src/client/streaming.ts +1 -7
  65. package/src/component/_generated/api.d.ts +1 -12
  66. package/src/component/schema.ts +2 -2
  67. package/src/component/streams.ts +36 -81
  68. package/src/react/deltas.ts +2 -4
  69. package/src/react/index.ts +10 -22
  70. package/src/react/optimisticallySendMessage.ts +1 -1
  71. package/src/validators.ts +0 -6
@@ -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 { Doc, Id } from "./_generated/dataModel.js";
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 = 1000 * 60; // 1 minute
25
- const DELETE_STREAM_DELAY = 1000 * 60 * 5; // 5 minutes
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
- const statuses = args.statuses ?? ["streaming"];
120
- const messages = await mergedStream(
121
- statuses.map((status) =>
122
- stream(ctx.db, schema)
123
- .query("streamingMessages")
124
- .withIndex("threadId_state_order_stepOrder", (q) =>
125
- q
126
- .eq("threadId", args.threadId)
127
- .eq("state.kind", status)
128
- .gte("order", args.startOrder ?? 0)
129
- )
130
- .order("desc")
131
- ),
132
- ["order", "stepOrder"]
133
- ).take(100);
134
-
135
- return messages.map((m) => ({
136
- streamId: m._id,
137
- status: m.state.kind,
138
- ...pick(m, [
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
- await cleanupTimeoutFn(ctx, stream);
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: result.continueCursor,
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
 
@@ -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":
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { omit, type ErrorMessage } from "convex-helpers";
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, useRef, useState } from "react";
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: (ThreadMessagesArgs<Query> & { startOrder?: number }) | "skip"
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
- queryArgs === "skip"
174
- ? queryArgs
164
+ args === "skip"
165
+ ? args
175
166
  : ({
176
- ...queryArgs,
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
- queryArgs === "skip" || !streamList
189
+ args === "skip" || !streamList
202
190
  ? ("skip" as const)
203
191
  : ({
204
- ...queryArgs,
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 = -1;
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