Reduce Agent Mode memory from retained provider processes#360
Open
morluto wants to merge 6 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR reduces Agent Mode memory pressure from retained provider subprocesses while preserving short-term session reuse.
RepoPrompt intentionally keeps some completed provider runtimes alive so follow-up prompts can reuse the existing session. That is useful, but before this change ACP/OpenCode and Claude-compatible runtimes did not have a bounded idle cleanup equivalent to Codex's idle shutdown.
This PR adds bounded cleanup for those retained runtimes, fixes terminal cleanup ordering, and reduces one smaller Codex model-polling resident process.
Local memory observations
This was motivated by local RepoPrompt CE debug-app investigation of Agent Mode memory pressure.
Observed retained subprocess RSS in that environment:
opencode acpprocess.These numbers are workload/provider/environment-dependent, but they show why unbounded retained provider processes can dominate RepoPrompt's memory footprint.
What was happening
ACP / OpenCode
Successful ACP-backed Agent Mode runs intentionally retained their
ACPAgentSessionControllerfor follow-up reuse. This keeps the underlying provider process alive after completion.That is useful briefly, but there was no idle TTL equivalent to Codex's 300s idle shutdown. In local investigation, retained OpenCode ACP processes were the largest memory contributor.
Claude-compatible runtimes
Claude-compatible completed sessions had the same lifecycle shape: the controller/process could remain retained after completion for reuse, but without a Codex-like idle shutdown.
A local Claude-compatible probe confirmed a completed session retained a live native process until the session was explicitly deleted.
Codex model polling
Codex model polling intentionally kept a dedicated non-agent app-server warm while subscribers existed. That avoided restart cost and kept refresh latency low, but also kept an otherwise idle app-server process resident between 60s refreshes.
Since the model snapshot is cached and the client can restart on demand, this PR stops the polling app-server after each refresh while preserving subscriber/cache behavior.
Retained-runtime lifecycle
flowchart TD A[Agent run completes] --> B{Terminal publication accepted?} B -- no --> C[Do not schedule idle cleanup] B -- yes --> D[Keep controller briefly for follow-up reuse] D --> E{New run / steering / provider switch / tab close?} E -- yes --> F[Cancel idle task or explicit cleanup] E -- no, TTL expires --> G{Safe to teardown?} G -- no --> H[Keep controller] G -- yes --> I[Shutdown retained provider process] I --> J[Preserve resume metadata]Completed sessions remain reusable during the idle TTL, but ACP/OpenCode and Claude-compatible provider processes are torn down after the TTL if the session is still inactive and safe to clean up.
What changed
AgentModeIdleShutdownPolicyTabSession.providerSessionIDNativeAgentRuntimeSessionRef.sessionIDRelated issue
Follow-up to #291.
This PR also covers the broader retained-process case beyond unreachable/orphaned ACP sessions: reachable completed ACP/OpenCode and Claude-compatible sessions now have bounded idle cleanup.
Validation
make dev-test FILTER=CodexModelPollingServiceTestsmake dev-test FILTER=AgentModeRunServiceLifecycleTestsmake dev-test-listmake dev-lintmake dev-swift-build PRODUCT=RepoPromptLedger note:
Scripts/Fixtures/test-suite-contract-ledger.tsvfor this PR's new executable tests.python3 Scripts/test_suite_optimizer.py verify-ledger --ledger Scripts/Fixtures/test-suite-contract-ledger.tsvwas run after the update. It still reports unrelated existing repository drift (missing=50 stale=3); the PR-added rows reduced the missing count from 63 to 50.Review notes
Commits are split by concern:
chore(agent-mode): add DEBUG process memory diagnosticsfix(codex): release model polling app-server after refreshfix(agent-mode): bound retained runtime controller lifetimestest(agent-mode): update lifecycle contract ledgerSuggested review order: