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
{{ message }}
Repository navigation
[Feature]: Inject custom headers into outgoing LLM requests (OPENCODE_OUTBOUND_HEADERS) #100
When opencode talks to an LLM through a self-hosted gateway (LiteLLM, vLLM), that gateway often needs specific request headers — feature flags, routing hints, or tracing toggles such as Arize Phoenix's x-enable-phoenix-tracing. There is currently no way to set custom headers on opencode's outgoing LLM requests from this plugin.
The plugin already exposes a chat.headers-shaped surface conceptually (it owns the OTel integration), and @opencode-ai/plugin provides a chat.headers hook that fires for each outgoing LLM request. That hook is the natural, protocol-level place to add headers — no request interception or monkey-patching.
Describe the solution you'd like
Add a chat.headers hook with two settings:
OPENCODE_OUTBOUND_HEADERS — comma-separated key=value headers to inject (parsed by the existing parseAttributePairs).
OPENCODE_OUTBOUND_ENDPOINTS — comma-separated endpoint URLs. When set, headers are injected only for requests whose resolved URL matches by hostname; when unset, headers go to every provider (backward compatible).
Endpoint scoping matters because chat.headers fires for every LLM request, including third-party providers (Anthropic, OpenAI). Without scoping, an unintended header — or worse, a credential someone puts in the env var — would be sent to all of them. The resolved URL mirrors opencode's own resolution: non-empty provider.options.baseURL if overridden, else model.api.url.
Both settings would also be available via the plugin-tuple options form (outboundHeaders, outboundEndpoints), following the established option > env > default precedence from #65.
Doing this in opencode core — the header need is deployment-specific (which gateway, which flags), so a plugin-level toggle is the right granularity.
Additional context
I have an implementation ready (handler extracted to src/handlers/chat-headers.ts, unit tests, README, all four checks passing) and will open a PR referencing this issue. This is scoped to custom headers only; W3C traceparent propagation is a natural follow-up but is a separate, opt-in concern (it would leak trace IDs to third parties by default), so I would like to keep it to a second PR.
One design question for you: endpoint matching is currently by hostname, which tolerates port/path differences. I am happy to switch to origin (scheme + host + port) if you prefer stricter matching.
Activity