mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description Extracts mixed-content parsing out of the large `ContentRouter` module into a pure transform-domain module. The router still exports the existing compatibility names, but section typing, mixed-content indicators, section splitting, and JSON block extraction now live in a focused domain object/function layer. Closes # ## Type of Change - [ ] 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 - [x] Code refactoring (no functional changes) ## Changes Made - Added `headroom.transforms.mixed_content` with `ContentSection`, `mixed_content_indicators`, `is_mixed_content`, `split_into_sections`, and JSON block extraction. - Updated `ContentRouter` to delegate mixed-content debug indicators and parsing to the new module while preserving legacy imports from `content_router.py`. - Added direct unit coverage for mixed-content detection, section boundaries, and JSON delimiters inside string literals. - Included the LiteLLM callback signature compatibility shim needed for repo-wide mypy while the earlier architecture PRs are still open. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text python -m pytest tests/test_mixed_content_sections.py tests/test_transforms_content_router.py tests/test_litellm_callback.py tests/test_compress_api.py::TestLiteLLMCallback -q 50 passed in 6.82s python -m ruff check . All checks passed! python -m ruff format --check . 1095 files already formatted python -m mypy headroom --ignore-missing-imports headroom\proxy\server.py:1457: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked] headroom\proxy\server.py:1468: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs [annotation-unchecked] Success: no issues found in 409 source files ``` ## Real Behavior Proof - Environment: Windows, Python 3.13.13, clean worktree `C:\git\headroom-pr-slice6` - Exact command / steps: ran the pytest, Ruff, format, and mypy commands listed above. - Observed result: mixed-content parsing behavior remains covered through existing router tests and new direct tests; repo-wide lint/type checks pass. - Not tested: full pytest suite and Docker/native CI jobs are left to GitHub Actions. ## 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 - [ ] 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 ## Screenshots (if applicable) N/A. ## Additional Notes - Documentation, changelog, and screenshots are N/A for this internal refactor. - Manual UI testing is N/A; this is pure transform parsing logic. - Comment checklist is unchecked because the extracted functions are small and covered by direct tests.
63 lines
1.8 KiB
Python
63 lines
1.8 KiB
Python
from headroom.transforms.content_detector import ContentType
|
|
from headroom.transforms.mixed_content import (
|
|
_extract_json_block,
|
|
is_mixed_content,
|
|
split_into_sections,
|
|
)
|
|
|
|
|
|
def test_mixed_content_detection_requires_multiple_signals():
|
|
prose = "\n".join(
|
|
[
|
|
"First sentence has enough words to count.",
|
|
"Second sentence has enough words to count.",
|
|
"Third sentence has enough words to count.",
|
|
"Fourth sentence has enough words to count.",
|
|
"Fifth sentence has enough words to count.",
|
|
"Sixth sentence has enough words to count.",
|
|
]
|
|
)
|
|
|
|
assert is_mixed_content(prose) is False
|
|
assert is_mixed_content(f"{prose}\n```python\nprint('x')\n```") is True
|
|
|
|
|
|
def test_split_into_sections_preserves_typed_boundaries():
|
|
content = "\n".join(
|
|
[
|
|
"Intro text",
|
|
"```python",
|
|
"print('x')",
|
|
"```",
|
|
'[{"id": 1}]',
|
|
"src/app.py:10:print('x')",
|
|
]
|
|
)
|
|
|
|
sections = split_into_sections(content)
|
|
|
|
assert [section.content_type for section in sections] == [
|
|
ContentType.PLAIN_TEXT,
|
|
ContentType.SOURCE_CODE,
|
|
ContentType.JSON_ARRAY,
|
|
ContentType.SEARCH_RESULTS,
|
|
]
|
|
assert sections[1].language == "python"
|
|
assert sections[1].content == "print('x')"
|
|
assert sections[1].is_code_fence is True
|
|
assert sections[2].content == '[{"id": 1}]'
|
|
assert sections[3].start_line == 5
|
|
|
|
|
|
def test_extract_json_block_ignores_delimiters_inside_strings():
|
|
lines = [
|
|
"[",
|
|
' {"path": "a]b", "message": "keep {literal} braces"},',
|
|
' {"path": "c"}',
|
|
"]",
|
|
]
|
|
|
|
block, end_line = _extract_json_block(lines, 0)
|
|
|
|
assert end_line == 3
|
|
assert block == "\n".join(lines)
|