From cd4d449f8e1c7ffea9f6426121a86a30e8c0fff2 Mon Sep 17 00:00:00 2001 From: Rutimka <48045755+Rutimka@users.noreply.github.com> Date: Sat, 28 Mar 2026 17:59:23 +0100 Subject: [PATCH] fix(openclaw): add recallTimeoutMs config option for auto-recall (#736) The auto-recall timeout was hardcoded to 10s but recall with budget=high can take 13s+. This adds a configurable recallTimeoutMs option (default: 10000ms) so users can increase the timeout when using higher recall budgets. Also adds recallInjectionPosition to the plugin schema (it was already implemented in code but missing from the JSON schema validation, causing config rejection). Co-authored-by: Marco Rutsch Co-authored-by: Claude Sonnet 4.6 --- .../openclaw/openclaw.plugin.json | 20 +++++++++++++++++++ hindsight-integrations/openclaw/src/index.ts | 10 ++++++---- hindsight-integrations/openclaw/src/types.ts | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/hindsight-integrations/openclaw/openclaw.plugin.json b/hindsight-integrations/openclaw/openclaw.plugin.json index f5244574..bd010890 100644 --- a/hindsight-integrations/openclaw/openclaw.plugin.json +++ b/hindsight-integrations/openclaw/openclaw.plugin.json @@ -188,6 +188,18 @@ "description": "Text shown above recalled memories in the injected context block.", "default": "Relevant memories from past conversations (prioritize recent when conflicting). Only use memories that are directly useful to continue this conversation; ignore the rest:" }, + "recallTimeoutMs": { + "type": "integer", + "minimum": 1000, + "description": "Timeout for auto-recall in milliseconds. Increase if recall times out with high budget.", + "default": 10000 + }, + "recallInjectionPosition": { + "type": "string", + "enum": ["prepend", "append", "user"], + "description": "Where to inject recalled memories. 'prepend' = start of system prompt (default), 'append' = end of system prompt (preserves prompt cache), 'user' = before user message.", + "default": "prepend" + }, "debug": { "type": "boolean", "description": "Enable debug logging for Hindsight plugin operations.", @@ -309,6 +321,14 @@ "label": "Recall Prompt Preamble", "placeholder": "Instruction shown above recalled memories in injected context" }, + "recallTimeoutMs": { + "label": "Recall Timeout (ms)", + "placeholder": "10000 (default)" + }, + "recallInjectionPosition": { + "label": "Recall Injection Position", + "placeholder": "prepend, append, or user" + }, "debug": { "label": "Debug" } diff --git a/hindsight-integrations/openclaw/src/index.ts b/hindsight-integrations/openclaw/src/index.ts index 6fa48ae8..b16bf7b1 100644 --- a/hindsight-integrations/openclaw/src/index.ts +++ b/hindsight-integrations/openclaw/src/index.ts @@ -33,7 +33,7 @@ import type { RecallResponse } from './types.js'; const inflightRecalls = new Map>(); const turnCountBySession = new Map(); const MAX_TRACKED_SESSIONS = 10_000; -const RECALL_TIMEOUT_MS = 10_000; +const DEFAULT_RECALL_TIMEOUT_MS = 10_000; // Cache sender IDs discovered in before_prompt_build (where event.prompt has the metadata // blocks) so agent_end can look them up — event.messages in agent_end is clean history. @@ -727,6 +727,7 @@ function getPluginConfig(api: MoltbotPluginAPI): PluginConfig { ? config.recallPromptPreamble : DEFAULT_RECALL_PROMPT_PREAMBLE, recallInjectionPosition: typeof config.recallInjectionPosition === 'string' && ['prepend', 'append', 'user'].includes(config.recallInjectionPosition) ? config.recallInjectionPosition as PluginConfig['recallInjectionPosition'] : undefined, + recallTimeoutMs: typeof config.recallTimeoutMs === 'number' && config.recallTimeoutMs >= 1000 ? config.recallTimeoutMs : undefined, debug: config.debug ?? false, }; } @@ -1112,7 +1113,8 @@ export default function (api: MoltbotPluginAPI) { debug(`[Hindsight] Reusing in-flight recall for bank ${bankId}`); recallPromise = existing; } else { - recallPromise = client.recall({ query: prompt, max_tokens: pluginConfig.recallMaxTokens || 1024, budget: pluginConfig.recallBudget, types: pluginConfig.recallTypes }, RECALL_TIMEOUT_MS); + const recallTimeoutMs = pluginConfig.recallTimeoutMs ?? DEFAULT_RECALL_TIMEOUT_MS; + recallPromise = client.recall({ query: prompt, max_tokens: pluginConfig.recallMaxTokens || 1024, budget: pluginConfig.recallBudget, types: pluginConfig.recallTypes }, recallTimeoutMs); inflightRecalls.set(recallKey, recallPromise); void recallPromise.catch(() => {}).finally(() => inflightRecalls.delete(recallKey)); } @@ -1156,9 +1158,9 @@ ${memoriesFormatted} } } catch (error) { if (error instanceof DOMException && error.name === 'TimeoutError') { - console.warn(`[Hindsight] Auto-recall timed out after ${RECALL_TIMEOUT_MS}ms, skipping memory injection`); + console.warn(`[Hindsight] Auto-recall timed out after ${pluginConfig.recallTimeoutMs ?? DEFAULT_RECALL_TIMEOUT_MS}ms, skipping memory injection`); } else if (error instanceof Error && error.name === 'AbortError') { - console.warn(`[Hindsight] Auto-recall aborted after ${RECALL_TIMEOUT_MS}ms, skipping memory injection`); + console.warn(`[Hindsight] Auto-recall aborted after ${pluginConfig.recallTimeoutMs ?? DEFAULT_RECALL_TIMEOUT_MS}ms, skipping memory injection`); } else { console.error('[Hindsight] Auto-recall error:', error); } diff --git a/hindsight-integrations/openclaw/src/types.ts b/hindsight-integrations/openclaw/src/types.ts index 06cb0e62..22eea630 100644 --- a/hindsight-integrations/openclaw/src/types.ts +++ b/hindsight-integrations/openclaw/src/types.ts @@ -70,6 +70,7 @@ export interface PluginConfig { retainOverlapTurns?: number; // Extra prior turns included when chunked retention fires (default: 0). Window = retainEveryNTurns + retainOverlapTurns. recallTopK?: number; // Max number of memories to inject. Default: unlimited recallContextTurns?: number; // Number of user turns to include in recall query context. Default: 1 (latest only) + recallTimeoutMs?: number; // Timeout for auto-recall in milliseconds. Default: 10000 recallMaxQueryChars?: number; // Max chars for composed recall query. Default: 800 recallPromptPreamble?: string; // Prompt preamble placed above recalled memories. Default: built-in guidance text. recallInjectionPosition?: 'prepend' | 'append' | 'user'; // Where to inject recalled memories. 'prepend' = start of system prompt (default), 'append' = end of system prompt (preserves prompt cache), 'user' = before user message.