Skip to content

fix: duplicate compaction triggered by stale usage stats and cache-ttl custom entry bypass #9282

@1kuna

Description

@1kuna

Summary

Double compaction is triggered by two related issues:

  1. _checkCompaction() runs both after agent_end and again before the next prompt. The pre-prompt path uses the last assistant message’s original usage (kept region), which can still exceed the threshold even after compaction.
  2. prepareCompaction() only blocks when the last entry is compaction. When a custom entry (like openclaw.cache-ttl) is appended after compaction, the guard misses the prior compaction and allows another compaction immediately.

Evidence (session JSONL)

Session: /Users/clawd/.openclaw/agents/main/sessions/93259adc-570a-4234-9e69-81ab7b1ba744.jsonl

  • 2026-02-02T18:14:29.008Z compaction id bd55f1c2 tokensBefore 170231 parent f78129f3
  • 2026-02-02T18:14:30.600Z compaction id 08b283f4 tokensBefore 170231 parent 96aed843
    • Same tokensBefore within ~1.6s indicates the same assistant usage triggered threshold twice.
  • 2026-02-02T22:45:18.470Z compaction id 31d6859f tokensBefore 171992 parent 685f68df
  • 2026-02-02T22:45:18.632Z compaction id 39121230 tokensBefore 2933 parent bfc4bdb2
    • Second compaction fires ~0.16s later even after context was already reduced (tiny tokensBefore).

Root Cause

  • _checkCompaction() doesn’t skip threshold-based compaction when the last assistant message predates the latest compaction entry. The kept-region message retains large usage and causes an immediate second compaction in the pre-prompt check.
  • prepareCompaction() only checks the last entry for compaction, so a trailing custom entry (e.g. openclaw.cache-ttl) bypasses the guard and allows compaction to run again.

Proposed Fix

  • In _checkCompaction(), find the latest compaction entry in the branch and return early for threshold compaction if assistantMessage.timestamp < lastCompaction.timestamp.
  • In prepareCompaction(), ignore trailing custom entries when deciding whether a compaction just occurred.
  • Add a regression test that:
    • Ensures pre-prompt threshold compaction is skipped when the last assistant message predates the latest compaction.
    • Ensures prepareCompaction() returns undefined if a cache-ttl custom entry follows a compaction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions