Skip to content

refactor(gmi): declare User-Agent attribution on provider profile (salvage #20907)#21701

Merged
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/gmi-ua-attribution
May 8, 2026
Merged

refactor(gmi): declare User-Agent attribution on provider profile (salvage #20907)#21701
kshitijk4poor merged 2 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/gmi-ua-attribution

Conversation

@kshitijk4poor

@kshitijk4poor kshitijk4poor commented May 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a User-Agent: HermesAgent/<version> header on all outbound requests to api.gmi-serving.com so GMI can identify traffic from Hermes Agent.

Based on #20907 by @isaachuangGMICLOUD.

Approach

Instead of sprinkling GMI-specific elif base_url_host_matches(..., "api.gmi-serving.com"): branches across run_agent.py and agent/auxiliary_client.py, this revision uses the existing ProviderProfile.default_headers field (already commented as "Client-level quirks (set once at client construction)") and the generic profile-fallback plumbing that's already there for that purpose.

GMI plugin owns the header:

# plugins/model-providers/gmi/__init__.py
gmi = ProviderProfile(
    name="gmi",
    base_url="https://api.gmi-serving.com/v1",
    default_headers={"User-Agent": f"HermesAgent/{_HERMES_VERSION}"},
    ...
)

Other plugins already use this pattern for the same purpose — ai-gateway (HTTP-Referer + X-Title) and kimi-coding (User-Agent).

Two of the four client-construction sites already had a profile-fallback else branch that picks up profile.default_headers after the URL-specific hardcodes miss. Both run_agent.py sites (__init__ client construction and _apply_client_headers_for_base_url) already had it. This PR adds the same generic fallback block to the remaining two sites in agent/auxiliary_client.py (_to_async_client and resolve_provider_client's main path), closing the asymmetry.

As a side benefit, this also fixes a pre-existing gap: ai-gateway's HTTP-Referer / X-Title attribution headers now flow through _to_async_client too.

Files changed

File Change
plugins/model-providers/gmi/__init__.py +5 — default_headers={"User-Agent": ...} on GMI profile
agent/auxiliary_client.py +36 — generic else: profile.default_headers fallback in two sites (applies to every provider that declares default_headers, not just GMI)
tests/hermes_cli/test_gmi_provider.py +16 — assert aux client carries the UA header; assert GMI profile declares it
tests/run_agent/test_provider_attribution_headers.py +25 — _apply_client_headers_for_base_url picks up the profile's UA
scripts/release.py +1 — AUTHOR_MAP entry for isaac.h@gmicloud.ai

Net diff: +83/-0 across 5 files. No core files (run_agent.py, cli.py, gateway/) are modified.

What data GMI receives

Only User-Agent: HermesAgent/<version>. No HTTP-Referer, no X-Title, no X-OpenRouter-Categories (those are OpenRouter-specific). The OpenAI Python SDK always sends X-Stainless-* telemetry headers (OS, arch, runtime version) — SDK behavior, same for every provider.

Testing

  • scripts/run_tests.sh tests/hermes_cli/test_gmi_provider.py tests/run_agent/test_provider_attribution_headers.py tests/agent/test_auxiliary_client.py tests/providers/253 passed.
  • E2E integration check (real imports, all four client-construction paths):
    • profile declares UA ✓
    • resolve_provider_client("gmi") main path applies UA ✓
    • _to_async_client applies UA via hostname inference ✓
    • AIAgent._apply_client_headers_for_base_url applies UA via profile fallback ✓
  • Ruff clean on the diff.

Closes #20907

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent loop, run_agent.py, prompt builder labels May 8, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This PR supersedes #20907 with improvements (dedicated _HERMES_UA_HEADERS constant, additional test coverage for run_agent.py path). Related: #20907.

@kshitijk4poor kshitijk4poor force-pushed the salvage/gmi-ua-attribution branch from d515f11 to 96f3442 Compare May 8, 2026 07:14
isaachuangGMICLOUD and others added 2 commits May 8, 2026 15:04
The previous revision of this PR added six GMI-specific branches
(`elif base_url_host_matches(..., 'api.gmi-serving.com')`) across
run_agent.py and agent/auxiliary_client.py, plus a _HERMES_UA_HEADERS
constant in auxiliary_client.py.

ProviderProfile already has a `default_headers: dict[str, str]` field
commented as 'Client-level quirks (set once at client construction)'.
Other plugins (ai-gateway, kimi-coding) already use it. Two of the four
auxiliary_client sites we previously patched already had a generic
`else: profile.default_headers` fallback that picked it up (so did
both run_agent sites).

This revision:

* Sets `default_headers={'User-Agent': 'HermesAgent/<ver>'}` on the
  GMI profile in plugins/model-providers/gmi/__init__.py.
* Reverts all six GMI-specific branches in run_agent.py and
  auxiliary_client.py.
* Adds the generic profile-fallback `else` block to the two
  auxiliary_client sites (`_to_async_client`, `resolve_provider_client`)
  that didn't have it yet. This benefits every provider whose profile
  declares default_headers, not just GMI — e.g. Vercel AI Gateway's
  HTTP-Referer/X-Title now flow through the async client path too.
* Replaces the GMI-specific URL-branch tests with a profile-level
  assertion and keeps the run_agent integration test (with
  `provider='gmi'` so the fallback picks up the profile).

Net diff vs main: +82/-0 across 5 files, touching only the GMI plugin,
two generic fallback blocks in auxiliary_client.py, AUTHOR_MAP, and
tests. No core files change.

Based on NousResearch#20907 by @isaachuangGMICLOUD.
@kshitijk4poor kshitijk4poor force-pushed the salvage/gmi-ua-attribution branch from 96f3442 to cfec180 Compare May 8, 2026 09:43
@kshitijk4poor kshitijk4poor changed the title feat: add Hermes User-Agent attribution for GMI requests refactor(gmi): declare User-Agent attribution on provider profile (salvage #20907) May 8, 2026
@kshitijk4poor kshitijk4poor merged commit 81928f0 into NousResearch:main May 8, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants