@convex-dev/agent 0.0.1-alpha.3 → 0.0.1

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 +9 -7
  2. package/dist/commonjs/client/index.d.ts +12 -5
  3. package/dist/commonjs/client/index.d.ts.map +1 -1
  4. package/dist/commonjs/client/index.js +127 -44
  5. package/dist/commonjs/client/index.js.map +1 -1
  6. package/dist/commonjs/component/messages.d.ts +114 -103
  7. package/dist/commonjs/component/messages.d.ts.map +1 -1
  8. package/dist/commonjs/component/messages.js +143 -246
  9. package/dist/commonjs/component/messages.js.map +1 -1
  10. package/dist/commonjs/component/schema.d.ts +808 -738
  11. package/dist/commonjs/component/schema.d.ts.map +1 -1
  12. package/dist/commonjs/component/schema.js +12 -3
  13. package/dist/commonjs/component/schema.js.map +1 -1
  14. package/dist/commonjs/component/vector/index.d.ts +21 -6
  15. package/dist/commonjs/component/vector/index.d.ts.map +1 -1
  16. package/dist/commonjs/component/vector/index.js +33 -21
  17. package/dist/commonjs/component/vector/index.js.map +1 -1
  18. package/dist/commonjs/component/vector/tables.d.ts +25 -5
  19. package/dist/commonjs/component/vector/tables.d.ts.map +1 -1
  20. package/dist/commonjs/component/vector/tables.js +14 -6
  21. package/dist/commonjs/component/vector/tables.js.map +1 -1
  22. package/dist/commonjs/validators.d.ts +101 -89
  23. package/dist/commonjs/validators.d.ts.map +1 -1
  24. package/dist/commonjs/validators.js +8 -1
  25. package/dist/commonjs/validators.js.map +1 -1
  26. package/dist/esm/client/index.d.ts +12 -5
  27. package/dist/esm/client/index.d.ts.map +1 -1
  28. package/dist/esm/client/index.js +127 -44
  29. package/dist/esm/client/index.js.map +1 -1
  30. package/dist/esm/component/messages.d.ts +114 -103
  31. package/dist/esm/component/messages.d.ts.map +1 -1
  32. package/dist/esm/component/messages.js +143 -246
  33. package/dist/esm/component/messages.js.map +1 -1
  34. package/dist/esm/component/schema.d.ts +808 -738
  35. package/dist/esm/component/schema.d.ts.map +1 -1
  36. package/dist/esm/component/schema.js +12 -3
  37. package/dist/esm/component/schema.js.map +1 -1
  38. package/dist/esm/component/vector/index.d.ts +21 -6
  39. package/dist/esm/component/vector/index.d.ts.map +1 -1
  40. package/dist/esm/component/vector/index.js +33 -21
  41. package/dist/esm/component/vector/index.js.map +1 -1
  42. package/dist/esm/component/vector/tables.d.ts +25 -5
  43. package/dist/esm/component/vector/tables.d.ts.map +1 -1
  44. package/dist/esm/component/vector/tables.js +14 -6
  45. package/dist/esm/component/vector/tables.js.map +1 -1
  46. package/dist/esm/validators.d.ts +101 -89
  47. package/dist/esm/validators.d.ts.map +1 -1
  48. package/dist/esm/validators.js +8 -1
  49. package/dist/esm/validators.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/client/index.ts +149 -50
  52. package/src/component/_generated/api.d.ts +28 -16
  53. package/src/component/messages.ts +175 -289
  54. package/src/component/schema.ts +13 -3
  55. package/src/component/vector/index.ts +65 -26
  56. package/src/component/vector/tables.ts +38 -6
  57. package/src/validators.ts +11 -4
@@ -17,12 +17,12 @@ export const schema = defineSchema({
17
17
  // the parent thread(s). There are multiple if the thread is a merging of
18
18
  // multiple threads.
19
19
  parentThreadIds: v.optional(v.array(v.id("threads"))),
20
- }).index("status_userId_order", ["status", "userId", "order"]),
20
+ }).index("userId_status_order", ["userId", "status", "order"]),
21
21
  // TODO: text search on title/ summary
