[FEATURE]
Problem Statement
Claude Code v2.1.129+ supports running non-Claude models via gateway model discovery (CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1 + a GET /v1/models endpoint). LiteLLM documents this pattern in their Claude Code tutorial. Headroom's backend is LiteLLM and already does 90% of the Anthropic↔OpenAI API translation needed to serve non-Claude models — but three hard-coded filters and a missing endpoint prevent it from working.
Current State
LiteLLMBackend already:
- Converts Anthropic content blocks (text, tool_use, tool_result) ↔ OpenAI format
- Converts tool schemas, tool_choice, stop reasons, and usage stats
- Streams Anthropic SSE events from OpenAI-format upstream responses
- Handles API key routing (
_caller_key_travels_tostripssk-ant-keys for non-Anthropic providers) - Has pass-through providers in the registry (OpenRouter, Databricks) that accept any model name
The PROVIDER_REGISTRY, map_model_id(), _convert_messages_for_litellm(), and _to_anthropic_response() / stream_message() paths are provider-agnostic. The only Claude-specific assumptions are in discovery and validation.
What Blocks It
1. Bedrock discovery filters out non-Claude models
_fetch_bedrock_inference_profiles() skips every non-Anthropic profile:
# backends/litellm.py line ~227
if "anthropic" not in profile_id.lower():
continue
_normalize_bedrock_profile_id() gates on claude:
# backends/litellm.py line ~330
if not profile_id.startswith("claude"):
return None
supports_model() rejects non-Claude names for non-pass-through providers:
# backends/litellm.py line ~747
return "claude" in model.lower() or model in self._model_map
2. No GET /v1/models endpoint
Claude Code discovers proxy-hosted models by querying GET /v1/models on ANTHROPIC_BASE_URL. Headroom has no such endpoint — the OpenAI handler's /v1/models is a passthrough to an upstream, not a self-served list. Without this, non-Claude models can't appear in Claude Code's /model picker.
This was previously requested in #77 ([FEATURE] Dynamic model registry for headroom wrap — auto-discover available models), which proposes the same OpenAI-compatible GET /v1/models endpoint derived from the backend's model map. The Copilot path is getting live catalog discovery via #2935, but the Anthropic/Bedrock proxy path has no equivalent. This feature request subsumes #77's /v1/models ask and adds the backend-level gating changes that #77 doesn't cover.
3. Extended thinking headers aren't stripped for non-Claude targets
Claude Code sends anthropic-beta: extended-thinking-* headers and may send "thinking" in the request body. Non-Claude models don't understand these. The proxy should strip them when the target model isn't Claude, rather than forwarding and hoping the upstream ignores them.
Proposed Solution
Minimum viable: widen discovery + add /v1/models
Make Bedrock discovery configurable. Add an opt-in flag (env var or CLI flag, e.g.
--discover-all-models/HEADROOM_DISCOVER_ALL_MODELS=1) that removes the"anthropic" not in profile_idfilter and generalizes_normalize_bedrock_profile_id()to handle Meta/Mistral/Amazon model ID formats. Default remains Claude-only so nothing changes for existing users.Extend
HEADROOM_BEDROCK_MODEL_MAPto bypasssupports_model(). Models registered via the override map are already operator-approved —supports_model()should accept them regardless of whether "claude" is in the name.Add a
GET /v1/modelsendpoint that returns an OpenAI-compatible model list derived from the backend's resolved model map (discovery + overrides). This is what Claude Code queries whenCLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1is set. This would also close #77.Strip extended-thinking from non-Claude requests. When the resolved model target doesn't contain "claude"/"anthropic", drop the
anthropic-betaheader andthinkingbody field before forwarding.
Stretch: explicit multi-model config
A HEADROOM_EXTRA_MODELS env var or config section that defines non-Claude models with their provider, LiteLLM model string, context window, and display name — similar to LiteLLM's config.yaml model_list. This would cleanly separate "what models are available" from "how Bedrock discovery works."
Use Case
- Using Claude Code through Headroom for context compression and cost tracking
- Want to experiment with non-Claude models (GPT, Gemini, Llama on Bedrock, OpenRouter models) for cost comparison or capability testing, without giving up Headroom's compression pipeline
- LiteLLM's standalone proxy supports this today, but requires running a second process and loses Headroom's compression, dashboard, and savings tracking
- The translation layer is already in Headroom — only the discovery/validation gates need widening
Alternatives Considered
- Running a standalone LiteLLM proxy chained behind Headroom. Works today, no Headroom changes needed. Costs a second process and duplicates model routing logic. Headroom's compression still applies but savings tracking may double-count.
- Using OpenRouter as the backend (
--backend openrouter). Works for pass-through providers sincesupports_model()returnsTrueforpass_through=True. Loses Bedrock billing, AWS auth, and compliance. Not viable for orgs that require Bedrock. - Using
HEADROOM_BEDROCK_MODEL_MAPto manually register non-Claude models. Almost works today — the map resolves correctly, butsupports_model()rejects the model name beforemap_model_id()is ever called. Fixing this one gate (supports_modelshould check the override map) would unblock manual registration with zero other changes.
Related Issues
- #77 —
[FEATURE] Dynamic model registry for headroom wrap — auto-discover available models. Requests theGET /v1/modelsendpoint this feature also needs. This request subsumes that ask and adds the backend-level discovery/validation changes #77 doesn't cover. - #2935 —
feat(copilot): drive model routing and discovery from the live model catalog. Implements live model discovery for the Copilot path. The Anthropic/Bedrock proxy path has no equivalent; this request fills that gap. - #1264 —
[FEATURE] Anthropic-compatible third-party upstream support (DashScope, XF-Yun, SiliconFlow, etc.). Adjacent but different — that issue is about third-party providers that mimic the Anthropic API upstream. This request is about routing Anthropic API requests from Claude Code to non-Claude models downstream. - #3272 —
Stacking Headroom with a single OpenAI-compatible gateway. Describes chaining Headroom with a separate gateway for multi-model routing — the "Option D" workaround this feature request would make unnecessary.
Additional Context
- Headroom v0.37.0, using
headroom proxy --backend bedrock - Claude Code's gateway discovery docs: the client sends
GET /v1/modelsand expects{"object": "list", "data": [{"id": "model-name", "object": "model", ...}]} - The model router (
HEADROOM_MODEL_ROUTER_ENABLED) and route advice extension system (request.state.headroom_route) already support per-request model+provider switching — this feature request is about making the backend accept and translate for non-Claude models, which the routing infrastructure already assumes it can _caller_key_travels_to()already handles the credential mismatch case (Anthropic key → non-Anthropic provider), so auth routing is solved- Are you willing to contribute this feature? Yes.
Source: headroomlabs-ai/headroom