chopratejas commited on
Commit
c32da96
·
2 Parent(s): 138b32e9f37321

Merge pull request #60 from gglucass/feat/add-headroom-sdk

Browse files

feat: allow overriding proxy telemetry sdk via HEADROOM_SDK

CHANGELOG.md CHANGED
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
  ## [Unreleased]
9
 
10
  ### Added
 
 
 
11
  - **`headroom learn`** — Offline failure learning for coding agents
12
  - Analyzes past conversation history (Claude Code, extensible to Cursor/Codex)
13
  - **Success correlation**: for each failure, finds what succeeded after and extracts the specific correction
 
8
  ## [Unreleased]
9
 
10
  ### Added
11
+ - **Proxy telemetry SDK override** via `HEADROOM_SDK`
12
+ - Downstream apps can override the anonymous telemetry `sdk` field without patching installed files
13
+ - Blank values fall back to the default `proxy` label
14
  - **`headroom learn`** — Offline failure learning for coding agents
15
  - Analyzes past conversation history (Claude Code, extensible to Cursor/Codex)
16
  - **Success correlation**: for each failure, finds what succeeded after and extracts the specific correction
docs/proxy.md CHANGED
@@ -21,6 +21,8 @@ headroom proxy \
21
  --budget 100.0
22
  ```
23
 
 
 
24
  ## Command Line Options
25
 
26
  ### Core Options
 
21
  --budget 100.0
22
  ```
23
 
24
+ Telemetry is enabled by default. Opt out with `HEADROOM_TELEMETRY=off` or `headroom proxy --no-telemetry`. Downstream apps can set `HEADROOM_SDK=headroom-app` to override the anonymous telemetry `sdk` label; the default remains `proxy`.
25
+
26
  ## Command Line Options
27
 
28
  ### Core Options
headroom/proxy/server.py CHANGED
@@ -7000,7 +7000,7 @@ def create_app(config: ProxyConfig | None = None) -> FastAPI:
7000
 
7001
  _beacon = TelemetryBeacon(
7002
  port=config.port if hasattr(config, "port") else 8787,
7003
- sdk="proxy",
7004
  backend=config.backend if hasattr(config, "backend") else "anthropic",
7005
  )
7006
 
 
7000
 
7001
  _beacon = TelemetryBeacon(
7002
  port=config.port if hasattr(config, "port") else 8787,
7003
+ sdk=os.environ.get("HEADROOM_SDK", "proxy").strip() or "proxy",
7004
  backend=config.backend if hasattr(config, "backend") else "anthropic",
7005
  )
7006
 
tests/test_proxy_telemetry_env.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for proxy telemetry environment variable handling."""
2
+
3
+ from unittest.mock import patch
4
+
5
+ import pytest
6
+
7
+ pytest.importorskip("fastapi")
8
+
9
+ from headroom.proxy.server import ProxyConfig, create_app
10
+
11
+
12
+ class TestProxyTelemetrySDKEnv:
13
+ """Test HEADROOM_SDK handling when the proxy builds telemetry beacons."""
14
+
15
+ def test_proxy_telemetry_sdk_defaults_to_proxy(self, monkeypatch):
16
+ """Telemetry beacon uses the default SDK label when env var is unset."""
17
+ monkeypatch.delenv("HEADROOM_SDK", raising=False)
18
+
19
+ with patch("headroom.telemetry.beacon.TelemetryBeacon") as mock_beacon:
20
+ create_app(
21
+ ProxyConfig(
22
+ cache_enabled=False,
23
+ rate_limit_enabled=False,
24
+ cost_tracking_enabled=False,
25
+ )
26
+ )
27
+
28
+ assert mock_beacon.call_args.kwargs["sdk"] == "proxy"
29
+
30
+ def test_proxy_telemetry_sdk_uses_env_override(self, monkeypatch):
31
+ """Telemetry beacon uses HEADROOM_SDK when it is non-empty."""
32
+ monkeypatch.setenv("HEADROOM_SDK", "headroom-app")
33
+
34
+ with patch("headroom.telemetry.beacon.TelemetryBeacon") as mock_beacon:
35
+ create_app(
36
+ ProxyConfig(
37
+ cache_enabled=False,
38
+ rate_limit_enabled=False,
39
+ cost_tracking_enabled=False,
40
+ )
41
+ )
42
+
43
+ assert mock_beacon.call_args.kwargs["sdk"] == "headroom-app"
44
+
45
+ def test_proxy_telemetry_sdk_empty_env_falls_back_to_proxy(self, monkeypatch):
46
+ """Telemetry beacon falls back to proxy when HEADROOM_SDK is blank."""
47
+ monkeypatch.setenv("HEADROOM_SDK", " ")
48
+
49
+ with patch("headroom.telemetry.beacon.TelemetryBeacon") as mock_beacon:
50
+ create_app(
51
+ ProxyConfig(
52
+ cache_enabled=False,
53
+ rate_limit_enabled=False,
54
+ cost_tracking_enabled=False,
55
+ )
56
+ )
57
+
58
+ assert mock_beacon.call_args.kwargs["sdk"] == "proxy"