Commit graph

2630 commits

Author SHA1 Message Date
JerrettDavis
ebfb64f9c2 style: align lazy import modules with ruff
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:07:04 -05:00
JerrettDavis
dc79976d79 fix: preserve proxy compatibility exports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 21:02:06 -05:00
JerrettDavis
f45822c178 fix: restore lazy import compatibility
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 20:56:27 -05:00
JerrettDavis
f63cfe7a1e fix: lazy-load proxy startup dependencies
Keep the default Headroom proxy startup path lightweight so OpenClaw can launch it reliably on Windows. This defers heavyweight provider, cache, transform, pricing, and detector imports until they are actually needed, adds a lightweight version module, and keeps the OpenClaw launcher on the configured Python path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 20:33:46 -05:00
Gyeonghun Park
da4b971128 Merge remote-tracking branch 'origin/main' into feat/cli-llm-backend
# Conflicts:
#	docs/learn.md
2026-04-11 10:05:45 +09:00
chopratejas
1ccab7de43 Fix CodeAwareCompressor: statement-based truncation, docstring fix
Major fix to code compression that was broken for most real-world files.

Root cause: body truncation used line-based slicing (keep first N lines),
which cut mid-expression (e.g., line 3 of a multi-line dict literal),
producing invalid syntax. 4 out of 5 files failed before this fix.

Changes:
- Statement-based truncation: walk body_node.children (AST statements)
  instead of slicing lines. Each child is a complete, syntactically
  valid statement. Never cuts mid-expression.
- Skip unnamed AST tokens: filter out { } ; punctuation nodes in
  brace-language bodies (JS, Go, Rust, Java, C/C++)
- Fix FIRST_LINE docstring: use source lines directly instead of
  reconstructing from byte offsets. Properly handles all quote styles.
- Remove Kompress fallback on syntax failure: return original code
  (never serve broken code)

Results: 6/10 real Python files now compress successfully (was 1/5).
  anthropic.py: 21,605 → 1,797 tokens (92% saved)
  openai.py:    18,032 → 1,162 tokens (94% saved)
  core.py:       7,319 → 3,238 tokens (56% saved)
  local.py:      7,998 → 3,341 tokens (58% saved)
All 60 existing tests pass including JavaScript.
2026-04-10 16:46:07 -07:00
chopratejas
1336e6a793 Replace demo GIF with HeadroomDemo-Fast.gif 2026-04-10 15:05:25 -07:00
Tejas Chopra
f15ef784a3
Merge pull request #131 from JerrettDavis/jd/healthchecks
feat: add proxy liveness and readiness healthchecks
2026-04-10 14:55:25 -07:00
Tejas Chopra
897c70a4c9
Merge branch 'main' into jd/healthchecks 2026-04-10 14:55:16 -07:00
Tejas Chopra
5b81395511
Merge pull request #132 from JerrettDavis/jd/devcontainers
feat: add reproducible devcontainers
2026-04-10 14:54:27 -07:00
chopratejas
dd488fdaaf Update docs: cross-agent memory, plugin learn architecture, dedup
README.md:
- Add cross-agent memory section with --memory flag examples
- Update learn section with multi-agent support (Claude, Codex, Gemini)
- Update features table: memory now cross-agent, learn now plugin-based
- Add --memory to wrap examples

docs/memory.md:
- Add "Cross-Agent Memory (Proxy)" section with architecture diagram
- Document project-scoped DB, auto user_id, agent provenance
- Document intelligent dedup (enriched hints + async background)
- Document supported providers table (Anthropic, OpenAI, Gemini)
- Update comparison table with new features vs Mem0/Letta

docs/learn.md:
- Replace scanner/analyzer architecture with plugin system diagram
- Document plugin-based architecture (auto-discovery + entry points)
- Add supported agents table (Claude, Codex, Gemini + output files)
- Update CLI reference (--agent, --model flags)
- Fix "Where Learnings Go" table for multi-agent output
2026-04-10 14:46:46 -07:00
chopratejas
8033bbaafe Agent provenance, LLM-mediated dedup hints, async background dedup
Memory system now tracks who saved what and prevents duplicates:

- Agent provenance: every memory_save records source_agent, source_provider,
  created_via, and timestamp in metadata
