Repository navigation
Conversation
Claude Code marks every request for the prompt cache, and the route's one-turn calls get a one-hour entry, which the API prices at twice the input. An indexing prompt is never sent twice, so no later call reads the entry: on 64 real leaf-summary prompts (Haiku, 16 at a time) the run wrote 140,939 tokens to the one-hour cache and read none. With DISABLE_PROMPT_CACHING=1 the same prompts go in as plain input (141,067 tokens), no slower (19.8 s against 21.6 s), and the run costs about 35% less at API prices. How a subscription's quota weighs cache writes is not published. Chat on the route keeps the cache: a run's later turns read it.
Each call on the route is one Claude Code process, about 150 MB, so 16 at a time is about 2.4 GB. On 32 real leaf-summary prompts (Haiku), 16 processes took 11.8 s against 17.4-19.7 s at 8, with the same tokens. The cap's comment names SUMMARY_CONCURRENCY instead of its value, so a change to the summary lane's width leaves it right. The other ways to raise concurrency on a subscription were measured and dropped: - One process fanning out subagents through the Agent tool: 42 s and 2-3x the tokens; each subagent reads, answers and reports in two to three turns. - A Workflow script with every task inline: one process ran 64 prompts at once in 11.5 s (16 processes: 19.8 s) on 0.4 GB, but cost about 22% more at API prices than 16 processes without the cache write (previous commit). Each workflow agent carries a fixed workflow note and writes its prompt to the 5-minute cache, and each run adds main-session turns worth about 16k input tokens. Unless a permission mode is set, the CLI also sends each agent's reply to a Sonnet security check of about 46k tokens. And a workflow needs its task list up front, while indexing calls become ready one by one (children before parents, expand before summaries). - Several summaries per call: about 15% fewer tokens, but in 2 of 8 batches the model answered only the first task and dropped the rest without an error. Risk: the route does not retry (the CLI already has), and starting many sessions at once can trip a server-side burst limit (anthropics/claude-code#53922). A call that fails that way fails the indexing run loudly.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
macOS's temp dir sits under /var, a symlink to /private/var. Started there, the CLI lists the directory twice in the environment block it adds to every prompt: resolved, as the primary working directory, and again as given, as an additional working directory. Resolving the path first drops the second listing: a one-line prompt goes from 622 input tokens to 560 (Haiku), about 3% of the input of an average leaf-summary call. Index and chat calls share these options. Linux temp dirs are not symlinks, so nothing changes there.
Flash runs expand and the summaries on one loop, each lane wider than the route's cap of 16 CLI processes (expand 32, summaries 64), so their calls waited at that cap in arrival order. The summary lane's deepest-first order held only for the calls it let through, and an expand call, which every summary under its node waits on, could sit behind dozens of summaries. The cap is now a priority gate, like the summary lane's. Each lane sets a contextvar priority around its calls: expand ahead of every summary, summaries by depth, anything else 0, first come first served within a priority. API models have no gate below the lanes, so nothing changes there. Measured with a faked CLI whose calls sleep 1 s on average (expand 3 s), the same per prompt in both runs, on the 758-page PRML and the 222-page annual report: expand finished 13-15% sooner, the whole run 2-3% sooner (52.8 -> 51.6 s, 20.6 -> 20.1 s). The lanes keep the cap busy either way. Order matters more where expand splits nodes and so adds summaries, which this fake never does.
A response that stops sending bytes, keep-alive pings included, is dead, yet the CLI's byte watchdog waits 3 minutes on the direct API (5 through a custom base URL) before it aborts and re-sends the request. On a 64-prompt run through a logging proxy, one stream hung 300 s before the CLI re-sent it, and the whole run waited on it. CLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS, documented with a range of 10 s to 30 minutes, sets that watchdog; the first-byte deadline follows it, so a request with no response headers is re-sent sooner too. Index calls only, as with the cache setting: chat keeps the defaults. Checked live through a proxy that stalls the first response: stalled after its headers and stalled after its first text delta, the CLI re-sent the request and the call returned the whole 120-word reply both times, never the cut-off part (10 s watchdog); with this change's value the re-send came 30.05 s after the stall. A stream the server keeps pinging without output still waits for the event watchdog, 5 minutes at the least.
…w effort Claude Code won't turn thinking off for some models: the model table in CLI 2.1.301 marks Haiku 5.5, Sonnet 5.5, Opus 5.5 and the Fable models rejects_disabled_thinking, and the CLI rewrites --thinking disabled to adaptive thinking at the model's default effort, medium on Haiku 5.5, though the API itself takes thinking off on Haiku 5.5 at effort low to high. Summaries pass "none" by default, so on claude-code/haiku they ran at medium. An index call with "none" now also asks for low effort: no thinking where the model allows it, the least thinking where it doesn't. Chat keeps its "none" as before. Flash on the 222-page 2023-annual-report.pdf (run on the workflow prototype, 64 lanes), summaries and expand at low against medium: the one summary that thought at medium (452 tokens, 5.0 s, on the run's critical path) thought none and took 2.7 s; the calls phase took 22.0 s against 24.0 s; the same 192-node tree; leaf summaries averaged 119 words against 116 and cited 6.21 of their text's numbers against 5.98. Expand stays at the model's default: at low its largest call still thought 1,254 tokens against 1,304.
Member
Author
|
Folded into #640, which now carries all six of this PR's commits and its description. |
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.
Indexing on the
claude-code/route runs 16 calls at a time instead of 8, and stops writing each prompt to a one-hour cache entry that no later call reads. On 64 real leaf-summary prompts (Haiku, 16 at a time), skipping the cache write cut the run's cost by about 35% at API prices, no slower; on 32 prompts, 16 processes took 11.8 s against 17.4–19.7 s at 8. Calls waiting for one of the 16 slots now go by priority, expand first and then the deepest summaries, instead of in arrival order, and a response stream that goes silent is re-sent after 30 s instead of 3 minutes. On macOS, every call on the route also sends 62 fewer input tokens, since the CLI now lists its working directory once instead of twice. Index calls that passreasoning_effort="none", as the summaries do by default, also ask for low effort: Claude Code keeps thinking on for Haiku 5.5 and ran them at its default, medium. Chat keeps its cache and its"none".Changes
claude_code_completesetsDISABLE_PROMPT_CACHING=1for the CLI. Claude Code gives each of the route's one-turn calls a one-hour cache entry, which the API prices at twice the input, and no indexing prompt is ever sent twice, so none is read back. Chat keeps the cache, since a run's later turns read it.CLAUDE_CODE_CONCURRENCY8 → 16, moved here from Retries follow the official SDK rule everywhere; flash summaries run 128 at a time #638. Each call is one Claude Code process of about 150 MB, so 16 at a time is about 2.4 GB. The comment namesSUMMARY_CONCURRENCYinstead of its value, so a later change to the summary lane's width leaves it right.claude_code_optionsresolves the route's working directory to its real path. macOS's temp dir sits under/var, a symlink to/private/var, and the CLI listed it twice in the environment block of every prompt: resolved, as the primary working directory, and as given, as an additional working directory. Linux temp dirs are not symlinks._PriorityGate, like the summary lane's. Flash runs expand (32 wide) and the summaries (64 wide) on one loop, so both lanes' calls waited at this cap of 16 in arrival order, and the summary lane's deepest-first order held only for the calls it let through. Each lane now sets a priority around its calls withllm_priority, a contextvar: expand ahead of every summary, since no summary under a node starts while expand may still change it; summaries by depth, the order the summary lane already used; anything else 0; first come first served within a priority. API models have no gate below the lanes, so nothing changes for them.claude_code_completesetsCLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS=30000. A response that sends no bytes, keep-alive pings included, is dead, but the CLI's byte watchdog waits 3 minutes on the direct API before it aborts and re-sends the request. The first-byte deadline follows this value, so a request with no response headers is re-sent sooner too. Index calls only, as with the cache setting.claude_code_completeadds effort low toreasoning_effort="none". The model table in Claude Code 2.1.301 marks Haiku 5.5, Sonnet 5.5, Opus 5.5 and the Fable models as rejecting disabled thinking, and the CLI turns--thinking disabledinto adaptive thinking at the model's default effort, medium on Haiku 5.5, though the API itself takes thinking off on Haiku 5.5 at effort low to high. With low, a model that can turn thinking off still does, and one that can't thinks the least it can. Index calls only, as with the cache setting; expand sends no effort and keeps the model's default.Behavior changes
claude-code/haiku, summaries run at effort low instead of medium. A model without effort levels drops it, as before.Verification
claude_code_complete, before the path change: 2,026 input tokens, 0 cache writes, 0 cache reads.PRML.pdfand the 222-page2023-annual-report.pdffromexamples/documents: expand finished 13–15% sooner, the whole run 2–3% sooner (52.8 → 51.6 s, 20.6 → 20.1 s). The 16 slots stay busy either way. Order matters more where expand splits nodes and so adds summaries, which the fake never does.2023-annual-report.pdfwith summaries and expand at low against medium, run on a workflow prototype with 64 lanes that is not in this PR: the one summary that thought at medium (452 tokens, 5.0 s, on the run's critical path) thought none and took 2.7 s; the calls phase took 22.0 s against 24.0 s; the same 192-node tree; leaf summaries averaged 119 words against 116 and cited 6.21 of their text's numbers against 5.98. Expand at low still thought 1,254 tokens on its largest call against 1,304, so expand keeps the model's default.DISABLE_PROMPT_CACHING=1(chat's do not) andCLAUDE_BYTE_STREAM_IDLE_TIMEOUT_MS=30000; an index call's working directory is its real path; queued index calls go highest priority first (fails with the old FIFO cap); expand and summary calls carry their priorities; an index call with"none"carries effort low (fails without the change). Local: 988 passed, 7 skipped; without frameworks, simulated: 685 passed, 310 skipped.