Commit graph

2630 commits

Author SHA1 Message Date
Stavros Korokithakis
997f364e9f
Add support for custom Anthropic API URL 2026-04-16 22:34:08 +03:00
Tejas Chopra
73f6673d03
Merge pull request #173 from JerrettDavis/fix/pipeline-permissions-and-docs
fix: repair release and docs pipelines
2026-04-16 10:56:17 -07:00
JerrettDavis
0ba104248c fix: repair release and docs pipelines
Grant the release job contents write permission so GitHub releases can be created, and add the missing docs/overrides directory required by MkDocs deployment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-16 12:53:51 -05:00
Tejas Chopra
f95984b249
Merge pull request #170 from JerrettDavis/ci/release-automation
ci: implement optimized release pipeline
2026-04-16 10:16:27 -07:00
JerrettDavis
ee2c6325a0 fix: use continue-on-error for yellow/warning status on publish failures 2026-04-15 23:11:44 -05:00
JerrettDavis
66e1e6a67f fix: use /tmp for changelog artifact to avoid . file matching issues 2026-04-15 22:54:34 -05:00
JerrettDavis
5f0067012b fix: use if-no-files-found error and add pwd to debug artifact upload 2026-04-15 22:50:16 -05:00
JerrettDavis
d12c7d95cf ci: force new run to test updated workflow 2026-04-15 22:45:45 -05:00
JerrettDavis
7bf5190449 fix: add diagnostic step to verify changelog file before upload 2026-04-15 22:41:47 -05:00
JerrettDavis
4a75e73194 fix: add debug step to diagnose changelog artifact issue 2026-04-15 22:38:53 -05:00
JerrettDavis
e91e4f9672 fix: correct YAML mapping for permissions block 2026-04-15 22:10:21 -05:00
JerrettDavis
bc49e6da16 fix: build TypeScript packages, add OIDC permission, sync SDK dep, scope GPR publish
- publish-pypi: add permissions: id-token: write for OIDC trusted publishing
- publish-npm: add npm run build before npm publish for both packages
- publish-github-packages: add npm run build, use --registry for GPR
- version-sync: add update_openclaw_package_json to sync headroom-ai dep range

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 22:09:05 -05:00
JerrettDavis
ea5d83a161 chore: remove PR.md from branch (draft preserved locally) 2026-04-15 22:01:52 -05:00
JerrettDavis
af7d6b7430 Merge branch 'ci/release-automation' of https://github.com/JerrettDavis/headroom into ci/release-automation 2026-04-15 22:00:06 -05:00
JD Davis
9e37b38c7a
Merge branch 'chopratejas:main' into ci/release-automation 2026-04-15 21:44:11 -05:00
JerrettDavis
049b3527a8 refactor: implement canonical+commit-height release algorithm
The release workflow now uses a loop-free algorithm:
- pyproject.toml is the canonical source of truth (never committed by workflow)
- Git tags use v{canonical}.{height} format (e.g. v0.5.25.3)
- npm publishes use 3-part semver bumped from canonical
- No commit step eliminates infinite release loops
- paths-ignore reduces unnecessary workflow triggers

