@convex-dev/rag 0.5.3 → 0.6.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.
- package/README.md +89 -82
- package/dist/client/index.d.ts +39 -26
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +26 -8
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +100 -481
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js +10 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +380 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +4 -18
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +10 -38
- package/dist/component/_generated/server.d.ts.map +1 -1
- package/dist/component/_generated/server.js +9 -5
- package/dist/component/_generated/server.js.map +1 -1
- package/dist/component/chunks.d.ts +5 -5
- package/dist/component/chunks.d.ts.map +1 -1
- package/dist/component/chunks.js +11 -44
- package/dist/component/chunks.js.map +1 -1
- package/dist/component/embeddings/tables.d.ts +4 -5
- package/dist/component/embeddings/tables.d.ts.map +1 -1
- package/dist/component/embeddings/tables.js.map +1 -1
- package/dist/component/entries.d.ts +6 -6
- package/dist/component/namespaces.d.ts +8 -8
- package/dist/component/namespaces.d.ts.map +1 -1
- package/dist/component/namespaces.js +2 -2
- package/dist/component/namespaces.js.map +1 -1
- package/dist/component/schema.d.ts +185 -224
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/search.d.ts +4 -3
- package/dist/component/search.d.ts.map +1 -1
- package/dist/component/search.js +1 -1
- package/dist/component/search.js.map +1 -1
- package/dist/shared.d.ts +9 -4
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +1 -4
- package/dist/shared.js.map +1 -1
- package/package.json +71 -42
- package/src/client/defaultChunker.test.ts +1 -1
- package/src/client/defaultChunker.ts +7 -7
- package/src/client/fileUtils.ts +3 -3
- package/src/client/hybridRank.ts +1 -1
- package/src/client/index.test.ts +18 -18
- package/src/client/index.ts +135 -90
- package/src/client/setup.test.ts +2 -2
- package/src/component/_generated/api.ts +152 -0
- package/src/component/_generated/component.ts +442 -0
- package/src/component/_generated/{server.d.ts → server.ts} +33 -21
- package/src/component/chunks.test.ts +14 -14
- package/src/component/chunks.ts +49 -82
- package/src/component/embeddings/importance.test.ts +4 -4
- package/src/component/embeddings/importance.ts +1 -1
- package/src/component/embeddings/index.test.ts +3 -4
- package/src/component/embeddings/index.ts +6 -6
- package/src/component/embeddings/tables.ts +9 -8
- package/src/component/entries.test.ts +10 -10
- package/src/component/entries.ts +29 -29
- package/src/component/filters.ts +8 -8
- package/src/component/namespaces.ts +31 -34
- package/src/component/schema.ts +2 -2
- package/src/component/search.test.ts +5 -5
- package/src/component/search.ts +8 -9
- package/src/component/setup.test.ts +2 -8
- package/src/shared.ts +47 -45
- package/src/test.ts +20 -0
- package/dist/client/types.d.ts +0 -29
- package/dist/client/types.d.ts.map +0 -1
- package/dist/client/types.js +0 -2
- package/dist/client/types.js.map +0 -1
- package/dist/package.json +0 -3
- package/src/client/types.ts +0 -69
- package/src/component/_generated/api.d.ts +0 -507
- package/src/component/_generated/api.js +0 -23
- package/src/component/_generated/server.js +0 -90
- package/src/vitest.config.ts +0 -7
- /package/src/component/_generated/{dataModel.d.ts → dataModel.ts} +0 -0
package/src/client/index.ts
CHANGED
|
@@ -2,13 +2,14 @@ import {
|
|
|
2
2
|
embed,
|
|
3
3
|
embedMany,
|
|
4
4
|
generateText,
|
|
5
|
-
type ModelMessage,
|
|
6
5
|
type EmbeddingModel,
|
|
7
6
|
type EmbeddingModelUsage,
|
|
7
|
+
type ModelMessage,
|
|
8
8
|
} from "ai";
|
|
9
9
|
import { assert } from "convex-helpers";
|
|
10
10
|
import {
|
|
11
11
|
createFunctionHandle,
|
|
12
|
+
FunctionReference,
|
|
12
13
|
internalActionGeneric,
|
|
13
14
|
internalMutationGeneric,
|
|
14
15
|
type FunctionArgs,
|
|
@@ -23,36 +24,30 @@ import {
|
|
|
23
24
|
type RegisteredMutation,
|
|
24
25
|
} from "convex/server";
|
|
25
26
|
import { type Value } from "convex/values";
|
|
27
|
+
import { ComponentApi } from "../component/_generated/component.js";
|
|
28
|
+
import type { NamedFilter } from "../component/filters.js";
|
|
26
29
|
import {
|
|
27
30
|
CHUNK_BATCH_SIZE,
|
|
28
31
|
filterNamesContain,
|
|
32
|
+
OnCompleteArgs,
|
|
29
33
|
vChunkerArgs,
|
|
30
34
|
vEntryId,
|
|
31
35
|
vNamespaceId,
|
|
32
36
|
vOnCompleteArgs,
|
|
33
37
|
type Chunk,
|
|
38
|
+
type ChunkerAction,
|
|
34
39
|
type CreateChunkArgs,
|
|
35
40
|
type Entry,
|
|
36
41
|
type EntryFilter,
|
|
37
42
|
type EntryId,
|
|
38
43
|
type Namespace,
|
|
39
44
|
type NamespaceId,
|
|
45
|
+
type OnComplete,
|
|
46
|
+
type OnCompleteNamespace,
|
|
40
47
|
type SearchEntry,
|
|
41
48
|
type SearchResult,
|
|
42
49
|
type Status,
|
|
43
50
|
} from "../shared.js";
|
|
44
|
-
import {
|
|
45
|
-
type RAGComponent,
|
|
46
|
-
type RunActionCtx,
|
|
47
|
-
type RunMutationCtx,
|
|
48
|
-
type RunQueryCtx,
|
|
49
|
-
} from "./types.js";
|
|
50
|
-
import {
|
|
51
|
-
type ChunkerAction,
|
|
52
|
-
type OnComplete,
|
|
53
|
-
type OnCompleteNamespace,
|
|
54
|
-
} from "../shared.js";
|
|
55
|
-
import type { NamedFilter } from "../component/filters.js";
|
|
56
51
|
import { defaultChunker } from "./defaultChunker.js";
|
|
57
52
|
|
|
58
53
|
export { hybridRank } from "./hybridRank.js";
|
|
@@ -61,7 +56,6 @@ export type {
|
|
|
61
56
|
ChunkerAction,
|
|
62
57
|
Entry,
|
|
63
58
|
EntryId,
|
|
64
|
-
RAGComponent,
|
|
65
59
|
NamespaceId,
|
|
66
60
|
OnComplete,
|
|
67
61
|
OnCompleteNamespace,
|
|
@@ -71,18 +65,18 @@ export type {
|
|
|
71
65
|
};
|
|
72
66
|
|
|
73
67
|
export {
|
|
74
|
-
type VEntry,
|
|
75
|
-
type VSearchEntry,
|
|
76
|
-
type EntryFilter,
|
|
77
68
|
vEntry,
|
|
69
|
+
vOnCompleteArgs,
|
|
78
70
|
vSearchEntry,
|
|
79
71
|
vSearchResult,
|
|
80
|
-
|
|
72
|
+
type EntryFilter,
|
|
73
|
+
type VEntry,
|
|
74
|
+
type VSearchEntry,
|
|
81
75
|
} from "../shared.js";
|
|
82
76
|
export {
|
|
83
77
|
contentHashFromArrayBuffer,
|
|
84
|
-
guessMimeTypeFromExtension,
|
|
85
78
|
guessMimeTypeFromContents,
|
|
79
|
+
guessMimeTypeFromExtension,
|
|
86
80
|
} from "./fileUtils.js";
|
|
87
81
|
|
|
88
82
|
const DEFAULT_SEARCH_LIMIT = 10;
|
|
@@ -115,12 +109,12 @@ export class RAG<
|
|
|
115
109
|
* and then entry results will have the metadata type `{ source: "website" }`.
|
|
116
110
|
*/
|
|
117
111
|
constructor(
|
|
118
|
-
public component:
|
|
112
|
+
public component: ComponentApi,
|
|
119
113
|
public options: {
|
|
120
114
|
embeddingDimension: number;
|
|
121
115
|
textEmbeddingModel: EmbeddingModel<string>;
|
|
122
116
|
filterNames?: FilterNames<FitlerSchemas>;
|
|
123
|
-
}
|
|
117
|
+
},
|
|
124
118
|
) {}
|
|
125
119
|
|
|
126
120
|
/**
|
|
@@ -134,7 +128,7 @@ export class RAG<
|
|
|
134
128
|
* The filterValues you provide can be used later to search for it.
|
|
135
129
|
*/
|
|
136
130
|
async add(
|
|
137
|
-
ctx:
|
|
131
|
+
ctx: CtxWith<"runMutation">,
|
|
138
132
|
args: NamespaceSelection &
|
|
139
133
|
EntryArgs<FitlerSchemas, EntryMetadata> &
|
|
140
134
|
(
|
|
@@ -158,7 +152,7 @@ export class RAG<
|
|
|
158
152
|
/** @deprecated You cannot specify both chunks and text currently. */
|
|
159
153
|
chunks?: undefined;
|
|
160
154
|
}
|
|
161
|
-
)
|
|
155
|
+
),
|
|
162
156
|
): Promise<{
|
|
163
157
|
entryId: EntryId;
|
|
164
158
|
status: Status;
|
|
@@ -185,7 +179,7 @@ export class RAG<
|
|
|
185
179
|
if (Array.isArray(chunks) && chunks.length < CHUNK_BATCH_SIZE) {
|
|
186
180
|
const result = await createChunkArgsBatch(
|
|
187
181
|
this.options.textEmbeddingModel,
|
|
188
|
-
chunks
|
|
182
|
+
chunks,
|
|
189
183
|
);
|
|
190
184
|
allChunks = result.chunks;
|
|
191
185
|
totalUsage.tokens += result.usage.tokens;
|
|
@@ -208,7 +202,7 @@ export class RAG<
|
|
|
208
202
|
},
|
|
209
203
|
onComplete,
|
|
210
204
|
allChunks,
|
|
211
|
-
}
|
|
205
|
+
},
|
|
212
206
|
);
|
|
213
207
|
if (status === "ready") {
|
|
214
208
|
return {
|
|
@@ -230,7 +224,7 @@ export class RAG<
|
|
|
230
224
|
for await (const batch of batchIterator(chunks, CHUNK_BATCH_SIZE)) {
|
|
231
225
|
const result = await createChunkArgsBatch(
|
|
232
226
|
this.options.textEmbeddingModel,
|
|
233
|
-
batch
|
|
227
|
+
batch,
|
|
234
228
|
);
|
|
235
229
|
totalUsage.tokens += result.usage.tokens;
|
|
236
230
|
const { status } = await ctx.runMutation(this.component.chunks.insert, {
|
|
@@ -250,7 +244,7 @@ export class RAG<
|
|
|
250
244
|
while (true) {
|
|
251
245
|
const { status, nextStartOrder } = await ctx.runMutation(
|
|
252
246
|
this.component.chunks.replaceChunksPage,
|
|
253
|
-
{ entryId, startOrder }
|
|
247
|
+
{ entryId, startOrder },
|
|
254
248
|
);
|
|
255
249
|
if (status === "ready") {
|
|
256
250
|
break;
|
|
@@ -268,7 +262,7 @@ export class RAG<
|
|
|
268
262
|
}
|
|
269
263
|
const promoted = await ctx.runMutation(
|
|
270
264
|
this.component.entries.promoteToReady,
|
|
271
|
-
{ entryId }
|
|
265
|
+
{ entryId },
|
|
272
266
|
);
|
|
273
267
|
return {
|
|
274
268
|
entryId: entryId as EntryId,
|
|
@@ -306,7 +300,7 @@ export class RAG<
|
|
|
306
300
|
* ```
|
|
307
301
|
*/
|
|
308
302
|
async addAsync(
|
|
309
|
-
ctx:
|
|
303
|
+
ctx: CtxWith<"runMutation">,
|
|
310
304
|
args: NamespaceSelection &
|
|
311
305
|
EntryArgs<FitlerSchemas, EntryMetadata> & {
|
|
312
306
|
/**
|
|
@@ -324,7 +318,7 @@ export class RAG<
|
|
|
324
318
|
* });
|
|
325
319
|
*/
|
|
326
320
|
chunkerAction: ChunkerAction;
|
|
327
|
-
}
|
|
321
|
+
},
|
|
328
322
|
): Promise<{ entryId: EntryId; status: "ready" | "pending" }> {
|
|
329
323
|
let namespaceId: NamespaceId;
|
|
330
324
|
if ("namespaceId" in args) {
|
|
@@ -358,7 +352,7 @@ export class RAG<
|
|
|
358
352
|
},
|
|
359
353
|
onComplete,
|
|
360
354
|
chunker,
|
|
361
|
-
}
|
|
355
|
+
},
|
|
362
356
|
);
|
|
363
357
|
return { entryId: entryId as EntryId, status };
|
|
364
358
|
}
|
|
@@ -369,7 +363,7 @@ export class RAG<
|
|
|
369
363
|
* parameters to filter and constrain the results.
|
|
370
364
|
*/
|
|
371
365
|
async search(
|
|
372
|
-
ctx:
|
|
366
|
+
ctx: CtxWith<"runAction">,
|
|
373
367
|
args: {
|
|
374
368
|
/**
|
|
375
369
|
* The namespace to search in. e.g. a userId if entries are per-user.
|
|
@@ -381,7 +375,7 @@ export class RAG<
|
|
|
381
375
|
* The query to search for. Optional if embedding is provided.
|
|
382
376
|
*/
|
|
383
377
|
query: string | Array<number>;
|
|
384
|
-
} & SearchOptions<FitlerSchemas
|
|
378
|
+
} & SearchOptions<FitlerSchemas>,
|
|
385
379
|
): Promise<{
|
|
386
380
|
results: SearchResult[];
|
|
387
381
|
text: string;
|
|
@@ -410,12 +404,12 @@ export class RAG<
|
|
|
410
404
|
{
|
|
411
405
|
embedding,
|
|
412
406
|
namespace,
|
|
413
|
-
modelId: this.options.textEmbeddingModel
|
|
407
|
+
modelId: getModelId(this.options.textEmbeddingModel),
|
|
414
408
|
filters,
|
|
415
409
|
limit,
|
|
416
410
|
vectorScoreThreshold,
|
|
417
411
|
chunkContext,
|
|
418
|
-
}
|
|
412
|
+
},
|
|
419
413
|
);
|
|
420
414
|
const entriesWithTexts = entries.map((e) => {
|
|
421
415
|
const ranges = results
|
|
@@ -458,7 +452,7 @@ export class RAG<
|
|
|
458
452
|
* extra context / conversation history.
|
|
459
453
|
*/
|
|
460
454
|
async generateText(
|
|
461
|
-
ctx:
|
|
455
|
+
ctx: CtxWith<"runAction">,
|
|
462
456
|
args: {
|
|
463
457
|
/**
|
|
464
458
|
* The search options to use for context search, including the namespace.
|
|
@@ -485,7 +479,7 @@ export class RAG<
|
|
|
485
479
|
* to the prompt, in which case it will precede the prompt.
|
|
486
480
|
*/
|
|
487
481
|
messages?: ModelMessage[];
|
|
488
|
-
} & Parameters<typeof generateText>[0]
|
|
482
|
+
} & Parameters<typeof generateText>[0],
|
|
489
483
|
): Promise<
|
|
490
484
|
Awaited<ReturnType<typeof generateText>> & {
|
|
491
485
|
context: {
|
|
@@ -530,7 +524,7 @@ export class RAG<
|
|
|
530
524
|
.map((e) =>
|
|
531
525
|
e.title
|
|
532
526
|
? `<document title="${e.title}">${e.text}</document>`
|
|
533
|
-
: `<document>${e.text}</document
|
|
527
|
+
: `<document>${e.text}</document>`,
|
|
534
528
|
)
|
|
535
529
|
.join("\n");
|
|
536
530
|
contextFooter = "</context>";
|
|
@@ -576,12 +570,12 @@ export class RAG<
|
|
|
576
570
|
* List all entries in a namespace.
|
|
577
571
|
*/
|
|
578
572
|
async list(
|
|
579
|
-
ctx:
|
|
573
|
+
ctx: CtxWith<"runQuery">,
|
|
580
574
|
args: {
|
|
581
575
|
namespaceId?: NamespaceId;
|
|
582
576
|
order?: "desc" | "asc";
|
|
583
577
|
status?: Status;
|
|
584
|
-
} & ({ paginationOpts: PaginationOptions } | { limit: number })
|
|
578
|
+
} & ({ paginationOpts: PaginationOptions } | { limit: number }),
|
|
585
579
|
): Promise<PaginationResult<Entry<FitlerSchemas, EntryMetadata>>> {
|
|
586
580
|
const paginationOpts =
|
|
587
581
|
"paginationOpts" in args
|
|
@@ -600,10 +594,10 @@ export class RAG<
|
|
|
600
594
|
* Get entry metadata by its id.
|
|
601
595
|
*/
|
|
602
596
|
async getEntry(
|
|
603
|
-
ctx:
|
|
597
|
+
ctx: CtxWith<"runQuery">,
|
|
604
598
|
args: {
|
|
605
599
|
entryId: EntryId;
|
|
606
|
-
}
|
|
600
|
+
},
|
|
607
601
|
): Promise<Entry<FitlerSchemas, EntryMetadata> | null> {
|
|
608
602
|
const entry = await ctx.runQuery(this.component.entries.get, {
|
|
609
603
|
entryId: args.entryId,
|
|
@@ -617,19 +611,19 @@ export class RAG<
|
|
|
617
611
|
* when updating content.
|
|
618
612
|
*/
|
|
619
613
|
async findEntryByContentHash(
|
|
620
|
-
ctx:
|
|
614
|
+
ctx: CtxWith<"runQuery">,
|
|
621
615
|
args: {
|
|
622
616
|
namespace: string;
|
|
623
617
|
key: string;
|
|
624
618
|
/** The hash of the entry contents to try to match. */
|
|
625
619
|
contentHash: string;
|
|
626
|
-
}
|
|
620
|
+
},
|
|
627
621
|
): Promise<Entry<FitlerSchemas, EntryMetadata> | null> {
|
|
628
622
|
const entry = await ctx.runQuery(this.component.entries.findByContentHash, {
|
|
629
623
|
namespace: args.namespace,
|
|
630
624
|
dimension: this.options.embeddingDimension,
|
|
631
625
|
filterNames: this.options.filterNames ?? [],
|
|
632
|
-
modelId: this.options.textEmbeddingModel
|
|
626
|
+
modelId: getModelId(this.options.textEmbeddingModel),
|
|
633
627
|
key: args.key,
|
|
634
628
|
contentHash: args.contentHash,
|
|
635
629
|
});
|
|
@@ -641,7 +635,7 @@ export class RAG<
|
|
|
641
635
|
* filterNames of the RAG instance. If it doesn't exist, it will be created.
|
|
642
636
|
*/
|
|
643
637
|
async getOrCreateNamespace(
|
|
644
|
-
ctx:
|
|
638
|
+
ctx: CtxWith<"runMutation">,
|
|
645
639
|
args: {
|
|
646
640
|
/**
|
|
647
641
|
* The namespace to get or create. e.g. a userId if entries are per-user.
|
|
@@ -657,7 +651,7 @@ export class RAG<
|
|
|
657
651
|
* along the way.
|
|
658
652
|
*/
|
|
659
653
|
onComplete?: OnCompleteNamespace;
|
|
660
|
-
}
|
|
654
|
+
},
|
|
661
655
|
): Promise<{
|
|
662
656
|
namespaceId: NamespaceId;
|
|
663
657
|
status: "pending" | "ready";
|
|
@@ -667,7 +661,7 @@ export class RAG<
|
|
|
667
661
|
: undefined;
|
|
668
662
|
assert(
|
|
669
663
|
!onComplete || args.status === "pending",
|
|
670
|
-
"You can only supply an onComplete handler for pending namespaces"
|
|
664
|
+
"You can only supply an onComplete handler for pending namespaces",
|
|
671
665
|
);
|
|
672
666
|
const { namespaceId, status } = await ctx.runMutation(
|
|
673
667
|
this.component.namespaces.getOrCreate,
|
|
@@ -675,10 +669,10 @@ export class RAG<
|
|
|
675
669
|
namespace: args.namespace,
|
|
676
670
|
status: args.status ?? "ready",
|
|
677
671
|
onComplete,
|
|
678
|
-
modelId: this.options.textEmbeddingModel
|
|
672
|
+
modelId: getModelId(this.options.textEmbeddingModel),
|
|
679
673
|
dimension: this.options.embeddingDimension,
|
|
680
674
|
filterNames: this.options.filterNames ?? [],
|
|
681
|
-
}
|
|
675
|
+
},
|
|
682
676
|
);
|
|
683
677
|
return { namespaceId: namespaceId as NamespaceId, status };
|
|
684
678
|
}
|
|
@@ -688,14 +682,14 @@ export class RAG<
|
|
|
688
682
|
* filterNames of the RAG instance. If it doesn't exist, it will return null.
|
|
689
683
|
*/
|
|
690
684
|
async getNamespace(
|
|
691
|
-
ctx:
|
|
685
|
+
ctx: CtxWith<"runQuery">,
|
|
692
686
|
args: {
|
|
693
687
|
namespace: string;
|
|
694
|
-
}
|
|
688
|
+
},
|
|
695
689
|
): Promise<Namespace | null> {
|
|
696
690
|
return ctx.runQuery(this.component.namespaces.get, {
|
|
697
691
|
namespace: args.namespace,
|
|
698
|
-
modelId: this.options.textEmbeddingModel
|
|
692
|
+
modelId: getModelId(this.options.textEmbeddingModel),
|
|
699
693
|
dimension: this.options.embeddingDimension,
|
|
700
694
|
filterNames: this.options.filterNames ?? [],
|
|
701
695
|
}) as Promise<Namespace | null>;
|
|
@@ -705,12 +699,12 @@ export class RAG<
|
|
|
705
699
|
* List all chunks for an entry, paginated.
|
|
706
700
|
*/
|
|
707
701
|
async listChunks(
|
|
708
|
-
ctx:
|
|
702
|
+
ctx: CtxWith<"runQuery">,
|
|
709
703
|
args: {
|
|
710
704
|
paginationOpts: PaginationOptions;
|
|
711
705
|
entryId: EntryId;
|
|
712
706
|
order?: "desc" | "asc";
|
|
713
|
-
}
|
|
707
|
+
},
|
|
714
708
|
): Promise<PaginationResult<Chunk>> {
|
|
715
709
|
return ctx.runQuery(this.component.chunks.list, {
|
|
716
710
|
entryId: args.entryId,
|
|
@@ -722,7 +716,7 @@ export class RAG<
|
|
|
722
716
|
/**
|
|
723
717
|
* Delete an entry and all its chunks in the background using a workpool.
|
|
724
718
|
*/
|
|
725
|
-
async deleteAsync(ctx:
|
|
719
|
+
async deleteAsync(ctx: CtxWith<"runMutation">, args: { entryId: EntryId }) {
|
|
726
720
|
await ctx.runMutation(this.component.entries.deleteAsync, {
|
|
727
721
|
entryId: args.entryId,
|
|
728
722
|
startOrder: 0,
|
|
@@ -735,17 +729,26 @@ export class RAG<
|
|
|
735
729
|
* you're likely running this in a mutation.
|
|
736
730
|
* Use `deleteAsync` or run `delete` in an action.
|
|
737
731
|
*/
|
|
738
|
-
async delete(
|
|
732
|
+
async delete(
|
|
733
|
+
ctx: CtxWith<"runAction">,
|
|
734
|
+
args: { entryId: EntryId },
|
|
735
|
+
): Promise<void>;
|
|
739
736
|
/** @deprecated Use `deleteAsync` in mutations. */
|
|
740
|
-
async delete(
|
|
741
|
-
|
|
737
|
+
async delete(
|
|
738
|
+
ctx: CtxWith<"runMutation">,
|
|
739
|
+
args: { entryId: EntryId },
|
|
740
|
+
): Promise<void>;
|
|
741
|
+
async delete(
|
|
742
|
+
ctx: CtxWith<"runMutation"> | CtxWith<"runAction">,
|
|
743
|
+
args: { entryId: EntryId },
|
|
744
|
+
) {
|
|
742
745
|
if ("runAction" in ctx) {
|
|
743
746
|
await ctx.runAction(this.component.entries.deleteSync, {
|
|
744
747
|
entryId: args.entryId,
|
|
745
748
|
});
|
|
746
749
|
} else {
|
|
747
750
|
console.warn(
|
|
748
|
-
"You are running `rag.delete` in a mutation. This is deprecated. Use `rag.deleteAsync` from mutations, or `rag.delete` in actions."
|
|
751
|
+
"You are running `rag.delete` in a mutation. This is deprecated. Use `rag.deleteAsync` from mutations, or `rag.delete` in actions.",
|
|
749
752
|
);
|
|
750
753
|
await ctx.runMutation(this.component.entries.deleteAsync, {
|
|
751
754
|
entryId: args.entryId,
|
|
@@ -758,8 +761,8 @@ export class RAG<
|
|
|
758
761
|
* Delete all entries with a given key (asynchrounously).
|
|
759
762
|
*/
|
|
760
763
|
async deleteByKeyAsync(
|
|
761
|
-
ctx:
|
|
762
|
-
args: { namespaceId: NamespaceId; key: string; beforeVersion?: number }
|
|
764
|
+
ctx: CtxWith<"runMutation">,
|
|
765
|
+
args: { namespaceId: NamespaceId; key: string; beforeVersion?: number },
|
|
763
766
|
) {
|
|
764
767
|
await ctx.runMutation(this.component.entries.deleteByKeyAsync, {
|
|
765
768
|
namespaceId: args.namespaceId,
|
|
@@ -775,8 +778,8 @@ export class RAG<
|
|
|
775
778
|
* Use `deleteByKeyAsync` or run `delete` in an action.
|
|
776
779
|
*/
|
|
777
780
|
async deleteByKey(
|
|
778
|
-
ctx:
|
|
779
|
-
args: { namespaceId: NamespaceId; key: string; beforeVersion?: number }
|
|
781
|
+
ctx: CtxWith<"runAction">,
|
|
782
|
+
args: { namespaceId: NamespaceId; key: string; beforeVersion?: number },
|
|
780
783
|
) {
|
|
781
784
|
await ctx.runAction(this.component.entries.deleteByKeySync, args);
|
|
782
785
|
}
|
|
@@ -802,13 +805,9 @@ export class RAG<
|
|
|
802
805
|
defineOnComplete<DataModel extends GenericDataModel>(
|
|
803
806
|
fn: (
|
|
804
807
|
ctx: GenericMutationCtx<DataModel>,
|
|
805
|
-
args:
|
|
806
|
-
) => Promise<void
|
|
807
|
-
): RegisteredMutation<
|
|
808
|
-
"internal",
|
|
809
|
-
FunctionArgs<OnComplete<FitlerSchemas, EntryMetadata>>,
|
|
810
|
-
null
|
|
811
|
-
> {
|
|
808
|
+
args: OnCompleteArgs<FitlerSchemas, EntryMetadata>,
|
|
809
|
+
) => Promise<void>,
|
|
810
|
+
): RegisteredMutation<"internal", FunctionArgs<OnComplete>, null> {
|
|
812
811
|
return internalMutationGeneric({
|
|
813
812
|
args: vOnCompleteArgs,
|
|
814
813
|
handler: fn,
|
|
@@ -836,8 +835,11 @@ export class RAG<
|
|
|
836
835
|
defineChunkerAction<DataModel extends GenericDataModel>(
|
|
837
836
|
fn: (
|
|
838
837
|
ctx: GenericActionCtx<DataModel>,
|
|
839
|
-
args: {
|
|
840
|
-
|
|
838
|
+
args: {
|
|
839
|
+
namespace: Namespace;
|
|
840
|
+
entry: Entry<FitlerSchemas, EntryMetadata>;
|
|
841
|
+
},
|
|
842
|
+
) => AsyncIterable<InputChunk> | Promise<{ chunks: InputChunk[] }>,
|
|
841
843
|
): RegisteredAction<
|
|
842
844
|
"internal",
|
|
843
845
|
FunctionArgs<ChunkerAction>,
|
|
@@ -847,29 +849,30 @@ export class RAG<
|
|
|
847
849
|
args: vChunkerArgs,
|
|
848
850
|
handler: async (ctx, args) => {
|
|
849
851
|
const { namespace, entry } = args;
|
|
850
|
-
|
|
852
|
+
const modelId = getModelId(this.options.textEmbeddingModel);
|
|
853
|
+
if (namespace.modelId !== modelId) {
|
|
851
854
|
console.error(
|
|
852
|
-
`You are using a different embedding model ${
|
|
853
|
-
`generating chunks than the one provided when it was started: ${namespace.modelId}
|
|
855
|
+
`You are using a different embedding model ${modelId} for asynchronously ` +
|
|
856
|
+
`generating chunks than the one provided when it was started: ${namespace.modelId}`,
|
|
854
857
|
);
|
|
855
858
|
return;
|
|
856
859
|
}
|
|
857
860
|
if (namespace.dimension !== this.options.embeddingDimension) {
|
|
858
861
|
console.error(
|
|
859
862
|
`You are using a different embedding dimension ${this.options.embeddingDimension} for asynchronously ` +
|
|
860
|
-
`generating chunks than the one provided when it was started: ${namespace.dimension}
|
|
863
|
+
`generating chunks than the one provided when it was started: ${namespace.dimension}`,
|
|
861
864
|
);
|
|
862
865
|
return;
|
|
863
866
|
}
|
|
864
867
|
if (
|
|
865
868
|
!filterNamesContain(
|
|
866
869
|
namespace.filterNames,
|
|
867
|
-
this.options.filterNames ?? []
|
|
870
|
+
this.options.filterNames ?? [],
|
|
868
871
|
)
|
|
869
872
|
) {
|
|
870
873
|
console.error(
|
|
871
874
|
`You are using a different filters (${this.options.filterNames?.join(", ")}) for asynchronously ` +
|
|
872
|
-
`generating chunks than the one provided when it was started: ${namespace.filterNames.join(", ")}
|
|
875
|
+
`generating chunks than the one provided when it was started: ${namespace.filterNames.join(", ")}`,
|
|
873
876
|
);
|
|
874
877
|
return;
|
|
875
878
|
}
|
|
@@ -891,23 +894,23 @@ export class RAG<
|
|
|
891
894
|
let batchOrder = 0;
|
|
892
895
|
for await (const batch of batchIterator(
|
|
893
896
|
chunkIterator,
|
|
894
|
-
CHUNK_BATCH_SIZE
|
|
897
|
+
CHUNK_BATCH_SIZE,
|
|
895
898
|
)) {
|
|
896
899
|
const result = await createChunkArgsBatch(
|
|
897
900
|
this.options.textEmbeddingModel,
|
|
898
|
-
batch
|
|
901
|
+
batch,
|
|
899
902
|
);
|
|
900
903
|
await ctx.runMutation(
|
|
901
904
|
args.insertChunks as FunctionHandle<
|
|
902
905
|
"mutation",
|
|
903
|
-
FunctionArgs<
|
|
906
|
+
FunctionArgs<ComponentApi["chunks"]["insert"]>,
|
|
904
907
|
null
|
|
905
908
|
>,
|
|
906
909
|
{
|
|
907
910
|
entryId: entry.entryId,
|
|
908
911
|
startOrder: batchOrder,
|
|
909
912
|
chunks: result.chunks,
|
|
910
|
-
}
|
|
913
|
+
},
|
|
911
914
|
);
|
|
912
915
|
batchOrder += result.chunks.length;
|
|
913
916
|
}
|
|
@@ -918,7 +921,7 @@ export class RAG<
|
|
|
918
921
|
|
|
919
922
|
async function* batchIterator<T>(
|
|
920
923
|
iterator: Iterable<T> | AsyncIterable<T>,
|
|
921
|
-
batchSize: number
|
|
924
|
+
batchSize: number,
|
|
922
925
|
): AsyncIterable<T[]> {
|
|
923
926
|
let batch: T[] = [];
|
|
924
927
|
for await (const item of iterator) {
|
|
@@ -935,21 +938,21 @@ async function* batchIterator<T>(
|
|
|
935
938
|
|
|
936
939
|
function validateAddFilterValues(
|
|
937
940
|
filterValues: NamedFilter[] | undefined,
|
|
938
|
-
filterNames: string[] | undefined
|
|
941
|
+
filterNames: string[] | undefined,
|
|
939
942
|
) {
|
|
940
943
|
if (!filterValues) {
|
|
941
944
|
return;
|
|
942
945
|
}
|
|
943
946
|
if (!filterNames) {
|
|
944
947
|
throw new Error(
|
|
945
|
-
"You must provide filter names to RAG to add entries with filters."
|
|
948
|
+
"You must provide filter names to RAG to add entries with filters.",
|
|
946
949
|
);
|
|
947
950
|
}
|
|
948
951
|
const seen = new Set<string>();
|
|
949
952
|
for (const filterValue of filterValues) {
|
|
950
953
|
if (seen.has(filterValue.name)) {
|
|
951
954
|
throw new Error(
|
|
952
|
-
`You cannot provide the same filter name twice: ${filterValue.name}
|
|
955
|
+
`You cannot provide the same filter name twice: ${filterValue.name}.`,
|
|
953
956
|
);
|
|
954
957
|
}
|
|
955
958
|
seen.add(filterValue.name);
|
|
@@ -957,7 +960,7 @@ function validateAddFilterValues(
|
|
|
957
960
|
for (const filterName of filterNames) {
|
|
958
961
|
if (!seen.has(filterName)) {
|
|
959
962
|
throw new Error(
|
|
960
|
-
`Filter name ${filterName} is not valid (one of ${filterNames.join(", ")})
|
|
963
|
+
`Filter name ${filterName} is not valid (one of ${filterNames.join(", ")}).`,
|
|
961
964
|
);
|
|
962
965
|
}
|
|
963
966
|
}
|
|
@@ -973,7 +976,7 @@ function makeBatches<T>(items: T[], batchSize: number): T[][] {
|
|
|
973
976
|
|
|
974
977
|
async function createChunkArgsBatch(
|
|
975
978
|
embedModel: EmbeddingModel<string>,
|
|
976
|
-
chunks: InputChunk[]
|
|
979
|
+
chunks: InputChunk[],
|
|
977
980
|
): Promise<{ chunks: CreateChunkArgs[]; usage: EmbeddingModelUsage }> {
|
|
978
981
|
const argsMaybeMissingEmbeddings: (Omit<CreateChunkArgs, "embedding"> & {
|
|
979
982
|
embedding?: number[];
|
|
@@ -1005,7 +1008,7 @@ async function createChunkArgsBatch(
|
|
|
1005
1008
|
: {
|
|
1006
1009
|
text: arg.content.text,
|
|
1007
1010
|
index,
|
|
1008
|
-
}
|
|
1011
|
+
},
|
|
1009
1012
|
)
|
|
1010
1013
|
.filter((b) => b !== null);
|
|
1011
1014
|
const totalUsage: EmbeddingModelUsage = { tokens: 0 };
|
|
@@ -1191,3 +1194,45 @@ function getModelCategory(model: string | { provider: string }) {
|
|
|
1191
1194
|
}
|
|
1192
1195
|
return model;
|
|
1193
1196
|
}
|
|
1197
|
+
|
|
1198
|
+
// fetch metadata from either a string or EmbeddingModelV2 or LanguageModelV2
|
|
1199
|
+
export type ModelOrMetadata =
|
|
1200
|
+
| string
|
|
1201
|
+
| ({ provider: string } & ({ modelId: string } | { model: string }));
|
|
1202
|
+
|
|
1203
|
+
export function getModelId(embeddingModel: ModelOrMetadata): string {
|
|
1204
|
+
if (typeof embeddingModel === "string") {
|
|
1205
|
+
if (embeddingModel.includes("/")) {
|
|
1206
|
+
return embeddingModel.split("/").slice(1).join("/");
|
|
1207
|
+
}
|
|
1208
|
+
return embeddingModel;
|
|
1209
|
+
}
|
|
1210
|
+
return "modelId" in embeddingModel
|
|
1211
|
+
? embeddingModel.modelId
|
|
1212
|
+
: embeddingModel.model;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
export function getProviderName(embeddingModel: ModelOrMetadata): string {
|
|
1216
|
+
if (typeof embeddingModel === "string") {
|
|
1217
|
+
return embeddingModel.split("/").at(0)!;
|
|
1218
|
+
}
|
|
1219
|
+
return embeddingModel.provider;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
type CtxWith<T extends "runQuery" | "runMutation" | "runAction"> = Pick<
|
|
1223
|
+
{
|
|
1224
|
+
runQuery: <Query extends FunctionReference<"query", "internal">>(
|
|
1225
|
+
query: Query,
|
|
1226
|
+
args: FunctionArgs<Query>,
|
|
1227
|
+
) => Promise<FunctionReturnType<Query>>;
|
|
1228
|
+
runMutation: <Mutation extends FunctionReference<"mutation", "internal">>(
|
|
1229
|
+
mutation: Mutation,
|
|
1230
|
+
args: FunctionArgs<Mutation>,
|
|
1231
|
+
) => Promise<FunctionReturnType<Mutation>>;
|
|
1232
|
+
runAction: <Action extends FunctionReference<"action", "internal">>(
|
|
1233
|
+
action: Action,
|
|
1234
|
+
args: FunctionArgs<Action>,
|
|
1235
|
+
) => Promise<FunctionReturnType<Action>>;
|
|
1236
|
+
},
|
|
1237
|
+
T
|
|
1238
|
+
>;
|
package/src/client/setup.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type GenericSchema,
|
|
9
9
|
type SchemaDefinition,
|
|
10
10
|
} from "convex/server";
|
|
11
|
-
import { type
|
|
11
|
+
import { type ComponentApi } from "../component/_generated/component.js";
|
|
12
12
|
import { componentsGeneric } from "convex/server";
|
|
13
13
|
import componentSchema from "../component/schema.js";
|
|
14
14
|
export { componentSchema };
|
|
@@ -22,7 +22,7 @@ export function initConvexTest<
|
|
|
22
22
|
return t;
|
|
23
23
|
}
|
|
24
24
|
export const components = componentsGeneric() as unknown as {
|
|
25
|
-
rag:
|
|
25
|
+
rag: ComponentApi;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
test("setup", () => {});
|