opencode
opencode copied to clipboard
fix: prevent unbounded memory growth in long-running sessions
Summary
- Fix multiple sources of memory accumulation causing infinite growth in long-running OpenCode sessions
- Add configurable limits and automatic cleanup mechanisms across 5 subsystems
- Maintain full backward compatibility with existing behavior
Problem
During extended sessions (hundreds of tool calls), OpenCode accumulates memory without bounds due to:
- Full message history materialized every loop iteration
- FileTime read cache growing indefinitely per session
- Tool outputs and attachments retained even after compaction
- Instance cache never releasing idle projects
- LSP diagnostics accumulating for all opened files
Solution
Phase 1: Quick Wins (Low Risk)
| Change | File | Impact |
|---|---|---|
| Skip attachments for compacted parts | message-v2.ts |
Reduces model message size |
| Cap queued callbacks at 10 | prompt.ts |
Prevents callback accumulation |
| LRU cache with 500-entry limit | time.ts |
Bounds file tracking memory |
| Memory config options | config.ts |
Makes limits configurable |
Phase 2: Structural Improvements (Medium Risk)
| Change | File | Impact |
|---|---|---|
| 2000 message safety limit | message-v2.ts |
Hard cap on history size |
| 30-minute idle timeout | instance.ts |
Auto-cleanup idle instances |
| 1000-file diagnostics limit | client.ts |
Bounds LSP cache size |
Testing
- Added
test/file/time.test.tswith 4 unit tests for LRU eviction - All 371 existing tests pass
- Typechecks pass across all 12 packages
Files Changed
-
packages/opencode/src/file/time.ts- LRU cache implementation -
packages/opencode/src/session/prompt.ts- Callback limits -
packages/opencode/src/session/message-v2.ts- Attachment skipping & message limit -
packages/opencode/src/project/instance.ts- Idle timeout cleanup -
packages/opencode/src/lsp/client.ts- Diagnostics cache limit -
packages/opencode/src/config/config.ts- Memory config schema -
packages/opencode/test/file/time.test.ts- New tests (created)
Config Options Added
memory: {
fileCacheLimit: 500, // Max file entries per session
maxQueuedCallbacks: 10 // Max queued loop callbacks
}
Breaking Changes
None - all changes are additive with sensible defaults matching previous implicit behavior.