- Enriched save response: when similar memory exists (>75% cosine),
  tool result includes a note suggesting the LLM call memory_update
  to consolidate — piggybacks on the user's own LLM for dedup decisions
- Async background dedup: obvious duplicates (>92% cosine) are
  automatically removed in a fire-and-forget background task
- Edit history: memory_update tracks which agent updated and why
- Project-scoped DB: defaults to {cwd}/.headroom/memory.db
- Auto user_id: detects from $USER instead of hardcoded "default"
- Memory wired into OpenAI and Gemini handlers (context + tools)
- OpenAI embedder auto-detected when sentence-transformers unavailable

Verified E2E: Claude saves → Codex sees dedup hint → Codex calls
memory_update instead of saving duplicate → Claude reads back all.
2026-04-10 14:34:50 -07:00
chopratejas
cd1f0a2b9a Cross-agent memory: OpenAI + Gemini handlers, project-scoped DB, auto user_id
Make memory work across ALL providers sharing the same vector store:
- Wire memory context injection into OpenAI handler (Codex, GPT, etc.)
- Wire memory context injection into Gemini handler
- Add memory tool call handling for OpenAI function calling format
- Project-scoped DB: default to {cwd}/.headroom/memory.db
- Auto-detect user_id from $USER instead of hardcoded "default"
- Auto-detect embedder: use OpenAI embeddings when sentence-transformers
  unavailable (no torch/2GB dependency needed)
- Support embedder_backend/openai_api_key in LocalBackendConfig

Verified E2E: Claude saves memories → Codex reads them → Codex adds
new memories → Claude reads back everything including Codex's additions.
Cross-agent memory sharing works through the same proxy and DB.
2026-04-10 14:34:50 -07:00
JerrettDavis
fdf7d1e138 fix: harden devcontainer worktree startup
Make the devcontainer bootstrap and CI smoke tests work from linked worktrees, including git metadata translation, cache ownership fixes, workspace path handling, and config-scoped smoke checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 13:49:29 -05:00
JerrettDavis
a1beb08d53 feat: add reproducible devcontainers
Add a default devcontainer and a compose-backed memory-stack profile, validate them in CI, and document the contributor workflow.

Also lock the memory-stack dependencies, pin related container tooling, and sync the latest healthcheck shutdown fix for stubbed memory handlers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:58:35 -05:00
JerrettDavis
2b549c5c59 fix: tolerate stubbed memory handlers on shutdown
Guard proxy cleanup so tests and integrations that swap in lightweight memory-handler stubs do not fail during FastAPI lifespan shutdown.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:25:53 -05:00
JerrettDavis
1e940f822d fix: tighten healthcheck typing
Address the new mypy regression in the healthcheck helpers without changing endpoint behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:23:23 -05:00
JerrettDavis
7a18b71c0d feat: add proxy healthcheck endpoints
Add /livez and /readyz, keep /health backward-compatible, and wire readiness into Docker artifacts and docs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:23:23 -05:00
JerrettDavis
bd1ac22855 fix: tighten healthcheck typing
Address the new mypy regression in the healthcheck helpers without changing endpoint behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:17:35 -05:00
JerrettDavis
aa99db8f06 feat: add proxy healthcheck endpoints
Add /livez and /readyz, keep /health backward-compatible, and wire readiness into Docker artifacts and docs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 12:09:10 -05:00
Gyeonghun Park
c3cf022886 fix(learn): handle FileNotFoundError when CLI tool is not installed
When --model codex-cli is used but codex is not in PATH,
subprocess.run raises FileNotFoundError. Catch it and raise
a clear RuntimeError with guidance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 22:11:19 +09:00
Gyeonghun Park
e98c975153 feat(learn): add CLI-based LLM backends for keyless headroom learn
Allow `headroom learn` to use locally installed coding agent CLIs
(claude, gemini, codex) as LLM backends, so subscription users
without raw API keys can run failure analysis.

Priority: --model flag > API key > HEADROOM_LEARN_CLI env var > auto-detect

