Skip to content

Fix STLTMemory consolidation discarding the oldest memory entry before LLM summarization#187

Closed
BEASTSHRIRAM wants to merge 2 commits intomesa:mainfrom
BEASTSHRIRAM:fixbug
Closed

Fix STLTMemory consolidation discarding the oldest memory entry before LLM summarization#187
BEASTSHRIRAM wants to merge 2 commits intomesa:mainfrom
BEASTSHRIRAM:fixbug

Conversation

@BEASTSHRIRAM
Copy link

Summary

Fixes a silent data loss bug in STLTMemory.process_step() and aprocess_step() where the oldest short-term memory entry was permanently dropped during consolidation because popleft() was called before _update_long_term_memory() ran. The fix moves popleft() to after the LLM summarization completes, ensuring every evicted entry is captured in long-term memory before being removed.

Bug / Issue

Fixes #186

In a multi-round negotiation simulation using the negotiation example (or any model with long-running agents), each LLMAgent uses STLTMemory(capacity=5, consolidation_capacity=2) by default. After step 7 — when the deque first exceeds capacity + consolidation_capacity — consolidation triggers for the first time.

At that moment, the agent's oldest entry (e.g., step 1: "Counterparty opened with $500k, non-negotiable on delivery timeline") is evicted from the deque before the LLM runs. The consolidation prompt only includes steps 2–7. The agent's long-term memory never records the opening offer.

By step 20, the agent has completely forgotten the counterparty's original constraints and begins making proposals that violate the terms it had agreed to never challenge — causing the negotiation to loop indefinitely or reach a logically inconsistent outcome. No error is raised; the model simply behaves incorrectly.

The bug is in _process_step_core():

# BEFORE (buggy): evict first, then consolidate — entry is already gone
if len(self.short_term_memory) > self.capacity + ...:
    self.short_term_memory.popleft()   # ← entry removed HERE
    should_consolidate = True

# Later in process_step():
if should_consolidate:
    self._update_long_term_memory()    # ← prompt built WITHOUT the evicted entry

Implementation

Removed popleft() from the consolidation branch in _process_step_core() so the entry remains in the deque when _build_consolidation_prompt() calls format_short_term(). The eviction is then performed in both process_step() and aprocess_step() after the LLM call completes:

# _process_step_core() — consolidation branch (fixed)
if len(self.short_term_memory) > self.capacity + ...:
    should_consolidate = True          # ← entry stays in deque

# process_step() (fixed)
if should_consolidate:
    self._update_long_term_memory()    # ← entry IS in the prompt
    self.short_term_memory.popleft()   # ← evict only after summary is written

# aprocess_step() (fixed)
if should_consolidate:
    await self._aupdate_long_term_memory()
    self.short_term_memory.popleft()

The no-consolidation branch (not self.consolidation_capacity) intentionally discards without summarizing — that path is unchanged.

Testing

Added test_consolidation_includes_evicted_entry() in test_STLT_memory.py. The test:

  1. Creates an STLTMemory with capacity=2, consolidation_capacity=1
  2. Fills it with 4 entries to trigger consolidation
  3. Asserts that the LLM consolidation prompt received by the mock includes the content of the oldest entry (the one that would have been silently dropped before this fix)

All 11 tests pass.

Additional Notes

This is a correctness bug in the default memory type used by every LLMAgent. Any simulation longer than capacity + consolidation_capacity steps is affected. The failure is completely silent — the agent continues running with a corrupted long-term memory, making it very hard to diagnose in practice.

No API changes. No new dependencies. The fix is 3 lines moved to a later point in the call sequence.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 21641506-ea3a-48f3-8b83-5e0c4076c7e9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@IlamaranMagesh
Copy link

Already a fix for this issue here, #166. Please look into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: STLTMemory silently drops the oldest memory entry during consolidation

2 participants