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)}`);
}
}
}