memory-lancedb-pro 1.0.24 → 1.0.25
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/index.ts +16 -5
- package/openclaw.plugin.json +13 -3
- package/package.json +1 -1
- package/src/embedder.ts +32 -10
package/index.ts
CHANGED
|
@@ -743,11 +743,22 @@ function parsePluginConfig(value: unknown): PluginConfig {
|
|
|
743
743
|
}
|
|
744
744
|
|
|
745
745
|
// Accept single key (string) or array of keys for round-robin rotation
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
746
|
+
let apiKey: string | string[];
|
|
747
|
+
if (typeof embedding.apiKey === "string") {
|
|
748
|
+
apiKey = embedding.apiKey;
|
|
749
|
+
} else if (Array.isArray(embedding.apiKey) && embedding.apiKey.length > 0) {
|
|
750
|
+
// Validate every element is a non-empty string
|
|
751
|
+
const invalid = embedding.apiKey.findIndex((k: unknown) => typeof k !== "string" || (k as string).trim().length === 0);
|
|
752
|
+
if (invalid !== -1) {
|
|
753
|
+
throw new Error(`embedding.apiKey[${invalid}] is invalid: expected non-empty string`);
|
|
754
|
+
}
|
|
755
|
+
apiKey = embedding.apiKey as string[];
|
|
756
|
+
} else if (embedding.apiKey !== undefined) {
|
|
757
|
+
// apiKey is present but wrong type — throw, don't silently fall back
|
|
758
|
+
throw new Error("embedding.apiKey must be a string or non-empty array of strings");
|
|
759
|
+
} else {
|
|
760
|
+
apiKey = process.env.OPENAI_API_KEY || "";
|
|
761
|
+
}
|
|
751
762
|
|
|
752
763
|
if (!apiKey || (Array.isArray(apiKey) && apiKey.length === 0)) {
|
|
753
764
|
throw new Error("embedding.apiKey is required (set directly or via OPENAI_API_KEY env var)");
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "memory-lancedb-pro",
|
|
3
3
|
"name": "Memory (LanceDB Pro)",
|
|
4
4
|
"description": "Enhanced LanceDB-backed long-term memory with hybrid retrieval, multi-scope isolation, long-context chunking, and management CLI",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.24",
|
|
6
6
|
"kind": "memory",
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
|
@@ -18,8 +18,18 @@
|
|
|
18
18
|
},
|
|
19
19
|
"apiKey": {
|
|
20
20
|
"oneOf": [
|
|
21
|
-
{
|
|
22
|
-
|
|
21
|
+
{
|
|
22
|
+
"type": "string",
|
|
23
|
+
"minLength": 1
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"minLength": 1
|
|
30
|
+
},
|
|
31
|
+
"minItems": 1
|
|
32
|
+
}
|
|
23
33
|
],
|
|
24
34
|
"description": "Single API key or array of keys for round-robin rotation"
|
|
25
35
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-lancedb-pro",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"description": "OpenClaw enhanced LanceDB memory plugin with hybrid retrieval (Vector + BM25), cross-encoder rerank, multi-scope isolation, long-context chunking, and management CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
package/src/embedder.ts
CHANGED
|
@@ -208,14 +208,28 @@ export class Embedder {
|
|
|
208
208
|
return client;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
/** Check whether an error is a rate-limit / quota-exceeded error. */
|
|
211
|
+
/** Check whether an error is a rate-limit / quota-exceeded / overload error. */
|
|
212
212
|
private isRateLimitError(error: unknown): boolean {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
if (!error || typeof error !== "object") return false;
|
|
214
|
+
|
|
215
|
+
const err = error as Record<string, any>;
|
|
216
|
+
|
|
217
|
+
// HTTP status: 429 (rate limit) or 503 (service overload)
|
|
218
|
+
if (err.status === 429 || err.status === 503) return true;
|
|
219
|
+
|
|
220
|
+
// OpenAI SDK structured error code
|
|
221
|
+
if (err.code === "rate_limit_exceeded" || err.code === "insufficient_quota") return true;
|
|
222
|
+
|
|
223
|
+
// Nested error object (some providers)
|
|
224
|
+
const nested = err.error;
|
|
225
|
+
if (nested && typeof nested === "object") {
|
|
226
|
+
if (nested.type === "rate_limit_exceeded" || nested.type === "insufficient_quota") return true;
|
|
227
|
+
if (nested.code === "rate_limit_exceeded" || nested.code === "insufficient_quota") return true;
|
|
216
228
|
}
|
|
229
|
+
|
|
230
|
+
// Fallback: message text matching
|
|
217
231
|
const msg = error instanceof Error ? error.message : String(error);
|
|
218
|
-
return /rate.limit|quota|too many requests|insufficient.*credit|429/i.test(msg);
|
|
232
|
+
return /rate.limit|quota|too many requests|insufficient.*credit|429|503.*overload/i.test(msg);
|
|
219
233
|
}
|
|
220
234
|
|
|
221
235
|
/**
|
|
@@ -231,19 +245,27 @@ export class Embedder {
|
|
|
231
245
|
try {
|
|
232
246
|
return await client.embeddings.create(payload);
|
|
233
247
|
} catch (error) {
|
|
248
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
249
|
+
|
|
234
250
|
if (this.isRateLimitError(error) && attempt < maxAttempts - 1) {
|
|
235
251
|
console.log(
|
|
236
|
-
`[memory-lancedb-pro]
|
|
252
|
+
`[memory-lancedb-pro] Attempt ${attempt + 1}/${maxAttempts} hit rate limit, rotating to next key...`
|
|
237
253
|
);
|
|
238
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
239
254
|
continue;
|
|
240
255
|
}
|
|
241
|
-
|
|
242
|
-
|
|
256
|
+
|
|
257
|
+
// Non-rate-limit error → don't retry, let caller handle (e.g. chunking)
|
|
258
|
+
if (!this.isRateLimitError(error)) {
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
243
261
|
}
|
|
244
262
|
}
|
|
245
263
|
|
|
246
|
-
|
|
264
|
+
// All keys exhausted with rate-limit errors
|
|
265
|
+
throw new Error(
|
|
266
|
+
`All ${maxAttempts} API keys exhausted (rate limited). Last error: ${lastError?.message || "unknown"}`,
|
|
267
|
+
{ cause: lastError }
|
|
268
|
+
);
|
|
247
269
|
}
|
|
248
270
|
|
|
249
271
|
/** Number of API keys in the rotation pool. */
|