Skip to content

Fix proxy decompression bug, correct savings accounting, wire heuristic strip - #12

Merged
varchanaiyer merged 2 commits into
mainfrom
feat/heuristic-strip-fold-fixes
Sep 8, 2026
Merged

varchanaiyer merged 2 commits into
mainfrom
feat/heuristic-strip-fold-fixes

Conversation

@soham96

@soham96 soham96 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fixed a real bug where the proxy forwarded a stale content-encoding header on responses already decompressed by undici's fetch, causing Claude Code's own fetch client to throw BrotliDecompressionError on every single proxied request. This was silent (task completions still succeeded with is_error: false) but meant compaction never actually helped, since the fold logic could still run but the surfaced error path was invisible until a terminal-bench run exposed it.
  • Fixed savedTokens accounting: ScaleDown's summarize-call cost was netted against Anthropic's savings as raw token counts (1:1), but ScaleDown ($0.05/M) and Anthropic (cache read/write, much higher per-token) are priced very differently — a cheap ScaleDown call could wipe out a real, substantial Anthropic-side saving down to 0. Now nets in dollars; both netSavingsUsd and a token-equivalent savedTokens are returned.
  • client.summarize() now optionally sends structured message blocks (not just flattened text) so ScaleDown can run a heuristic tool-result-stripping pass server-side instead of a model call, gated on x-source: kode (companion PR in the compression repo).
  • Lowered foldEveryTurns default from 10 to 5.

Known follow-up (not fixed here)

Fold cadence counts real user prompts (excluding tool_result-bearing messages). A single-instruction agentic session — which is what most of terminal-bench looks like, and a meaningful share of real Claude Code sessions — has only ~1 real prompt no matter how many tool calls happen, so compaction can never fire for that shape of session. Confirmed via direct testing (a 63-message real session never folded). Worth a follow-up to recount cadence by total turns/messages rather than literal new user prompts.

Test plan

  • npm run build clean
  • npm test — 115 passed, 5 skipped (pre-existing), 0 failed
  • Verified end-to-end against a real multi-prompt (15-prompt) synthetic conversation through the actual proxy + a locally running compression server: fold fires at the expected turn, heuristic strip runs server-side, netSavingsUsd/savedTokens now report a genuine positive number instead of clamping to 0

🤖 Generated with Claude Code

soham96 and others added 2 commits September 8, 2026 16:18
…ic strip

- pipeUpstream forwarded a stale content-encoding header on responses that
  undici's fetch had already decompressed, causing Claude Code's own fetch
  client to throw BrotliDecompressionError on every proxied request. Strip
  content-encoding/content-length from the forwarded response headers.

- transformRequest netted ScaleDown's summarize-call cost against Anthropic's
  savings as raw token counts (1:1), but the two are priced very differently
  (~$0.05/M vs Anthropic's cache read/write rates) — a cheap ScaleDown call
  could wipe out a real, substantial Anthropic-side saving. Net in dollars
  instead and expose both netSavingsUsd and a token-equivalent savedTokens.

- client.summarize() now optionally sends structured message blocks alongside
  the flattened text, so ScaleDown can run a heuristic tool-result-stripping
  pass server-side (x-source: kode) instead of a model call for DietCode's
  traffic specifically.

- foldEveryTurns default lowered 10 -> 5, closer to the point where the token
  safety net alone would otherwise trigger, based on real-session analysis.

Verified end-to-end against a real multi-prompt conversation: fold fires
correctly, heuristic strip runs server-side, and net savings are now reported
correctly instead of clamping to 0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This repo is open source; comments describing exactly how the backend
decides to run its cheaper tool-result-stripping path (naming a private
file, and spelling out the client-identification header that gates it)
shouldn't be public here. Describe only what this client sends and why,
not how the backend routes on it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@varchanaiyer
varchanaiyer merged commit 1287b04 into main Sep 8, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants