mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
memory-neo4j: filter open proposals and cron noise from memory
Open proposals ("Want me to...?", "Should I...?") are dangerous in
long-term memory because other sessions interpret them as active
instructions and attempt to carry them out. This adds:
- Attention gate patterns for cron delivery outputs and assistant proposals
- Extractor scoring rules to rate proposals/action items as low importance
- Sleep-cycle Phase 7 to retroactively clean existing noise-pattern memories
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,22 @@ const NOISE_PATTERNS = [
|
||||
// --- Conversation metadata that survived stripping ---
|
||||
/^Conversation info\s*\(/i,
|
||||
/^\[Queued messages/i,
|
||||
|
||||
// --- Cron delivery outputs & scheduled reminders ---
|
||||
// Scheduled reminder injection text (appears mid-message)
|
||||
/A scheduled reminder has been triggered/i,
|
||||
// Cron delivery instruction to agent (summarize for user)
|
||||
/Summarize this naturally for the user/i,
|
||||
// Relay instruction from cron announcements
|
||||
/Please relay this reminder to the user/i,
|
||||
// Subagent completion announcements (date-stamped)
|
||||
/^\[.*\d{4}-\d{2}-\d{2}.*\]\s*A sub-?agent task/i,
|
||||
// Formatted urgency/priority reports (email summaries, briefings)
|
||||
/(\*\*)?🔴\s*(URGENT|Priority)/i,
|
||||
// Subagent findings header
|
||||
/^Findings:\s*$/im,
|
||||
// "Stats:" lines from subagent completions
|
||||
/^Stats:\s*runtime\s/im,
|
||||
];
|
||||
|
||||
/** Maximum message length — code dumps, logs, etc. are not memories. */
|
||||
@@ -171,6 +187,22 @@ const ASSISTANT_NARRATION_PATTERNS = [
|
||||
/^All (good|set|done)[!.]/i,
|
||||
// "Here's what changed" / "Summary of changes" (session-specific)
|
||||
/^(here'?s\s+(what|the|a)\s+(changed?|summary|breakdown|recap))/i,
|
||||
|
||||
// --- Open proposals / action items (cause rogue actions when recalled) ---
|
||||
// These are dangerous in memory: when auto-recalled, other sessions interpret
|
||||
// them as active instructions and attempt to carry them out.
|
||||
// "Want me to...?" / "Should I...?" / "Shall I...?" / "Would you like me to...?"
|
||||
/want me to\s.+\?/i,
|
||||
/should I\s.+\?/i,
|
||||
/shall I\s.+\?/i,
|
||||
/would you like me to\s.+\?/i,
|
||||
// "Do you want me to...?"
|
||||
/do you want me to\s.+\?/i,
|
||||
// "Can I...?" / "May I...?" assistant proposals
|
||||
/^(can|may) I\s.+\?/i,
|
||||
// "Ready to...?" / "Proceed with...?"
|
||||
/ready to\s.+\?/i,
|
||||
/proceed with\s.+\?/i,
|
||||
];
|
||||
|
||||
export function passesAssistantAttentionGate(text: string): boolean {
|
||||
|
||||
@@ -358,6 +358,8 @@ KEY RULES:
|
||||
- AI assistant self-narration ("Let me check...", "I'll now...", "Done! Here's what changed...") is ALWAYS 1-3
|
||||
- System prompts, formatting instructions, voice mode rules are ALWAYS 1-2
|
||||
- Technical debugging details ("the WebSocket failed because...") are 2-4 unless they encode a reusable lesson
|
||||
- Open proposals and unresolved action items ("Want me to fix it?", "Should I submit a PR?", "Would you like me to proceed?") are ALWAYS 1-2. These are dangerous in long-term memory because other sessions interpret them as active instructions.
|
||||
- Messages ending with questions directed at the user ("What do you think?", "How should I handle this?") are 1-3 unless they also contain substantial factual content worth remembering
|
||||
- Personal facts about the user or their family/contacts are 7-10
|
||||
- Business rules and operational procedures are 7-9
|
||||
- Preferences and opinions expressed by the user are 6-8
|
||||
|
||||
@@ -657,6 +657,63 @@ export async function runSleepCycle(
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Phase 7: Noise Pattern Cleanup
|
||||
// Removes memories matching dangerous patterns that should never have been
|
||||
// stored (open proposals, action items that trigger rogue sessions).
|
||||
// --------------------------------------------------------------------------
|
||||
if (!abortSignal?.aborted) {
|
||||
logger.info("memory-neo4j: [sleep] Phase 7: Noise Pattern Cleanup");
|
||||
|
||||
try {
|
||||
const noisePatterns = [
|
||||
"(?i)want me to\\s.+\\?",
|
||||
"(?i)should I\\s.+\\?",
|
||||
"(?i)shall I\\s.+\\?",
|
||||
"(?i)would you like me to\\s.+\\?",
|
||||
"(?i)do you want me to\\s.+\\?",
|
||||
"(?i)ready to\\s.+\\?",
|
||||
"(?i)proceed with\\s.+\\?",
|
||||
];
|
||||
|
||||
let noiseRemoved = 0;
|
||||
const noiseSession = (db as any).driver!.session();
|
||||
try {
|
||||
for (const pattern of noisePatterns) {
|
||||
if (abortSignal?.aborted) {
|
||||
break;
|
||||
}
|
||||
|
||||
const agentFilter = agentId ? "AND m.agentId = $agentId" : "";
|
||||
const result = await noiseSession.run(
|
||||
`MATCH (m:Memory)
|
||||
WHERE m.text =~ $pattern
|
||||
AND coalesce(m.userPinned, false) = false
|
||||
AND m.category <> 'core'
|
||||
${agentFilter}
|
||||
WITH m LIMIT 100
|
||||
DETACH DELETE m
|
||||
RETURN count(*) AS removed`,
|
||||
{ pattern: `.*${pattern}.*`, agentId },
|
||||
);
|
||||
noiseRemoved += (result.records[0]?.get("removed") as number) ?? 0;
|
||||
}
|
||||
} finally {
|
||||
await noiseSession.close();
|
||||
}
|
||||
|
||||
if (noiseRemoved > 0) {
|
||||
onProgress?.("cleanup", `Removed ${noiseRemoved} noise-pattern memories`);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`memory-neo4j: [sleep] Phase 7 complete — ${noiseRemoved} noise memories removed`,
|
||||
);
|
||||
} catch (err) {
|
||||
logger.warn(`memory-neo4j: [sleep] Phase 7 error: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
result.durationMs = Date.now() - startTime;
|
||||
result.aborted = abortSignal?.aborted ?? false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user