opencode icon indicating copy to clipboard operation
opencode copied to clipboard

fix: clear tool output and attachments when pruning to prevent memory leak

Open hendem opened this issue 1 week ago • 4 comments

Fixes #3013

Summary

Clear tool output and attachments when compaction prunes old tool results, actually freeing memory instead of just flagging.

Evidence

In a real session working on this repo:

Metric Value
OpenCode process RAM 16.4 GB
Tool parts on disk 34,887 files
Session duration ~3 hours

Sample tool output sizes from this session:

  • webfetch of docs page: 10 KB
  • read of source file: 5-50 KB
  • git diff / gh pr diff: 10-100 KB
  • bash command outputs: 1-50 KB

All of these outputs stay in memory even after compaction marks them "old".

The Problem

In SessionCompaction.prune(), when tool outputs are pruned:

// BEFORE: Only sets a flag, output data stays in memory
part.state.time.compacted = Date.now()
await Session.updatePart(part)

The compacted timestamp is used by toModelMessage() to replace output with placeholder text like "(Old tool result content cleared)" - but the actual data never gets freed.

Over a long session:

  • 34,887 tool calls × average output size = hundreds of MB to GBs retained
  • Memory never decreases, even after compaction runs
  • Eventually Bun runs out of memory and crashes

The Fix

// AFTER: Actually clear the data
part.state.time.compacted = Date.now()
part.state.output = ""              // Free the output string
part.state.attachments = undefined  // Free any attachments
await Session.updatePart(part)

Now when compaction runs, the memory is actually freed. The placeholder text is already shown to the LLM (that logic exists), we just were not clearing the source data.

Testing

Existing compaction tests pass. Added test verifying output/attachments are cleared after prune.

hendem avatar Jan 06 '26 05:01 hendem

The following comment was made by an LLM, it may be inaccurate:

No duplicate PRs found

github-actions[bot] avatar Jan 06 '26 05:01 github-actions[bot]

Addressed review comment about test not verifying behavior when pruning is disabled (commit 488173440).

The test now:

  1. Creates a tool part with large output (200,000 chars) and an attachment (similar to the first test)
  2. Creates additional user messages to get past turn protection
  3. Calls prune() with pruning disabled via config
  4. Verifies that:
    • output.length remains 200,000 (unchanged)
    • attachments.length remains 1 (unchanged)
    • time.compacted is undefined (not set)

hendem avatar Jan 06 '26 06:01 hendem

this would be really helpful

kevoconnell avatar Jan 07 '26 08:01 kevoconnell