diff --git a/examples/openclaw-plugin/index.ts b/examples/openclaw-plugin/index.ts index 2d773a59..539c53e6 100644 --- a/examples/openclaw-plugin/index.ts +++ b/examples/openclaw-plugin/index.ts @@ -24,6 +24,7 @@ import { quickRecallPrecheck, resolvePythonCommand, prepareLocalPort, + withTimeout, } from "./process-manager.js"; import { createMemoryOpenVikingContextEngine } from "./context-engine.js"; @@ -429,6 +430,7 @@ const contextEnginePlugin = { } const prependContextParts: string[] = []; + const autoRecallTimeoutMs = 5_000; if (cfg.autoRecall && queryText.length >= 5) { const precheck = await quickRecallPrecheck(cfg.mode, cfg.baseUrl, cfg.port, localProcess); @@ -438,69 +440,75 @@ const contextEnginePlugin = { ); } else { try { - const candidateLimit = Math.max(cfg.recallLimit * 4, 20); - const [userSettled, agentSettled] = await Promise.allSettled([ - client.find(queryText, { - targetUri: "viking://user/memories", - limit: candidateLimit, - scoreThreshold: 0, - }), - client.find(queryText, { - targetUri: "viking://agent/memories", - limit: candidateLimit, - scoreThreshold: 0, - }), - ]); - - const userResult = userSettled.status === "fulfilled" ? userSettled.value : { memories: [] }; - const agentResult = agentSettled.status === "fulfilled" ? agentSettled.value : { memories: [] }; - if (userSettled.status === "rejected") { - api.logger.warn(`openviking: user memories search failed: ${String(userSettled.reason)}`); - } - if (agentSettled.status === "rejected") { - api.logger.warn(`openviking: agent memories search failed: ${String(agentSettled.reason)}`); - } - - const allMemories = [...(userResult.memories ?? []), ...(agentResult.memories ?? [])]; - const uniqueMemories = allMemories.filter((memory, index, self) => - index === self.findIndex((m) => m.uri === memory.uri) - ); - const leafOnly = uniqueMemories.filter((m) => m.level === 2); - const processed = postProcessMemories(leafOnly, { - limit: candidateLimit, - scoreThreshold: cfg.recallScoreThreshold, - }); - const memories = pickMemoriesForInjection(processed, cfg.recallLimit, queryText); - - if (memories.length > 0) { - const memoryLines = await Promise.all( - memories.map(async (item: FindResultItem) => { - if (item.level === 2) { - try { - const content = await client.read(item.uri); - if (content && typeof content === "string" && content.trim()) { - return `- [${item.category ?? "memory"}] ${content.trim()}`; + await withTimeout( + (async () => { + const candidateLimit = Math.max(cfg.recallLimit * 4, 20); + const [userSettled, agentSettled] = await Promise.allSettled([ + client.find(queryText, { + targetUri: "viking://user/memories", + limit: candidateLimit, + scoreThreshold: 0, + }), + client.find(queryText, { + targetUri: "viking://agent/memories", + limit: candidateLimit, + scoreThreshold: 0, + }), + ]); + + const userResult = userSettled.status === "fulfilled" ? userSettled.value : { memories: [] }; + const agentResult = agentSettled.status === "fulfilled" ? agentSettled.value : { memories: [] }; + if (userSettled.status === "rejected") { + api.logger.warn(`openviking: user memories search failed: ${String(userSettled.reason)}`); + } + if (agentSettled.status === "rejected") { + api.logger.warn(`openviking: agent memories search failed: ${String(agentSettled.reason)}`); + } + + const allMemories = [...(userResult.memories ?? []), ...(agentResult.memories ?? [])]; + const uniqueMemories = allMemories.filter((memory, index, self) => + index === self.findIndex((m) => m.uri === memory.uri) + ); + const leafOnly = uniqueMemories.filter((m) => m.level === 2); + const processed = postProcessMemories(leafOnly, { + limit: candidateLimit, + scoreThreshold: cfg.recallScoreThreshold, + }); + const memories = pickMemoriesForInjection(processed, cfg.recallLimit, queryText); + + if (memories.length > 0) { + const memoryLines = await Promise.all( + memories.map(async (item: FindResultItem) => { + if (item.level === 2) { + try { + const content = await client.read(item.uri); + if (content && typeof content === "string" && content.trim()) { + return `- [${item.category ?? "memory"}] ${content.trim()}`; + } + } catch { + // fallback to abstract + } } - } catch { - // fallback to abstract - } - } - return `- [${item.category ?? "memory"}] ${item.abstract ?? item.uri}`; - }), - ); - const memoryContext = memoryLines.join("\n"); - api.logger.info(`openviking: injecting ${memories.length} memories into context`); - api.logger.info( - `openviking: inject-detail ${toJsonLog({ count: memories.length, memories: summarizeInjectionMemories(memories) })}`, - ); - prependContextParts.push( - "\nThe following OpenViking memories may be relevant:\n" + - `${memoryContext}\n` + - "", - ); - } + return `- [${item.category ?? "memory"}] ${item.abstract ?? item.uri}`; + }), + ); + const memoryContext = memoryLines.join("\n"); + api.logger.info(`openviking: injecting ${memories.length} memories into context`); + api.logger.info( + `openviking: inject-detail ${toJsonLog({ count: memories.length, memories: summarizeInjectionMemories(memories) })}`, + ); + prependContextParts.push( + "\nThe following OpenViking memories may be relevant:\n" + + `${memoryContext}\n` + + "", + ); + } + })(), + autoRecallTimeoutMs, + `openviking: auto-recall timed out after ${autoRecallTimeoutMs}ms`, + ); } catch (err) { - api.logger.warn(`openviking: auto-recall failed: ${String(err)}`); + api.logger.warn(`openviking: auto-recall failed or timed out: ${String(err)}`); } } }