Skip to content

Commit 981cf60

Browse files
slayofferclaude
andauthored
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>
1 parent d90588b commit 981cf60

File tree

1 file changed

+33
-9
lines changed
  • hindsight-integrations/openclaw/src

1 file changed

+33
-9
lines changed

hindsight-integrations/openclaw/src/index.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -554,17 +554,40 @@ export default function (api: MoltbotPluginAPI) {
554554
console.log(`[Hindsight] before_agent_start - bank: ${bankId}, channel: ${ctx?.messageProvider}/${ctx?.channelId}`);
555555

556556
// Get the user's latest message for recall
557-
let prompt = event.prompt;
557+
// Prefer rawMessage (clean user text) over prompt (envelope-formatted)
558+
let prompt = event.rawMessage ?? event.prompt;
558559
if (!prompt || typeof prompt !== 'string' || prompt.length < 5) {
559560
return; // Skip very short messages
560561
}
561562

562-
// Extract actual message from Telegram format: [Telegram ... GMT+1] actual message
563-
const telegramMatch = prompt.match(/\[Telegram[^\]]+\]\s*(.+)$/);
564-
if (telegramMatch) {
565-
prompt = telegramMatch[1].trim();
563+
// Strip envelope-formatted prompts from any channel
564+
// The prompt may contain: System: lines, abort hints, [Channel ...] header, [from: ...] suffix
565+
let cleaned = prompt;
566+
567+
// Remove leading "System: ..." lines (from prependSystemEvents)
568+
cleaned = cleaned.replace(/^(?:System:.*\n)+\n?/, '');
569+
570+
// Remove session abort hint
571+
cleaned = cleaned.replace(
572+
/^Note: The previous agent run was aborted[^\n]*\n\n/,
573+
'',
574+
);
575+
576+
// Extract message after [ChannelName ...] envelope header
577+
// Handles any channel: Telegram, Slack, Discord, WhatsApp, Signal, etc.
578+
// Uses [\s\S]+ instead of .+ to support multiline messages
579+
const envelopeMatch = cleaned.match(
580+
/\[[A-Z][A-Za-z]*(?:\s[^\]]+)?\]\s*([\s\S]+)$/,
581+
);
582+
if (envelopeMatch) {
583+
cleaned = envelopeMatch[1];
566584
}
567585

586+
// Remove trailing [from: SenderName] metadata (group chats)
587+
cleaned = cleaned.replace(/\n\[from:[^\]]*\]\s*$/, '');
588+
589+
prompt = cleaned.trim() || prompt;
590+
568591
if (prompt.length < 5) {
569592
return; // Skip very short messages after extraction
570593
}
@@ -587,10 +610,10 @@ export default function (api: MoltbotPluginAPI) {
587610

588611
console.log(`[Hindsight] Auto-recall for bank ${bankId}, prompt: ${prompt.substring(0, 50)}`);
589612

590-
// Recall relevant memories (up to 512 tokens)
613+
// Recall relevant memories
591614
const response = await client.recall({
592615
query: prompt,
593-
max_tokens: 512,
616+
max_tokens: 2048,
594617
});
595618

596619
if (!response.results || response.results.length === 0) {
@@ -675,8 +698,9 @@ User message: ${prompt}
675698
return;
676699
}
677700

678-
// Use session key as document ID (prefer context over captured value)
679-
const documentId = effectiveCtx?.sessionKey || currentSessionKey || 'default-session';
701+
// Use unique document ID per conversation (sessionKey + timestamp)
702+
// Static sessionKey (e.g. "agent:main:main") causes CASCADE delete of old memories
703+
const documentId = `${effectiveCtx?.sessionKey || currentSessionKey || 'session'}-${Date.now()}`;
680704

681705
// Retain to Hindsight
682706
await client.retain({

0 commit comments

Comments
 (0)