mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description
Propagate `--no-ccr-marker` flag to SearchCompressor, LogCompressor,
DiffCompressor, and CodeAwareCompressor — previously only SmartCrusher
honored the flag. When `ccr_inject_marker` is `False`, the other
compressors still defaulted to `enable_ccr=True`, injecting
`<<ccr:...>>` markers into compressed output.
Closes #1022
## 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
- `headroom/transforms/content_router.py`: pass
`enable_ccr=self.config.ccr_inject_marker` from
`_get_search_compressor`, `_get_log_compressor`, `_get_diff_compressor`,
and `_get_code_compressor` — mirroring what `_get_smart_crusher` already
does with `inject_retrieval_marker`
## Testing
- [x] Unit tests pass (`pytest`)
- [ ] Linting passes (`ruff check .`)
- [ ] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
Baseline: 1 pre-existing failure, 2020 pass, 131 skip
Post-fix: 1 pre-existing failure, 2022 pass, 131 skip
No regressions — 5 new tests in TestNoCcrMarkerCompressors, all pass.
```
## TDD verification
- RED check (without fix):
`test_content_router_propagates_ccr_inject_marker_false_to_compressors`
FAILED — `SearchCompressor enable_ccr=True, expected False`
- GREEN check (with fix): all 5 new tests PASS — propagation test
confirms `enable_ccr=False` reaches all compressors; integration tests
confirm no `<<ccr:` markers in compressed output
## Real Behavior Proof
- Environment: Linux, Python 3.13.12, headroom main @ f4bd2fe6
- Exact command / steps: `uv run pytest
tests/test_cli_proxy_env.py::TestNoCcrMarkerCompressors -v`
- Observed result: 5 passed — ContentRouter propagates
`enable_ccr=False` to SearchCompressor, LogCompressor, DiffCompressor;
markers are absent in compressed output
- Not tested: end-to-end proxy smoke with `--no-ccr-marker` flag;
Codex/live provider routing paths
## 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
- [ ] I have commented my code, particularly in hard-to-understand areas
— N/A (change is self-documenting)
- [ ] I have made corresponding changes to the documentation — N/A (bug
fix, no doc surface change)
- [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
- Root cause analysis by akb4q in the issue thread: `ccr_inject_marker`
was only wired into `_get_smart_crusher`; the other compressor getters
constructed bare instances that ignored the flag
- Minimal fix: each compressor already had `enable_ccr` in its config —
the fix only propagates the existing flag
---------
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8da0b4e565
commit
0c9b42a919
2 changed files with 174 additions and 7 deletions
|
|
@ -1848,10 +1848,18 @@ class ContentRouter(Transform):
|
|||
"""Get CodeAwareCompressor (lazy load)."""
|
||||
if self._code_compressor is None:
|
||||
try:
|
||||
from .code_compressor import CodeAwareCompressor, _check_tree_sitter_available
|
||||
from .code_compressor import (
|
||||
CodeAwareCompressor,
|
||||
CodeCompressorConfig,
|
||||
_check_tree_sitter_available,
|
||||
)
|
||||
|
||||
if _check_tree_sitter_available():
|
||||
self._code_compressor = CodeAwareCompressor()
|
||||
self._code_compressor = CodeAwareCompressor(
|
||||
CodeCompressorConfig(
|
||||
enable_ccr=self.config.ccr_inject_marker,
|
||||
)
|
||||
)
|
||||
else:
|
||||
logger.debug("tree-sitter not available")
|
||||
except ImportError:
|
||||
|
|
@ -1895,7 +1903,10 @@ class ContentRouter(Transform):
|
|||
from .search_compressor import SearchCompressor, SearchCompressorConfig
|
||||
|
||||
self._search_compressor = SearchCompressor(
|
||||
SearchCompressorConfig(group_by_file=self.config.search_group_by_file)
|
||||
SearchCompressorConfig(
|
||||
group_by_file=self.config.search_group_by_file,
|
||||
enable_ccr=self.config.ccr_inject_marker,
|
||||
)
|
||||
)
|
||||
except ImportError:
|
||||
logger.debug("SearchCompressor not available")
|
||||
|
|
@ -1905,9 +1916,11 @@ class ContentRouter(Transform):
|
|||
"""Get LogCompressor (lazy load)."""
|
||||
if self._log_compressor is None:
|
||||
try:
|
||||
from .log_compressor import LogCompressor
|
||||
from .log_compressor import LogCompressor, LogCompressorConfig
|
||||
|
||||
self._log_compressor = LogCompressor()
|
||||
self._log_compressor = LogCompressor(
|
||||
LogCompressorConfig(enable_ccr=self.config.ccr_inject_marker)
|
||||
)
|
||||
except ImportError:
|
||||
logger.debug("LogCompressor not available")
|
||||
return self._log_compressor
|
||||
|
|
@ -1944,9 +1957,11 @@ class ContentRouter(Transform):
|
|||
retired in Stage 3b. The wheel (`headroom._core`) is a hard import.
|
||||
"""
|
||||
if self._diff_compressor is None:
|
||||
from .diff_compressor import DiffCompressor
|
||||
from .diff_compressor import DiffCompressor, DiffCompressorConfig
|
||||
|
||||
self._diff_compressor = DiffCompressor()
|
||||
self._diff_compressor = DiffCompressor(
|
||||
DiffCompressorConfig(enable_ccr=self.config.ccr_inject_marker)
|
||||
)
|
||||
return self._diff_compressor
|
||||
|
||||
def _get_html_extractor(self) -> Any:
|
||||
|
|
|
|||
|
|
@ -904,6 +904,158 @@ class TestCLICompressionOnlyFlags:
|
|||
assert captured_config["config"].ccr_inject_marker is False
|
||||
|
||||
|
||||
class TestNoCcrMarkerCompressors:
|
||||
"""Verify --no-ccr-marker actually suppresses <<ccr:...>> markers
|
||||
from every compressor, not just SmartCrusher (#1022)."""
|
||||
|
||||
def test_content_router_propagates_ccr_inject_marker_false_to_compressors(self):
|
||||
"""#1022: ContentRouter must pass enable_ccr=False to compressors
|
||||
when ccr_inject_marker=False. Before the fix, only SmartCrusher
|
||||
received the flag — Search/Log/Diff compressors always got
|
||||
enable_ccr=True (the default)."""
|
||||
from headroom.transforms.content_router import (
|
||||
ContentRouter,
|
||||
ContentRouterConfig,
|
||||
)
|
||||
|
||||
router = ContentRouter(ContentRouterConfig(ccr_inject_marker=False, ccr_enabled=True))
|
||||
|
||||
# search compressor
|
||||
sc = router._get_search_compressor()
|
||||
assert sc is not None
|
||||
assert sc.config.enable_ccr is False, (
|
||||
f"SearchCompressor enable_ccr={sc.config.enable_ccr}, expected False"
|
||||
)
|
||||
|
||||
# log compressor
|
||||
lc = router._get_log_compressor()
|
||||
assert lc is not None
|
||||
assert lc.config.enable_ccr is False, (
|
||||
f"LogCompressor enable_ccr={lc.config.enable_ccr}, expected False"
|
||||
)
|
||||
|
||||
# diff compressor
|
||||
dc = router._get_diff_compressor()
|
||||
assert dc is not None
|
||||
assert dc.config.enable_ccr is False, (
|
||||
f"DiffCompressor enable_ccr={dc.config.enable_ccr}, expected False"
|
||||
)
|
||||
|
||||
# SmartCrusher already works (regression guard)
|
||||
sc2 = router._get_smart_crusher()
|
||||
assert sc2 is not None
|
||||
# SmartCrusher uses inject_retrieval_marker, not enable_ccr
|
||||
|
||||
def test_content_router_default_ccr_inject_marker_true(self):
|
||||
"""Default config (ccr_inject_marker=True) should give enable_ccr=True."""
|
||||
from headroom.transforms.content_router import (
|
||||
ContentRouter,
|
||||
ContentRouterConfig,
|
||||
)
|
||||
|
||||
router = ContentRouter(ContentRouterConfig())
|
||||
sc = router._get_search_compressor()
|
||||
assert sc.config.enable_ccr is True
|
||||
|
||||
lc = router._get_log_compressor()
|
||||
assert lc.config.enable_ccr is True
|
||||
|
||||
dc = router._get_diff_compressor()
|
||||
assert dc.config.enable_ccr is True
|
||||
|
||||
def test_search_compressor_suppresses_markers_with_enable_ccr_false(self):
|
||||
"""SearchCompressor with enable_ccr=False must not emit <<ccr: markers."""
|
||||
from headroom.transforms.search_compressor import (
|
||||
SearchCompressor,
|
||||
SearchCompressorConfig,
|
||||
)
|
||||
|
||||
compressor = SearchCompressor(
|
||||
SearchCompressorConfig(
|
||||
enable_ccr=False,
|
||||
min_matches_for_ccr=1,
|
||||
context_keywords=["error"],
|
||||
)
|
||||
)
|
||||
content = "\n".join(
|
||||
f"src/file{i}.py:{line}: error: something went wrong here"
|
||||
for i in range(20)
|
||||
for line in range(1, 11)
|
||||
)
|
||||
result = compressor.compress(content)
|
||||
assert "<<ccr:" not in result.compressed, (
|
||||
f"SearchCompressor emitted marker when enable_ccr=False: {result.compressed[:300]!r}"
|
||||
)
|
||||
|
||||
def test_log_compressor_suppresses_markers_with_enable_ccr_false(self):
|
||||
"""LogCompressor with enable_ccr=False must not emit <<ccr: markers."""
|
||||
from headroom.transforms.log_compressor import (
|
||||
LogCompressor,
|
||||
LogCompressorConfig,
|
||||
)
|
||||
|
||||
npm_lines = ["npm WARN deprecated x"] * 30 + ["npm ERR! something broke"] * 5
|
||||
content = "\n".join(npm_lines)
|
||||
compressor = LogCompressor(LogCompressorConfig(enable_ccr=False, min_lines_for_ccr=3))
|
||||
result = compressor.compress(content)
|
||||
assert "<<ccr:" not in result.compressed, (
|
||||
f"LogCompressor emitted marker when enable_ccr=False: {result.compressed[:300]!r}"
|
||||
)
|
||||
|
||||
def test_diff_compressor_suppresses_markers_with_enable_ccr_false(self):
|
||||
"""DiffCompressor with enable_ccr=False must not emit <<ccr: markers."""
|
||||
from headroom.transforms.diff_compressor import (
|
||||
DiffCompressor,
|
||||
DiffCompressorConfig,
|
||||
)
|
||||
|
||||
compressor = DiffCompressor(DiffCompressorConfig(enable_ccr=False, min_lines_for_ccr=10))
|
||||
diff_lines = []
|
||||
for i in range(30):
|
||||
diff_lines.append(f"diff --git a/src/file{i}.py b/src/file{i}.py")
|
||||
diff_lines.append(f"--- a/src/file{i}.py")
|
||||
diff_lines.append(f"+++ b/src/file{i}.py")
|
||||
for line in range(1, 6):
|
||||
diff_lines.append(f"+added line {line} in file {i}")
|
||||
diff_lines.append(f"-removed line {line} in file {i}")
|
||||
content = "\n".join(diff_lines)
|
||||
result = compressor.compress(content)
|
||||
assert "<<ccr:" not in result.compressed, (
|
||||
f"DiffCompressor emitted marker when enable_ccr=False: {result.compressed[:300]!r}"
|
||||
)
|
||||
|
||||
def test_code_compressor_suppresses_markers_with_enable_ccr_false(self):
|
||||
"""CodeAwareCompressor with enable_ccr=False must not emit <<ccr:
|
||||
markers when tree-sitter is available (#1022 coverage gap)."""
|
||||
from headroom.transforms.code_compressor import (
|
||||
CodeAwareCompressor,
|
||||
CodeCompressorConfig,
|
||||
_check_tree_sitter_available,
|
||||
)
|
||||
|
||||
if not _check_tree_sitter_available():
|
||||
pytest.skip("tree-sitter not available in this environment")
|
||||
|
||||
# Code that would compress with tree-sitter (enough to trigger CCR)
|
||||
func_template = (
|
||||
"def func_{i}(x: int) -> int:\n"
|
||||
' """Docstring for func_{i}."""\n'
|
||||
" # Line {j}\n"
|
||||
" result = x + {j}\n"
|
||||
" result *= 2\n"
|
||||
" return result\n"
|
||||
)
|
||||
content = "\n".join(func_template.format(i=i, j=j) for i in range(30) for j in range(1, 6))
|
||||
|
||||
compressor = CodeAwareCompressor(
|
||||
CodeCompressorConfig(enable_ccr=False, min_tokens_for_compression=1)
|
||||
)
|
||||
result = compressor.compress(content)
|
||||
assert "<<ccr:" not in result.compressed, (
|
||||
f"CodeAwareCompressor emitted marker when enable_ccr=False: {result.compressed[:300]!r}"
|
||||
)
|
||||
|
||||
|
||||
class TestArgparseBackendValidation:
|
||||
"""Test that the argparse path (python -m headroom.proxy.server) accepts litellm-* backends."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue