Skip to content

feat(llm): custom request headers for OpenAI-compatible endpoints via LLM_EXTRA_HEADERS - #936

Merged
0xallam merged 2 commits into
mainfrom
devin/1785373289-llm-extra-headers
Jul 30, 2026
Merged

feat(llm): custom request headers for OpenAI-compatible endpoints via LLM_EXTRA_HEADERS#936
0xallam merged 2 commits into
mainfrom
devin/1785373289-llm-extra-headers

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a generic LLM_EXTRA_HEADERS knob so Strix can talk to OpenAI-compatible
gateways that require extra HTTP headers (attribution / tenant routing / etc.)
on top of the bearer token. Today Strix exposes STRIX_LLM / LLM_API_KEY /
LLM_API_BASE but has no way to send arbitrary request headers, so such gateways
are unreachable.

LLM_EXTRA_HEADERS is a JSON object applied to every LLM request, e.g.:

export STRIX_LLM="openai/your-model"
export LLM_API_BASE="https://your-gateway.example/v1"
export LLM_API_KEY="your-bearer-token"          # -> Authorization: Bearer ...
export LLM_EXTRA_HEADERS='{"X-Feature-Key":"value","X-Tenant":"acme"}'

What changed

  • LlmSettings.extra_headers: dict[str, str] | None bound to LLM_EXTRA_HEADERS
    (pydantic-settings JSON-decodes the env value).
  • configure_sdk_model_defaults now calls _configure_extra_headers(llm), which
    injects the headers on both routing paths so it works regardless of the
    STRIX_LLM prefix:
    • LiteLLM route (litellm/…, and any non-openai/ provider) — merged into
      litellm.headers (same mechanism the existing OpenRouter attribution uses).
    • Native OpenAI route (openai/…) — a default AsyncOpenAI client carrying
      default_headers is registered via set_default_openai_client. base_url
      defaults to the real OpenAI endpoint when no custom LLM_API_BASE is set.
def _configure_extra_headers(llm):
    headers = llm.extra_headers
    if not headers:
        return
    _merge_litellm_headers(headers)              # litellm.headers = {**existing, **headers}
    _register_openai_client_with_headers(llm, headers)  # AsyncOpenAI(base_url=llm.api_base, default_headers=headers)

No behavior change when LLM_EXTRA_HEADERS is unset (guarded by the early return).
The bearer token still comes from LLM_API_KEY; TLS is unchanged (use the standard
SSL_CERT_FILE for private CAs).

Tests

New tests/test_llm_extra_headers.py:

  • JSON env parsing into extra_headers.
  • Headers merged into litellm.headers (LiteLLM route).
  • Headers land on the native OpenAI default client's default_headers — both with
    a custom base and against the default OpenAI endpoint.
  • Unset → litellm.headers untouched (no regression).

Also validated end-to-end against a local mock OpenAI-compatible gateway that
rejects requests missing the header (401): headers arrive on both routes, with
tool-calling and streaming responses passing through correctly.

Docs

  • docs/advanced/configuration.mdx — new LLM_EXTRA_HEADERS param.
  • docs/llm-providers/local.mdx — "Gateways that require custom headers" example.

Link to Devin session: https://app.devin.ai/sessions/54414ea3ecb34ade9189534e5c690969
Requested by: @0xallam

@0xallam 0xallam self-assigned this Jul 30, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Comment thread strix/config/models.py Outdated
@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds configurable custom HTTP headers for LLM requests.

  • Parses LLM_EXTRA_HEADERS as a JSON header mapping.
  • Applies configured headers to both LiteLLM and native OpenAI clients.
  • Registers the native client even when no custom API base is configured.
  • Documents gateway configuration and adds coverage for both routing paths.

Confidence Score: 5/5

The PR appears safe to merge.

The previously reported native OpenAI path now registers a header-bearing client regardless of whether a custom API base is configured, and no blocking failure remains.

Important Files Changed

Filename Overview
strix/config/models.py Applies custom headers across both model-routing paths and completes the prior fix for native OpenAI requests without a custom base URL.
strix/config/settings.py Adds the environment-backed optional header mapping to LLM settings.
tests/test_llm_extra_headers.py Covers environment parsing, LiteLLM merging, native client registration with and without a custom base, and unset behavior.
docs/advanced/configuration.mdx Documents the new environment variable and its routing scope.
docs/llm-providers/local.mdx Adds an OpenAI-compatible gateway example using custom request headers.

Reviews (2): Last reviewed commit: "fix(llm): apply LLM_EXTRA_HEADERS on nat..." | Re-trigger Greptile

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

@greptile

@0xallam
0xallam merged commit e9ebdc5 into main Jul 30, 2026
1 check passed
@0xallam
0xallam deleted the devin/1785373289-llm-extra-headers branch July 30, 2026 01:13
5hy7xz92nd-oss

This comment was marked as spam.

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.

2 participants