0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
194 lines
6.0 KiB
Markdown
194 lines
6.0 KiB
Markdown
# Text Compression Utilities
|
|
|
|
For coding tasks, Headroom provides **standalone text compression utilities** that applications can use explicitly. These are **opt-in** — they're not applied automatically, giving you full control over when and how to compress text content.
|
|
|
|
> **Design Philosophy**: SmartCrusher compresses JSON automatically because it's structure-preserving and safe. Text compression is lossy and context-dependent, so applications should decide when to use it.
|
|
|
|
## Available Utilities
|
|
|
|
| Utility | Input Type | Use Case |
|
|
|---------|------------|----------|
|
|
| `SearchCompressor` | grep/ripgrep output | Search results with `file:line:content` format |
|
|
| `LogCompressor` | Build/test logs | pytest, npm, cargo, make output |
|
|
| `TextCompressor` | Generic text | Any plain text with anchor preservation |
|
|
| `detect_content_type` | Any content | Detect content type for routing decisions |
|
|
|
|
## SearchCompressor
|
|
|
|
Compresses search results (grep, ripgrep, ag) while preserving relevant matches.
|
|
|
|
```python
|
|
from headroom.transforms import SearchCompressor
|
|
|
|
# Your grep/ripgrep output (could be 1000s of lines)
|
|
search_results = """
|
|
src/utils.py:42:def process_data(items):
|
|
src/utils.py:43: \"\"\"Process items.\"\"\"
|
|
src/models.py:15:class DataProcessor:
|
|
src/models.py:89: def process(self, items):
|
|
... hundreds more matches ...
|
|
"""
|
|
|
|
# Explicitly compress when you decide it's appropriate
|
|
compressor = SearchCompressor()
|
|
result = compressor.compress(search_results, context="find process")
|
|
|
|
print(f"Compressed {result.original_match_count} matches to {result.compressed_match_count}")
|
|
print(result.compressed)
|
|
```
|
|
|
|
### What Gets Preserved
|
|
|
|
- **Exact query matches**: Lines containing the search term
|
|
- **High-relevance matches**: Scored by BM25 similarity to context
|
|
- **File diversity**: Ensures results from different files are kept
|
|
- **First/last matches**: Context from start and end of results
|
|
|
|
## LogCompressor
|
|
|
|
Compresses build and test output while preserving errors, warnings, and summaries.
|
|
|
|
```python
|
|
from headroom.transforms import LogCompressor
|
|
|
|
# pytest output with 1000s of lines
|
|
build_output = """
|
|
===== test session starts =====
|
|
collected 500 items
|
|
tests/test_foo.py::test_1 PASSED
|
|
... hundreds of passed tests ...
|
|
tests/test_bar.py::test_fail FAILED
|
|
AssertionError: expected 5, got 3
|
|
===== 1 failed, 499 passed =====
|
|
"""
|
|
|
|
# Compress logs, preserving errors and stack traces
|
|
compressor = LogCompressor()
|
|
result = compressor.compress(build_output)
|
|
|
|
# Errors, stack traces, and summary are preserved
|
|
print(result.compressed)
|
|
print(f"Compression ratio: {result.compression_ratio:.1%}")
|
|
```
|
|
|
|
### What Gets Preserved
|
|
|
|
- **Errors and failures**: Any line with ERROR, FAILED, Exception, etc.
|
|
- **Warnings**: Warning messages that might be important
|
|
- **Stack traces**: Full tracebacks for debugging
|
|
- **Summaries**: Test/build summary lines
|
|
- **Section headers**: Structural markers like `=====`
|
|
|
|
## TextCompressor
|
|
|
|
General-purpose text compression with anchor preservation.
|
|
|
|
```python
|
|
from headroom.transforms import TextCompressor
|
|
|
|
long_text = """
|
|
... thousands of lines of documentation ...
|
|
"""
|
|
|
|
compressor = TextCompressor()
|
|
result = compressor.compress(long_text, context="authentication")
|
|
|
|
print(result.compressed)
|
|
```
|
|
|
|
### What Gets Preserved
|
|
|
|
- **Relevant paragraphs**: Scored by similarity to context
|
|
- **Anchors**: Headers, section markers, important keywords
|
|
- **Structure**: Document organization is maintained
|
|
|
|
## Content Type Detection
|
|
|
|
Automatically detect content type to route to the right compressor.
|
|
|
|
```python
|
|
from headroom.transforms import detect_content_type, ContentType
|
|
|
|
content = "src/main.py:42:def process():"
|
|
|
|
detection = detect_content_type(content)
|
|
if detection.content_type == ContentType.SEARCH_RESULTS:
|
|
# Route to SearchCompressor
|
|
pass
|
|
elif detection.content_type == ContentType.BUILD_OUTPUT:
|
|
# Route to LogCompressor
|
|
pass
|
|
elif detection.content_type == ContentType.PLAIN_TEXT:
|
|
# Route to TextCompressor
|
|
pass
|
|
```
|
|
|
|
### Content Types
|
|
|
|
| Type | Detection Pattern |
|
|
|------|-------------------|
|
|
| `SEARCH_RESULTS` | `file:line:content` format |
|
|
| `BUILD_OUTPUT` | pytest, npm, cargo markers |
|
|
| `JSON` | Valid JSON structure |
|
|
| `PLAIN_TEXT` | Default fallback |
|
|
|
|
## Integration Pattern
|
|
|
|
```python
|
|
from headroom.transforms import (
|
|
detect_content_type, ContentType,
|
|
SearchCompressor, LogCompressor, TextCompressor
|
|
)
|
|
|
|
def compress_tool_output(content: str, context: str = "") -> str:
|
|
"""Application-level compression with explicit control."""
|
|
detection = detect_content_type(content)
|
|
|
|
if detection.content_type == ContentType.SEARCH_RESULTS:
|
|
result = SearchCompressor().compress(content, context)
|
|
return result.compressed
|
|
elif detection.content_type == ContentType.BUILD_OUTPUT:
|
|
result = LogCompressor().compress(content)
|
|
return result.compressed
|
|
elif detection.content_type == ContentType.PLAIN_TEXT:
|
|
result = TextCompressor().compress(content, context)
|
|
return result.compressed
|
|
else:
|
|
# JSON or other - let SmartCrusher handle it automatically
|
|
return content
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Each compressor accepts configuration options:
|
|
|
|
```python
|
|
from headroom.transforms import SearchCompressor, SearchCompressorConfig
|
|
|
|
config = SearchCompressorConfig(
|
|
max_results=50, # Keep up to 50 matches
|
|
preserve_file_diversity=True, # Ensure different files represented
|
|
relevance_threshold=0.3, # Minimum relevance score to keep
|
|
)
|
|
|
|
compressor = SearchCompressor(config)
|
|
```
|
|
|
|
## Performance
|
|
|
|
| Compressor | Typical Input | Output | Speed |
|
|
|------------|---------------|--------|-------|
|
|
| SearchCompressor | 1000 matches | 30-50 matches | ~2ms |
|
|
| LogCompressor | 5000 lines | 100-200 lines | ~3ms |
|
|
| TextCompressor | 10000 chars | 2000 chars | ~2ms |
|
|
|
|
## When to Use
|
|
|
|
| Scenario | Recommendation |
|
|
|----------|----------------|
|
|
| JSON tool output | Let SmartCrusher handle automatically |
|
|
| grep/ripgrep results | Use SearchCompressor |
|
|
| pytest/npm/cargo output | Use LogCompressor |
|
|
| Documentation/README | Use TextCompressor |
|
|
| Unknown content | Use detect_content_type to route |
|