Commit graph

181 commits

Author SHA1 Message Date
chopratejas
a9aa66e4c6 Fix 19 test failures: missing security attr, nosec inside f-strings, stale test mock
- Initialize self.security = None on HeadroomProxy (enterprise plugin hook)
- Move '# nosec B608' comments outside f-strings in sqlite.py and fts5.py
  (SQLite doesn't understand # as comment, causing OperationalError)
- Add mark_stable_from_messages to _FakeCompressionCache test mocks
- Update token mode freeze assertion to match cache-aware behavior
2026-04-07 18:30:29 -07:00
Tejas Chopra
22dad133e2 fix: eliminate prefix cache busts from frozen count underestimation
Root cause: CompressionCache.compute_frozen_count() stopped at the first
tool_result not in its cache, capping frozen_message_count at 2. Tool
results excluded by content_router (Read/Glob) or skipped (ratio too
high) never entered the cache, so every subsequent message was eligible
for recompression — causing 192 cache busts per session.

Four fixes:
1. Add _stable_hashes set to CompressionCache so excluded/skipped
   tool_results don't block the frozen count walk
2. Fix _estimate_message_tokens to count tool_result content and
   tool_use input fields (were counted as 0 tokens in Anthropic format)
3. Fix streaming handler to include assistant response and
   original_messages in prefix tracker updates (parity with non-streaming)
4. TTL-aware batch recompression: defer first-time compressions within
   the 5-min cache TTL window, batching them at the boundary to trade
   many small busts for one
2026-04-07 17:10:20 -07:00
Tejas Chopra
c2dde5f6b8
Merge pull request #110 from rrubayet321/main
Add security audit reports and update dependency management
2026-04-07 15:09:15 -07:00
chopratejas
feb163d8c8 Fix Bedrock/Vertex auth regression: don't forward api_key for env-auth providers (#105)
The 0.5.18 refactor added api_key forwarding from request headers to
LiteLLM kwargs in all 4 handler methods. This breaks Bedrock (AWS SigV4)
and Vertex AI (Google ADC) which authenticate via env vars, not API keys.
Forwarding a dummy key like sk-ant-dummy overrides AWS credentials.

Fix: skip api_key forwarding for bedrock, vertex_ai, vertex_ai_beta,
and sagemaker providers. Applied to all 4 occurrences.
2026-04-07 14:24:19 -07:00
chopratejas
8f18468f3b Fix Strands SDK content block tokenization (#111)
Strands SDK sends content blocks without a 'type' field:
  {"text": "..."} instead of {"type": "text", "text": "..."}
  {"toolUse": {...}} instead of {"type": "tool_use", ...}
  {"toolResult": {...}} instead of {"type": "tool_result", ...}

The tokenizer's _count_content_parts() only matched on type field,
causing Strands blocks to fall through to json.dumps estimation.
Now explicitly handles Strands text, toolUse, and toolResult formats
with proper recursive counting for nested toolResult content.

8 new tests covering Strands text blocks, tool blocks, and mixed formats.
2026-04-07 14:19:15 -07:00
rrubayet321
2ae71fe44d chore: add nosec B324 annotations to non-cryptographic MD5 usages and update temporary database path to use system temp directory 2026-04-07 13:07:26 +06:00
JerrettDavis
6f701033a1 test: align anthropic cache stability fixtures
Sync the Anthropic cache stability test double with the prefix tracker contract used by the handler.

Format the benchmark scripts that were failing ruff format --check in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-06 23:26:51 -05:00
JerrettDavis
78163199c4 Merge upstream/main into feat/extended-cache-ttl-metrics 2026-04-06 21:59:46 -05:00
JerrettDavis
a6787556be Add observed cache TTL metrics and dashboard coverage 2026-04-06 21:13:30 -05:00
JerrettDavis
8e4d7759de Harden cache validation reporting and TTL analysis 2026-04-06 20:11:21 -05:00
chopratejas
f4160f9e47 Fix Codex WebSocket HTTP 500: ChatGPT auth routing, correct beta header, HTTP fallback (#71)
Root causes:
- ChatGPT session auth tokens sent to api.openai.com instead of chatgpt.com
- Fallback beta header was responses-api=v1 instead of responses_websockets=2026-02-06

Fixes:
- Detect ChatGPT-Account-ID header and route WS/HTTP to chatgpt.com/backend-api/codex/responses
- Update beta header fallback to match what Codex actually sends
- Add HTTP POST streaming fallback when upstream WS fails (relay SSE over client WS)
- Unwrap response.create envelope in HTTP fallback for correct POST body
- Initialize body before JSON parse to prevent NameError in fallback path
- Fix async test failures: convert asyncio.get_event_loop() to asyncio.run()
2026-04-06 12:48:46 -07:00
JerrettDavis
5ffa77f4a3 Harden anthropic cache-mode replay stability 2026-04-05 16:11:39 -05:00
JerrettDavis
d00c6739e1 Fix CI regressions for cache benchmark work 2026-04-04 22:33:44 -05:00
JerrettDavis
96fd3d9652 Add Anthropic cache-mode delta replay 2026-04-04 22:23:10 -05:00
JerrettDavis
f2a32f9721 Harden Anthropic cache mode stability 2026-04-04 22:06:52 -05:00
JerrettDavis
1206c0ede2 Improve Claude cache simulation accounting 2026-04-04 21:54:45 -05:00
JerrettDavis
09829be0f4 Add memory-conscious Claude session benchmark harness 2026-04-04 21:19:40 -05:00
JerrettDavis
83b730f2b9 Fix CI lint/format failures after proxy mode hardening 2026-04-04 14:42:32 -05:00
JerrettDavis
2625789a28 Harden cache-mode immutability for OpenAI and fix stats mode reporting 2026-04-04 14:36:29 -05:00
JerrettDavis
54419ad8b8 Rebrand proxy modes to token/cache and harden cache-mode stability 2026-04-04 14:32:07 -05:00
JerrettDavis
d78fdfe02d Merge remote-tracking branch 'upstream/main' into fix/anthropic-prefix-cache-stability
# Conflicts:
#	headroom/proxy/handlers/anthropic.py
2026-04-04 13:54:54 -05:00
JerrettDavis
7d02829f02 Harden Anthropic prefix cache stability across proxy and batch paths 2026-04-04 13:45:37 -05:00
JerrettDavis
cd2741cfff test(cli): add branch coverage for wrap openclaw flows 2026-04-03 23:55:14 -05:00
JerrettDavis
61dacc94a1 fix(cli): default wrap openclaw spec to headroom-ai/openclaw 2026-04-03 23:36:23 -05:00
JerrettDavis
490cf15a57 style: apply ruff formatting for wrap openclaw changes 2026-04-03 23:20:15 -05:00
JerrettDavis
3a25ed4571 fix(cli): make wrap openclaw npm-first and idempotent 2026-04-03 23:15:24 -05:00
JerrettDavis
c5e3686c89 feat(cli): add one-command OpenClaw wrap bootstrap 2026-04-03 23:08:13 -05:00
chopratejas
6a8ae297d6 Refactor: extract 7 modules from server.py (Steps 2-4)
server.py: 8778 → 7412 lines (-1366, -15.5%)

Extracted modules:
- cost.py (629 lines): CostTracker, build_prefix_cache_stats, merge_cost_stats
- prometheus_metrics.py (312 lines): PrometheusMetrics
- semantic_cache.py (142 lines): SemanticCache
- rate_limiter.py (101 lines): TokenBucketRateLimiter
- request_logger.py (108 lines): RequestLogger
- helpers.py (195 lines): _read_request_json, constants, lazy loaders
- models.py (199 lines): ProxyConfig, RequestLog, CacheEntry (from Step 1)

All existing imports via headroom.proxy.server continue to work
through re-exports. Updated test patches to target new module paths.

181 tests pass, 0 regressions.
2026-04-03 16:18:08 -07:00
Garm
d88c6e205f Apply Ruff formatting to rebased stack 2026-04-02 13:40:57 +02:00
Garm
07fcfd493c Polish rebased display-session stack 2026-04-02 13:27:07 +02:00
Garm
02b74607e4 Format display-session tracker changes 2026-04-02 13:10:05 +02:00
Garm
460247c93f Add canonical display-session metrics for downstream dashboards 2026-04-02 13:10:05 +02:00
Garm
ec6753205a feat: add spend and input-token rollups to stats-history 2026-04-02 11:36:41 +02:00
chopratejas
d7ab580aa3 Fix dashboard cost savings: use model list price, not moving average
savings_usd is now tokens_saved * model list input price (monotonic,
transparent). Removed non-monotonic moving-average repricing and
confusing cost_without_headroom counterfactual.

Dashboard hero shows "Compression Savings" with clear subtitle.
Savings Breakdown section shows compression, cache, and RTK separately
with distinct colors and no scope mixing.

All beacon/telemetry fields preserved. RTK token counts still reported.

Fixes #83
2026-03-31 08:50:25 -07:00
Garm
dd509585b0 Merge remote-tracking branch 'origin/main' into feat/persist-savings-history 2026-03-31 10:57:36 +02:00
Garm
3892774b53 style: format savings history tests 2026-03-31 10:39:08 +02:00
Garm
bb5b60f6e6 Update test_proxy_savings_history.py 2026-03-31 10:32:05 +02:00
Garm
9a695249af feat: add historical rollups and exports 2026-03-31 10:25:45 +02:00
chopratejas
2d97d8e900 Kompress ONNX INT8: text compression without torch dependency
KompressCompressor now tries ONNX Runtime first (156MB INT8 model),
falls back to PyTorch only if ONNX unavailable. No torch needed for
text compression — just onnxruntime (~50MB) + transformers (tokenizer).

Changes:
- Add onnxruntime + transformers to [proxy] extra in pyproject.toml
- Add _OnnxModel wrapper with get_scores/get_keep_mask interface
- _load_kompress() tries ONNX first, falls back to PyTorch
- is_kompress_available() returns True if EITHER backend available
- compress() handles both numpy (ONNX) and tensor (PyTorch) outputs

Dependency impact:
  Before: pip install headroom-ai[proxy] → no text compression
  After:  pip install headroom-ai[proxy] → Kompress ONNX INT8 (156MB)
  [ml] extra still available for full PyTorch (600MB, GPU support)
2026-03-30 22:50:13 -07:00
chopratejas
0007a9f0f4 Add compression for OpenAI Responses API (/v1/responses)
The /v1/responses handler was passing through without compression,
meaning Codex CLI users got zero savings. Now converts Responses API
items (function_call, function_call_output, reasoning, message) to
Chat Completions format, runs the existing pipeline, and converts back.

- New: headroom/proxy/responses_converter.py — pure conversion functions
- 21 unit tests + 3 integration tests (tested with real OpenAI API)
- Preserves reasoning items, images, unknown types verbatim
- Skips compression when previous_response_id is set
- 27% compression on real Codex-pattern payloads (500 records → 14K tokens saved)

Closes #73
2026-03-30 20:13:00 -07:00
chopratejas
7d25c87286 Fix tool_result ordering: no stray user message between tool_calls and tool
Bedrock requires role=tool messages immediately after assistant tool_calls.
The previous fix inserted a user text message in between when the message
contained both text and tool_result blocks, breaking the pairing.

Drop text alongside tool_result (Claude Code never sends it in practice).
Added ordering regression tests for the Bedrock constraint.
2026-03-30 16:25:22 -07:00
chopratejas
8228f0edfb Fix streaming tool calls, compressed request bodies, beacon field names; bump to 0.5.13
- Fix LiteLLM stream_message: emit tool_use blocks from delta.tool_calls,
  set stop_reason from finish_reason (fixes silent MCP tool call failures)
- Fix _convert_messages_for_litellm: convert Anthropic tool_result/tool_use
  to OpenAI role=tool/tool_calls format (fixes 500 on tool round-trips)
- Fix proxy request body parsing: decompress zstd/gzip/deflate/brotli
  Content-Encoding before JSON decode (fixes Codex UnicodeDecodeError crash)
- Fix telemetry beacon field names to match /stats endpoint
  (tokens.total_before_compression, not tokens.original)
- Add dedupe_telemetry.py script for hourly Supabase row deduplication
2026-03-30 14:48:48 -07:00
chopratejas
de862d9830 fix: remove unused imports in test_langgraph.py (ruff F401) 2026-03-30 09:27:49 -07:00
chopratejas
c7731b1d21 Fix Windows drive letter path decoding in headroom learn (fixes #69)
_decode_project_path now detects single-letter first component as a
Windows drive letter: -C-MQ2-macros → C:\MQ2\macros instead of
/C/MQ2/macros (which becomes \\C\MQ2\macros on Windows).

- Add Windows drive detection before Unix path attempts
- Fix fallback path construction for Windows patterns
- Add Linux /home/ support in greedy decoder
- Add 2 tests for Windows drive letter patterns
2026-03-30 09:08:21 -07:00
gglucass
165d3ca726
Merge branch 'main' into feat/persist-savings-history 2026-03-30 12:04:39 +02:00
Garm
3b887ff79a test: cover savings tracker branches 2026-03-30 12:02:03 +02:00
Garm
3652bcb182 fix: restore anthropic compression when hooks enabled 2026-03-30 11:25:15 +02:00
Garm
06c1b32cdf refactor: move dashboard mode switch to header 2026-03-30 10:54:46 +02:00
Tejas Chopra
42ea085751
Merge pull request #60 from gglucass/feat/add-headroom-sdk
feat: allow overriding proxy telemetry sdk via HEADROOM_SDK
2026-03-29 18:21:13 -07:00
kunallohtia
9590dbc214 feat: add LangGraph compress_tool_messages node for ToolMessage compression 2026-03-29 17:11:15 -07:00