opencode-rag-plugin 1.19.0 → 1.19.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.
- package/ReadMe.md +1 -1
- package/dist/core/config.js +1 -1
- package/dist/embedder/factory.d.ts +10 -3
- package/dist/embedder/factory.js +38 -9
- package/dist/indexer/pipeline.js +3 -3
- package/package.json +1 -1
package/ReadMe.md
CHANGED
|
@@ -55,7 +55,7 @@ opencode-rag query "authentication middleware"
|
|
|
55
55
|
|
|
56
56
|
A browser-based dashboard for exploring the indexed vector database - browse and inspect chunks and evaluate the OpenCode sessions in terms of retrieved chunks, consumed tokens and more.
|
|
57
57
|
|
|
58
|
-

|
|
59
59
|
|
|
60
60
|
Launch with `opencode-rag ui`. See [Web UI documentation](doc/webui.md) for details.
|
|
61
61
|
|
package/dist/core/config.js
CHANGED
|
@@ -16,12 +16,16 @@ import type { RagConfig } from "../core/config.js";
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function createEmbedder(config: RagConfig): EmbeddingProvider;
|
|
18
18
|
/**
|
|
19
|
-
* Embed a list of texts in batches with optional concurrency control.
|
|
19
|
+
* Embed a list of texts in batches with optional concurrency control and per-batch retry.
|
|
20
20
|
*
|
|
21
21
|
* Splits the input texts into chunks of `batchSize` and embeds them sequentially
|
|
22
22
|
* (or concurrently when `concurrency > 1`). When concurrency is limited, uses
|
|
23
23
|
* `p-limit` to cap the number of in-flight requests.
|
|
24
24
|
*
|
|
25
|
+
* Each batch is retried up to `retryMax` times with exponential backoff. If all
|
|
26
|
+
* retries are exhausted, the batch is skipped and empty arrays are returned for
|
|
27
|
+
* those texts so the caller can still process successfully embedded batches.
|
|
28
|
+
*
|
|
25
29
|
* @param embedder - The embedding provider to use
|
|
26
30
|
* @param texts - Array of text strings to embed
|
|
27
31
|
* @param batchSize - Number of texts per batch (default 10)
|
|
@@ -29,6 +33,9 @@ export declare function createEmbedder(config: RagConfig): EmbeddingProvider;
|
|
|
29
33
|
* @param concurrency - Maximum number of concurrent batch requests (default 1)
|
|
30
34
|
* @param onProgress - Optional callback invoked after each batch with the running
|
|
31
35
|
* completed count and total; per-text granularity when `concurrency <= 1`.
|
|
32
|
-
* @
|
|
36
|
+
* @param retryMax - Maximum retry attempts per batch (default 3)
|
|
37
|
+
* @param retryBaseDelayMs - Base delay for exponential backoff (default 1000)
|
|
38
|
+
* @returns A promise resolving to a flat array of embedding vectors (one per input text);
|
|
39
|
+
* failed batches return empty arrays
|
|
33
40
|
*/
|
|
34
|
-
export declare function embedBatch(embedder: EmbeddingProvider, texts: string[], batchSize?: number, purpose?: "query" | "document", concurrency?: number, onProgress?: (completed: number, total: number) => void): Promise<number[][]>;
|
|
41
|
+
export declare function embedBatch(embedder: EmbeddingProvider, texts: string[], batchSize?: number, purpose?: "query" | "document", concurrency?: number, onProgress?: (completed: number, total: number) => void, retryMax?: number, retryBaseDelayMs?: number): Promise<number[][]>;
|
package/dist/embedder/factory.js
CHANGED
|
@@ -35,12 +35,16 @@ export function createEmbedder(config) {
|
|
|
35
35
|
throw new Error(`Unknown embedding provider: ${provider}`);
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
|
-
* Embed a list of texts in batches with optional concurrency control.
|
|
38
|
+
* Embed a list of texts in batches with optional concurrency control and per-batch retry.
|
|
39
39
|
*
|
|
40
40
|
* Splits the input texts into chunks of `batchSize` and embeds them sequentially
|
|
41
41
|
* (or concurrently when `concurrency > 1`). When concurrency is limited, uses
|
|
42
42
|
* `p-limit` to cap the number of in-flight requests.
|
|
43
43
|
*
|
|
44
|
+
* Each batch is retried up to `retryMax` times with exponential backoff. If all
|
|
45
|
+
* retries are exhausted, the batch is skipped and empty arrays are returned for
|
|
46
|
+
* those texts so the caller can still process successfully embedded batches.
|
|
47
|
+
*
|
|
44
48
|
* @param embedder - The embedding provider to use
|
|
45
49
|
* @param texts - Array of text strings to embed
|
|
46
50
|
* @param batchSize - Number of texts per batch (default 10)
|
|
@@ -48,31 +52,56 @@ export function createEmbedder(config) {
|
|
|
48
52
|
* @param concurrency - Maximum number of concurrent batch requests (default 1)
|
|
49
53
|
* @param onProgress - Optional callback invoked after each batch with the running
|
|
50
54
|
* completed count and total; per-text granularity when `concurrency <= 1`.
|
|
51
|
-
* @
|
|
55
|
+
* @param retryMax - Maximum retry attempts per batch (default 3)
|
|
56
|
+
* @param retryBaseDelayMs - Base delay for exponential backoff (default 1000)
|
|
57
|
+
* @returns A promise resolving to a flat array of embedding vectors (one per input text);
|
|
58
|
+
* failed batches return empty arrays
|
|
52
59
|
*/
|
|
53
|
-
export async function embedBatch(embedder, texts, batchSize = 10, purpose, concurrency = 1, onProgress) {
|
|
60
|
+
export async function embedBatch(embedder, texts, batchSize = 10, purpose, concurrency = 1, onProgress, retryMax = 3, retryBaseDelayMs = 1000) {
|
|
54
61
|
if (texts.length === 0)
|
|
55
62
|
return [];
|
|
56
63
|
const batches = [];
|
|
57
64
|
for (let i = 0; i < texts.length; i += batchSize) {
|
|
58
65
|
batches.push({ index: i, texts: texts.slice(i, i + batchSize) });
|
|
59
66
|
}
|
|
67
|
+
async function embedWithRetry(batchTexts) {
|
|
68
|
+
for (let attempt = 0; attempt <= retryMax; attempt++) {
|
|
69
|
+
try {
|
|
70
|
+
return await embedder.embed(batchTexts, purpose);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (attempt < retryMax) {
|
|
74
|
+
const delay = retryBaseDelayMs * Math.pow(2, attempt);
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
60
81
|
if (concurrency <= 1 || batches.length <= 1) {
|
|
61
82
|
const results = [];
|
|
62
83
|
for (const batch of batches) {
|
|
63
|
-
const embeddings = await
|
|
64
|
-
|
|
84
|
+
const embeddings = await embedWithRetry(batch.texts);
|
|
85
|
+
if (embeddings) {
|
|
86
|
+
results.push(...embeddings);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
for (let i = 0; i < batch.texts.length; i++) {
|
|
90
|
+
results.push([]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
65
93
|
onProgress?.(results.length, texts.length);
|
|
66
94
|
}
|
|
67
95
|
return results;
|
|
68
96
|
}
|
|
69
|
-
const limit = pLimit(concurrency);
|
|
70
97
|
let completedCount = 0;
|
|
98
|
+
const limit = pLimit(concurrency);
|
|
71
99
|
const batchResults = await Promise.all(batches.map((batch) => limit(async () => {
|
|
72
|
-
const embeddings = await
|
|
73
|
-
|
|
100
|
+
const embeddings = await embedWithRetry(batch.texts);
|
|
101
|
+
const flatResult = embeddings ?? batch.texts.map(() => []);
|
|
102
|
+
completedCount += embeddings?.length ?? 0;
|
|
74
103
|
onProgress?.(completedCount, texts.length);
|
|
75
|
-
return { index: batch.index, embeddings };
|
|
104
|
+
return { index: batch.index, embeddings: flatResult };
|
|
76
105
|
})));
|
|
77
106
|
batchResults.sort((a, b) => a.index - b.index);
|
|
78
107
|
const results = [];
|
package/dist/indexer/pipeline.js
CHANGED
|
@@ -590,7 +590,7 @@ async function runIndexPassInner(options, logger) {
|
|
|
590
590
|
hash: prepared[fileIdx].hash,
|
|
591
591
|
chunkCount: 0, fileLabel: prepared[fileIdx].fileLabel,
|
|
592
592
|
isNew: false, isModified: false, isUnchanged: false, isEmpty: false,
|
|
593
|
-
isTooSmall: false, isRemoved:
|
|
593
|
+
isTooSmall: false, isRemoved: false, hadChunks: false,
|
|
594
594
|
descriptionFailed: prepared[fileIdx].descriptionFailed,
|
|
595
595
|
});
|
|
596
596
|
}
|
|
@@ -639,14 +639,14 @@ async function runIndexPassInner(options, logger) {
|
|
|
639
639
|
const result = {
|
|
640
640
|
normalizedPath: prep.normalizedPath,
|
|
641
641
|
hash: prep.hash,
|
|
642
|
-
chunkCount:
|
|
642
|
+
chunkCount: validChunks.length,
|
|
643
643
|
fileLabel: prep.fileLabel,
|
|
644
644
|
isNew: !prep.isModified,
|
|
645
645
|
isModified: prep.isModified,
|
|
646
646
|
isUnchanged: false,
|
|
647
647
|
isEmpty: false,
|
|
648
648
|
isTooSmall: false,
|
|
649
|
-
isRemoved: validChunks.length === 0,
|
|
649
|
+
isRemoved: (prep.chunks?.length ?? 0) > 0 && validChunks.length === 0 ? false : validChunks.length === 0,
|
|
650
650
|
hadChunks: (prep.chunks?.length ?? 0) > 0,
|
|
651
651
|
descriptionFailed: prep.descriptionFailed,
|
|
652
652
|
descHash: prep.descHash,
|