You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR adds automatic OpenRouter app attribution headers (HTTP-Referer: https://hadriangateway.com and X-OpenRouter-Title: Hadrian Gateway) for any OpenAI-compatible provider whose base_url contains openrouter.ai, with a clean opt-out mechanism via empty-string overrides in the config.
src/providers/open_ai/mod.rs: Uses HashMap::entry().or_insert_with() to inject defaults only when the user hasn't already configured those keys. The build_request and build_multipart_request methods filter out empty-string headers to support opt-out. Logic is correct and well-structured.
src/bin/record_fixtures.rs: Aligns fixture-recording headers with the new URL and header name — note that this path detects OpenRouter by provider name ("openrouter") while the production path detects by URL; this divergence is acceptable for a dev tool.
src/config/providers.rs: Doc comment updated to explain the new auto-injection behavior.
docs/content/docs/configuration/providers.mdx: Correctly documents the automatic headers and the opt-out pattern.
One minor concern: the opt-out is case-sensitive — a user who configures http-referer = "" (wrong case) won't successfully opt out, as the entry() lookup won't match, and the default will be inserted silently. A comment or key normalization would make this more robust.
Confidence Score: 5/5
Safe to merge — the attribution logic is correct, the opt-out works for properly-cased keys, and all four files are consistent with each other.
The core logic using entry().or_insert_with() is sound: user-provided headers always win, defaults are injected only when absent, and empty-string values are filtered before sending. The only issue is a case-sensitivity footgun in the opt-out path (P2 style), which won't affect users following the documented example. Documentation, config struct, fixture tool, and production code are all consistent.
No files require special attention.
Important Files Changed
Filename
Overview
src/providers/open_ai/mod.rs
Injects OpenRouter attribution headers (HTTP-Referer, X-OpenRouter-Title) by default when the base URL contains openrouter.ai, with an opt-out via empty-string override. Logic is correct; case-sensitive key matching is a minor footgun for the opt-out path.
src/config/providers.rs
Doc comment updated to reflect automatic OpenRouter header injection. No logic changes.
src/bin/record_fixtures.rs
Updated fixture recording headers to match the new names (X-OpenRouter-Title) and URL (hadriangateway.com). Uses provider-name-based detection (def.provider == "openrouter") rather than URL-based, which is consistent with it being a dev tool.
docs/content/docs/configuration/providers.mdx
Documentation updated to reflect automatic header injection and correct opt-out instructions. Consistent with the code implementation.
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[from_config_with_registry] --> B{base_url contains\nopenrouter.ai?}
B -- No --> D[Use config.headers as-is]
B -- Yes --> C{HTTP-Referer key\nalready in headers?}
C -- No --> E[Insert HTTP-Referer:\nhttps://hadriangateway.com]
C -- Yes --> F[Keep user value]
E --> G{X-OpenRouter-Title key\nalready in headers?}
F --> G
G -- No --> H[Insert X-OpenRouter-Title:\nHadrian Gateway]
G -- Yes --> I[Keep user value]
H --> J[build_request]
I --> J
D --> J
J --> K{Filter headers:\nvalue is empty?}
K -- Empty string --> L[Skip header\nopt-out achieved]
K -- Non-empty --> M[Add header to request]
The opt-out mechanism relies on exact case-sensitive key matching. If a user configures http-referer = "" or Http-Referer = "" (wrong casing) in their TOML config, the entry("HTTP-Referer") call won't find it, so the default Hadrian attribution value gets inserted — and the user's empty-string opt-out is silently ignored.
In practice, users following the documented example will use the correct casing, but it's a subtle footgun. A more robust approach would be to normalize header keys to lowercase before the entry() check (HTTP headers are case-insensitive at the wire level anyway), or at least call it out with a comment:
// Note: key matching is case-sensitive. Users must use the exact casing// shown in the docs ("HTTP-Referer", "X-OpenRouter-Title") to override.if base_url.contains("openrouter.ai"){
headers
.entry("HTTP-Referer".to_string()).or_insert_with(|| "https://hadriangateway.com".to_string());
headers
.entry("X-OpenRouter-Title".to_string()).or_insert_with(|| "Hadrian Gateway".to_string());}
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/providers/open_ai/mod.rs
Line: 75-82
Comment:
**Case-sensitive opt-out may silently fail**
The opt-out mechanism relies on exact case-sensitive key matching. If a user configures `http-referer = ""` or `Http-Referer = ""` (wrong casing) in their TOML config, the `entry("HTTP-Referer")` call won't find it, so the default Hadrian attribution value gets inserted — and the user's empty-string opt-out is silently ignored.
In practice, users following the documented example will use the correct casing, but it's a subtle footgun. A more robust approach would be to normalize header keys to lowercase before the `entry()` check (HTTP headers are case-insensitive at the wire level anyway), or at least call it out with a comment:
```rust// Note: key matching is case-sensitive. Users must use the exact casing// shown in the docs ("HTTP-Referer", "X-OpenRouter-Title") to override.ifbase_url.contains("openrouter.ai") {
headers.entry("HTTP-Referer".to_string())
.or_insert_with(||"https://hadriangateway.com".to_string());
headers.entry("X-OpenRouter-Title".to_string())
.or_insert_with(||"Hadrian Gateway".to_string());
}
```
How can I resolve this? If you propose a fix, please make it concise.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.