-
-
Notifications
You must be signed in to change notification settings - Fork 69.4k
Custom provider headers not propagated to model objects (buildInlineProviderModels missing headers) #15682
Description
Summary
Custom provider headers configured in models.providers are not passed through to model objects during inline model resolution. This causes custom HTTP headers (e.g., User-Agent) to be silently ignored for all API requests.
This is the same class of bug as #2903 (which was fixed for baseUrl in #2740), but headers was missed in that fix.
Environment
- OpenClaw Version: 2026.2.12
- Platform: macOS (Darwin 25.2.0)
- pi-ai: @mariozechner/pi-ai (bundled)
Steps to Reproduce
-
Configure a custom provider with
headersinopenclaw.json:{ "models": { "providers": { "my-proxy": { "baseUrl": "https://proxy.example.com/api", "apiKey": "...", "api": "anthropic-messages", "headers": { "User-Agent": "claude-code/2.1.0" }, "models": [...] } } } } -
Start the gateway and trigger an API request
-
Observe that the proxy receives the Anthropic SDK default
User-Agent: Anthropic/JS <version>instead of the configuredclaude-code/2.1.0
Expected Behavior
The headers from provider config should be included in the model object and merged into the Anthropic SDK's defaultHeaders via pi-ai.
Actual Behavior
headers is silently dropped. The Anthropic SDK sends its default User-Agent, which may be rejected by proxies that validate specific User-Agent patterns.
Root Cause
In buildInlineProviderModels() (reply entry, line ~3994), the function reads entry?.baseUrl and entry?.api but omits entry?.headers:
function buildInlineProviderModels(providers) {
return Object.entries(providers).flatMap(([providerId, entry]) => {
const trimmed = providerId.trim();
if (!trimmed) return [];
return (entry?.models ?? []).map((model) => ({
...model,
provider: trimmed,
baseUrl: entry?.baseUrl,
api: model.api ?? entry?.api
// ← headers missing!
}));
});
}Meanwhile, pi-ai's Anthropic provider (anthropic.js:394-398) already supports model.headers:
defaultHeaders: mergeHeaders({
accept: "application/json",
...
}, model.headers, dynamicHeaders, optionsHeaders),And the runner entry (runner-DWOMWPyI.js:1509) does read providerConfig?.headers — confirming it's only the main chat/reply path that's missing it.
Fix
Add headers: entry?.headers to buildInlineProviderModels():
return (entry?.models ?? []).map((model) => ({
...model,
provider: trimmed,
baseUrl: entry?.baseUrl,
api: model.api ?? entry?.api,
headers: entry?.headers
}));Workaround
Manually patch dist/reply-*.js to add the missing headers field. Note: patch is overwritten on updates.
Related Issues
- Custom Provider
baseUrlNot Propagated to Model Objects #2903 — Custom ProviderbaseUrlNot Propagated to Model Objects (same root cause, fixed forbaseUrlbutheaderswas missed) - fix(models): inherit baseUrl and api from provider config #2740 — The PR that fixed
baseUrlpropagation