Also:
- Add .releaseetadata to .gitignore
- Separate npm_version output for semver-compatible npm publishing
- create-release no longer blocks on publish jobs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 21:26:13 -05:00
chopratejas
d66fcd4ba9 Update number array tests for schema-preserving compression
Tests expected the old behavior where _crush_number_array prepended a
summary string into the array. The fix in 14415db moved stats to the
strategy string instead, keeping arrays homogeneously numeric. Update
3 tests to check strategy string instead of array[0].
2026-04-15 19:00:43 -07:00
JerrettDavis
d9520f8558 docs: update PR description with full release pipeline details 2026-04-15 20:38:21 -05:00
JerrettDavis
2df4a53be4 docs: add releases & CI/CD documentation 2026-04-15 20:33:06 -05:00
JerrettDavis
910796ded2 feat: add act testing config, fix gitignore, make workflow production-ready
- Add .actrc with act defaults (Ubuntu runner, reuse, quiet)
- Add .github/act/dry-run.json and push-feat.json for local workflow testing
- Add .actrc.local.example for local overrides (gitignored)
- Add .env.act.example documenting required secrets
- Fix .gitignore: .env.act excluded, .env.act.example allowed
- Replace all bash git commands with Python subprocess (act compatibility)
- Add pip install build wheel for python -m build step
- Use absolute paths for artifact uploads (github.workspace)
- All publish jobs: dry_run + *_SKIP vars as safety gates
2026-04-15 20:28:29 -05:00
JerrettDavis
f33ec4e269 refactor: fully parameterized release workflow with top-level env block 2026-04-15 19:56:17 -05:00
JerrettDavis
8ba43e9dea fix: use correct npm package names (headroom-openclaw), add config comment block 2026-04-15 19:51:04 -05:00
JerrettDavis
e81c13fc84 fix: add separate job for GitHub Package Registry publish 2026-04-15 19:49:20 -05:00
JerrettDavis
3d891264dd feat: add version alignment verification script 2026-04-15 19:37:55 -05:00
JerrettDavis
cf00b06b70 chore: disable publish.yml auto-trigger (superseded by release.yml) 2026-04-15 19:37:15 -05:00
JerrettDavis
272c9736ac ci: add commitlint for conventional commit enforcement 2026-04-15 19:36:49 -05:00
JerrettDavis
ba589be753 feat: add unified release workflow with semantic versioning 2026-04-15 19:36:28 -05:00
JerrettDavis
6299644b6d feat: add changelog generator from conventional commits
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 19:34:50 -05:00
JerrettDavis
93af60ac31 feat: add version synchronization script for multi-package releases 2026-04-15 19:29:15 -05:00
chopratejas
acb8ff39ef Add --stateless mode and graceful degradation for enterprise deployments
New --stateless flag (or HEADROOM_STATELESS=true env var) disables all
filesystem writes so the proxy runs purely in-memory. Designed for
containerized, read-only, and load-balanced deployments.

When stateless:
- Request logging: memory-only deque (no JSONL file)
- TOIN patterns: in-memory only (no JSON persistence)
- Memory system: disabled (requires SQLite on disk)
- Traffic learning: disabled (requires filesystem)
- Deploy manifests: graceful degradation on write failure

Graceful degradation improvements (apply even without --stateless):
- RequestLogger: wraps file I/O in try/except, falls back to memory
- save_manifest(): catches OSError instead of crashing on read-only FS
- TOIN: explicit "none" backend for stateless mode
2026-04-15 17:28:14 -07:00
chopratejas
4641e43891 Add supply chain hardening: SBOM, cosign signing, pinned digests, Dependabot
Enterprise supply chain improvements:
- publish.yml: Generate CycloneDX SBOM and attach to GitHub releases
- docker.yml: Sign all Docker images with Sigstore cosign (keyless OIDC)
- Dockerfile: Pin python:3.11-slim and distroless base images with SHA256
  digests to prevent silent upstream changes
- Add .github/dependabot.yml for automated Docker digest, GitHub Actions,
  and pip dependency update PRs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:28:14 -07:00
Tejas Chopra
4a6c54623c
Merge pull request #163 from JerrettDavis/chore/bump-openclaw-plugin-version
chore: bump openclaw plugin version #162
2026-04-15 17:13:10 -07:00
JerrettDavis
91c5835852 chore: bump openclaw plugin version 2026-04-15 19:09:29 -05:00
Vish Ranganathan
9685e4c476 fix: strip accept-encoding from forwarded proxy headers
Edge proxies such as Cloudflare Workers inject accept-encoding values
(e.g. gzip, br, zstd) into every outbound request. When Headroom
forwarded these headers unchanged to OpenAI or Anthropic, the upstream
could respond with Brotli-encoded content. Because httpx does not
decompress brotli without the optional brotli package, the raw
compressed bytes reached the JSON parser, causing a UnicodeDecodeError
and a 502 response to the client.

Fix: pop accept-encoding before forwarding so httpx negotiates its own
encoding independently. Applied consistently across all four request
header construction sites:

- openai.py: chat completions handler
- openai.py: Responses API handler
- openai.py: generic passthrough handler
- anthropic.py: main messages handler (CCR continuation already had the strip)

Closes #135
2026-04-15 11:40:11 -07:00
chopratejas
4ee519f2c4 Auto-register codebase-memory-mcp as MCP server with --code-graph
Previously `headroom wrap claude --code-graph` downloaded the binary
and indexed the project, but never registered codebase-memory-mcp as
an MCP server — users had to run `claude mcp add` manually.

Now _setup_code_graph() calls `claude mcp add codebase-memory-mcp`
automatically (idempotent, skips if already registered). The uninstall
path (`headroom mcp uninstall`) also cleans up the registration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 23:13:49 -07:00
chopratejas
14415dbbb5 Fix SmartCrusher bugs: schema violation, race condition, thread safety, recursion
- Number array compression no longer mixes types (string summary was
  prepended to numeric array, violating schema-preserving guarantee).
  Statistics now go in the strategy string instead.
