





















@@ -149,6 +149,7 @@ function resolveAutoCaptureStartIndex(
149149// ============================================================================
150150151151const TABLE_NAME = "memories";
152+const DEFAULT_AUTO_RECALL_TIMEOUT_MS = 15_000;
152153153154class MemoryDB {
154155private db: LanceDB.Connection | null = null;
@@ -262,7 +263,7 @@ class MemoryDB {
262263// ============================================================================
263264264265type Embeddings = {
265-embed(text: string): Promise<number[]>;
266+embed(text: string, options?: { timeoutMs?: number }): Promise<number[]>;
266267};
267268268269class OpenAiCompatibleEmbeddings implements Embeddings {
@@ -277,7 +278,7 @@ class OpenAiCompatibleEmbeddings implements Embeddings {
277278this.client = new OpenAI({ apiKey, baseURL: baseUrl });
278279}
279280280-async embed(text: string): Promise<number[]> {
281+async embed(text: string, options?: { timeoutMs?: number }): Promise<number[]> {
281282const params: OpenAI.EmbeddingCreateParams = {
282283model: this.model,
283284input: text,
@@ -292,6 +293,7 @@ class OpenAiCompatibleEmbeddings implements Embeddings {
292293// transport and normalize the response ourselves.
293294const response = await this.client.post<EmbeddingCreateResponse>("/embeddings", {
294295body: params,
296+ ...(options?.timeoutMs ? { timeout: options.timeoutMs, maxRetries: 0 } : {}),
295297});
296298return normalizeEmbeddingVector(response.data?.[0]?.embedding);
297299}
@@ -353,6 +355,32 @@ class ProviderAdapterEmbeddings implements Embeddings {
353355}
354356}
355357358+async function runWithTimeout<T>(params: {
359+timeoutMs: number;
360+task: () => Promise<T>;
361+}): Promise<{ status: "ok"; value: T } | { status: "timeout" }> {
362+let timeout: ReturnType<typeof setTimeout> | undefined;
363+const TIMEOUT = Symbol("timeout");
364+const timeoutPromise = new Promise<typeof TIMEOUT>((resolve) => {
365+timeout = setTimeout(() => resolve(TIMEOUT), params.timeoutMs);
366+timeout.unref?.();
367+});
368+const taskPromise = params.task();
369+taskPromise.catch(() => undefined);
370+371+try {
372+const result = await Promise.race([taskPromise, timeoutPromise]);
373+if (result === TIMEOUT) {
374+return { status: "timeout" };
375+}
376+return { status: "ok", value: result };
377+} finally {
378+if (timeout) {
379+clearTimeout(timeout);
380+}
381+}
382+}
383+356384function createEmbeddings(api: OpenClawPluginApi, cfg: MemoryConfig): Embeddings {
357385const { provider, model, dimensions, apiKey, baseUrl } = cfg.embedding;
358386if (provider === "openai" && apiKey) {
@@ -818,8 +846,22 @@ export default definePluginEntry({
818846event.prompt,
819847currentCfg.recallMaxChars,
820848);
821-const vector = await embeddings.embed(recallQuery);
822-const results = await db.search(vector, 3, 0.3);
849+const recall = await runWithTimeout({
850+timeoutMs: DEFAULT_AUTO_RECALL_TIMEOUT_MS,
851+task: async () => {
852+const vector = await embeddings.embed(recallQuery, {
853+timeoutMs: DEFAULT_AUTO_RECALL_TIMEOUT_MS,
854+});
855+return await db.search(vector, 3, 0.3);
856+},
857+});
858+if (recall.status === "timeout") {
859+api.logger.warn?.(
860+`memory-lancedb: auto-recall timed out after ${DEFAULT_AUTO_RECALL_TIMEOUT_MS}ms; skipping memory injection to avoid stalling agent startup`,
861+);
862+return undefined;
863+}
864+const results = recall.value;
823865824866if (results.length === 0) {
825867return undefined;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。