Repository navigation
Conversation
… agents stay running Idle provider processes were always released after 30 minutes, which ends keep-alive tools running inside the provider process (such as a prompt-cache keep-warm plugin) before they can act. The default ProviderSessionManager layer now reads the timeout from the host environment; unset keeps 30 minutes and invalid values are logged and ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Adds a bounded, opt-in environment setting for idle agent lifetime while preserving the 30-minute default. Invalid settings fall back safely, and documentation explains the memory cost of longer lifetimes. You can add or adjust custom eligibility rules. Learn more. |
|
Thanks for this. #25624 makes the same change and is the one being kept. #25624 already makes idle agent lifetime configurable through Settings on web, desktop, and mobile. It also applies changes to agents already waiting while idle and offers Never, so it covers the underlying need more completely. Your bounded validation and explanation of the memory cost are useful. Keeping the configuration in the existing settings system gives hosts one place to control this behavior. Closing as a duplicate. |
Problem
T3 Code stops an agent's process 30 minutes after its thread goes idle (
DEFAULT_IDLE_TIMEOUT_MSinProviderSessionManager.ts) and resumes it on the next message. A host cannot change this. That breaks tools that run inside the provider process and need it to stay alive. For example, a Claude Code plugin can keep a long thread's prompt cache warm by sending a small forked request shortly before the one-hour subscription cache expires. Inside T3 Code, the process is gone after 30 minutes, so the keep-alive never runs. When the user comes back, the whole conversation is sent again uncached. For a thread with 200k+ tokens, that costs far more than the keep-alive would have.Change
ProviderSessionManager.layerWithOptionsalready acceptsidleTimeoutMs. Until now, only tests set it. The defaultlayernow readsT3CODE_PROVIDER_IDLE_TIMEOUT_MINUTESfrom the host environment:The background-service guide documents the variable next to the other
service.envsettings, including the memory cost of keeping idle processes alive.Scope
This is a focused configuration option for an existing capability, the idle release of provider sessions, under CONTRIBUTING's configuration route. It does not change the default or add a workflow. It only exposes a parameter the layer already has. It is server-only, so clients need no changes.
The value applies to all providers. A per-provider-instance override could later follow the
idleCompactionpattern (a global default that each provider can override) if maintainers want it. I left that out to keep this PR to one problem.Verification
vp test run apps/server/src/orchestration-v2/ProviderSessionManager.test.ts: 72/72 pass, including a new case for parsing the variable: unset, blank,90,1440, and the rejected values0,1441,1.5,-5,30m,1e3.vp run check:changed: format, lint, knip, typecheck and tests all pass.serve --base-dir <checkout>/.t3and theReplay (dev)provider (command-outputscenario):T3CODE_PROVIDER_IDLE_TIMEOUT_MINUTES=1: the turn finished at 00:58:09 and the replay agent process exited at 00:59:09. The trace recordsProviderSessionManager.releaseIfStillIdleat 00:59:09.T3CODE_PROVIDER_IDLE_TIMEOUT_MINUTES=30m: startup loggedWARN Ignoring T3CODE_PROVIDER_IDLE_TIMEOUT_MINUTES: expected whole minutes from 1 to 1440 { value: '30m' }. After a turn finished at 00:59:38, the agent process was still alive 130 seconds later, so the 30-minute default applied.Written with Claude Opus 5.5 in Claude Code (running under T3 Code).
🤖 Generated with Claude Code