- Replace instance-level _current_field_semantics with threading.local()
  to prevent cross-thread contamination in concurrent crushes.
- Add lock to module-level _within_compressor lazy init (was unprotected).
- Add _MAX_PROCESS_DEPTH=50 guard to _process_value to prevent
  RecursionError on deeply nested JSON.
- Remove dead expression (unused stats.max_val - stats.min_val).
- Fix all UP038 isinstance(x, (A, B)) -> isinstance(x, A | B) across file.
- Add 11 regression tests covering all fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:16:13 -07:00
chopratejas
6cc8fd04b6 Parallelize headroom learn session scanning with --workers flag
Add ThreadPoolExecutor-based parallel file scanning to all three learn
plugins (Claude, Codex, Gemini). Each plugin's scan_project() now
accepts max_workers and fans out _scan_session() calls concurrently.

New CLI option: headroom learn --workers N (default: min(cpu_count, 8)).
Use --workers 1 for serial behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:14:35 -07:00
chopratejas
89061fd430 Fix CI lint errors and test failures
- test_memory_sync.py: remove unused imports (asyncio, MagicMock,
  AgentMemory, AgentMemoryAdapter, SyncResult), fix import sorting
- test_ws_memory_relay.py: remove unused pytest import and unused
  output_index variable, fix import sorting
- test_wrap_copilot.py: provide dummy API keys in test env — the
  BYOK validation added in 7a7b8b6 requires ANTHROPIC_API_KEY or
  OPENAI_API_KEY to be set
