feat(gemini): add X-Goog-Api-Client headers for API telemetry

Add `X-Goog-Api-Client` tracking headers and versioned `User-Agent`
strings to Gemini API requests across native inference adapter, tier
probes, and model probes.

This follows the Gemini API partner integration guidelines
(https://ai.google.dev/gemini-api/docs/partner-integration) and ensures
hermes-agent traffic is correctly attributed in Google Generative
Language API analytics.

Header format: `hermes-agent/<version>` (e.g., `hermes-agent/0.16.0`)
This commit is contained in:
Vishal Dharmadhikari 2026-06-15 02:51:55 +00:00 committed by teknium1
parent 2c6e266e88
commit 4437a5dade
No known key found for this signature in database
3 changed files with 65 additions and 3 deletions

View file

@ -31,6 +31,11 @@ from agent.gemini_schema import sanitize_gemini_tool_parameters
logger = logging.getLogger(__name__)
try:
from hermes_cli import __version__ as _HERMES_VERSION
except Exception:
_HERMES_VERSION = "0.0.0"
DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta"
# Published max output-token ceiling shared by every current Gemini text model
@ -98,7 +103,10 @@ def probe_gemini_tier(
url,
params={"key": key},
json=payload,
headers={"Content-Type": "application/json"},
headers={
"Content-Type": "application/json",
"X-Goog-Api-Client": f"hermes-agent/{_HERMES_VERSION}",
},
)
except Exception as exc:
logger.debug("probe_gemini_tier: network error: %s", exc)
@ -881,7 +889,8 @@ class GeminiNativeClient:
"Content-Type": "application/json",
"Accept": "application/json",
"x-goog-api-key": self.api_key,
"User-Agent": "hermes-agent (gemini-native)",
"User-Agent": f"hermes-agent/{_HERMES_VERSION} (gemini-native)",
"X-Goog-Api-Client": f"hermes-agent/{_HERMES_VERSION}",
}
headers.update(self._default_headers)
return headers

View file

@ -3417,7 +3417,10 @@ def probe_api_models(
candidates.append((alternate_base, True))
tried: list[str] = []
headers: dict[str, str] = {"User-Agent": _HERMES_USER_AGENT}
headers: dict[str, str] = {
"User-Agent": _HERMES_USER_AGENT,
"X-Goog-Api-Client": f"hermes-agent/{_HERMES_VERSION}",
}
if api_key and api_mode == "anthropic_messages":
headers["x-api-key"] = api_key
headers["anthropic-version"] = "2023-06-01"

View file

@ -408,3 +408,53 @@ def test_explicit_max_tokens_is_respected():
req = build_gemini_request(messages=[{"role": "user", "content": "hi"}], max_tokens=4096)
assert req["generationConfig"]["maxOutputTokens"] == 4096
# ---------------------------------------------------------------------------
# X-Goog-Api-Client header tests
# ---------------------------------------------------------------------------
def test_x_goog_api_client_header_is_set():
"""The X-Goog-Api-Client header should be set on inference requests."""
from agent.gemini_native_adapter import GeminiNativeClient
client = GeminiNativeClient(api_key="fake-key", model="gemini-2.0-flash")
headers = client._headers()
assert "X-Goog-Api-Client" in headers, "X-Goog-Api-Client header missing"
assert "hermes-agent/" in headers["X-Goog-Api-Client"], (
"hermes-agent not found in X-Goog-Api-Client header"
)
def test_x_goog_api_client_header_format():
"""Header value should be 'hermes-agent/<version>' matching the package version."""
from agent.gemini_native_adapter import GeminiNativeClient, _HERMES_VERSION
client = GeminiNativeClient(api_key="fake-key", model="gemini-2.0-flash")
headers = client._headers()
expected = f"hermes-agent/{_HERMES_VERSION}"
assert headers["X-Goog-Api-Client"] == expected
def test_user_agent_contains_version():
"""User-Agent should include the hermes-agent version."""
from agent.gemini_native_adapter import GeminiNativeClient, _HERMES_VERSION
client = GeminiNativeClient(api_key="fake-key", model="gemini-2.0-flash")
headers = client._headers()
assert f"hermes-agent/{_HERMES_VERSION}" in headers["User-Agent"]
def test_hermes_version_is_valid():
"""_HERMES_VERSION should be a non-empty string."""
from agent.gemini_native_adapter import _HERMES_VERSION
assert isinstance(_HERMES_VERSION, str)
assert len(_HERMES_VERSION) > 0
assert _HERMES_VERSION != "0.0.0", (
"Version should resolve from hermes_cli.__version__, not the fallback"
)