@convex-dev/agent 0.2.0-alpha.2 → 0.2.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.
Files changed (96) hide show
  1. package/dist/client/createTool.d.ts +3 -5
  2. package/dist/client/createTool.d.ts.map +1 -1
  3. package/dist/client/createTool.js +0 -1
  4. package/dist/client/createTool.js.map +1 -1
  5. package/dist/client/definePlaygroundAPI.d.ts +28 -28
  6. package/dist/client/files.d.ts +8 -1
  7. package/dist/client/files.d.ts.map +1 -1
  8. package/dist/client/files.js +60 -5
  9. package/dist/client/files.js.map +1 -1
  10. package/dist/client/index.d.ts +223 -239
  11. package/dist/client/index.d.ts.map +1 -1
  12. package/dist/client/index.js +368 -382
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/client/messages.d.ts +91 -373
  15. package/dist/client/messages.d.ts.map +1 -1
  16. package/dist/client/messages.js +7 -1
  17. package/dist/client/messages.js.map +1 -1
  18. package/dist/client/search.d.ts +15 -15
  19. package/dist/client/search.d.ts.map +1 -1
  20. package/dist/client/search.js +3 -3
  21. package/dist/client/search.js.map +1 -1
  22. package/dist/client/streaming.d.ts +21 -22
  23. package/dist/client/streaming.d.ts.map +1 -1
  24. package/dist/client/streaming.js +35 -40
  25. package/dist/client/streaming.js.map +1 -1
  26. package/dist/client/types.d.ts +148 -61
  27. package/dist/client/types.d.ts.map +1 -1
  28. package/dist/component/_generated/api.d.ts +47 -357
  29. package/dist/component/messages.d.ts +157 -150
  30. package/dist/component/messages.d.ts.map +1 -1
  31. package/dist/component/messages.js +124 -70
  32. package/dist/component/messages.js.map +1 -1
  33. package/dist/component/schema.d.ts +1147 -2687
  34. package/dist/component/schema.d.ts.map +1 -1
  35. package/dist/component/schema.js +5 -4
  36. package/dist/component/schema.js.map +1 -1
  37. package/dist/component/streams.d.ts +29 -323
  38. package/dist/component/streams.d.ts.map +1 -1
  39. package/dist/component/streams.js +104 -60
  40. package/dist/component/streams.js.map +1 -1
  41. package/dist/component/threads.d.ts +4 -4
  42. package/dist/component/users.d.ts +3 -3
  43. package/dist/mapping.d.ts +4 -1
  44. package/dist/mapping.d.ts.map +1 -1
  45. package/dist/mapping.js +17 -1
  46. package/dist/mapping.js.map +1 -1
  47. package/dist/parts.d.ts +3 -0
  48. package/dist/parts.d.ts.map +1 -0
  49. package/dist/parts.js +34 -0
  50. package/dist/parts.js.map +1 -0
  51. package/dist/react/SmoothText.d.ts +5 -0
  52. package/dist/react/SmoothText.d.ts.map +1 -0
  53. package/dist/react/SmoothText.js +6 -0
  54. package/dist/react/SmoothText.js.map +1 -0
  55. package/dist/react/deltas.d.ts +3 -2
  56. package/dist/react/deltas.d.ts.map +1 -1
  57. package/dist/react/deltas.js +19 -79
  58. package/dist/react/deltas.js.map +1 -1
  59. package/dist/react/index.d.ts +1 -0
  60. package/dist/react/index.d.ts.map +1 -1
  61. package/dist/react/index.js +31 -11
  62. package/dist/react/index.js.map +1 -1
  63. package/dist/react/optimisticallySendMessage.d.ts.map +1 -1
  64. package/dist/react/optimisticallySendMessage.js +2 -8
  65. package/dist/react/optimisticallySendMessage.js.map +1 -1
  66. package/dist/react/useSmoothText.d.ts +13 -12
  67. package/dist/react/useSmoothText.d.ts.map +1 -1
  68. package/dist/react/useSmoothText.js +1 -1
  69. package/dist/react/useSmoothText.js.map +1 -1
  70. package/dist/validators.d.ts +109 -1590
  71. package/dist/validators.d.ts.map +1 -1
  72. package/dist/validators.js +4 -81
  73. package/dist/validators.js.map +1 -1
  74. package/package.json +3 -3
  75. package/src/client/createTool.ts +4 -9
  76. package/src/client/files.ts +88 -10
  77. package/src/client/index.test.ts +9 -21
  78. package/src/client/index.ts +664 -650
  79. package/src/client/messages.ts +16 -2
  80. package/src/client/search.ts +10 -7
  81. package/src/client/streaming.ts +53 -57
  82. package/src/client/types.ts +227 -97
  83. package/src/component/_generated/api.d.ts +47 -357
  84. package/src/component/messages.ts +157 -96
  85. package/src/component/schema.ts +4 -4
  86. package/src/component/streams.ts +180 -69
  87. package/src/mapping.ts +23 -2
  88. package/src/parts.ts +39 -0
  89. package/src/react/SmoothText.tsx +9 -0
  90. package/src/react/deltas.test.ts +38 -42
  91. package/src/react/deltas.ts +24 -86
  92. package/src/react/index.ts +35 -13
  93. package/src/react/optimisticallySendMessage.ts +2 -8
  94. package/src/react/useSmoothText.ts +14 -15
  95. package/src/validators.test.ts +0 -17
  96. package/src/validators.ts +8 -101
