Skip to content

feat: OpenRouter app attribution on every harness - #1235

Merged
aaronjmars merged 1 commit into
mainfrom
feat/openrouter-attribution
Oct 17, 2026
Merged

aaronjmars merged 1 commit into
mainfrom
feat/openrouter-attribution

Conversation

@aaronjmars

@aaronjmars aaronjmars commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Every OpenRouter inference request aeon makes now carries the app attribution headers, so usage counts on aeon's OpenRouter app page (openrouter.ai/apps?url=https://aeon.fun).

Headers (one shared helper, harness-adapter/lib/openrouter-attribution.sh):

  • HTTP-Referer: https://aeon.fun (apex on purpose: the existing app page is keyed on it, a www referer would start a second, empty app)
  • X-OpenRouter-Title: Aeon plus the legacy X-Title: Aeon
  • X-OpenRouter-Categories: personal-agent,cloud-agent

OPENROUTER_SITE_URL / OPENROUTER_APP_TITLE still override (now on every harness, not only Claude); OPENROUTER_APP_CATEGORIES is new.

Call sites covered

Path How Checked against
Claude Code via gateway: openrouter (scripts/llm-gateway.sh) ANTHROPIC_CUSTOM_HEADERS gains X-OpenRouter-Title + Categories existing path
codex (install-harness.sh) model_providers.openrouter.http_headers codex rust-v0.159.3 model-provider-info
kimi (install-harness.sh) providers.openrouter.custom_headers kimi-code 2.1.1 config docs
vibe (install-harness.sh) [[providers]] extra_headers mistral-vibe 2.25.8 ProviderConfig + agent loop
pi (install-harness.sh) models.json providers.openrouter.headers (headers-only entry keeps built-in models; merged into an existing file) pi 0.99.2 model-config.ts, provider-attribution.ts (config headers override pi's own pi.dev ones)
hermes (adapters/hermes.sh) model.default_headers in the scratch-HOME config.yaml, OpenRouter mode only hermes-agent pin f97608f client_lifecycle.py / auxiliary_client.py (user headers win over its "Hermes Agent" ones)

Hermes is done in the adapter, not install-harness, because it runs under a fresh scratch HOME per call.

Not covered, and why

  • cursor, fx, grok: no OpenRouter path.
  • hermes side calls (compression, titles) built by its aux client go out with Hermes's own headers on some paths. Its main agent calls carry ours.
  • vibe's utility completions only send a user-agent. Its main agent calls carry ours.
  • No other direct OpenRouter inference calls in the repo: the dashboard OpenRouter OAuth flow only swaps a code for a key, and skills/apps/scripts don't call openrouter.ai.
  • The workflows don't pass vars.OPENROUTER_SITE_URL / vars.OPENROUTER_APP_TITLE into the run env, so in CI the overrides only work if set some other way. Left as is.

Tests

  • test_llm_gateway.sh: the exact ANTHROPIC_CUSTOM_HEADERS set, and that the overrides still work
  • test_install_harness.sh: codex/kimi/vibe TOML lines, the pi models.json merge, and pi native-key staging no models.json
  • test_hermes_adapter.sh: the staged config.yaml in OpenRouter mode (parsed as YAML), and none with a Nous login
  • harness_cli_smoke.sh (ci-harness-cli): codex, kimi, vibe and pi now check that every POST the real pinned CLI sent to the fake upstream carried all four headers

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Every OpenRouter inference request now carries HTTP-Referer, X-OpenRouter-Title,
the legacy X-Title and X-OpenRouter-Categories, from one shared helper
(harness-adapter/lib/openrouter-attribution.sh). The referer stays the apex
https://aeon.fun, which is what aeon's existing OpenRouter app is keyed on.

- claude via the openrouter gateway: ANTHROPIC_CUSTOM_HEADERS gains the two new headers
- codex: model_providers.openrouter.http_headers
- kimi: providers.openrouter.custom_headers
- vibe: providers extra_headers
- pi: models.json headers on its built-in openrouter provider (merged, not overwritten)
- hermes: model.default_headers in the adapter's scratch HOME config.yaml

OPENROUTER_SITE_URL / OPENROUTER_APP_TITLE still override, now on every
harness; OPENROUTER_APP_CATEGORIES is new. Unit tests cover each config and the
CLI smoke checks every call to the fake upstream carried the headers.
@aaronjmars
aaronjmars merged commit 8aba912 into main Oct 17, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant