diff --git a/index.ts b/index.ts index 52f1962..6614c69 100644 --- a/index.ts +++ b/index.ts @@ -120,6 +120,8 @@ interface PluginConfig { rerankApiKey?: string; rerankModel?: string; rerankEndpoint?: string; + /** Rerank API timeout in milliseconds (default: 5000). Increase for local/CPU-based rerank servers. */ + rerankTimeoutMs?: number; rerankProvider?: | "jina" | "siliconflow" diff --git a/openclaw.plugin.json b/openclaw.plugin.json index a2cfb1f..976b8a1 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -319,6 +319,12 @@ "default": "https://api.jina.ai/v1/rerank", "description": "Reranker API endpoint URL. Compatible with Jina-compatible endpoints and dedicated adapters such as TEI, SiliconFlow, Voyage, Pinecone, and DashScope." }, + "rerankTimeoutMs": { + "type": "integer", + "minimum": 1, + "default": 5000, + "description": "Rerank API timeout in milliseconds (default: 5000). Increase for local/CPU-based rerank servers." + }, "rerankProvider": { "type": "string", "enum": [ @@ -1078,6 +1084,12 @@ "help": "Custom reranker API endpoint URL", "advanced": true }, + "retrieval.rerankTimeoutMs": { + "label": "Rerank Timeout (ms)", + "placeholder": "5000", + "help": "Rerank API timeout in milliseconds. Increase for local/CPU-based rerank servers.", + "advanced": true + }, "retrieval.rerankProvider": { "label": "Reranker Provider", "help": "Provider format: jina (default), siliconflow, voyage, pinecone, dashscope, or tei", diff --git a/src/retriever.ts b/src/retriever.ts index 900db75..bf3aeee 100644 --- a/src/retriever.ts +++ b/src/retriever.ts @@ -58,6 +58,8 @@ export interface RetrievalConfig { | "pinecone" | "dashscope" | "tei"; + /** Rerank API timeout in milliseconds (default: 5000). Increase for local/CPU-based rerank servers. */ + rerankTimeoutMs?: number; /** * Length normalization: penalize long entries that dominate via sheer keyword * density. Formula: score *= 1 / (1 + log2(charLen / anchor)). @@ -127,6 +129,7 @@ export const DEFAULT_RETRIEVAL_CONFIG: RetrievalConfig = { filterNoise: true, rerankModel: "jina-reranker-v3", rerankEndpoint: "https://api.jina.ai/v1/rerank", + rerankTimeoutMs: 5000, lengthNormAnchor: 500, hardMinScore: 0.35, timeDecayHalfLifeDays: 60, @@ -858,18 +861,21 @@ export class MemoryRetriever { results.length, ); - // Timeout: 5 seconds to prevent stalling retrieval pipeline + // Timeout: configurable via rerankTimeoutMs (default: 5000ms) const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), 5000); + const timeout = setTimeout(() => controller.abort(), this.config.rerankTimeoutMs ?? 5000); - const response = await fetch(endpoint, { - method: "POST", - headers, - body: JSON.stringify(body), - signal: controller.signal, - }); - - clearTimeout(timeout); + let response: Response; + try { + response = await fetch(endpoint, { + method: "POST", + headers, + body: JSON.stringify(body), + signal: controller.signal, + }); + } finally { + clearTimeout(timeout); + } if (response.ok) { const data: unknown = await response.json(); @@ -928,7 +934,7 @@ export class MemoryRetriever { } } catch (error) { if (error instanceof Error && error.name === "AbortError") { - console.warn("Rerank API timed out (5s), falling back to cosine"); + console.warn(`Rerank API timed out (${this.config.rerankTimeoutMs ?? 5000}ms), falling back to cosine`); } else { console.warn("Rerank API failed, falling back to cosine:", error); }