mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
Bumps the pip-minor-patch group with 1 update in the / directory: [ruff](https://github.com/astral-sh/ruff). Updates `ruff` from 0.15.22 to 0.16.2 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p> <blockquote> <h2>0.16.2</h2> <h2>Release Notes</h2> <p>Released on 2026-08-06.</p> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-pyi</code>] Avoid false positives on <code>singledispatch</code> functions (<code>PYI041</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li> </ul> <h3>Server</h3> <ul> <li>Register formatting capabilities dynamically to exclude TOML files (<a href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/MeGaGiGaGon"><code>@MeGaGiGaGon</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/epage"><code>@epage</code></a></li> <li><a href="https://github.com/sharkdp"><code>@sharkdp</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> </ul> <h2>Install ruff 0.16.2</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.sh | sh </code></pre> <h3>Install prebuilt binaries via powershell script</h3> <pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c "irm https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-installer.ps1 | iex" </code></pre> <h2>Download ruff 0.16.2</h2> <table> <thead> <tr> <th>File</th> <th>Platform</th> <th>Checksum</th> </tr> </thead> <tbody> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz">ruff-aarch64-apple-darwin.tar.gz</a></td> <td>Apple Silicon macOS</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz">ruff-x86_64-apple-darwin.tar.gz</a></td> <td>Intel macOS</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip">ruff-aarch64-pc-windows-msvc.zip</a></td> <td>ARM64 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip">ruff-i686-pc-windows-msvc.zip</a></td> <td>x86 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip">ruff-x86_64-pc-windows-msvc.zip</a></td> <td>x64 Windows</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz">ruff-aarch64-unknown-linux-gnu.tar.gz</a></td> <td>ARM64 Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz">ruff-i686-unknown-linux-gnu.tar.gz</a></td> <td>x86 Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-i686-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz">ruff-powerpc64-unknown-linux-gnu.tar.gz</a></td> <td>PPC64 Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz">ruff-powerpc64le-unknown-linux-gnu.tar.gz</a></td> <td>PPC64LE Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-powerpc64le-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz">ruff-riscv64gc-unknown-linux-gnu.tar.gz</a></td> <td>RISCV Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-riscv64gc-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> <tr> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz">ruff-s390x-unknown-linux-gnu.tar.gz</a></td> <td>S390x Linux</td> <td><a href="https://releases.astral.sh/github/ruff/releases/download/0.16.2/ruff-s390x-unknown-linux-gnu.tar.gz.sha256">checksum</a></td> </tr> </tbody> </table> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p> <blockquote> <h2>0.16.2</h2> <p>Released on 2026-08-06.</p> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-pyi</code>] Avoid false positives on <code>singledispatch</code> functions (<code>PYI041</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27335">#27335</a>)</li> </ul> <h3>Server</h3> <ul> <li>Register formatting capabilities dynamically to exclude TOML files (<a href="https://redirect.github.com/astral-sh/ruff/pull/27332">#27332</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/MeGaGiGaGon"><code>@MeGaGiGaGon</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/epage"><code>@epage</code></a></li> <li><a href="https://github.com/sharkdp"><code>@sharkdp</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> </ul> <h2>0.16.1</h2> <p>Released on 2026-07-30.</p> <h3>Preview features</h3> <ul> <li>Add an option to opt out of human-readable names (<a href="https://redirect.github.com/astral-sh/ruff/pull/27160">#27160</a>)</li> <li>[<code>flake8-pytest-style</code>] Make fixes safe by default and unsafe only when comments are present (<code>PT018</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27201">#27201</a>)</li> <li>[<code>pyupgrade</code>] Skip fix when a defaulted <code>TypeVar</code> precedes a non-defaulted one (<code>UP040</code>, <code>UP046</code>, <code>UP047</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27133">#27133</a>)</li> <li>[<code>ruff</code>] Fix false positive with unpacked arguments (<code>RUF065</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26959">#26959</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>Bump <code>gen-lsp-types</code> to gracefully handle unknown enumeration values in LSP messages (<a href="https://redirect.github.com/astral-sh/ruff/pull/27230">#27230</a>)</li> <li>[<code>flake8-bugbear</code>] Mark <code>range</code> as immutable (<code>B008</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27247">#27247</a>)</li> <li>[<code>flake8-comprehensions</code>] NFKC-normalize keyword names in <code>C408</code> fix (<a href="https://redirect.github.com/astral-sh/ruff/pull/26813">#26813</a>)</li> <li>[<code>flake8-return</code>] Fix false positive when variable is read in <code>finally</code> clause (<code>RET504</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/25441">#25441</a>)</li> <li>[<code>pydocstyle</code>] Skip section detection inside RST directive bodies (<code>D214</code>, <code>D405</code>, <code>D413</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/23635">#23635</a>)</li> <li>[<code>refurb</code>] Parenthesize <code>yield</code> arguments in the <code>FURB192</code> fix (<a href="https://redirect.github.com/astral-sh/ruff/pull/27192">#27192</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>[<code>flake8-pytest-style</code>] Mark <code>PT022</code> fixes as unsafe (<a href="https://redirect.github.com/astral-sh/ruff/pull/26440">#26440</a>)</li> <li>[<code>refurb</code>] Mark fixes that remove unknown separators as unsafe (<code>FURB105</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27200">#27200</a>)</li> </ul> <h3>Server</h3> <ul> <li>Fix indexing of excluded nested Ruff workspaces (<a href="https://redirect.github.com/astral-sh/ruff/pull/27303">#27303</a>)</li> <li>Lint TOML files in the LSP (<a href="https://redirect.github.com/astral-sh/ruff/pull/26862">#26862</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="5b48a04097"><code>5b48a04</code></a> Bump 0.16.2 (<a href="https://redirect.github.com/astral-sh/ruff/issues/27555">#27555</a>)</li> <li><a href="1b9e5fc483"><code>1b9e5fc</code></a> Update Swatinem/rust-cache action to v2.9.2 (<a href="https://redirect.github.com/astral-sh/ruff/issues/27568">#27568</a>)</li> <li><a href="c4e86fc039"><code>c4e86fc</code></a> [ty] Add helper extension methods for half-range and equality constraints (<a href="https://redirect.github.com/astral-sh/ruff/issues/2">#2</a>...</li> <li><a href="17a00de2e2"><code>17a00de</code></a> [ty] Reuse primer commands in memory reports (<a href="https://redirect.github.com/astral-sh/ruff/issues/27553">#27553</a>)</li> <li><a href="6ea296b969"><code>6ea296b</code></a> [ty] Normalize type labels in structured docstrings (<a href="https://redirect.github.com/astral-sh/ruff/issues/26923">#26923</a>)</li> <li><a href="2fc445f005"><code>2fc445f</code></a> [ty] Diagnose invalid <strong>getattr</strong> calls (<a href="https://redirect.github.com/astral-sh/ruff/issues/27502">#27502</a>)</li> <li><a href="22c7823c4e"><code>22c7823</code></a> [ty] Enable (but downrank) auto-import completion suggestions from stub-only ...</li> <li><a href="05160d507f"><code>05160d5</code></a> [ty] Diagnose invalid descriptor <code>__get__</code> calls (<a href="https://redirect.github.com/astral-sh/ruff/issues/27400">#27400</a>)</li> <li><a href="baea3d0dce"><code>baea3d0</code></a> [ty] Expose strict analysis options in the playground (<a href="https://redirect.github.com/astral-sh/ruff/issues/27543">#27543</a>)</li> <li><a href="c88946ebeb"><code>c88946e</code></a> [ty] Bump ecosystem-analyzer for strict project settings (<a href="https://redirect.github.com/astral-sh/ruff/issues/27542">#27542</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ruff/compare/0.15.22...0.16.2">compare view</a></li> </ul> </details> <br /> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
510 lines
12 KiB
Markdown
510 lines
12 KiB
Markdown
# Troubleshooting Guide
|
|
|
|
Solutions for common Headroom issues.
|
|
|
|
---
|
|
|
|
## Proxy Server Issues
|
|
|
|
### "Proxy won't start"
|
|
|
|
**Symptom**: `headroom proxy` fails or hangs.
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Check if port is already in use
|
|
lsof -i :8787
|
|
# If something is using the port, either kill it or use a different port
|
|
|
|
# 2. Try a different port
|
|
headroom proxy --port 8788
|
|
|
|
# 3. Check for missing dependencies
|
|
pip install "headroom-ai[proxy]"
|
|
|
|
# 4. Run with request logging
|
|
headroom proxy --log-file ~/.headroom/logs/proxy.jsonl --log-messages
|
|
```
|
|
|
|
### "Connection refused" when calling proxy
|
|
|
|
**Symptom**: `curl: (7) Failed to connect to localhost port 8787`
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Verify proxy is running
|
|
curl http://localhost:8787/health
|
|
|
|
# 2. Check if proxy started on a different port
|
|
ps aux | grep headroom
|
|
|
|
# 3. Check firewall settings (macOS)
|
|
sudo pfctl -s rules | grep 8787
|
|
```
|
|
|
|
### "Upstream rejects a beta token the client no longer sends"
|
|
|
|
**Symptom**: The upstream API returns an error referencing a beta feature (`anthropic-beta` header) even though the client is no longer sending that header.
|
|
|
|
**Cause**: Headroom's `SessionBetaTracker` re-injects any `anthropic-beta` token seen earlier in the same session to preserve prefix-cache stability. Once a token is in the tracker it persists for the rest of the session. Stopping the token on the client side alone is not sufficient.
|
|
|
|
**Solution**: Set `HEADROOM_BETA_HEADER_STICKY=disabled` to pass the client's header value verbatim without accumulation:
|
|
|
|
```bash
|
|
export HEADROOM_BETA_HEADER_STICKY=disabled
|
|
headroom proxy ...
|
|
```
|
|
|
|
Alternatively, restarting the proxy process clears the in-memory tracker. See [Session Beta Header Tracking](configuration.md#session-beta-header-tracking) for details.
|
|
|
|
---
|
|
|
|
### "Proxy returns errors for some requests"
|
|
|
|
**Symptom**: Some requests work, others fail with 502/503.
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Check proxy logs for the actual error
|
|
headroom proxy --log-file ~/.headroom/logs/proxy.jsonl --log-messages
|
|
|
|
# 2. Verify API key is set
|
|
echo $OPENAI_API_KEY # or ANTHROPIC_API_KEY
|
|
|
|
# 3. Test the underlying API directly
|
|
curl https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"
|
|
```
|
|
|
|
---
|
|
|
|
## SDK Issues
|
|
|
|
### "No token savings"
|
|
|
|
**Symptom**: `stats['session']['tokens_saved_total']` is 0.
|
|
|
|
**Diagnosis**:
|
|
|
|
```python
|
|
# 1. Check mode
|
|
stats = client.get_stats()
|
|
print(f"Mode: {stats['config']['mode']}") # Should be "optimize"
|
|
|
|
# 2. Check transforms are enabled
|
|
print(f"SmartCrusher: {stats['transforms']['smart_crusher_enabled']}")
|
|
|
|
# 3. Check if content meets threshold
|
|
# SmartCrusher only compresses tool outputs > 200 tokens by default
|
|
```
|
|
|
|
**Solutions**:
|
|
|
|
```python
|
|
# 1. Ensure mode is "optimize"
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(),
|
|
provider=OpenAIProvider(),
|
|
default_mode="optimize", # NOT "audit"
|
|
)
|
|
|
|
# 2. Or override per-request
|
|
response = client.chat.completions.create(
|
|
model="gpt-4o",
|
|
messages=messages,
|
|
headroom_mode="optimize",
|
|
)
|
|
|
|
# 3. Lower the compression threshold
|
|
config = HeadroomConfig()
|
|
config.smart_crusher.min_tokens_to_crush = 100 # Default is 200
|
|
```
|
|
|
|
**Why It Might Be 0**:
|
|
- Mode is "audit" (observation only)
|
|
- Messages don't contain tool outputs
|
|
- Tool outputs are below the token threshold
|
|
- Data isn't compressible (high uniqueness)
|
|
|
|
### "Compression too aggressive"
|
|
|
|
**Symptom**: LLM responses are missing information that was in tool outputs.
|
|
|
|
**Solutions**:
|
|
|
|
```python
|
|
# 1. Keep more items
|
|
config = HeadroomConfig()
|
|
config.smart_crusher.max_items_after_crush = 50 # Default: 15
|
|
|
|
# 2. Skip compression for specific tools
|
|
response = client.chat.completions.create(
|
|
model="gpt-4o",
|
|
messages=messages,
|
|
headroom_tool_profiles={
|
|
"important_tool": {"skip_compression": True},
|
|
},
|
|
)
|
|
|
|
# 3. Disable SmartCrusher entirely
|
|
config.smart_crusher.enabled = False
|
|
```
|
|
|
|
### "High latency"
|
|
|
|
**Symptom**: Requests take longer than expected.
|
|
|
|
**Diagnosis**:
|
|
|
|
```python
|
|
import time
|
|
import logging
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
start = time.time()
|
|
response = client.chat.completions.create(...)
|
|
print(f"Total time: {time.time() - start:.2f}s")
|
|
|
|
# Check logs for:
|
|
# - "SmartCrusher" timing
|
|
# - "EmbeddingScorer" timing (slow if using embeddings)
|
|
```
|
|
|
|
**Solutions**:
|
|
|
|
```python
|
|
# 1. Use BM25 instead of embeddings (faster)
|
|
config = HeadroomConfig()
|
|
config.smart_crusher.relevance.tier = "bm25" # Default may use embeddings
|
|
|
|
# 2. Increase threshold to skip small payloads
|
|
config.smart_crusher.min_tokens_to_crush = 500
|
|
|
|
# 3. Disable transforms you don't need
|
|
config.cache_aligner.enabled = False
|
|
config.rolling_window.enabled = False
|
|
```
|
|
|
|
### "ValidationError on setup"
|
|
|
|
**Symptom**: `validate_setup()` returns errors.
|
|
|
|
**Common Issues**:
|
|
|
|
```python
|
|
result = client.validate_setup()
|
|
print(result)
|
|
|
|
# Provider error:
|
|
# {"provider": {"ok": False, "error": "No API key"}}
|
|
# → Set OPENAI_API_KEY or pass api_key to OpenAI()
|
|
|
|
# Storage error:
|
|
# {"storage": {"ok": False, "error": "unable to open database"}}
|
|
# → Check path permissions, use :memory: for testing
|
|
|
|
# Config error:
|
|
# {"config": {"ok": False, "error": "Invalid mode"}}
|
|
# → Use "audit" or "optimize" only
|
|
```
|
|
|
|
**Solutions**:
|
|
|
|
```python
|
|
# 1. For testing, use in-memory storage
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(),
|
|
provider=OpenAIProvider(),
|
|
store_url="sqlite:///:memory:", # No file created
|
|
)
|
|
|
|
# 2. For temp directory storage
|
|
import tempfile
|
|
import os
|
|
|
|
db_path = os.path.join(tempfile.gettempdir(), "headroom.db")
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(),
|
|
provider=OpenAIProvider(),
|
|
store_url=f"sqlite:///{db_path}",
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Import/Installation Issues
|
|
|
|
### "pip install fails with C++ compilation error"
|
|
|
|
**Symptom**: Installation fails with an error like:
|
|
|
|
```
|
|
RuntimeError: Unsupported compiler -- at least C++11 support is needed!
|
|
ERROR: Failed building wheel for hnswlib
|
|
```
|
|
|
|
**Cause**: `headroom-ai` depends on `hnswlib`, a C++ extension that must be compiled from source. Slim environments (Docker slim images, minimal CI runners) lack the required build tools.
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# Linux / Debian-based (including Docker)
|
|
apt-get install -y build-essential && pip install headroom-ai
|
|
|
|
# macOS (Xcode command line tools)
|
|
xcode-select --install && pip install headroom-ai
|
|
```
|
|
|
|
In a Dockerfile, install and remove build tools in one layer to keep the image slim:
|
|
|
|
```dockerfile
|
|
FROM python:3.11-slim
|
|
RUN apt-get update && apt-get install -y --no-install-recommends build-essential \
|
|
&& pip install "headroom-ai[proxy]" \
|
|
&& apt-get purge -y build-essential && apt-get autoremove -y \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
```
|
|
|
|
---
|
|
|
|
### "ModuleNotFoundError: No module named 'headroom'"
|
|
|
|
```bash
|
|
# 1. Check it's installed in the right environment
|
|
pip show headroom-ai
|
|
|
|
# 2. If using virtual environment, ensure it's activated
|
|
source venv/bin/activate # or equivalent
|
|
|
|
# 3. Reinstall
|
|
pip install --upgrade headroom-ai
|
|
```
|
|
|
|
### "ImportError: cannot import name 'X' from 'headroom'"
|
|
|
|
```python
|
|
# Check available imports
|
|
import headroom
|
|
|
|
print(dir(headroom))
|
|
|
|
# Common imports:
|
|
from headroom import (
|
|
HeadroomClient,
|
|
OpenAIProvider,
|
|
AnthropicProvider,
|
|
HeadroomConfig,
|
|
# Exceptions
|
|
HeadroomError,
|
|
ConfigurationError,
|
|
ProviderError,
|
|
)
|
|
```
|
|
|
|
### "Missing optional dependency"
|
|
|
|
```bash
|
|
# For proxy server
|
|
pip install "headroom-ai[proxy]"
|
|
|
|
# For embedding-based relevance scoring
|
|
pip install "headroom-ai[relevance]"
|
|
|
|
# For everything
|
|
pip install "headroom-ai[all]"
|
|
```
|
|
|
|
---
|
|
|
|
## Provider-Specific Issues
|
|
|
|
### OpenAI: "Invalid API key"
|
|
|
|
```python
|
|
from openai import OpenAI
|
|
import os
|
|
|
|
# Ensure key is set
|
|
api_key = os.environ.get("OPENAI_API_KEY")
|
|
if not api_key:
|
|
raise ValueError("OPENAI_API_KEY not set")
|
|
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(api_key=api_key),
|
|
provider=OpenAIProvider(),
|
|
)
|
|
```
|
|
|
|
### Anthropic: "Authentication error"
|
|
|
|
```python
|
|
from anthropic import Anthropic
|
|
import os
|
|
|
|
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
client = HeadroomClient(
|
|
original_client=Anthropic(api_key=api_key),
|
|
provider=AnthropicProvider(),
|
|
)
|
|
```
|
|
|
|
### "Unknown model" warnings
|
|
|
|
```python
|
|
# For custom/fine-tuned models, specify context limit
|
|
client = HeadroomClient(
|
|
original_client=OpenAI(),
|
|
provider=OpenAIProvider(),
|
|
model_context_limits={
|
|
"ft:gpt-4o-2024-08-06:my-org::abc123": 128000,
|
|
"my-custom-model": 32000,
|
|
},
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## Debugging Techniques
|
|
|
|
### Enable Full Logging
|
|
|
|
```python
|
|
import logging
|
|
|
|
# See everything
|
|
logging.basicConfig(
|
|
level=logging.DEBUG,
|
|
format="%(asctime)s %(name)s %(levelname)s %(message)s",
|
|
)
|
|
|
|
# Or just Headroom logs
|
|
logging.getLogger("headroom").setLevel(logging.DEBUG)
|
|
```
|
|
|
|
### Inspect Transform Results
|
|
|
|
```python
|
|
# Use simulate to see what would happen
|
|
plan = client.chat.completions.simulate(
|
|
model="gpt-4o",
|
|
messages=messages,
|
|
)
|
|
|
|
print(f"Tokens: {plan.tokens_before} -> {plan.tokens_after}")
|
|
print(f"Transforms: {plan.transforms}")
|
|
print(f"Waste signals: {plan.waste_signals}")
|
|
|
|
# See the actual optimized messages
|
|
import json
|
|
|
|
print(json.dumps(plan.messages_optimized, indent=2))
|
|
```
|
|
|
|
### Check Storage Contents
|
|
|
|
```python
|
|
from datetime import datetime, timedelta
|
|
|
|
# Get recent metrics
|
|
metrics = client.get_metrics(
|
|
start_time=datetime.utcnow() - timedelta(hours=1),
|
|
limit=10,
|
|
)
|
|
|
|
for m in metrics:
|
|
print(f"{m.timestamp}: {m.tokens_input_before} -> {m.tokens_input_after}")
|
|
print(f" Transforms: {m.transforms_applied}")
|
|
if m.error:
|
|
print(f" ERROR: {m.error}")
|
|
```
|
|
|
|
### Manual Transform Testing
|
|
|
|
```python
|
|
from headroom import SmartCrusher, Tokenizer
|
|
from headroom.config import SmartCrusherConfig
|
|
import json
|
|
|
|
# Test compression directly
|
|
config = SmartCrusherConfig()
|
|
crusher = SmartCrusher(config)
|
|
tokenizer = Tokenizer()
|
|
|
|
messages = [
|
|
{"role": "tool", "content": json.dumps({"items": list(range(100))}), "tool_call_id": "1"}
|
|
]
|
|
|
|
result = crusher.apply(messages, tokenizer)
|
|
print(f"Tokens: {result.tokens_before} -> {result.tokens_after}")
|
|
print(f"Compressed content: {result.messages[0]['content'][:200]}...")
|
|
```
|
|
|
|
---
|
|
|
|
### "Native detector crashes with illegal instruction"
|
|
|
|
On some older or virtualized x86_64 CPUs, AVX2 may be unavailable. The
|
|
Magika/ONNX Runtime detector can require AVX2 through its precompiled runtime
|
|
binary. Headroom skips that detector tier on x86/x86_64 hosts without AVX2 and
|
|
falls back to non-Magika detection tiers instead of crashing.
|
|
|
|
If native startup still fails on an older CPU, set:
|
|
|
|
```bash
|
|
export HEADROOM_REQUIRE_RUST_CORE=false
|
|
```
|
|
|
|
---
|
|
|
|
## Error Reference
|
|
|
|
| Exception | Meaning | Solution |
|
|
|-----------|---------|----------|
|
|
| `ConfigurationError` | Invalid config values | Check config parameters |
|
|
| `ProviderError` | Provider issue (unknown model, etc.) | Set model_context_limits |
|
|
| `StorageError` | Database issue | Check path/permissions |
|
|
| `CompressionError` | Compression failed | Rare - check data format |
|
|
| `TokenizationError` | Token counting failed | Check model name |
|
|
| `ValidationError` | Setup validation failed | Run validate_setup() |
|
|
|
|
### Handling Errors
|
|
|
|
```python
|
|
from headroom import (
|
|
HeadroomClient,
|
|
HeadroomError,
|
|
ConfigurationError,
|
|
StorageError,
|
|
)
|
|
|
|
try:
|
|
client = HeadroomClient(...)
|
|
response = client.chat.completions.create(...)
|
|
except ConfigurationError as e:
|
|
print(f"Config issue: {e}")
|
|
print(f"Details: {e.details}")
|
|
except StorageError as e:
|
|
print(f"Storage issue: {e}")
|
|
# Headroom continues to work, just without metrics persistence
|
|
except HeadroomError as e:
|
|
print(f"Headroom error: {e}")
|
|
```
|
|
|
|
---
|
|
|
|
## Getting Help
|
|
|
|
1. **Enable debug logging** and check the output
|
|
2. **Use simulate()** to see what transforms would apply
|
|
3. **Check validate_setup()** for configuration issues
|
|
4. **File an issue** at https://github.com/headroom-sdk/headroom/issues
|
|
|
|
When filing an issue, include:
|
|
- Headroom version (`pip show headroom`)
|
|
- Python version
|
|
- Provider (OpenAI/Anthropic)
|
|
- Debug log output
|
|
- Minimal reproduction code
|