mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description
Adds first-class Grok Build support to Headroom so Grok CLI sessions can
route through the local proxy for context compression and savings
tracking.
This PR introduces `headroom wrap grok-build` / `headroom unwrap
grok-build`, a `grok_build` provider slice, Grok MCP registrar support,
and install/telemetry wiring so Grok traffic is attributed correctly in
the proxy and dashboard.
Review follow-up (`9368c413`): when users already own
`[model.grok-build]` in `~/.grok/config.toml`, wrap rewrites `base_url`
in that table in place instead of appending a duplicate header (invalid
TOML).
## Type of Change
- [x] New feature (non-breaking change that adds functionality)
## Changes Made
- Added `headroom/providers/grok_build/` with runtime helpers,
reversible `~/.grok/config.toml` injection, and install env builders.
- Added `headroom wrap grok-build` and `headroom unwrap grok-build` CLI
commands.
- Added `GrokRegistrar` for Headroom MCP registration in Grok config.
- Wired `grok_build` into install planner/registry, agent savings,
telemetry, and proxy client detection (`grok/` user agent).
- **Review fix:** rewrite `base_url` inside an existing user-owned
`[model.grok-build]` table in place (`# was: …` metadata).
- Added regression tests + docs (`grok-build.mdx`, `proxy.mdx`) and
CHANGELOG entry.
## Testing
- [x] Unit tests pass (`pytest`)
- [x] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
$ pytest -q tests/test_provider_grok_build.py tests/test_mcp_registry/test_grok_registrar.py
============================== 12 passed in 1.13s ==============================
```
See **Screenshots** below for terminal captures (pytest, review-fix
in-place rewrite, proxy `/readyz`, unwrap).
## Real Behavior Proof
- Environment: macOS, Python 3.11.12 venv, feat/grok-build @ `9368c413`,
isolated `GROK_HOME` temp dirs, proxy port 8799
- Exact command / steps: see screenshot evidence (wrap/unwrap, in-place
table rewrite, `/readyz`)
- Observed result: see screenshots — 12 tests pass; single
`[model.grok-build]` table after wrap on pre-existing config; proxy
healthy; unwrap restores backup
- Not tested: Live interactive Grok chat with xAI auth through the proxy
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable
## Screenshots (if applicable)
Terminal captures from local verification (`9368c413`). Assets hosted on
fork prerelease only — **not** in the source tree.
**1. Pytest — 12 passed (incl. review-fix regression)**

**2. Review fix — in-place `[model.grok-build]` rewrite (single table,
`# was:` metadata)**

**3. Proxy health — `/readyz` healthy on port 8799**

**4. Unwrap — restores pre-wrap backup**

