@convex-dev/agent 0.1.9-alpha.1 → 0.1.9-alpha.10

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 (57) hide show
  1. package/README.md +3 -3
  2. package/dist/commonjs/client/index.d.ts.map +1 -1
  3. package/dist/commonjs/client/index.js +3 -1
  4. package/dist/commonjs/client/index.js.map +1 -1
  5. package/dist/commonjs/client/streaming.d.ts +3 -0
  6. package/dist/commonjs/client/streaming.d.ts.map +1 -1
  7. package/dist/commonjs/client/streaming.js +23 -1
  8. package/dist/commonjs/client/streaming.js.map +1 -1
  9. package/dist/commonjs/client/types.d.ts +0 -2
  10. package/dist/commonjs/client/types.d.ts.map +1 -1
  11. package/dist/commonjs/component/_generated/api.d.ts +12 -4
  12. package/dist/commonjs/component/streams.d.ts +1 -1
  13. package/dist/commonjs/component/streams.d.ts.map +1 -1
  14. package/dist/commonjs/component/streams.js +15 -5
  15. package/dist/commonjs/component/streams.js.map +1 -1
  16. package/dist/commonjs/component/threads.d.ts +8 -2
  17. package/dist/commonjs/component/threads.d.ts.map +1 -1
  18. package/dist/commonjs/component/threads.js +44 -18
  19. package/dist/commonjs/component/threads.js.map +1 -1
  20. package/dist/commonjs/component/vector/tables.d.ts +4 -2
  21. package/dist/commonjs/component/vector/tables.d.ts.map +1 -1
  22. package/dist/commonjs/react/deltas.d.ts.map +1 -1
  23. package/dist/commonjs/react/deltas.js +1 -0
  24. package/dist/commonjs/react/deltas.js.map +1 -1
  25. package/dist/commonjs.tsbuildinfo +1 -1
  26. package/dist/esm/client/index.d.ts.map +1 -1
  27. package/dist/esm/client/index.js +3 -1
  28. package/dist/esm/client/index.js.map +1 -1
  29. package/dist/esm/client/streaming.d.ts +3 -0
  30. package/dist/esm/client/streaming.d.ts.map +1 -1
  31. package/dist/esm/client/streaming.js +23 -1
  32. package/dist/esm/client/streaming.js.map +1 -1
  33. package/dist/esm/client/types.d.ts +0 -2
  34. package/dist/esm/client/types.d.ts.map +1 -1
  35. package/dist/esm/component/_generated/api.d.ts +12 -4
  36. package/dist/esm/component/streams.d.ts +1 -1
  37. package/dist/esm/component/streams.d.ts.map +1 -1
  38. package/dist/esm/component/streams.js +15 -5
  39. package/dist/esm/component/streams.js.map +1 -1
  40. package/dist/esm/component/threads.d.ts +8 -2
  41. package/dist/esm/component/threads.d.ts.map +1 -1
  42. package/dist/esm/component/threads.js +44 -18
  43. package/dist/esm/component/threads.js.map +1 -1
  44. package/dist/esm/component/vector/tables.d.ts +4 -2
  45. package/dist/esm/component/vector/tables.d.ts.map +1 -1
  46. package/dist/esm/react/deltas.d.ts.map +1 -1
  47. package/dist/esm/react/deltas.js +1 -0
  48. package/dist/esm/react/deltas.js.map +1 -1
  49. package/dist/esm.tsbuildinfo +1 -1
  50. package/package.json +1 -1
  51. package/src/client/index.ts +3 -3
  52. package/src/client/streaming.ts +26 -1
  53. package/src/client/types.ts +0 -2
  54. package/src/component/_generated/api.d.ts +12 -4
  55. package/src/component/streams.ts +18 -5
  56. package/src/component/threads.ts +48 -26
  57. package/src/react/deltas.ts +1 -0
@@ -9,7 +9,6 @@ import type {
9
9
  StepResult,
10
10
  StreamObjectResult,
11
11
  StreamTextResult,
12
- TextPart,
13
12
  ToolSet,
14
13
  } from "ai";
15
14
  import { generateObject, generateText, streamObject, streamText } from "ai";
@@ -544,6 +543,7 @@ export class Agent<AgentTools extends ToolSet> {
544
543
  providerOptions: aiArgs.providerOptions,
545
544
  order,
546
545
  stepOrder,
546
+ abortSignal: aiArgs.abortSignal,
547
547
  })
548
548
  : undefined;
