fix(openclaw): prevent memory wipe on every session (#323)

Use unique document_id per conversation (sessionKey + timestamp) instead
of static sessionKey. The backend CASCADE-deletes old memories when the
same document_id is reused, causing all prior facts to be lost.

Also:
- Universal envelope stripping for all channels (was Telegram-only)
- Prefer rawMessage over prompt for cleaner recall queries
- Increase recall max_tokens from 512 to 2048

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Anton Evseev 2026-02-09 19:13:19 +10:00 committed by GitHub
parent d90588b3e1
commit 981cf6057f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -554,17 +554,40 @@ export default function (api: MoltbotPluginAPI) {
console.log(`[Hindsight] before_agent_start - bank: ${bankId}, channel: ${ctx?.messageProvider}/${ctx?.channelId}`);
// Get the user's latest message for recall
let prompt = event.prompt;
// Prefer rawMessage (clean user text) over prompt (envelope-formatted)
let prompt = event.rawMessage ?? event.prompt;
if (!prompt || typeof prompt !== 'string' || prompt.length < 5) {
return; // Skip very short messages
}
// Extract actual message from Telegram format: [Telegram ... GMT+1] actual message
const telegramMatch = prompt.match(/\[Telegram[^\]]+\]\s*(.+)$/);
if (telegramMatch) {
prompt = telegramMatch[1].trim();
// Strip envelope-formatted prompts from any channel
// The prompt may contain: System: lines, abort hints, [Channel ...] header, [from: ...] suffix
let cleaned = prompt;
// Remove leading "System: ..." lines (from prependSystemEvents)
cleaned = cleaned.replace(/^(?:System:.*\n)+\n?/, '');
// Remove session abort hint
cleaned = cleaned.replace(
/^Note: The previous agent run was aborted[^\n]*\n\n/,
'',
);
// Extract message after [ChannelName ...] envelope header
// Handles any channel: Telegram, Slack, Discord, WhatsApp, Signal, etc.
// Uses [\s\S]+ instead of .+ to support multiline messages
const envelopeMatch = cleaned.match(
/\[[A-Z][A-Za-z]*(?:\s[^\]]+)?\]\s*([\s\S]+)$/,
);
if (envelopeMatch) {
cleaned = envelopeMatch[1];
}
// Remove trailing [from: SenderName] metadata (group chats)
cleaned = cleaned.replace(/\n\[from:[^\]]*\]\s*$/, '');
prompt = cleaned.trim() || prompt;
if (prompt.length < 5) {
return; // Skip very short messages after extraction
}
@ -587,10 +610,10 @@ export default function (api: MoltbotPluginAPI) {
console.log(`[Hindsight] Auto-recall for bank ${bankId}, prompt: ${prompt.substring(0, 50)}`);
// Recall relevant memories (up to 512 tokens)
// Recall relevant memories
const response = await client.recall({
query: prompt,
max_tokens: 512,
max_tokens: 2048,
});
if (!response.results || response.results.length === 0) {
@ -675,8 +698,9 @@ User message: ${prompt}
return;
}
// Use session key as document ID (prefer context over captured value)
const documentId = effectiveCtx?.sessionKey || currentSessionKey || 'default-session';
// Use unique document ID per conversation (sessionKey + timestamp)
// Static sessionKey (e.g. "agent:main:main") causes CASCADE delete of old memories
const documentId = `${effectiveCtx?.sessionKey || currentSessionKey || 'session'}-${Date.now()}`;
// Retain to Hindsight
await client.retain({