Subagent requests don't place cache_control on trailing system-context block — ~4.7K tokens re-written per fresh spawn
Observation
Spawning the same subagent multiple times within the 5-min cache TTL shows a stable split:
cache_read_input_tokens: ~5400 (agent system prompt + tool schemas)cache_creation_input_tokens: ~4700 (written fresh every spawn)input_tokens: 2
Measured across 4 back-to-back spawns of a small custom subagent (tools: Glob/Grep/Read/Bash/Write; ~650-token system prompt + ~70-token skill). With byte-identical task prompts, cache_creation still holds at ~4700.
Root cause
The uncached ~4700 tokens come from the system-context block appended after the cache boundary:
- Main-session path splits the system prompt at a
DYNAMIC_BOUNDARYsentinel — static prefix gets a cache marker, dynamic tail (env_info, gitStatus, cwd, date) doesn't. - Subagent path (
runAgent/AgentTool) passes the agent's prompt as an override that bypasses theDYNAMIC_BOUNDARYsplit — the whole prompt gets one marker, thenappendSystemContext()tacks git/env/cwd/date on after that marker with no further marker. - Net: every fresh subagent spawn pushes the trailing ~3.5K env block + ~1.2K of user messages into
cache_creationregardless of byte-identity with the prior spawn.
Why it matters
Context-heavy workflows (research / search / spawn-heavy agents) pay full cache-write price (1.25×) on ~4.7K tokens per spawn, even at sub-second spacing. Scales linearly with spawn count.
Suggested fix
Either:
- Apply the
DYNAMIC_BOUNDARYsplit to the composed (agent prompt +enhanceSystemPromptWithEnvDetails+appendSystemContext) system prompt in the subagent path, OR - Add a second
cache_controlmarker at the end of the composed system prompt in the subagent path (API allows up to 4).
Workaround
SendMessage(to: <agentId>) to a still-alive subagent sidesteps cold-start — the full conversation stays cached. Doesn't help for fire-and-forget search spawns.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