549
549
 
@@ -552,6 +552,7 @@ export class Agent<AgentTools extends ToolSet> {
552
552
  maxSteps: this.options.maxSteps,
553
553
  ...aiArgs,
554
554
  tools,
555
+ abortSignal: streamer?.abortController.signal ?? aiArgs.abortSignal,
555
556
  experimental_transform: mergeTransforms(
556
557
  options?.saveStreamDeltas,
557
558
  args.experimental_transform
@@ -1050,8 +1051,7 @@ export class Agent<AgentTools extends ToolSet> {
1050
1051
  this.component.messages.listMessagesByThreadId,
1051
1052
  {
1052
1053
  threadId: args.threadId,
1053
- excludeToolMessages:
1054
- opts.includeToolCalls === true ? false : opts.excludeToolMessages,
1054
+ excludeToolMessages: opts.excludeToolMessages,
1055
1055
  paginationOpts: {
1056
1056
  numItems: opts.recentMessages ?? DEFAULT_RECENT_MESSAGES,
1057
1057
  cursor: null,
@@ -65,6 +65,7 @@ export class DeltaStreamer {
65
65
  #latestWrite: number = 0;
66
66
  #ongoingWrite: Promise<void> | undefined;
67
67
  #cursor: number = 0;
68
+ public abortController: AbortController;
68
69
 
69
70
  constructor(
70
71
  public readonly component: AgentComponent,
@@ -79,6 +80,7 @@ export class DeltaStreamer {
79
80
  userId: string | undefined;
80
81
  order: number | undefined;
81
82
  stepOrder: number | undefined;
83
+ abortSignal: AbortSignal | undefined;
82
84
  }
83
85
  ) {
84
86
  this.options =
@@ -92,8 +94,17 @@ export class DeltaStreamer {
92
94
  this.#nextParts = [];
93
95
  this.#nextOrder = metadata.order ?? 0;
94
96
  this.#nextStepOrder = (metadata.stepOrder ?? 0) + 1;
97
+ this.abortController = new AbortController();
98
+ if (metadata.abortSignal) {
99
+ metadata.abortSignal.addEventListener("abort", () => {
100
+ this.abortController.abort();
101
+ });
102
+ }
95
103
  }
96
104
  public async addParts(parts: TextStreamPart[]) {
105
+ if (this.abortController.signal.aborted) {
106
+ return;
107
+ }
97
108
  if (!this.streamId) {
98
109
  this.streamId = await this.ctx.runMutation(
99
110
  this.component.streams.create,
@@ -114,9 +125,23 @@ export class DeltaStreamer {
114
125
  }
115
126
 
116
127
  async #sendDelta() {
128
+ if (this.abortController.signal.aborted) {
129
+ return;
130
+ }
117
131
  const delta = this.#createDelta();
118
132
  this.#latestWrite = Date.now();
119
- await this.ctx.runMutation(this.component.streams.addDelta, delta);
133
+ try {
134
+ const success = await this.ctx.runMutation(
135
+ this.component.streams.addDelta,
136
+ delta
137
+ );
138
+ if (!success) {
139
+ this.abortController.abort();
140
+ }
141
+ } catch (e) {
142
+ this.abortController.abort();
143
+ throw e;
144
+ }
120
145
  // Now that we've sent the delta, check if we need to send another one.
121
146
  if (
122
147
  this.#nextParts.length > 0 &&
@@ -48,8 +48,6 @@ import type { StreamingOptions } from "./streaming.js";
48
48
  * automatically with thread.generateText, or directly via search.
49
49
  */
50
50
  export type ContextOptions = {
51
- /** @deprecated Use excludeToolMessages instead. */
52
- includeToolCalls?: boolean;
53
51
  /**
54
52
  * Whether to include tool messages in the context.
55
53
  * By default, tool calls and results are not included.
@@ -1467,7 +1467,7 @@ export type Mounts = {
1467
1467
  start: number;
1468
1468
  streamId: string;
1469
1469
  },
1470
- null
1470
+ boolean
1471
1471
  >;
1472
1472
  create: FunctionReference<
1473
1473
  "mutation",
@@ -1663,13 +1663,21 @@ export type Mounts = {
1663
1663
  deleteAllForThreadIdAsync: FunctionReference<
1664
1664
  "mutation",
1665
1665
  "public",
1666
- { cursor?: string; limit?: number; threadId: string },
1667
- { cursor: string; isDone: boolean }
1666
+ {
1667
+ cursor?: string;
1668
+ deltaCursor?: string;
1669
+ limit?: number;
1670
+ messagesDone?: boolean;
1671
+ streamOrder?: number;
1672
+ streamsDone?: boolean;
1673
+ threadId: string;
1674
+ },
1675
+ { isDone: boolean }
1668
1676
  >;
1669
1677
  deleteAllForThreadIdSync: FunctionReference<
1670
1678
  "action",
1671
1679
  "public",
1672
- { cursor?: string; limit?: number; threadId: string },
1680
+ { limit?: number; threadId: string },
1673
1681
  null
1674
1682
  >;
1675
1683
  getThread: FunctionReference<
@@ -17,20 +17,30 @@ import {
17
17
  import schema from "./schema.js";
18
18
  import { stream } from "convex-helpers/server/stream";
19
19
  import { mergedStream } from "convex-helpers/server/stream";
20
+ import { paginator } from "convex-helpers/server/pagination";
21
+
22
+ const SECOND = 1000;
23
+ const MINUTE = 60 * SECOND;
20
24
 
21
25
  const MAX_DELTAS_PER_REQUEST = 1000;
22
26
  const MAX_DELTAS_PER_STREAM = 100;
23
- const TIMEOUT_INTERVAL = 1000 * 60; // 1 minute
24
- const DELETE_STREAM_DELAY = 1000 * 60 * 5; // 5 minutes
27
+ const TIMEOUT_INTERVAL = 10 * MINUTE;
28
+ const DELETE_STREAM_DELAY = MINUTE * 5; // 5 minutes
25
29
 
26
30
  const deltaValidator = schema.tables.streamDeltas.validator;
27
31
 
28
32
  export const addDelta = mutation({
29
33
  args: deltaValidator,
30
- returns: v.null(),
34
+ returns: v.boolean(),
31
35
  handler: async (ctx, args) => {
32
36
  await ctx.db.insert("streamDeltas", args);
33
37
  await heartbeatStream(ctx, { streamId: args.streamId });
38
+ const stream = await ctx.db.get(args.streamId);
39
+ if (stream?.state.kind !== "streaming") {
40
+ console.warn(`Stream is not streaming: ${args.streamId}`);
41
+ return false;
42
+ }
43
+ return true;
34
44
  },
35
45
  });
36
46
 
@@ -138,7 +148,10 @@ export const finish = mutation({
138
148
  throw new Error(`Stream not found: ${args.streamId}`);
139
149
  }
140
150
  if (stream.state.kind !== "streaming") {
141
- throw new Error(`Stream is not streaming: ${args.streamId}`);
151
+ console.warn(
152
+ `Stream trying to finish but not currently streaming: ${args.streamId}`
153
+ );
154
+ return;
142
155
  }
143
156
  if (stream.state.timeoutFnId) {
144
157
  const timeoutFn = await ctx.db.system.get(stream.state.timeoutFnId);
@@ -221,7 +234,7 @@ async function deletePageForStreamId(
221
234
  ctx: MutationCtx,
222
235
  args: { streamId: Id<"streamingMessages">; cursor?: string }
223
236
  ) {
224
- const deltas = await ctx.db
237
+ const deltas = await paginator(ctx.db, schema)
225
238
  .query("streamDeltas")
226
239
  .withIndex("streamId_start_end", (q) => q.eq("streamId", args.streamId))
227
240
  .paginate({
@@ -16,6 +16,7 @@ import {
16
16
  } from "./_generated/server.js";
17
17
  import { deleteMessage } from "./messages.js";
18
18
  import { schema, v } from "./schema.js";
19
+ import { deleteStreamsPageForThreadId } from "./streams.js";
19
20
 
20
21
  function publicThreadOrNull(thread: Doc<"threads"> | null): ThreadDoc | null {
21
22
  if (thread === null) {
@@ -100,29 +101,17 @@ export const updateThread = mutation({
100
101
 
101
102
  // TODO: delete thread
102
103
 
103
- const deleteThreadArgs = {
104
- threadId: v.id("threads"),
105
- cursor: v.optional(v.string()),
106
- limit: v.optional(v.number()),
107
- };
108
- type DeleteThreadArgs = ObjectType<typeof deleteThreadArgs>;
109
- const deleteThreadReturns = {
110
- cursor: v.string(),
111
- isDone: v.boolean(),
112
- };
113
- type DeleteThreadReturns = ObjectType<typeof deleteThreadReturns>;
114
-
115
104
  /**
116
105
  * Use this to delete a thread and everything it contains.
117
106
  * It will try to delete all pages synchronously.
118
107
  * If it times out or fails, you'll have to run it again.
119
108
  */
120
109
  export const deleteAllForThreadIdSync = action({
121
- args: deleteThreadArgs,
110
+ args: { threadId: v.id("threads"), limit: v.optional(v.number()) },
122
111
  handler: async (ctx, args) => {
123
- let cursor = args.cursor;
112
+ let cursor: string | undefined = undefined;
124
113
  while (true) {
125
- const result = await ctx.runMutation(
114
+ const result: DeleteThreadReturns = await ctx.runMutation(
126
115
  internal.threads._deletePageForThreadId,
127
116
  { threadId: args.threadId, cursor, limit: args.limit }
128
117
  );
@@ -138,6 +127,22 @@ export const deleteAllForThreadIdSync = action({
138
127
  returns: v.null(),
139
128
  });
140
129
 
130
+ const deleteThreadArgs = {
131
+ threadId: v.id("threads"),
132
+ cursor: v.optional(v.string()),
133
+ messagesDone: v.optional(v.boolean()),
134
+ streamsDone: v.optional(v.boolean()),
135
+ streamOrder: v.optional(v.number()),
136
+ deltaCursor: v.optional(v.string()),
137
+ limit: v.optional(v.number()),
138
+ };
139
+ type DeleteThreadArgs = ObjectType<typeof deleteThreadArgs>;
140
+ const deleteThreadReturns = {
141
+ cursor: v.string(),
142
+ isDone: v.boolean(),
143
+ };
144
+ type DeleteThreadReturns = ObjectType<typeof deleteThreadReturns>;
145
+
141
146
  export const _deletePageForThreadId = internalMutation({
142
147
  args: deleteThreadArgs,
143
148
  handler: deletePageForThreadIdHandler,
@@ -151,22 +156,39 @@ export const _deletePageForThreadId = internalMutation({
151
156
  export const deleteAllForThreadIdAsync = mutation({
152
157
  args: deleteThreadArgs,
153
158
  handler: async (ctx, args) => {
154
- const result = await deletePageForThreadIdHandler(ctx, args);
155
- if (!result.isDone) {
159
+ let messagesResult = {
160
+ isDone: args.messagesDone ?? false,
161
+ cursor: args.cursor,
162
+ };
163
+ if (!args.messagesDone) {
164
+ messagesResult = await deletePageForThreadIdHandler(ctx, args);
165
+ }
166
+ let streamResult = {
167
+ isDone: args.streamsDone ?? false,
168
+ streamOrder: args.streamOrder,
169
+ deltaCursor: args.deltaCursor,
170
+ };
171
+ if (!args.streamsDone) {
172
+ streamResult = await deleteStreamsPageForThreadId(ctx, {
173
+ threadId: args.threadId,
174
+ streamOrder: args.streamOrder,
175
+ deltaCursor: args.deltaCursor,
176
+ });
177
+ }
178
+ const isDone = messagesResult.isDone && streamResult.isDone;
179
+ if (!isDone) {
156
180
  await ctx.scheduler.runAfter(0, api.threads.deleteAllForThreadIdAsync, {
157
181
  threadId: args.threadId,
158
- cursor: result.cursor,
182
+ cursor: messagesResult.cursor,
183
+ messagesDone: messagesResult.isDone,
184
+ streamsDone: streamResult.isDone,
185
+ streamOrder: streamResult.streamOrder,
186
+ deltaCursor: streamResult.deltaCursor,
159
187
  });
160
188
  }
161
- // Kick off the streams deletion
162
- await ctx.scheduler.runAfter(
163
- 0,
164
- api.streams.deleteAllStreamsForThreadIdSync,
165
- { threadId: args.threadId }
166
- );
167
- return result;
189
+ return { isDone };
168
190
  },
169
- returns: deleteThreadReturns,
191
+ returns: v.object({ isDone: v.boolean() }),
170
192
  });
171
193
 
172
194
  async function deletePageForThreadIdHandler(
@@ -189,6 +189,7 @@ export function applyDeltasToStreamMessage(
189
189
  contentToAdd = part;
190
190
  break;
191
191
  case "reasoning":
192
+ currentMessage.reasoning += part.textDelta;
192
193
  if (lastContent?.type === "reasoning") {
193
194
  lastContent.text += part.textDelta;
194
195
  } else {