Skip to content

[Feature]: Inject custom headers into outgoing LLM requests (OPENCODE_OUTBOUND_HEADERS) #100

Description

@waiyong

Is your feature request related to a problem?

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.

Describe alternatives you've considered

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions