Repository navigation
Align wait_agent default timeout with prompt-cache TTL (30 min on GPT-5.6+) to cut parent-agent polling cost #41875
Description
What variant of Codex are you using?
CLI (multi-agent / collab mode, GPT-5.6 family)
What feature would you like to see?
Summary: Raise the wait_agent default timeout so the parent-agent polling cadence aligns with the model's prompt-cache TTL (30 min on GPT-5.6+), or make the harness TTL-aware. Today's 30 s default burns parent-agent tokens at ~40 no-op model turns per 20 minutes of waiting, all of which are avoidable.
Background (evidence from existing reports)
wait_agent is already event-driven internally (status watch channels; it returns early on completion), but each timeout expiry returns a timed_out result that re-enters the parent model with the full conversation context. With the 30 s default, a long-running subagent produces a steady stream of no-op parent turns. This is well documented:
- Desktop wait/status orchestration re-meters full cached context every 10-30s; stale 'running' subagents keep it looping (90% of weekly Pro in 15.5h) #37299: 83% of
wait_agentcalls ended intimed_out; each poll re-meters ~140k tokens of context (97%+ cached); 90% of a weekly allowance consumed in 15.5 h. - Codex Desktop repeatedly re-enters the model during wait/status polling, consuming substantial credits #35259: across a full week window, wait/status-only turns accounted for 19.8% of all raw token volume (96.8% of it cached input), ≈3,948 credits on the public rate card.
- Abnormal token consumption: ~678M tokens used while editing 3 resume versions due to repeated multi-agent polling #39854: ~678M tokens for a small task, 98.4% cached input. Per the official credit rate card (help.openai.com, "ChatGPT Rate Card"), cached input is metered at ~10% of the input rate (e.g. GPT-5.3-Codex: 43.75 input / 4.375 cached / 350 output credits per 1M) — the quota exhaustion here came from the absolute cached volume (~666M tokens), not from a missing cached discount.
- Make wait_agent default timeout configurable #18394: requests a configurable default timeout (the v2 config knobs
default/min/max_wait_timeout_msnow exist; thanks — but the default is still 30 s, and the v1 namespace constants inmulti_agents_common.rsremain hardcoded).
What is missing from the discussion so far: the cache-TTL dimension
All quantified reports observe polling cadences of 10–60 s. That is far below any cache TTL, so existing measurements only capture the regime where the prefix never falls out of cache. The interaction between wait interval and cache lifetime has not been analyzed.
GPT-5.6-and-later models guarantee a minimum 30-minute prompt cache lifetime (prompt_cache_options.ttl, only supported value 30m, also the default; per the OpenAI prompt-caching docs). Once wait intervals approach or exceed that TTL, each parent turn pays full uncached input price to rebuild the prefix.
A simple per-hour cost model for a parent holding context C while waiting (cached input ≈ 0.1× uncached price):
- 30 s interval (current default): 120 turns/h × 0.1·pC = 12 pC/h
- 20 min interval (keep-alive, every turn cache-hit): 3 × 0.1·pC = 0.3 pC/h
- ~28 min interval (just under TTL with safety margin): ≈ 0.21 pC/h — the cost optimum
- 60 min interval (every turn a cache miss, full-price refill): 1 × 1.0·pC = 1.0 pC/h
Two useful invariants from this model:
- Even in the worst case (the TTL assumption is wrong and every 20-min turn misses), a 20-min interval costs 3 × 1.0 = 3 pC/h — still 4× cheaper than the best case of the current 30 s default (12 pC/h, all hits). The 30 s default is dominated regardless of TTL behavior.
- Within the 1 h hard cap on
timeout_ms, a keep-alive interval below TTL is structurally cheaper than any miss interval: at a 0.1 cached discount, a miss interval only wins if it exceeds 10× TTL (10 h) — unreachable.
Caveat, stated separately from the evidence: under the official credit rate card, cached input is metered at ~10% of the input rate, so staying cache-hot is a ~10x difference under quota metering too; what remains officially unspecified is how cached context is weighted inside the included 5-hour/weekly subscription limits (asked in #37299, unanswered; the rate card covers credit-based usage). Regardless of that weighting, turn-count reduction dominates under every metering regime, and for intervals ≤ ~25 min both goals align (fewer turns AND cache-hot).
Request
- Raise the default
wait_agenttimeout for models with a known cache TTL (30 min on GPT-5.6+) from 30 s to a TTL-aligned value (~20–25 min), or surface the cache-TTL consideration in the tool description so the model scalestimeout_msaccordingly (the collab prompt already says the value "should be wisely scaled" — the default undercuts that guidance). - Alternatively/additionally, adopt the stronger fix already proposed in Desktop wait/status orchestration re-meters full cached context every 10-30s; stale 'running' subagents keep it looping (90% of weekly Pro in 15.5h) #37299 / Codex Desktop repeatedly re-enters the model during wait/status polling, consuming substantial credits #35259: don't re-enter the model at all when a
wait_agenttimeout produced no state change — the harness already knows nothing happened. - Align the v1 multi-agent namespace with the v2 config knobs —
DEFAULT_WAIT_TIMEOUT_MS = 30_000inmulti_agents_common.rsis hardcoded and ignores[features.multi_agent_v2]settings, so users on the v1 toolset cannot tune this without patching source (noted in Make wait_agent default timeout configurable #18394). - When documenting the knobs, mention the quota-vs-cost trade-off above so users can pick
min_wait_timeout_ms/default_wait_timeout_msdeliberately (quota-constrained: larger; cost-constrained: just under TTL).
Additional information
- Cache TTL reference: OpenAI prompt caching documentation (
prompt_cache_options.ttl,30mdefault/only value on GPT-5.6+). On pre-5.6 models the effective TTL is 5–10 min, where a 20-min interval would miss every turn — hence request update summary to auto #1 is phrased per-model-family, and the harness knows which model is in use. - The 30 s constant also propagates into the tool schema default shown to the model (
spec.rspassesdefault_timeout_ms), so the model tends to inherit the 30 s cadence even when it could pass a larger value. - Related: Make wait_agent default timeout configurable #18394 (configurable default), Desktop wait/status orchestration re-meters full cached context every 10-30s; stale 'running' subagents keep it looping (90% of weekly Pro in 15.5h) #37299 (no-op turns shouldn't re-enter the model), Codex Desktop repeatedly re-enters the model during wait/status polling, consuming substantial credits #35259 (19.8% volume from wait/status turns), Abnormal token consumption: ~678M tokens used while editing 3 resume versions due to repeated multi-agent polling #39854 / Unexpectedly high token consumption when GPT-5.6 Sol delegated #41817 / [Codex Desktop] Nested functions.exec wait_agent polling causes repeated parent turns and token usage #35108 (excess consumption reports), [Feature Request] Introduce a status indicator to prevent "Waiting for agents" terminal spam #33485 (UX for wait spam).
Activity
johnlanni commentedon Aug 31, 2026
Follow-up: a case where a short wait interval is optimal — and a debounce idea it motivates
The cost model in this issue assumed the parent's wake cadence is set by
timeout_ms. That holds for quiet waits, but there is a second regime worth spelling out, because it inverts the conclusion.In MultiAgentV2,
wait_agentreturns early on any mailbox update from a live agent. So when the subagent is active, the parent's actual wake interval isg = min(e, T), whereeis the subagent's inter-update interval andTis the requested timeout — the timeout only caps, not paces, the wake-ups.Worked example with a provider whose cache TTL is 5 min (e.g. Alibaba Model Studio explicit cache, or Anthropic's default 5-min TTL):
e = 6 minand finishes at 30 min.e > TTL, so every parent re-entry finds the cache expired: 5 turns × full-price context rebuild.Two consequences:
e < TTLthe parent is woken for every subagent turn even though nothing actionable happened; whene > TTLit is woken exactly often enough to always miss. Both are wasteful in different directions.Suggested addition to the fix space: debounce/coalesce parent wake-ups to the TTL boundary.
When the parent is idle in
wait_agentand a non-final mailbox update arrives, don't wake it immediately. Hold pending updates and wake the parent at most once per cache-TTL window (or when updates accumulate past a threshold), and always wake immediately on:This bounds the parent's no-op turn rate regardless of subagent chattiness, keeps wake intervals inside the cache window by construction (the harness doesn't need to know the exact TTL — a conservative internal cap such as 5 min achieves the bounded-turn property on its own), and eliminates the
e > TTLalways-miss regime. It composes with the existing suggestion of not re-entering the model when a timeout produced no state change: one rule covers timeout-expiry no-ops, the other covers event-driven no-ops.For tracing/diagnostics, the wait/status turn attribution work in #35259 would make the effect of such a debounce directly measurable (parent wait-turns per child completion before/after).
razdgann commentedon Sep 3, 2026
I like the TTL-aware approach because this looks like a case where the optimization shouldn’t only be “make the LLM call cheaper.”
The first question should be whether another model invocation is necessary just to check if the agent finished.
Ideally the runtime could wait deterministically for state changes and only wake the model when there is actually new information to reason about.
We’re exploring this distinction in ModelGate: finding repetitive and expensive LLM traffic that may not need to stay an LLM call.
Agent polling is probably one of the clearest examples of that problem.
tagorr commentedon Sep 8, 2026
I have a clean Codex CLI reproduction that strongly supports the failure mode described here.
Environment: Codex CLI 0.153.1, Plus, Windows; parent gpt-6-astra / low, with 2 × gpt-5.6-luna / xhigh workers.
During one ~33-minute orchestration run:
wait_agenttimeout_ms = 30000timed_out: trueDuring the same interval, server-reported 5h usage went from 53% to the 100% cap.
The session guidance explicitly said:
but the parent nevertheless continued using 30-second waits.
For additional scale, I measured an active Luna Max control session from the same account earlier the same day: 9.54M input tokens over 127 minutes increased the 5h metric by only 8 percentage points.
So in this reproduction, 7.13M input tokens were spent solely on timeout polls that returned no new worker state.
Full telemetry, worker accounting, and the uploaded diagnostic thread are here:
#35259 (comment)
This seems to support both fixes proposed here: substantially increasing the wait interval, and preferably avoiding parent-model re-entry entirely when a
wait_agenttimeout contains no state change.