opencode icon indicating copy to clipboard operation
opencode copied to clipboard

fix: wire up ACP agent cleanup on connection end to prevent memory leaks

Open hendem opened this issue 1 week ago • 4 comments

Summary

This PR wires up cleanup to be called when ACP connections end, ensuring memory is properly freed.

Problem

When an ACP connection ends (e.g., IDE closes, client disconnects):

  • Event subscription loops (for await in setupEventSubscriptions) run forever
  • Session state in ACPSessionManager.sessions Map accumulates indefinitely
  • sessionAbortControllers never get cleaned up

This leads to the memory leak crashes reported in #4315 and #5363.

Solution

  1. ACP.Agent.dispose() - New method that:

    • Aborts all active event subscriptions via AbortController
    • Clears all session state from the session manager
    • Logs cleanup for debugging
  2. AbortController pattern in setupEventSubscriptions() - Each session's event subscription loop now:

    • Has an associated AbortController
    • Checks controller.signal.aborted in the loop
    • Cleans up controller reference in finally block
    • Handles errors gracefully during abort
  3. Cleanup wired to connection lifecycle - In acp.ts command:

    • Agent instance is captured when created
    • agent.dispose() is called after stdin ends
    • Ensures cleanup happens even on unexpected disconnection

Changes

File Change
src/acp/agent.ts Add dispose(), cleanupSession(), AbortController pattern
src/acp/session.ts Add remove(), size(), sessionIds(), clear() methods
src/cli/cmd/acp.ts Capture agent instance and call dispose() on connection end
test/acp/session.test.ts Tests for session manager cleanup methods

Testing

  • 5 tests added for ACPSessionManager
  • All tests pass
  • Typecheck passes
  • Build passes

Related Issues

  • #4315 - Memory stays unbounded: ACP session map + compacted tool outputs
  • #5363 - opencode eating 70gb of memory?

Related PRs

  • #6682 - FileTime session cleanup (by @elithrar)
  • #7032 - Bus subscription cleanup (dispose methods for Share, ShareNext, Format, Plugin)

hendem avatar Jan 06 '26 05:01 hendem