Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ucode/agents/claude.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
sync_smart_routing_hooks,
)
from ucode.state import MANAGED_OVERLAY_KEY, is_tool_managed, mark_tool_managed, save_state
from ucode.telemetry import agent_version, ucode_version
from ucode.telemetry import agent_version, ucode_release_version
from ucode.tracing import tracing_env
from ucode.ui import print_note, print_success, print_warning

Expand Down Expand Up @@ -363,7 +363,7 @@ def render_overlay(
# traffic to ucode.
header_lines = [
"x-databricks-use-coding-agent-mode: true",
f"User-Agent: ucode/{ucode_version()} claude/{agent_version('claude')}",
f"User-Agent: ucode/{ucode_release_version()}",
]
if provider:
header_lines.append(f"{MODEL_PROVIDER_SERVICE_HEADER}: {provider}")
Expand Down
5 changes: 5 additions & 0 deletions src/ucode/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ def ucode_version() -> str:
return "unknown"


def ucode_release_version() -> str:
"""Return the package release version without local build metadata."""
return ucode_version().split("+", 1)[0]


@cache
def agent_version(binary: str) -> str:
"""Return the agent CLI's reported version, or "unknown" on any failure.
Expand Down
18 changes: 12 additions & 6 deletions tests/test_agent_claude.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,20 @@ def test_managed_keys_include_env_entries(self):


class TestRenderOverlayUserAgent:
def _ua(self, monkeypatch) -> str:
monkeypatch.setattr(claude, "ucode_version", lambda: "0.1.0")
monkeypatch.setattr(claude, "agent_version", lambda binary: "2.1.136")
def _ua(self, monkeypatch, claude_version: str = "2.1.136") -> str:
monkeypatch.setattr(claude, "ucode_release_version", lambda: "0.1.0")
monkeypatch.setattr(claude, "agent_version", lambda binary: claude_version)
overlay, _ = claude.render_overlay(WS, "s4")
return overlay["env"]["ANTHROPIC_CUSTOM_HEADERS"]

def test_user_agent_present(self, monkeypatch):
assert "User-Agent: ucode/0.1.0 claude/2.1.136" in self._ua(monkeypatch)
assert "User-Agent: ucode/0.1.0" in self._ua(monkeypatch)

def test_user_agent_does_not_change_when_claude_updates(self, monkeypatch):
user_agent = self._ua(monkeypatch, "2.1.272")

assert user_agent == "x-databricks-use-coding-agent-mode: true\nUser-Agent: ucode/0.1.0"
assert "claude/" not in user_agent

def test_existing_databricks_header_preserved(self, monkeypatch):
assert "x-databricks-use-coding-agent-mode: true" in self._ua(monkeypatch)
Expand Down Expand Up @@ -853,7 +859,7 @@ def test_managed_file_merges_anthropic_custom_headers(self, monkeypatch):
}
}
self._patch(monkeypatch, private_writes, managed_writes, existing_managed_settings)
monkeypatch.setattr(claude, "ucode_version", lambda: "1.0")
monkeypatch.setattr(claude, "ucode_release_version", lambda: "1.0")
monkeypatch.setattr(claude, "agent_version", lambda _binary: "2.0")
state = {"workspace": WS, "codex_models": []}

Expand All @@ -863,7 +869,7 @@ def test_managed_file_merges_anthropic_custom_headers(self, monkeypatch):
merged_headers = json.loads(text)["env"]["ANTHROPIC_CUSTOM_HEADERS"]
assert merged_headers.splitlines() == [
"X-Enterprise-Header: retain", # Preserved from existing managed settings.
"User-Agent: ucode/1.0 claude/2.0", # From ucode; overwrites existing.
"User-Agent: ucode/1.0", # From ucode; overwrites existing.
"x-databricks-use-coding-agent-mode: true", # Newly added by ucode.
]

Expand Down
5 changes: 3 additions & 2 deletions tests/test_e2e_user_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import pytest

from ucode.telemetry import agent_version, ucode_version
from ucode.telemetry import agent_version, ucode_release_version, ucode_version


def _require_binary(binary: str):
Expand Down Expand Up @@ -126,7 +126,8 @@ def capture_server():


def _expected_ua(agent_name: str, binary: str) -> str:
return f"ucode/{ucode_version()} {agent_name}/{agent_version(binary)}"
version = ucode_release_version() if agent_name == "claude" else ucode_version()
return f"ucode/{version} {agent_name}/{agent_version(binary)}"
Comment on lines +129 to +130


def _assert_ua(req: _CapturedRequest, expected: str) -> None:
Expand Down
7 changes: 7 additions & 0 deletions tests/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ def test_returns_string(self):
assert telemetry.ucode_version() != ""


class TestUcodeReleaseVersion:
def test_drops_local_build_metadata(self, monkeypatch):
monkeypatch.setattr(telemetry, "ucode_version", lambda: "0.1.0+172.g673cff4")

assert telemetry.ucode_release_version() == "0.1.0"


class TestAgentVersion:
def setup_method(self):
# The helper is @cache'd; clear between tests so each gets a clean run.
Expand Down