@@ -74,6 +74,10 @@ export type SaveMessagesArgs = {
74
74
  * The embeddings to save with the messages.
75
75
  */
76
76
  embeddings?: MessageEmbeddings;
77
+ /**
78
+ * A pending message ID to replace when adding messages.
79
+ */
80
+ pendingMessageId?: string;
77
81
  };
78
82
 
79
83
  /**
@@ -88,7 +92,7 @@ export async function saveMessages(
88
92
  */
89
93
  agentName?: string;
90
94
  },
91
- ) {
95
+ ): Promise<{ messages: MessageDoc[] }> {
92
96
  let embeddings: MessageEmbeddingsWithDimension | undefined;
93
97
  if (args.embeddings) {
94
98
  const dimension = args.embeddings.vectors.find((v) => v !== null)?.length;
@@ -106,14 +110,19 @@ export async function saveMessages(
106
110
  userId: args.userId ?? undefined,
107
111
  agentName: args.agentName,
108
112
  promptMessageId: args.promptMessageId,
113
+ pendingMessageId: args.pendingMessageId,
109
114
  embeddings,
110
115
  messages: await Promise.all(
111
116
  args.messages.map(async (m, i) => {
112
117
  const { message, fileIds } = await serializeMessage(ctx, component, m);
118
+ const allFileIds = args.metadata?.[i]?.fileIds ?? [];
119
+ if (fileIds) {
120
+ allFileIds.push(...fileIds);
121
+ }
113
122
  return parse(vMessageWithMetadata, {
114
123
  ...args.metadata?.[i],
115
124
  message,
116
- fileIds,
125
+ fileIds: allFileIds.length > 0 ? allFileIds : undefined,
117
126
  });
118
127
  }),
119
128
  ),
@@ -134,6 +143,10 @@ export type SaveMessageArgs = {
134
143
  * The embedding to save with the message.
135
144
  */
136
145
  embedding?: { vector: number[]; model: string };
146
+ /**
147
+ * A pending message ID to replace with this message.
148
+ */
149
+ pendingMessageId?: string;
137
150
  } & (
138
151
  | {
139
152
  prompt?: undefined;
@@ -179,6 +192,7 @@ export async function saveMessage(
179
192
  threadId: args.threadId,
180
193
  userId: args.userId ?? undefined,
181
194
  agentName: args.agentName,
195
+ pendingMessageId: args.pendingMessageId,
182
196
  messages:
183
197
  args.prompt !== undefined
184
198
  ? [{ role: "user", content: args.prompt }]
@@ -16,9 +16,11 @@ import type { Message } from "../validators.js";
16
16
 
17
17
  const DEFAULT_VECTOR_SCORE_THRESHOLD = 0.0;
18
18
 
19
- export type GetEmbedding = (text: string) => Promise<{
19
+ export type GetEmbedding = (
20
+ text: string,
21
+ ) => Promise<{
20
22
  embedding: number[];
21
- embeddingModel: string | EmbeddingModel<string>;
23
+ textEmbeddingModel: string | EmbeddingModel<string>;
22
24
  }>;
23
25
 
24
26
  /**
@@ -96,9 +98,10 @@ export async function fetchContextMessages(
96
98
  "You must provide an embedding and embeddingModel to use vector search",
97
99
  );
98
100
  }
99
- const embeddingFields = opts.searchOptions?.vectorSearch
100
- ? await args.getEmbedding?.(text)
101
- : undefined;
101
+ const embeddingFields =
102
+ opts.searchOptions?.vectorSearch && text
103
+ ? await args.getEmbedding?.(text)
104
+ : undefined;
102
105
  const searchMessages = await ctx.runAction(
103
106
  component.messages.searchMessages,
104
107
  {
@@ -123,8 +126,8 @@ export async function fetchContextMessages(
123
126
  opts.searchOptions?.vectorScoreThreshold ??
124
127
  DEFAULT_VECTOR_SCORE_THRESHOLD,
125
128
  embedding: embeddingFields?.embedding,
126
- embeddingModel: embeddingFields?.embeddingModel
127
- ? getModelName(embeddingFields.embeddingModel)
129
+ embeddingModel: embeddingFields?.textEmbeddingModel
130
+ ? getModelName(embeddingFields.textEmbeddingModel)
128
131
  : undefined,
129
132
  },
130
133
  );
@@ -2,6 +2,7 @@ import {
2
2
  type ChunkDetector,
3
3
  smoothStream,
4
4
  type StreamTextTransform,
5
+ type TextStreamPart,
5
6
  type ToolSet,
6
7
  } from "ai";
7
8
  import type {
@@ -9,9 +10,7 @@ import type {
9
10
  StreamArgs,
10
11
  StreamDelta,
11
12
  StreamMessage,
12
- vTextStreamPartV5,
13
13
  } from "../validators.js";
14
- import type { MessageDoc } from "../component/schema.js";
15
14
  import type {
16
15
  AgentComponent,
17
16
  RunActionCtx,
@@ -20,7 +19,7 @@ import type {
20
19
  SyncStreamsReturnValue,
21
20
  } from "./types.js";
22
21
  import { omit } from "convex-helpers";
23
- import type { Infer } from "convex/values";
22
+ import { serializeTextStreamingPartsV5 } from "../parts.js";
24
23
 
25
24
  /**
26
25
  * A function that handles fetching stream deltas, used with the React hooks
@@ -65,9 +64,10 @@ export async function syncStreams(
65
64
  export async function abortStream(
66
65
  ctx: RunMutationCtx,
67
66
  component: AgentComponent,
68
- args: {
69
- reason: string;
70
- } & ({ streamId: string } | { threadId: string; order: number }),
67
+ args: { reason: string } & (
68
+ | { streamId: string }
69
+ | { threadId: string; order: number }
70
+ ),
71
71
  ): Promise<boolean> {
72
72
  if ("streamId" in args) {
73
73
  return await ctx.runMutation(component.streams.abort, {
@@ -159,9 +159,7 @@ export function mergeTransforms<TOOLS extends ToolSet>(
159
159
  export class DeltaStreamer {
160
160
  public streamId: string | undefined;
161
161
  public readonly options: Required<StreamingOptions>;
162
- #nextParts: Infer<typeof vTextStreamPartV5>[] = [];
163
- #nextOrder: number;
164
- #nextStepOrder: number;
162
+ #nextParts: TextStreamPart<ToolSet>[] = [];
165
163
  #latestWrite: number = 0;
166
164
  #ongoingWrite: Promise<void> | undefined;
167
165
  #cursor: number = 0;
@@ -173,51 +171,46 @@ export class DeltaStreamer {
173
171
  options: true | StreamingOptions,
174
172
  public readonly metadata: {
175
173
  threadId: string;
176
- agentName: string | undefined;
177
- model: string | undefined;
178
- provider: string | undefined;
179
- providerOptions: ProviderOptions | undefined;
180
- userId: string | undefined;
181
- order: number | undefined;
182
- stepOrder: number | undefined;
183
- abortSignal: AbortSignal | undefined;
174
+ userId?: string;
175
+ order: number;
176
+ stepOrder: number;
177
+ agentName?: string;
178
+ model?: string;
179
+ provider?: string;
180
+ providerOptions?: ProviderOptions;
181
+ abortSignal?: AbortSignal;
184
182
  },
185
183
  ) {
186
184
  this.options =
187
185
  typeof options === "boolean"
188
186
  ? DEFAULT_STREAMING_OPTIONS
189
- : {
190
- ...DEFAULT_STREAMING_OPTIONS,
191
- ...options,
192
- };
187
+ : { ...DEFAULT_STREAMING_OPTIONS, ...options };
193
188
  this.#nextParts = [];
194
- this.#nextOrder = metadata.order ?? 0;
195
- this.#nextStepOrder = (metadata.stepOrder ?? 0) + 1;
196
189
  this.abortController = new AbortController();
197
190
  if (metadata.abortSignal) {
198
191
  metadata.abortSignal.addEventListener("abort", async () => {
199
192
  if (this.streamId) {
193
+ this.abortController.abort();
194
+ const finalDelta = this.#createDelta();
195
+ await this.#ongoingWrite;
200
196
  await this.ctx.runMutation(this.component.streams.abort, {
201
197
  streamId: this.streamId,
202
198
  reason: "abortSignal",
199
+ finalDelta,
203
200
  });
204
201
  }
205
- this.abortController.abort();
206
202
  });
207
203
  }
208
204
  }
209
- public async addParts(parts: Infer<typeof vTextStreamPartV5>[]) {
205
+
206
+ public async addParts(parts: TextStreamPart<ToolSet>[]) {
210
207
  if (this.abortController.signal.aborted) {
211
208
  return;
212
209
  }
213
210
  if (!this.streamId) {
214
211
  this.streamId = await this.ctx.runMutation(
215
212
  this.component.streams.create,
216
- {
217
- ...omit(this.metadata, ["abortSignal"]),
218
- order: this.#nextOrder,
219
- stepOrder: this.#nextStepOrder,
220
- },
213
+ omit(this.metadata, ["abortSignal"]),
221
214
  );
222
215
  }
223
216
  this.#nextParts.push(...parts);
@@ -234,6 +227,9 @@ export class DeltaStreamer {
234
227
  return;
235
228
  }
236
229
  const delta = this.#createDelta();
230
+ if (!delta) {
231
+ return;
232
+ }
237
233
  this.#latestWrite = Date.now();
238
234
  try {
239
235
  const success = await this.ctx.runMutation(
@@ -259,46 +255,46 @@ export class DeltaStreamer {
259
255
  }
260
256
  }
261
257
 
262
- #createDelta(): StreamDelta {
258
+ #createDelta(): StreamDelta | undefined {
259
+ if (this.#nextParts.length === 0) {
260
+ return undefined;
261
+ }
263
262
  const start = this.#cursor;
264
263
  const end = start + this.#nextParts.length;
265
264
  this.#cursor = end;
266
- const parts = this.#nextParts;
265
+ const parts = serializeTextStreamingPartsV5(this.#nextParts);
267
266
  this.#nextParts = [];
268
267
  if (!this.streamId) {
269
268
  throw new Error("Creating a delta before the stream is created");
270
269
  }
271
- return {
270
+ return { streamId: this.streamId, start, end, parts };
271
+ }
272
+
273
+ public async finish() {
274
+ if (!this.streamId) {
275
+ return;
276
+ }
277
+ const finalDelta = this.#createDelta();
278
+ await this.#ongoingWrite;
279
+ await this.ctx.runMutation(this.component.streams.finish, {
272
280
  streamId: this.streamId,
273
- start,
274
- end,
275
- parts,
276
- };
281
+ finalDelta,
282
+ });
277
283
  }
278
284
 
279
- public async finish(messages: MessageDoc[]) {
280
- if (this.#ongoingWrite) {
281
- await this.#ongoingWrite;
282
- this.#ongoingWrite = undefined;
285
+ public async fail(reason: string) {
286
+ if (this.abortController.signal.aborted) {
287
+ return;
283
288
  }
289
+ this.abortController.abort();
284
290
  if (!this.streamId) {
285
- throw new Error("Finish called before stream is created");
286
- }
287
- const lastMessage = messages.at(-1);
288
- if (lastMessage) {
289
- this.#nextOrder = lastMessage.order;
290
- this.#nextStepOrder = lastMessage.stepOrder + 1;
291
- } else {
292
- console.warn("Step finished without generating a message");
291
+ return;
293
292
  }
294
- const finalDelta =
295
- this.#nextParts.length > 0 ? this.#createDelta() : undefined;
296
- this.#nextParts = [];
297
- const streamId = this.streamId;
298
- this.streamId = undefined;
299
- this.#cursor = 0;
300
- await this.ctx.runMutation(this.component.streams.finish, {
301
- streamId,
293
+ const finalDelta = this.#createDelta();
294
+ await this.#ongoingWrite;
295
+ await this.ctx.runMutation(this.component.streams.abort, {
296
+ streamId: this.streamId,
297
+ reason,
302
298
  finalDelta,
303
299
  });
304
300
  }