22
22
  messages: defineTable({
23
23
  id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
24
24
  userId: v.optional(v.string()), // useful for future indexes (text search)
25
- threadId: v.optional(v.id("threads")),
25
+ threadId: v.id("threads"),
26
26
  parentMessageId: v.optional(v.id("messages")),
27
27
  stepId: v.optional(v.id("steps")),
28
28
  agentName: v.optional(v.string()),
@@ -35,7 +35,7 @@ export const schema = defineSchema({
35
35
  // Repeats until a non-tool message.
36
36
  // Unset if it's not in a thread.
37
37
  order: v.number(),
38
- stepOrder: v.optional(v.number()),
38
+ stepOrder: v.number(),
39
39
  fileId: v.optional(v.id("files")),
40
40
  status: vMessageStatus,
41
41
  })
@@ -92,6 +92,16 @@ export const schema = defineSchema({
92
92
  "stepOrder",
93
93
  ]),
94
94
 
95
+ memories: defineTable({
96
+ threadId: v.optional(v.id("threads")),
97
+ userId: v.optional(v.string()),
98
+ memory: v.string(),
99
+ embeddingId: v.optional(vVectorId),
100
+ })
101
+ .index("threadId", ["threadId"])
102
+ .index("userId", ["userId"])
103
+ .index("embeddingId", ["embeddingId"]),
104
+
95
105
  files: defineTable({
96
106
  storageId: v.string(),
97
107
  hash: v.string(),
@@ -1,7 +1,20 @@
1
1
  import { paginator } from "convex-helpers/server/pagination";
2
2
  import { v } from "convex/values";
3
- import { mutation, query } from "../_generated/server";
4
- import { getVectorTableName, vVectorDimension, vVectorId } from "./tables";
3
+ import {
4
+ ActionCtx,
5
+ mutation,
6
+ MutationCtx,
7
+ query,
8
+ QueryCtx,
9
+ } from "../_generated/server";
10
+ import {
11
+ EmbeddingsWithoutDenormalizedFields,
12
+ getVectorTableName,
13
+ VectorDimension,
14
+ vEmbeddingsWithoutDenormalizedFields,
15
+ vVectorDimension,
16
+ vVectorId,
17
+ } from "./tables";
5
18
  import schema from "../schema";
6
19
  import { mergedStream } from "convex-helpers/server/stream";
7
20
  import { stream } from "convex-helpers/server/stream";
@@ -10,6 +23,7 @@ export const paginate = query({
10
23
  args: {
11
24
  vectorDimension: vVectorDimension,
12
25
  targetModel: v.string(),
26
+ table: v.optional(v.string()),
13
27
  cursor: v.optional(v.string()),
14
28
  limit: v.number(),
15
29
  },
@@ -23,8 +37,11 @@ export const paginate = query({
23
37
  const vectors = await paginator(ctx.db, schema)
24
38
  .query(tableName)
25
39
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- .withIndex("model_kind_threadId" as any, (q) =>
27
- q.eq("model", args.targetModel)
40
+ .withIndex("model_table_threadId" as any, (q) =>
41
+ args.table
42
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+ (q.eq("model", args.targetModel) as any).eq("table", args.table)
44
+ : q.eq("model", args.targetModel)
28
45
  )
29
46
  .paginate({
30
47
  cursor: args.cursor ?? null,
@@ -82,36 +99,58 @@ export const deleteBatchForThread = mutation({
82
99
  export const insertBatch = mutation({
83
100
  args: {
84
101
  vectorDimension: vVectorDimension,
85
- vectors: v.array(
86
- v.object({
87
- model: v.string(),
88
- kind: v.union(v.literal("thread"), v.literal("memory")),
89
- userId: v.optional(v.string()),
90
- threadId: v.optional(v.string()),
91
- vector: v.array(v.number()),
92
- })
93
- ),
102
+ vectors: v.array(vEmbeddingsWithoutDenormalizedFields),
94
103
  },
95
104
  returns: v.null(),
96
105
  handler: async (ctx, args) => {
97
106
  await Promise.all(
98
- args.vectors.map((v) =>
99
- ctx.db.insert(getVectorTableName(args.vectorDimension), {
100
- model: v.model,
101
- kind: v.kind,
102
- userId: v.userId,
103
- threadId: v.threadId,
104
- vector: v.vector,
105
- model_kind_userId: v.userId ? [v.model, v.kind, v.userId] : undefined,
106
- model_kind_threadId: v.threadId
107
- ? [v.model, v.kind, v.threadId]
108
- : undefined,
109
- })
110
- )
107
+ args.vectors.map((v) => insertVector(ctx, args.vectorDimension, v))
111
108
  );
112
109
  },
113
110
  });
114
111
 
112
+ export async function insertVector(
113
+ ctx: MutationCtx,
114
+ dimension: VectorDimension,
115
+ v: EmbeddingsWithoutDenormalizedFields
116
+ ) {
117
+ return ctx.db.insert(getVectorTableName(dimension), {
118
+ ...v,
119
+ model_table_userId: v.userId ? [v.model, v.table, v.userId] : undefined,
120
+ model_table_threadId: v.threadId
121
+ ? [v.model, v.table, v.threadId]
122
+ : undefined,
123
+ });
124
+ }
125
+
126
+ export function searchVectors(
127
+ ctx: ActionCtx,
128
+ vector: number[],
129
+ args: {
130
+ dimension: VectorDimension;
131
+ model: string;
132
+ table: string;
133
+ userId?: string;
134
+ threadId?: string;
135
+ limit?: number;
136
+ }
137
+ ) {
138
+ const tableName = getVectorTableName(args.dimension);
139
+ return ctx.vectorSearch(tableName, "vector", {
140
+ vector,
141
+ // TODO: to support more tables, add more "OR" clauses for each.
142
+ filter: (q) =>
143
+ args.userId
144
+ ? q.eq("model_table_userId", [args.model, args.table, args.userId])
145
+ : q.eq("model_table_threadId", [
146
+ args.model,
147
+ args.table,
148
+ args.threadId!,
149
+ ]),
150
+ limit: args.limit,
151
+ });
152
+ }
153
+
115
154
  export const updateBatch = mutation({
116
155
  args: {
117
156
  vectors: v.array(
@@ -1,37 +1,69 @@
1
+ import { omit } from "convex-helpers";
1
2
  import { literals } from "convex-helpers/validators";
2
3
  import {
3
4
  defineTable,
4
5
  GenericTableSearchIndexes,
6
+ SchemaDefinition,
5
7
  TableDefinition,
6
8
  } from "convex/server";
7
- import { GenericId, ObjectType, v, VId, VObject, VUnion } from "convex/values";
9
+ import {
10
+ GenericId,
11
+ Infer,
12
+ ObjectType,
13
+ v,
14
+ VId,
15
+ VObject,
16
+ VUnion,
17
+ } from "convex/values";
8
18
  import { QueryCtx } from "../_generated/server";
9
19
 
10
20
  // We only generate embeddings for non-tool, non-system messages
11
21
  const embeddings = {
12
22
  model: v.string(),
13
- kind: v.union(v.literal("thread"), v.literal("memory")),
23
+ // What table it's stored in. (usually messages or memories)
24
+ table: v.string(),
14
25
  userId: v.optional(v.string()),
15
26
  threadId: v.optional(v.string()),
16
27
  // not set for private threads
17
- model_kind_userId: v.optional(v.array(v.string())),
18
- model_kind_threadId: v.optional(v.array(v.string())),
28
+ model_table_userId: v.optional(v.array(v.string())),
29
+ model_table_threadId: v.optional(v.array(v.string())),
19
30
  vector: v.array(v.number()),
20
31
  };
21
32
 
33
+ export const vEmbeddingsWithoutDenormalizedFields = v.object(
34
+ omit(embeddings, ["model_table_userId", "model_table_threadId"])
35
+ );
36
+ export type EmbeddingsWithoutDenormalizedFields = Infer<
37
+ typeof vEmbeddingsWithoutDenormalizedFields
38
+ >;
39
+
22
40
  function table<D extends number>(dimensions: D): Table<D> {
23
41
  return defineTable(embeddings)
24
42
  .vectorIndex("vector", {
25
43
  vectorField: "vector",
26
44
  dimensions,
27
- filterFields: ["model_kind_userId", "model_kind_threadId"],
45
+ filterFields: ["model_table_userId", "model_table_threadId"],
28
46
  })
29
- .index("model_kind_threadId", ["model", "kind", "threadId"]);
47
+ .index("model_table_threadId", ["model", "table", "threadId"]);
30
48
  }
31
49
 
50
+ export type VectorSchema = SchemaDefinition<
51
+ { [key in VectorTableName]: Table<128> },
52
+ true
53
+ >;
54
+
32
55
  export const VectorDimensions = [
33
56
  128, 256, 512, 768, 1024, 1536, 2048, 3072, 4096,
34
57
  ] as const;
58
+ export function validateVectorDimension(
59
+ dimension: number
60
+ ): asserts dimension is VectorDimension {
61
+ if (!VectorDimensions.includes(dimension as VectorDimension)) {
62
+ throw new Error(
63
+ `Unsupported vector dimension${dimension}. Supported: ${VectorDimensions.join(", ")}`
64
+ );
65
+ }
66
+ }
35
67
  export type VectorDimension = (typeof VectorDimensions)[number];
36
68
  export const VectorTableNames = VectorDimensions.map(
37
69
  (d) => `embeddings_${d}`
package/src/validators.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Infer, v } from "convex/values";
2
+ import { vVectorDimension } from "./component/vector/tables";
2
3
 
3
4
  // const deprecated = v.optional(v.any()) as unknown as VNull<unknown, "optional">;
4
5
 
@@ -243,19 +244,18 @@ export const vStep = v.object({
243
244
  });
244
245
  export type Step = Infer<typeof vStep>;
245
246
 
246
- export const vStepWithMessagesWithFileAndId = v.object({
247
+ export const vStepWithMessages = v.object({
247
248
  step: vStep,
248
249
  messages: v.array(vMessageWithFileAndId),
249
250
  });
250
- export type StepWithMessagesWithFileAndId = Infer<
251
- typeof vStepWithMessagesWithFileAndId
252
- >;
251
+ export type StepWithMessagesWithFileAndId = Infer<typeof vStepWithMessages>;
253
252
 
254
253
  export const vSearchOptions = v.object({
255
254
  vector: v.optional(v.array(v.number())),
256
255
  vectorModel: v.optional(v.string()),
257
256
  text: v.optional(v.string()),
258
257
  limit: v.number(),
258
+ vectorScoreThreshold: v.optional(v.number()),
259
259
  messageRange: v.optional(v.object({ before: v.number(), after: v.number() })),
260
260
  });
261
261
  export type SearchOptions = Infer<typeof vSearchOptions>;
@@ -291,3 +291,10 @@ export const vObjectArgs = v.object({
291
291
  prompt: v.optional(v.string()),
292
292
  messages: v.optional(v.array(vMessage)),
293
293
  });
294
+
295
+ export const vEmbeddingsWithMetadata = v.object({
296
+ vectors: v.array(v.union(v.array(v.number()), v.null())),
297
+ dimension: vVectorDimension,
298
+ model: v.string(),
299
+ });
300
+ export type EmbeddingsWithMetadata = Infer<typeof vEmbeddingsWithMetadata>;