- Pass prompts via stdin to avoid ARG_MAX limits
- Handle TimeoutExpired, truncate stderr, enrich JSONDecodeError
- Add 31 new tests (48 total), all passing
- Update docs/learn.md with CLI backend documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 22:02:06 +09:00
Tejas Chopra
cd79d77438
Merge pull request #126 from JerrettDavis/jd/pr2-telemetry-transparency-fix
feat: anonymized telemetry warning across all user-facing paths
2026-04-10 00:23:20 -07:00
JerrettDavis
217bf16d3c fix: format telemetry warning tests for CI
Rebase the anonymous telemetry transparency warning work onto the latest main branch and format the new telemetry warning tests so the Python 3.12 lint lane passes cleanly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 23:29:56 -05:00
copilot-swe-agent[bot]
73b34ae2ea fix: use single spaces around 'or' in telemetry disable instructions
Agent-Logs-Url: https://github.com/JerrettDavis/headroom/sessions/880a7bb3-3ad9-49f4-a0b6-3ffdde233e48

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
2026-04-09 23:26:31 -05:00
copilot-swe-agent[bot]
de311f7da4 feat: add anonymous telemetry warning across all user-facing paths
- Add is_telemetry_warn_enabled() feature flag (HEADROOM_TELEMETRY_WARN=off
  to suppress at build/pack time) and format_telemetry_notice() helper to beacon.py
- Export new helpers from headroom.telemetry.__init__
- Proxy CLI startup banner now shows Telemetry: ENABLED/DISABLED with opt-out
  instructions when enabled
- Log telemetry status at proxy server startup() so it appears in log stream
- wrap CLI _launch_tool() and the bespoke claude wrap command both call
  _print_telemetry_notice() so users see the notice before the tool launches
- /stats endpoint now includes anon_telemetry_shipping boolean flag
- Dashboard header shows amber Anon Telemetry indicator chip when
  anon_telemetry_shipping is true (theme-matching, with tooltip showing opt-out)
- 30 new tests covering all paths; all 82 tests pass

Agent-Logs-Url: https://github.com/JerrettDavis/headroom/sessions/880a7bb3-3ad9-49f4-a0b6-3ffdde233e48

Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com>
2026-04-09 23:26:31 -05:00
Tejas Chopra
ed780b837a
Merge pull request #123 from JerrettDavis/feat/otel-support
Add OTEL metrics and Langfuse tracing support
2026-04-09 21:08:15 -07:00
chopratejas
446872ed53 Plugin architecture for headroom learn + live traffic flush
Refactor headroom learn into a plugin architecture where each coding
agent (Claude Code, Codex, Gemini CLI) is a self-contained plugin
with scanner, writer, and detection logic. External plugins can
register via the headroom.learn_plugin entry point.

- Add LearnPlugin ABC (base.py) and plugin registry (registry.py)
- Move scanners from monolithic scanner.py into plugins/ directory
- Extract shared error classification and tool name map (_shared.py)
- Add GeminiScanner for Google Gemini CLI session parsing
- CLI uses dynamic agent detection via registry (no hardcoded choices)
- All existing imports preserved via backwards-compat re-exports
- Wire agent_type through wrap → proxy → TrafficLearner
- Flush learned patterns to correct .md file at proxy shutdown
- Fix shutdown queue drain bug (patterns were lost on exit)
- 97 tests pass (84 existing + 13 new registry/plugin tests)
2026-04-09 20:30:20 -07:00
JerrettDavis
01fc1aaf94 test: fix codex routing response stub
Update the OpenAI Codex routing test double to match the response shape
expected by the handler so the success path is exercised instead of
falling into the generic failure branch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:50:38 -05:00
JerrettDavis
be6aa14110 feat: expose proxy OTEL metrics and Langfuse status
Wire the proxy's operational metrics facade into the new observability
layer, expand built-in Prometheus export, surface OTEL and Langfuse status
in /stats, and document the split between anonymous telemetry, OTEL metrics,
and Langfuse traces.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:20:46 -05:00
JerrettDavis
ebd482c0a0 feat: add OTEL observability core
Add a shared observability layer for OTEL metrics and Langfuse tracing.
Instrument the shared compression pipeline once so SDK and proxy paths can
reuse the same metrics and spans without scattering telemetry concerns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-09 21:20:34 -05:00
Tejas Chopra
e4f72569c7
Merge pull request #109 from JerrettDavis/feat/openclaw-upstream-gateway
feat(openclaw): route configurable gateway providers through headroom
2026-04-09 17:10:50 -07:00
chopratejas
c9ac5f6270 Fix e2e cleanup: ignore errors from OpenClaw leftover files
TemporaryDirectory cleanup fails with OSError when OpenClaw gateway
leaves behind lock/session files. ignore_cleanup_errors=True lets
the test pass while the OS cleans up /tmp on reboot.
2026-04-09 16:41:15 -07:00
chopratejas
13081f4647 Skip image tests when Pillow not installed (CI fix)
Tests that create PIL images now have @needs_pillow decorator.
Token estimation and tile math tests still run without Pillow.
2026-04-09 16:24:15 -07:00
chopratejas
65e4a35546 Add OCR routing via RapidOCR + measure actual tokens after compression
Transcode technique now runs RapidOCR to extract text from images.
Falls back to full_low if OCR confidence < 70% or no text detected.