- test_package_init_lazy.py: stop hardcoding version string that
  breaks on every bump; assert it's a non-empty string instead

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:23:06 -07:00
chopratejas
51f1fc282f Fix all broken docs links in README after docs migration (#161)
Commit 911eb85 migrated docs from flat .md files to a Fumadocs site
under docs/content/docs/*.mdx but left the README pointing at the old
paths. Update all 30+ links to their new locations, remove rows for
docs that were deleted without replacement (CLI reference, persistent
installs, latency benchmarks), and consolidate Docker-native install
and TypeScript SDK links into their new homes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:13:02 -07:00
chopratejas
7c91fe1e4b Fix headroom learn failing on project paths with underscores (#159)
_component_tokenizations only split on `-` and `.`, so directory names
like `my_project` could never be reconstructed from the dash-encoded
slug. Add `_` as a separator so the greedy decoder matches snake_case
directory names correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:59:49 -07:00
chopratejas
7a7b8b608f Propagate API key to COPILOT_PROVIDER_API_KEY in wrap copilot
Copilot BYOK requires COPILOT_PROVIDER_API_KEY to be set, but the
wrapper only set COPILOT_PROVIDER_TYPE and COPILOT_PROVIDER_BASE_URL.
This caused Copilot to error with "Anthropic API key or bearer token
is required" even when the user had ANTHROPIC_API_KEY in their env.

Fix: auto-propagate ANTHROPIC_API_KEY (or OPENAI_API_KEY for openai
provider type) to COPILOT_PROVIDER_API_KEY. Warn if neither is found.

Fixes #156
2026-04-14 14:27:52 -07:00
chopratejas
744a580260 Fix memory tools returning 'unsupported call' in Chat Completions
The Chat Completions handler executed memory tool calls (memory_save,
memory_search, etc.) but discarded the results — returning the original
response with tool_calls but no tool results. The client saw
"unsupported call" because it never received the tool output.

Fix: after executing memory tools, send a continuation request to the
upstream model with the tool results appended as messages, so the model
produces a final user-facing response.

Fixes #157
2026-04-14 13:33:41 -07:00
chopratejas
b50136904c Make KompressCompressor model-configurable: model_id, chunk_words, score_threshold
KompressConfig now accepts model_id, chunk_words, and score_threshold so
domain-specific models (e.g. kompress-finance with 50-word chunks) can be
used without forking the compressor. Model cache is keyed by model_id,
allowing multiple models to coexist. All defaults match prior behavior.

Also fix mypy errors in memory/sync.py from recent merge.
2026-04-14 13:19:35 -07:00
Tejas Chopra
82301bbf76 Add cross-agent memory interoperability via MCP, sync engine, and atomic facts
Memory saved in one agent (Codex, Claude Code, Aider) is now accessible
from any other agent through a shared headroom DB. Three integration layers:

MCP Server (headroom.memory.mcp_server):
- stdio MCP server that Codex/Claude discover natively via config.toml
- memory_search with supersession filtering (only active memories returned)
- memory_save accepts atomic facts array — each fact stored/indexed individually
- Auto-supersession: new facts that match existing ones (≥0.70 similarity)
  retire the old entry via the supersedes/superseded_by lineage chain
- ONNX embedder pre-loaded at startup (no cold-start on first query)
- HuggingFace offline mode eliminates network latency on startup

Sync Engine (headroom.memory.sync):
- Bidirectional sync: DB ↔ agent-native memory files
- Pluggable adapters: ClaudeCodeAdapter (frontmatter .md files + MEMORY.md index),
  CodexAdapter (AGENTS.md sections)
- Fast no-op: fingerprint comparison skips sync when nothing changed (<5ms)
- Content-hash dedup prevents duplicate memories across agents
- Lineage metadata: source_agent, source_file, content_hash, synced_at
- Anti-echo: memories imported from an agent are not re-exported to that agent
- CLI entry point: python -m headroom.memory.sync --agent claude|codex

Wrap CLI integration:
- `wrap codex --memory`: registers MCP server + AGENTS.md guidance + syncs
  Claude memories into DB for MCP search
- `wrap claude --memory`: bidirectional sync at startup (DB ↔ Claude files)
- MCP config re-injected after provider config to survive file rewrite
- Cross-platform: Windows path handling in TOML configs and path sanitization

Proxy improvements:
- Responses API: tool format conversion (Chat Completions → Responses API)
- Responses API: memory tool calls handled with proper continuation
- WebSocket: buffer-then-decide relay suppresses memory tool events from
  Codex, executes them transparently, relays only the final answer
- memory_handler: supports Responses API function_call format (call_id,
  top-level arguments, output[] extraction)
- HNSW vector index now persists to disk via auto_save + save_path

Tests: 37 new tests covering WS relay event suppression, sync import/export,
bidirectional sync, idempotency, fast no-op, lineage, cross-agent interop
2026-04-13 23:38:44 -07:00
chopratejas
e306d6b338 Bump version to 0.5.25 for PyPI release
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:32:13 -07:00
Tejas Chopra
c2451296df Add memory support for Codex via OpenAI Responses API handler
Inject memory context into instructions and memory tools into Responses
API requests, and handle memory tool calls in responses.
2026-04-13 16:18:30 -07:00
Tejas Chopra
1b5cc9bbac Fix --memory flag silently dropped when proxy already running
_ensure_proxy() now queries the running proxy's /health config to
detect feature mismatches. When --memory, --learn, or --code-graph
is requested but not enabled on the running proxy, it merges flags
and restarts the proxy with the upgraded configuration.

- Expose memory, learn, code_graph, pid in /health config response
- Add _query_proxy_config() and _kill_proxy_by_pid() helpers
- Refactor _detect_running_proxy_backend() to use _query_proxy_config()
2026-04-13 14:36:30 -07:00
Tejas Chopra
5f4ff918a3 Add --memory flag to all wrap subcommands
Thread the proxy's --memory flag through _start_proxy, _ensure_proxy,
and _launch_tool so that `headroom wrap <tool> --memory` enables
persistent cross-session memory for claude, copilot, codex, aider,
and cursor.
2026-04-13 10:54:01 -07:00
Tejas Chopra
b119430e1c
Merge pull request #152 from SwiftWing21/feat/kompress-batch-compression
feat(kompress): add compress_batch with device-aware routing
2026-04-12 23:07:12 -07:00
SwiftWing21
951d021f97 feat(kompress): add compress_batch with device-aware routing
Implements compress_batch() for issue #151. Compresses N texts with
batched forward passes on GPU and falls back to sequential compress()
on CPU where batching doesn't help.

Measured performance (RTX 3080 Ti, 1000-word / ~6K-char inputs):

  GPU (PyTorch + CUDA):
    N=1:  2.68x speedup (multi-chunk text batches within single call)
    N=5:  2.75x speedup
    N=12: 2.49x speedup

  CPU (ONNX): fallback to sequential — parity with compress() in loop

ONNX Runtime's CPU execution provider does not parallelize across the
batch dimension for this model architecture; verified across default,
physical-cores-only, and single-thread configurations. The fallback
keeps the API useful while that limitation exists.

Features:
- Per-item target_ratio: scalar applies to all, list allows per-text
- Input order preserved in output
- Passthrough parity with compress() on short texts / errors
- Configurable batch_size (default 32)

Tests: 8 new (TestKompressCompressorBatch), 21 total pass.

Closes #151
2026-04-12 21:51:30 -07:00