From b3aa561faffd64f05436e429a6415d175e534ec9 Mon Sep 17 00:00:00 2001 From: rob-maron <132852777+rob-maron@users.noreply.github.com> Date: Fri, 7 Aug 2026 14:56:29 -0600 Subject: [PATCH] add Hermes headers to Fireworks provider (#81321) --- plugins/model-providers/fireworks/__init__.py | 12 +++++++--- tests/hermes_cli/test_fireworks_provider.py | 6 ++--- .../model_providers/test_fireworks_profile.py | 15 ++++++++++--- .../test_provider_attribution_headers.py | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/plugins/model-providers/fireworks/__init__.py b/plugins/model-providers/fireworks/__init__.py index 7245a9c345..338058e0bc 100644 --- a/plugins/model-providers/fireworks/__init__.py +++ b/plugins/model-providers/fireworks/__init__.py @@ -23,9 +23,15 @@ fireworks = ProviderProfile( env_vars=("FIREWORKS_API_KEY",), base_url="https://api.fireworks.ai/inference/v1", auth_type="api_key", - # Identifies the client, replacing the OpenAI SDK's own User-Agent. This is - # not partner attribution — HTTP-Referer/X-Title stay off (#61182). - default_headers={"User-Agent": f"HermesAgent/{_HERMES_VERSION}"}, + # Attribution headers sent on every Fireworks request. Values match the + # canonical Hermes set in agent/auxiliary_client.py. Applied through the + # generic profile.default_headers path, so they survive switch_model and + # credential rotation. + default_headers={ + "HTTP-Referer": "https://hermes-agent.nousresearch.com", + "X-Title": "Hermes Agent", + "User-Agent": f"HermesAgent/{_HERMES_VERSION}", + }, # Auxiliary model for cheap tasks (compaction, title generation, vision). # A standard pay-as-you-go catalog ``/models/`` ID. default_aux_model="accounts/fireworks/models/glm-5p2", diff --git a/tests/hermes_cli/test_fireworks_provider.py b/tests/hermes_cli/test_fireworks_provider.py index 12bca5d2b5..14b6a7e5a0 100644 --- a/tests/hermes_cli/test_fireworks_provider.py +++ b/tests/hermes_cli/test_fireworks_provider.py @@ -155,13 +155,13 @@ class TestFireworksAuxiliary: client, model = resolve_provider_client(name) return client, model, mock_openai.call_args.kwargs - def test_client_has_no_partner_attribution_headers(self, monkeypatch): + def test_client_sends_attribution_headers(self, monkeypatch): monkeypatch.setenv("FIREWORKS_API_KEY", "fw_test_key") client, model, kwargs = self._resolve("fireworks") assert client is not None headers = kwargs.get("default_headers", {}) - assert "HTTP-Referer" not in headers - assert "X-Title" not in headers + assert headers["HTTP-Referer"] == "https://hermes-agent.nousresearch.com" + assert headers["X-Title"] == "Hermes Agent" assert kwargs["base_url"] == "https://api.fireworks.ai/inference/v1" def test_client_sends_hermes_user_agent(self, monkeypatch): diff --git a/tests/plugins/model_providers/test_fireworks_profile.py b/tests/plugins/model_providers/test_fireworks_profile.py index aa0f9af1b4..bf12649adc 100644 --- a/tests/plugins/model_providers/test_fireworks_profile.py +++ b/tests/plugins/model_providers/test_fireworks_profile.py @@ -40,9 +40,18 @@ class TestFireworksIdentity: class TestFireworksHeaders: - def test_no_partner_attribution_headers(self, fireworks_profile): - assert "HTTP-Referer" not in fireworks_profile.default_headers - assert "X-Title" not in fireworks_profile.default_headers + def test_attribution_matches_canonical_hermes_values(self, fireworks_profile): + """Fireworks requests carry the same attribution identity Hermes sends + everywhere else. + + Asserted against the shared constant rather than the literals so a + rebrand can't leave one provider on a stale referer/title. + """ + from agent.auxiliary_client import _OR_HEADERS_BASE + + headers = fireworks_profile.default_headers + assert headers["HTTP-Referer"] == _OR_HEADERS_BASE["HTTP-Referer"] + assert headers["X-Title"] == _OR_HEADERS_BASE["X-Title"] def test_user_agent_identifies_hermes(self, fireworks_profile): # Prefix, not the full string — the version moves every release. diff --git a/tests/run_agent/test_provider_attribution_headers.py b/tests/run_agent/test_provider_attribution_headers.py index b7f3d493dd..ff4ef15e07 100644 --- a/tests/run_agent/test_provider_attribution_headers.py +++ b/tests/run_agent/test_provider_attribution_headers.py @@ -87,6 +87,28 @@ def test_nvidia_cloud_base_url_applies_billing_origin_header(mock_openai): assert headers["X-BILLING-INVOKE-ORIGIN"] == "HermesAgent" +@patch("run_agent.OpenAI") +def test_fireworks_applies_attribution_via_profile_fallback(mock_openai): + """Fireworks has no host-specific branch — its attribution headers come + from the profile.default_headers fallback, the path a model switch + re-runs.""" + mock_openai.return_value = MagicMock() + agent = AIAgent( + api_key="test-key", + base_url="https://api.fireworks.ai/inference/v1", + model="accounts/fireworks/models/kimi-k2p6", + provider="fireworks", + quiet_mode=True, + skip_context_files=True, + skip_memory=True, + ) + + agent._apply_client_headers_for_base_url("https://api.fireworks.ai/inference/v1") + + headers = agent._client_kwargs["default_headers"] + assert headers["HTTP-Referer"] == "https://hermes-agent.nousresearch.com" + assert headers["X-Title"] == "Hermes Agent" + assert headers["User-Agent"].startswith("HermesAgent/") @patch("run_agent.OpenAI")