## Additional Notes
Screenshot assets:
https://github.com/aashishtamsya/headroom/releases/tag/pr-1629-evidence
(temporary prerelease; safe to delete after merge).
---------
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
"""Deployment context detection for telemetry.
|
|
|
|
Derives two orthogonal identity fields the beacon reports:
|
|
|
|
* ``install_mode`` — how the proxy process is deployed
|
|
(``persistent`` / ``on_demand`` / ``wrapped`` / ``unknown``).
|
|
* ``headroom_stack`` — how Headroom is being invoked
|
|
(``proxy``, ``wrap_claude``, ``adapter_ts_openai``, ...).
|
|
|
|
Both helpers are best-effort and never raise: telemetry is fire-and-forget and
|
|
must not break the proxy.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
import re
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
_KNOWN_WRAP_AGENTS = frozenset(
|
|
{
|
|
"claude",
|
|
"copilot",
|
|
"codex",
|
|
"aider",
|
|
"cursor",
|
|
"grok_build",
|
|
"omp",
|
|
"openclaw",
|
|
"opencode",
|
|
}
|
|
)
|
|
|
|
# Stack slugs must start with a letter and contain only [a-z0-9_], max 64 chars.
|
|
# Applied at every ingress (env var, HTTP header, stats aggregation) so downstream
|
|
# sinks (Prometheus labels, OTEL attributes) see a bounded vocabulary.
|
|
_STACK_SLUG_RE = re.compile(r"^[a-z][a-z0-9_]{0,63}$")
|
|
|
|
# Cardinality cap on the per-process requests_by_stack dict. Protects the
|
|
# Prometheus scrape, the in-memory counter, and the JSONB telemetry payload
|
|
# from unbounded label explosion when clients send arbitrary X-Headroom-Stack
|
|
# header values.
|
|
MAX_DISTINCT_STACKS = 32
|
|
|
|
|
|
def normalize_stack(raw: str | None) -> str | None:
|
|
"""Validate and normalize a stack slug.
|
|
|
|
Returns the lowercased/stripped slug if it matches ``^[a-z][a-z0-9_]{0,63}$``,
|
|
else ``None``. All external stack identifiers (env var, HTTP header, stats
|
|
keys) must pass through this function — it is the single chokepoint that
|
|
bounds cardinality and rejects garbage before it reaches Prometheus or the
|
|
OTEL metrics layer.
|
|
"""
|
|
|
|
if not raw:
|
|
return None
|
|
slug = raw.strip().lower()
|
|
if not _STACK_SLUG_RE.match(slug):
|
|
return None
|
|
return slug
|
|
|
|
|
|
def _slug_from_agent_type(agent_type: str) -> str:
|
|
"""Return ``wrap_<agent>`` for known agents, otherwise ``unknown``."""
|
|
|
|
agent_type = agent_type.strip().lower()
|
|
if agent_type and agent_type in _KNOWN_WRAP_AGENTS:
|
|
return f"wrap_{agent_type}"
|
|
return "unknown"
|
|
|
|
|
|
def detect_install_mode(port: int) -> str:
|
|
"""Classify how the proxy is deployed.
|
|
|
|
Resolution order:
|
|
|
|
1. ``HEADROOM_AGENT_TYPE`` env var set → ``wrapped`` (spawned by ``headroom wrap``).
|
|
2. A ``DeploymentManifest`` on disk whose port matches ``port`` → ``persistent``.
|
|
3. Otherwise → ``on_demand``.
|
|
|
|
Any failure falls back to ``unknown`` so a broken install subsystem
|
|
doesn't silence telemetry.
|
|
"""
|
|
|
|
try:
|
|
if os.environ.get("HEADROOM_AGENT_TYPE"):
|
|
return "wrapped"
|
|
|
|
try:
|
|
from headroom.install.state import list_manifests
|
|
|
|
for manifest in list_manifests():
|
|
if getattr(manifest, "port", None) == port:
|
|
return "persistent"
|
|
except Exception:
|
|
logger.debug(
|
|
"Beacon: manifest lookup failed during install_mode detection",
|
|
exc_info=True,
|
|
)
|
|
|
|
return "on_demand"
|
|
except Exception:
|
|
logger.debug("Beacon: detect_install_mode crashed", exc_info=True)
|
|
return "unknown"
|
|
|
|
|
|
def detect_stack(stats: dict[str, Any] | None = None) -> str:
|
|
"""Classify how Headroom is being invoked.
|
|
|
|
Resolution order:
|
|
|
|
1. ``HEADROOM_STACK`` env var set → use that slug verbatim.
|
|
2. ``HEADROOM_AGENT_TYPE`` env var set → ``wrap_<agent>``.
|
|
3. ``stats['requests']['by_stack']`` dict populated →
|
|
pick the stack with >80% of requests, else ``mixed``.
|
|
4. Otherwise → ``proxy``.
|
|
|
|
Any failure falls back to ``unknown``.
|
|
"""
|
|
|
|
try:
|
|
explicit = normalize_stack(os.environ.get("HEADROOM_STACK"))
|
|
if explicit:
|
|
return explicit
|
|
|
|
agent_type = os.environ.get("HEADROOM_AGENT_TYPE")
|
|
if agent_type:
|
|
return _slug_from_agent_type(agent_type)
|
|
|
|
if stats:
|
|
by_stack = (stats.get("requests") or {}).get("by_stack") or {}
|
|
if by_stack:
|
|
total = sum(by_stack.values())
|
|
if total > 0:
|
|
dominant, count = max(by_stack.items(), key=lambda kv: kv[1])
|
|
if count / total >= 0.8:
|
|
return normalize_stack(str(dominant)) or "unknown"
|
|
return "mixed"
|
|
|
|
return "proxy"
|
|
except Exception:
|
|
logger.debug("Beacon: detect_stack crashed", exc_info=True)
|
|
return "unknown"
|