Skip to content

[Bug] Internal extraction prompts captured as observations, polluting context injection #20

Description

@wjiuxing

Summary

The observation extraction pipeline captures its own internal processing prompts as observations. These accumulate over time and get injected back into context via true_memory_context, wasting tokens and injecting stale user directives into new sessions.

Two symptoms, one root cause

Symptom 1: Internal prompts stored as observations

Every tool execution triggers an observation extraction flow:

  1. Tool output → pending_messages queue
  2. LLM analyzes the output with the prompt: <task>Analyze the following tool output and extract a structured observation.</task>
  3. Extracted observation → observations table

Bug: The internal extraction prompt itself (from step 2) gets captured as an observation with tool_name="chat.message" and stored in the database. The title field becomes "User request: <task>\nAnalyze the following tool output..." and the narrative contains the raw prompt + tool output.

Symptom 2: Garbage observations pollute context injection

The true_memory_context injection retrieves relevant observations and injects them into the prompt. These internal prompts are retrieved alongside legitimate observations, causing:

  • Token waste: Each garbage observation is ~2KB of narrative text
  • Stale directive injection: Old user directives like [search-mode], [analyze-mode], or one-off instructions get re-injected into new sessions, interfering with current behavior
  • Progressive degradation: Gets worse over time as more garbage accumulates

Evidence

In my project database (~/.open-mem/memory.db), out of 4710 total observations, 2330 (49%) were "User request:" type observations — all internal extraction prompts. Sample:

title: "User request: <task>\nAnalyze the following tool output and extract a struc..."
narrative: "<task>\nAnalyze the following tool output and extract a structured observation.\n</task>\n\n<tool_name>todowrite</tool_name>\n\n<tool_output>..."
type: discovery
tool_name: chat.message

The remaining 2380 legitimate observations (bugfix, change, feature, decision, real discovery) were unaffected.

Temporary workaround

Periodically run:

UPDATE observations SET deleted_at = datetime('now')
WHERE title LIKE 'User request:%' AND deleted_at IS NULL;

Suggested fix

The observation extraction pipeline should filter out messages where the content matches the internal extraction prompt pattern before inserting into the observations table. Specifically, skip any message whose content starts with <task>\nAnalyze the following tool output (the extraction prompt template).

Environment

  • open-mem: v0.14.2
  • OpenCode with oh-my-openagent plugin

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions