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.