feat: output-token reduction — verbosity shaper, per-user learning, counterfactual savings - #965
Merged
Merged
Conversation
Contributor
PR governanceThis PR follows the template and is marked ready for human review. |
21 tasks
chopratejas
added a commit
that referenced
this pull request
Jun 14, 2026
) ## Description Every `test (N)` shard has been failing on all PRs and on pushes to `main`, even though all tests pass. Root cause: **Codecov retired tokenless uploads.** Without a token, the upload is rejected with `Token required because branch is protected`, and `ci.yml` had `fail_ci_if_error: true` with no token — so the rejected upload failed the whole shard. This passes `CODECOV_TOKEN` to the coverage-upload steps so uploads authenticate again. Closes # ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `ci.yml`: add `token: ${{ secrets.CODECOV_TOKEN }}` to the shard upload step; guard `fail_ci_if_error` so it stays enforced on same-repo PRs and pushes but relaxes on fork PRs (which cannot read repo secrets). - `wrap-native-e2e.yml`, `install-native-e2e.yml`: add the same token so their coverage uploads authenticate too (these were silently dropping coverage; already non-fatal). ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ python -c "import yaml; [yaml.safe_load(open(f)) for f in [ '.github/workflows/ci.yml', '.github/workflows/wrap-native-e2e.yml', '.github/workflows/install-native-e2e.yml']]" OK ci.yml OK wrap-native-e2e.yml OK install-native-e2e.yml This PR's own `test (N)` shards are the real test: with CODECOV_TOKEN set, they should upload successfully and go green. ``` ## Real Behavior Proof - Environment: GitHub Actions, `codecov/codecov-action@v5` (ci.yml) / `@v4` (e2e); repo is public; `CODECOV_TOKEN` repo secret set by the maintainer. - Exact command / steps: open this PR → observe the `test (1..4)` shards upload coverage with the token instead of being rejected. - Observed result: prior runs showed `1592 passed` then `Token required because branch is protected` → shard failed; main's own push CI was red for the same reason. With the token referenced, the upload authenticates. - Not tested: fork-PR path (no secret) — by design it now relaxes `fail_ci_if_error` so the tokenless rejection is non-fatal there. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Requires the `CODECOV_TOKEN` repository secret (GitHub → Settings → Secrets and variables → Actions). No code/CHANGELOG change. Separate from the output-token-reduction feature PR #965.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds output-side token reduction to Headroom’s proxy (verbosity steering + effort routing), plus a per-user verbosity learning flow and a counterfactual/measured savings estimator surfaced via CLI and dashboard.
Changes:
- Introduces an opt-in request rewriter (
output_shaper) that appends cache-safe verbosity steering to the system-prompt tail and routes effort down on mechanical tool-result continuations. - Adds verbosity learning (
headroom learn --verbosity) that mines Claude Code transcripts for behavioral signals and seeds a per-stratum output-token baseline. - Adds an output-savings ledger/estimator with holdout arm assignment, CLI reporting, and dashboard stats surfacing.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_verbosity_learn.py | Unit tests for transcript signal extraction + heuristic recommendation. |
| tests/test_verbosity_controller.py | Unit tests for AIMD verbosity controller state machine + persistence. |
| tests/test_output_shaper.py | Unit tests for turn classification, steering idempotency, and effort routing. |
| tests/test_output_savings.py | Unit tests for stratification, arm assignment, baseline/holdout estimation, and echo ratio. |
| tests/test_output_savings_cli.py | Smoke tests for CLI output + outcome→ledger wiring via labels. |
| scripts/eval_output_shaper.py | Live eval script comparing baseline vs shaped request output tokens. |
| README.md | Documents the new “Output token reduction” feature and basic usage. |
| headroom/proxy/verbosity_controller.py | Adds AIMD controller + state load/save helpers. |
| headroom/proxy/server.py | Surfaces output reduction stats in /stats payload for dashboard consumption. |
| headroom/proxy/output_shaper.py | Implements request-side verbosity steering and effort routing. |
| headroom/proxy/output_savings.py | Implements ledger, stratification, deterministic holdout assignment, and estimators. |
| headroom/proxy/outcome.py | Records output-token observations into the savings ledger (best-effort). |
| headroom/proxy/handlers/anthropic.py | Wires shaper + holdout assignment + stratum labels into Anthropic request path. |
| headroom/learn/verbosity.py | Implements transcript parsing, signal extraction, baseline building, and recommendation logic. |
| headroom/dashboard/templates/dashboard.html | Adds “Output Tokens Saved” hero card. |
| headroom/cli/output_savings.py | Adds headroom output-savings command. |
| headroom/cli/main.py | Registers the new CLI command module. |
| headroom/cli/learn.py | Adds --verbosity / --llm-judge mode and persistence/baseline seeding. |
| docs/proposals/output-token-reduction.md | Design doc including methodology/constraints and measurement approach. |
| docs/output-token-reduction-guide.md | End-user guide for enabling, learning, and measuring output reduction. |
| .gitignore | Ensures the new eval script is not ignored under scripts/*. |
Comment on lines
+193
to
+210
| def lookup(self, key: str) -> tuple[float, float, int]: | ||
| """Return ``(mean, var, n)`` for *key* with hierarchical back-off. | ||
|
|
||
| Falls back by trimming trailing (least-specific) stratum fields, then | ||
| to the global mean. Back-off keeps the estimate defined for strata the | ||
| baseline never saw, at the cost of specificity. | ||
| """ | ||
| acc = self.strata.get(key) | ||
| if acc is not None and acc.n > 0: | ||
| return acc.mean, acc.var, acc.n | ||
| parts = key.split("|") | ||
| while len(parts) > 1: | ||
| parts = parts[:-1] | ||
| prefix = "|".join(parts) | ||
| for k, a in self.strata.items(): | ||
| if k.startswith(prefix + "|") and a.n > 0: | ||
| return a.mean, a.var, a.n | ||
| return self.glob.mean, self.glob.var, self.glob.n |
Comment on lines
+306
to
+315
| output_config = body.get("output_config") | ||
| if isinstance(output_config, dict): | ||
| effort = output_config.get("effort") | ||
| if ( | ||
| isinstance(effort, str) | ||
| and effort in _EFFORT_RANK | ||
| and _EFFORT_RANK[effort] > _EFFORT_RANK[settings.mechanical_effort] | ||
| ): | ||
| output_config["effort"] = settings.mechanical_effort | ||
| labels.append(f"output_shaper:effort:{effort}->{settings.mechanical_effort}") |
Comment on lines
+1734
to
+1742
| # Stratum from request features observable now (mirrors the | ||
| # offline baseline so live and learned strata line up). | ||
| _turn_kind = classify_turn(body.get("messages", [])).value | ||
| _stratum = stratum_key( | ||
| turn_kind=_turn_kind, | ||
| input_tokens=original_tokens, | ||
| model=model, | ||
| has_tools=bool(body.get("tools")), | ||
| ) |
Comment on lines
+96
to
+101
| try: | ||
| d = json.loads(Path(path).read_text()) | ||
| state = ControllerState.from_dict(d) | ||
| except (OSError, json.JSONDecodeError, ValueError): | ||
| state = ControllerState(level=default_level) | ||
| state.level = max(floor, min(ceil, state.level)) |
…c requests Verbosity steering (5 levels, cache-safe system-tail injection) + effort routing that lowers output_config.effort on mechanical tool_result continuations and clamps legacy thinking budgets. Opt-in via HEADROOM_OUTPUT_SHAPER; never injects effort where absent, never toggles thinking.type. Live eval: -22% (L2) / -63% (L3) output tokens on a code review ask; -29% on an agentic continuation turn (opus-4-8).
…s + dashboard Phase 2 of output-token reduction, built on the Phase 1 shaper: - learn --verbosity: mine Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommend a verbosity level (heuristic prior + optional --llm-judge), and seed the savings baseline. Real data: 11% interrupt / 26% fast-skip -> L3, high confidence. - Counterfactual savings estimator (output_savings.py): per-stratum synthetic control (estimated) + A/B holdout (measured), signed-delta aggregate with a propagated 95% CI. Conversation-stable arm assignment (clean A/B + cache-safe). - AIMD verbosity controller: additive-increase / fast-back-off state machine with hysteresis; live signal emission gated off by default. - Shaper resolves the learned level (env > controller > learned > default); recording rides the existing transforms_applied label channel through the outcome funnel, so all response paths feed the ledger with no RequestOutcome changes. - CLI: headroom output-savings (reduction % + CI, measured vs estimated). - Dashboard: 'Output Tokens Saved' hero card (count, %, CI, measured/estimated). - Docs: simple-words user guide + design doc with the counterfactual methodology. - Tests: 94 new (estimator stats, signal extraction, controller, CLI), all green; 44 existing outcome/dashboard tests still pass. Opt-in: HEADROOM_OUTPUT_SHAPER=1; HEADROOM_OUTPUT_HOLDOUT=0.1 for a measured number.
chopratejas
force-pushed
the
feat/verbosity-learning-and-counterfactual
branch
from
June 17, 2026 03:46
23a6828 to
803dbdf
Compare
Merged
chopratejas
pushed a commit
that referenced
this pull request
Jun 22, 2026
🤖 I have created a release *beep* *boop* --- <details><summary>0.27.0</summary> ## [0.27.0](v0.26.0...v0.27.0) (2026-06-22) ### Features * **cli:** add headroom doctor setup diagnostics ([#926](#926)) ([e45cf4e](e45cf4e)) * **cli:** add headroom update command and release banner ([#1088](#1088)) ([26be2c3](26be2c3)) * compression extraction — Rust knob exposure, CCR hardening, traffic audits ([#818](#818)) ([b7be381](b7be381)) * measure and surface token throughput (tokens/sec) through the proxy ([#983](#983)) ([0d89c67](0d89c67)) * output-token reduction — verbosity shaper, per-user learning, counterfactual savings ([#965](#965)) ([a99dc61](a99dc61)) * **policy:** decay P_alive from idle time near cache TTL ([#856](#856) P3b) ([#1028](#1028)) ([fe4f9ee](fe4f9ee)) * **providers:** add Cortex Code (Snowflake CoCo) as a supported agent ([#1190](#1190)) ([d9d0bf4](d9d0bf4)) * **proxy:** cc-switch reconciler — keep Headroom in the request path alongside cc-switch ([#1030](#1030)) ([e8fc8a0](e8fc8a0)) * **proxy:** hot-reload live env knobs so a reused proxy picks them up without a restart ([#1090](#1090)) ([6904d47](6904d47)) * **proxy:** make COMPRESSION_TIMEOUT_SECONDS configurable via env ([#946](#946)) ([#991](#991)) ([addebdb](addebdb)) * **transforms:** tabular + spreadsheet (.xlsx/.xls) compression ([#1128](#1128)) ([d789a7c](d789a7c)) * **vertex:** turnkey Claude Code + Vertex compression (+ fixes from the Vertex review) ([#1113](#1113)) ([0e05915](0e05915)) ### Bug Fixes * **ccr:** accept 12-char SmartCrusher hashes in tool injection ([#1095](#1095)) ([#1141](#1141)) ([9f7f3ad](9f7f3ad)) * **ccr:** return stored content when headroom_retrieve query matches nothing ([#1213](#1213)) ([#1236](#1236)) ([08fb845](08fb845)) * **content-router:** honor target_ratio in compression cache + add proxy --target-ratio flag ([#1108](#1108)) ([8894ee0](8894ee0)) * **dashboard:** light-mode backgrounds + aligned savings tables ([#1064](#1064)) ([5eae32b](5eae32b)) * **deps:** make litellm optional on Python 3.14 ([#956](#956)) ([#993](#993)) ([b2f04e4](b2f04e4)) * **e2e:** align Codex wrap e2e with global-only RTK guidance ([#1240](#1240)) ([#1254](#1254)) ([bc12ace](bc12ace)) * **init:** set ENABLE_TOOL_SEARCH=true so Claude Code keeps deferring tools ([#746](#746)) ([#995](#995)) ([500ec2b](500ec2b)) * **kompress:** never block the request path on the cold-cache model download ([#1161](#1161)) ([3fc2a78](3fc2a78)) * **memory:** use ONNX embedder for `wrap --memory` sync ([#1092](#1092)) ([#1262](#1262)) ([4f9feda](4f9feda)) * **openclaw:** wrap plugin export as {register} object for OpenClaw 2026.x compatibility ([#1218](#1218)) ([2e6c442](2e6c442)) * **providers:** update DeepSeek V3 context limit from 128K to 1M ([#1038](#1038)) ([#1137](#1137)) ([bcabc5c](bcabc5c)) * **proxy:** allow disabling periodic TOIN stats logging ([#1265](#1265)) ([b5f63d8](b5f63d8)) * **proxy:** honor HEADROOM_EXCLUDE_TOOLS for Codex /v1/responses tool outputs ([#940](#940)) ([#1053](#1053)) ([f03e77b](f03e77b)) * **proxy:** preserve byte-faithful Anthropic tool forwarding ([#1222](#1222)) ([1f18d59](1f18d59)) * **proxy:** route Codex OAuth image requests ([#1215](#1215)) ([381d771](381d771)) * **proxy:** scope CORS to loopback + gate operator/content endpoints ([#1226](#1226)) ([bd55a42](bd55a42)) * **proxy:** stamp X-Client: codex on Responses endpoint for unidentified callers ([#1036](#1036)) ([b0cd032](b0cd032)) * **proxy:** treat NODE_EXTRA_CA_CERTS as additive, not replacement ([#998](#998)) ([#1031](#1031)) ([c987283](c987283)) * **telemetry:** switch anonymous telemetry to opt-in (off by default) ([#1223](#1223)) ([b998697](b998697)) * **tokenizers:** bound tiktoken vocab load so a stalled download cannot hang requests ([#956](#956)) ([#994](#994)) ([7e86baf](7e86baf)) * **unwrap:** remove ANTHROPIC_BASE_URL + ENABLE_TOOL_SEARCH and init hooks on unwrap ([#992](#992)) ([5b84691](5b84691)) * **wrap:** keep Codex RTK guidance global ([#1240](#1240)) ([7c26a54](7c26a54)) * **wrap:** percent-encode non-ASCII cwd names in X-Headroom-Project header ([#1071](#1071)) ([9f712cc](9f712cc)) * **wrap:** write env.ANTHROPIC_BASE_URL to settings.json so daemon-spawned conversations inherit proxy ([#951](#951)) ([#1078](#1078)) ([a554c3a](a554c3a)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
studyzy
pushed a commit
to studyzy/headroom
that referenced
this pull request
Jun 24, 2026
…ounterfactual savings (headroomlabs-ai#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
studyzy
pushed a commit
to studyzy/headroom
that referenced
this pull request
Jun 24, 2026
🤖 I have created a release *beep* *boop* --- <details><summary>0.27.0</summary> ## [0.27.0](headroomlabs-ai/headroom@v0.26.0...v0.27.0) (2026-06-22) ### Features * **cli:** add headroom doctor setup diagnostics ([headroomlabs-ai#926](headroomlabs-ai#926)) ([e45cf4e](headroomlabs-ai@e45cf4e)) * **cli:** add headroom update command and release banner ([headroomlabs-ai#1088](headroomlabs-ai#1088)) ([26be2c3](headroomlabs-ai@26be2c3)) * compression extraction — Rust knob exposure, CCR hardening, traffic audits ([headroomlabs-ai#818](headroomlabs-ai#818)) ([b7be381](headroomlabs-ai@b7be381)) * measure and surface token throughput (tokens/sec) through the proxy ([headroomlabs-ai#983](headroomlabs-ai#983)) ([0d89c67](headroomlabs-ai@0d89c67)) * output-token reduction — verbosity shaper, per-user learning, counterfactual savings ([headroomlabs-ai#965](headroomlabs-ai#965)) ([a99dc61](headroomlabs-ai@a99dc61)) * **policy:** decay P_alive from idle time near cache TTL ([headroomlabs-ai#856](headroomlabs-ai#856) P3b) ([headroomlabs-ai#1028](headroomlabs-ai#1028)) ([fe4f9ee](headroomlabs-ai@fe4f9ee)) * **providers:** add Cortex Code (Snowflake CoCo) as a supported agent ([headroomlabs-ai#1190](headroomlabs-ai#1190)) ([d9d0bf4](headroomlabs-ai@d9d0bf4)) * **proxy:** cc-switch reconciler — keep Headroom in the request path alongside cc-switch ([headroomlabs-ai#1030](headroomlabs-ai#1030)) ([e8fc8a0](headroomlabs-ai@e8fc8a0)) * **proxy:** hot-reload live env knobs so a reused proxy picks them up without a restart ([headroomlabs-ai#1090](headroomlabs-ai#1090)) ([6904d47](headroomlabs-ai@6904d47)) * **proxy:** make COMPRESSION_TIMEOUT_SECONDS configurable via env ([headroomlabs-ai#946](headroomlabs-ai#946)) ([headroomlabs-ai#991](headroomlabs-ai#991)) ([addebdb](headroomlabs-ai@addebdb)) * **transforms:** tabular + spreadsheet (.xlsx/.xls) compression ([headroomlabs-ai#1128](headroomlabs-ai#1128)) ([d789a7c](headroomlabs-ai@d789a7c)) * **vertex:** turnkey Claude Code + Vertex compression (+ fixes from the Vertex review) ([headroomlabs-ai#1113](headroomlabs-ai#1113)) ([0e05915](headroomlabs-ai@0e05915)) ### Bug Fixes * **ccr:** accept 12-char SmartCrusher hashes in tool injection ([headroomlabs-ai#1095](headroomlabs-ai#1095)) ([headroomlabs-ai#1141](headroomlabs-ai#1141)) ([9f7f3ad](headroomlabs-ai@9f7f3ad)) * **ccr:** return stored content when headroom_retrieve query matches nothing ([headroomlabs-ai#1213](headroomlabs-ai#1213)) ([headroomlabs-ai#1236](headroomlabs-ai#1236)) ([08fb845](headroomlabs-ai@08fb845)) * **content-router:** honor target_ratio in compression cache + add proxy --target-ratio flag ([headroomlabs-ai#1108](headroomlabs-ai#1108)) ([8894ee0](headroomlabs-ai@8894ee0)) * **dashboard:** light-mode backgrounds + aligned savings tables ([headroomlabs-ai#1064](headroomlabs-ai#1064)) ([5eae32b](headroomlabs-ai@5eae32b)) * **deps:** make litellm optional on Python 3.14 ([headroomlabs-ai#956](headroomlabs-ai#956)) ([headroomlabs-ai#993](headroomlabs-ai#993)) ([b2f04e4](headroomlabs-ai@b2f04e4)) * **e2e:** align Codex wrap e2e with global-only RTK guidance ([headroomlabs-ai#1240](headroomlabs-ai#1240)) ([headroomlabs-ai#1254](headroomlabs-ai#1254)) ([bc12ace](headroomlabs-ai@bc12ace)) * **init:** set ENABLE_TOOL_SEARCH=true so Claude Code keeps deferring tools ([headroomlabs-ai#746](headroomlabs-ai#746)) ([headroomlabs-ai#995](headroomlabs-ai#995)) ([500ec2b](headroomlabs-ai@500ec2b)) * **kompress:** never block the request path on the cold-cache model download ([headroomlabs-ai#1161](headroomlabs-ai#1161)) ([3fc2a78](headroomlabs-ai@3fc2a78)) * **memory:** use ONNX embedder for `wrap --memory` sync ([headroomlabs-ai#1092](headroomlabs-ai#1092)) ([headroomlabs-ai#1262](headroomlabs-ai#1262)) ([4f9feda](headroomlabs-ai@4f9feda)) * **openclaw:** wrap plugin export as {register} object for OpenClaw 2026.x compatibility ([headroomlabs-ai#1218](headroomlabs-ai#1218)) ([2e6c442](headroomlabs-ai@2e6c442)) * **providers:** update DeepSeek V3 context limit from 128K to 1M ([headroomlabs-ai#1038](headroomlabs-ai#1038)) ([headroomlabs-ai#1137](headroomlabs-ai#1137)) ([bcabc5c](headroomlabs-ai@bcabc5c)) * **proxy:** allow disabling periodic TOIN stats logging ([headroomlabs-ai#1265](headroomlabs-ai#1265)) ([b5f63d8](headroomlabs-ai@b5f63d8)) * **proxy:** honor HEADROOM_EXCLUDE_TOOLS for Codex /v1/responses tool outputs ([headroomlabs-ai#940](headroomlabs-ai#940)) ([headroomlabs-ai#1053](headroomlabs-ai#1053)) ([f03e77b](headroomlabs-ai@f03e77b)) * **proxy:** preserve byte-faithful Anthropic tool forwarding ([headroomlabs-ai#1222](headroomlabs-ai#1222)) ([1f18d59](headroomlabs-ai@1f18d59)) * **proxy:** route Codex OAuth image requests ([headroomlabs-ai#1215](headroomlabs-ai#1215)) ([381d771](headroomlabs-ai@381d771)) * **proxy:** scope CORS to loopback + gate operator/content endpoints ([headroomlabs-ai#1226](headroomlabs-ai#1226)) ([bd55a42](headroomlabs-ai@bd55a42)) * **proxy:** stamp X-Client: codex on Responses endpoint for unidentified callers ([headroomlabs-ai#1036](headroomlabs-ai#1036)) ([b0cd032](headroomlabs-ai@b0cd032)) * **proxy:** treat NODE_EXTRA_CA_CERTS as additive, not replacement ([headroomlabs-ai#998](headroomlabs-ai#998)) ([headroomlabs-ai#1031](headroomlabs-ai#1031)) ([c987283](headroomlabs-ai@c987283)) * **telemetry:** switch anonymous telemetry to opt-in (off by default) ([headroomlabs-ai#1223](headroomlabs-ai#1223)) ([b998697](headroomlabs-ai@b998697)) * **tokenizers:** bound tiktoken vocab load so a stalled download cannot hang requests ([headroomlabs-ai#956](headroomlabs-ai#956)) ([headroomlabs-ai#994](headroomlabs-ai#994)) ([7e86baf](headroomlabs-ai@7e86baf)) * **unwrap:** remove ANTHROPIC_BASE_URL + ENABLE_TOOL_SEARCH and init hooks on unwrap ([headroomlabs-ai#992](headroomlabs-ai#992)) ([5b84691](headroomlabs-ai@5b84691)) * **wrap:** keep Codex RTK guidance global ([headroomlabs-ai#1240](headroomlabs-ai#1240)) ([7c26a54](headroomlabs-ai@7c26a54)) * **wrap:** percent-encode non-ASCII cwd names in X-Headroom-Project header ([headroomlabs-ai#1071](headroomlabs-ai#1071)) ([9f712cc](headroomlabs-ai@9f712cc)) * **wrap:** write env.ANTHROPIC_BASE_URL to settings.json so daemon-spawned conversations inherit proxy ([headroomlabs-ai#951](headroomlabs-ai#951)) ([headroomlabs-ai#1078](headroomlabs-ai#1078)) ([a554c3a](headroomlabs-ai@a554c3a)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
DevZonayed
pushed a commit
to DevZonayed/headroom
that referenced
this pull request
Aug 17, 2026
…eadroomlabs-ai#968) ## Description Every `test (N)` shard has been failing on all PRs and on pushes to `main`, even though all tests pass. Root cause: **Codecov retired tokenless uploads.** Without a token, the upload is rejected with `Token required because branch is protected`, and `ci.yml` had `fail_ci_if_error: true` with no token — so the rejected upload failed the whole shard. This passes `CODECOV_TOKEN` to the coverage-upload steps so uploads authenticate again. Closes # ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `ci.yml`: add `token: ${{ secrets.CODECOV_TOKEN }}` to the shard upload step; guard `fail_ci_if_error` so it stays enforced on same-repo PRs and pushes but relaxes on fork PRs (which cannot read repo secrets). - `wrap-native-e2e.yml`, `install-native-e2e.yml`: add the same token so their coverage uploads authenticate too (these were silently dropping coverage; already non-fatal). ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ python -c "import yaml; [yaml.safe_load(open(f)) for f in [ '.github/workflows/ci.yml', '.github/workflows/wrap-native-e2e.yml', '.github/workflows/install-native-e2e.yml']]" OK ci.yml OK wrap-native-e2e.yml OK install-native-e2e.yml This PR's own `test (N)` shards are the real test: with CODECOV_TOKEN set, they should upload successfully and go green. ``` ## Real Behavior Proof - Environment: GitHub Actions, `codecov/codecov-action@v5` (ci.yml) / `@v4` (e2e); repo is public; `CODECOV_TOKEN` repo secret set by the maintainer. - Exact command / steps: open this PR → observe the `test (1..4)` shards upload coverage with the token instead of being rejected. - Observed result: prior runs showed `1592 passed` then `Token required because branch is protected` → shard failed; main's own push CI was red for the same reason. With the token referenced, the upload authenticates. - Not tested: fork-PR path (no secret) — by design it now relaxes `fail_ci_if_error` so the tokenless rejection is non-fatal there. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Requires the `CODECOV_TOKEN` repository secret (GitHub → Settings → Secrets and variables → Actions). No code/CHANGELOG change. Separate from the output-token-reduction feature PR headroomlabs-ai#965.
DevZonayed
pushed a commit
to DevZonayed/headroom
that referenced
this pull request
Aug 17, 2026
…ounterfactual savings (headroomlabs-ai#965) ## Description Adds the first levers that reduce the tokens the model **writes back** (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off `main`: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - **Output shaper** (`output_shaper.py`, opt-in `HEADROOM_OUTPUT_SHAPER=1`): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowers `output_config.effort` on mechanical tool-result continuations; legacy `thinking.budget_tokens` clamp. Never injects effort where absent, never toggles `thinking.type`. - **`headroom learn --verbosity`**: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional `--llm-judge`), and seeds the savings baseline. - **Counterfactual estimator** (`output_savings.py`): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety. - **AIMD verbosity controller** (`verbosity_controller.py`): additive-increase / fast-back-off state machine; live signal emission gated off by default. - **Wiring + surfaces**: shaper resolves the learned level; recording rides the existing `transforms_applied` channel through the outcome funnel (no `RequestOutcome` changes); `headroom output-savings` CLI; dashboard "Output Tokens Saved" card. - **Docs**: simple-words user guide + design doc with the counterfactual methodology. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ pytest tests/test_output_savings.py tests/test_output_savings_cli.py \ tests/test_verbosity_learn.py tests/test_verbosity_controller.py \ tests/test_output_shaper.py -q 94 passed in 0.54s $ pytest tests/test_request_outcome.py tests/test_handler_outcome_tag_invariant.py \ tests/test_proxy_dashboard_stats_cache.py -q 44 passed $ ruff format --check . 831 files already formatted $ mypy headroom --ignore-missing-imports Success: no issues found in 361 source files ``` ## Real Behavior Proof - Environment: macOS, Python 3.12 (`.venv`), `anthropic` 0.76, live API model `claude-opus-4-8`. - Exact command / steps: `HEADROOM_OUTPUT_SHAPER=1`; `headroom learn --verbosity --apply` (seeds level + baseline); `python scripts/eval_output_shaper.py A` (live before/after); simulate holdout traffic then `headroom output-savings`. - Observed result: code-review ask — baseline 1,750 output tokens → L2 1,354 (−22.7%) → L3 599 (−65.8%), same bugs found. `learn --verbosity` on 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean. - Not tested: live streaming-path recording exercised only via unit tests (the `transforms_applied` funnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes Output savings are counterfactual (we never observe what the model *would* have written), so the estimator separates **estimated** (vs a learned baseline) from **measured** (A/B holdout via `HEADROOM_OUTPUT_HOLDOUT`) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behind `HEADROOM_VERBOSITY_AUTOTUNE`).
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.
Description
Adds the first levers that reduce the tokens the model writes back (output), complementing Headroom's existing input compression. Output costs 5× input on Opus-class models and is full of waste (ceremony, restated code, deep "thinking" on routine steps). Two phases in one self-contained PR off
main: the request-side output shaper, then per-user verbosity learning plus an honest counterfactual savings estimator and dashboard surfacing.Type of Change
Changes Made
output_shaper.py, opt-inHEADROOM_OUTPUT_SHAPER=1): cache-safe verbosity steering appended to the system-prompt tail (5 levels); effort routing that lowersoutput_config.efforton mechanical tool-result continuations; legacythinking.budget_tokensclamp. Never injects effort where absent, never togglesthinking.type.headroom learn --verbosity: mines Claude Code transcripts for behavioral signals (interrupts, length-adaptive fast-skips, echo ratio), recommends a verbosity level (heuristic + optional--llm-judge), and seeds the savings baseline.output_savings.py): per-stratum synthetic-control (estimated) + A/B holdout (measured) with a propagated 95% CI; conversation-stable arm assignment for A/B validity and prefix-cache safety.verbosity_controller.py): additive-increase / fast-back-off state machine; live signal emission gated off by default.transforms_appliedchannel through the outcome funnel (noRequestOutcomechanges);headroom output-savingsCLI; dashboard "Output Tokens Saved" card.Testing
pytest)ruff check .)mypy headroom)Test Output
Real Behavior Proof
.venv),anthropic0.76, live API modelclaude-opus-4-8.HEADROOM_OUTPUT_SHAPER=1;headroom learn --verbosity --apply(seeds level + baseline);python scripts/eval_output_shaper.py A(live before/after); simulate holdout traffic thenheadroom output-savings.learn --verbosityon 24 real sessions → 11% interrupt / 26% fast-skip → L3 (high confidence). Measured A/B path → 31.7% reduction (95% CI 27.7%–35.7%). 94 new tests + 44 existing outcome/dashboard tests green; ruff + mypy clean.transforms_appliedfunnel is shared across paths); runtime AIMD signal emission is gated off by default and not exercised live.Review Readiness
Checklist
Additional Notes
Output savings are counterfactual (we never observe what the model would have written), so the estimator separates estimated (vs a learned baseline) from measured (A/B holdout via
HEADROOM_OUTPUT_HOLDOUT) and always reports a confidence band — never a single made-up number. CHANGELOG left unchecked (release-please manages it). Runtime AIMD self-tuning is intentionally a TODO (controller built/tested; live signal emission gated behindHEADROOM_VERBOSITY_AUTOTUNE).