Token counting is now done AFTER compression by measuring the actual
output — no hardcoded estimates. OCR text counted by char length,
resized images re-estimated from new dimensions.

RapidOCR added to headroom-ai[image] extra (~15MB ONNX models, ~180ms CPU).
4 new OCR tests (extraction, blank image, confidence threshold, full pipeline).
29 total image compression tests passing.
2026-04-09 16:22:18 -07:00
chopratejas
7984bd2389 Re-enable image compression: tile optimizer + ONNX router, no PyTorch
Image compression pipeline:
1. Tile-boundary alignment (pure math, 0ms) — saves 340-680 tokens/image
   on OpenAI by snapping to 512px tile boundaries
2. ONNX technique router (32MB, 6ms) — classifies query intent
3. ONNX SigLIP image encoder (95MB, 49ms) — analyzes image properties

Total: ~127MB models, ~55ms latency, no PyTorch dependency.
Re-enabled in both Anthropic and OpenAI proxy handlers.
25 tests.
2026-04-09 16:11:00 -07:00
chopratejas
e74fd3b218 Add tile-boundary image optimizer — reduce vision tokens with pure math
OpenAI tiles images at 512px: tokens = 85 + 170 * tiles. Resizing to
land on tile boundaries reduces tile count without quality loss.

Examples: 1920x1080 screenshot: 1105 → 425 tokens (62% savings).
770x770 square: 765 → 255 tokens (67% savings). Pure math, zero
dependencies beyond Pillow, <1ms computation.

Matches token0's tile_optimized_resize output exactly. Also handles
Anthropic pre-resize (cap at 1568px/1.15MP) and PNG→JPEG conversion.
2026-04-09 00:22:20 -07:00
JerrettDavis
37f32a8922 test(openclaw): cover branch routing paths
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 23:46:16 -05:00
JerrettDavis
2f05705043 fix(openclaw): normalize provider proxy routing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 22:28:17 -05:00
JerrettDavis
d4f6e3938f fix(proxy): add fast-fail launch settings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 22:03:21 -05:00
Tejas Chopra
47e734cc14
Merge pull request #120 from gglucass/fix/mcp-tool-name-prefix
fix: use MCP-namespaced tool name in Claude Code instructions
2026-04-08 19:40:46 -07:00
JerrettDavis
4d8b76f7da fix(openclaw): use lightweight headroom launcher checks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 21:39:14 -05:00
JerrettDavis
eb302fa35e test(proxy): cover codex responses subpath aliases
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 21:22:05 -05:00
JerrettDavis
2ceceb4024 fix(proxy): alias nested codex responses routes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 21:17:24 -05:00
JerrettDavis
afb339059b fix(openclaw): launch Windows headroom shims via shell
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 21:16:32 -05:00
JerrettDavis
9c1bef56bf chore: apply ruff formatting
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-08 21:16:32 -05:00
JerrettDavis
0da1a7b4de Add OpenClaw unwrap flow and non-blocking proxy startup 2026-04-08 21:16:32 -05:00
JerrettDavis
8134939efb fix(openclaw): preserve upstream response paths 2026-04-08 21:15:52 -05:00
JerrettDavis
621c3b6f43 fix(openclaw): wait for proxy before gateway routing 2026-04-08 21:10:49 -05:00
JerrettDavis
e0383675aa fix(openclaw): keep gateway routing runtime-only 2026-04-08 21:10:49 -05:00