How free-claude-code Routes Requests to NVIDIA NIM, OpenRouter, DeepSeek, and LM Studio
The free-claude-code proxy uses a FastAPI-based three-layer routing system that parses model prefixes to dynamically instantiate provider-specific clients, converting Claude-compatible /v1/messages requests into OpenAI-compatible streaming calls for each backend.
The free-claude-code repository implements a unified proxy layer that exposes a Claude-compatible API surface while dynamically routing traffic to diverse LLM backends. This architecture allows developers to use a single client interface while leveraging specialized providers like NVIDIA NIM, OpenRouter, DeepSeek, and LM Studio under the hood. The routing mechanism relies on model string parsing, lazy provider instantiation via a factory pattern, and a shared OpenAI-compatible streaming interface.
Three-Layer Routing Architecture
The proxy implements routing through three distinct layers, each handling a specific aspect of request translation and forwarding.
Layer 1: Model String Parsing
Request routing begins in config/settings.py where the Settings.parse_provider_type method extracts the provider prefix from the model identifier. The function splits the incoming model string (or resolved_provider_model) on the "/" character and returns the first segment as the provider type.
# From config/settings.py
provider_type = Settings.parse_provider_type(
request_data.resolved_provider_model or settings.model
)
Valid prefixes include nvidia_nim, open_router, deepseek, and lmstudio. This prefix determines which concrete provider class handles the request.
Layer 2: Provider Factory
The get_provider_for_type function in api/dependencies.py acts as a factory that lazily creates and caches provider instances. Based on the parsed prefix, it instantiates one of four concrete providers:
- NvidiaNimProvider: Configured with NIM API keys and optional proxy settings
- OpenRouterProvider: Configured with OpenRouter API keys and reasoning hooks
- DeepSeekProvider: Thin wrapper forwarding requests unchanged
- LMStudioProvider: Configured to point at local LM Studio endpoints
Each provider receives a ProviderConfig object containing base URLs, API keys, and provider-specific knobs injected from environment settings.
Layer 3: Unified Streaming Interface
All providers inherit from OpenAICompatibleProvider defined in providers/openai_compat.py. This base class wraps the official AsyncOpenAI client and implements the Claude-compatible streaming protocol using Server-Sent Events (SSE).
The base class provides a hook method _build_request_body that each provider overrides to customize the JSON payload sent to the upstream service. After building the request, the base class calls self._client.chat.completions.create(..., stream=True) and translates OpenAI-style chunks into Claude-compatible events using the SSEBuilder utility.
Provider-Specific Routing Implementations
Each backend requires specific request handling and error management.
NVIDIA NIM Routing
The NvidiaNimProvider class in providers/nvidia_nim/client.py extends the base OpenAI-compatible client with NIM-specific request building logic located in providers/nvidia_nim/request.py.
Key routing characteristics:
- Automatically strips
reasoning_budgetandchat_templateparameters from retries when the upstream returns HTTP 400 errors - Injects NVIDIA-specific metadata into request headers
- Handles model paths formatted as
nvidia_nim/meta/llama-3.1-70b-instruct
OpenRouter Routing
The OpenRouterProvider in providers/open_router/client.py adds specialized handling for OpenRouter's extended reasoning capabilities.
Key routing characteristics:
- Renders OpenRouter's
reasoning_detailsfield as Claude "thinking" events in the SSE stream - Maps model identifiers from the
open_router/prefix to OpenRouter's internal model strings - Builds request bodies via
providers/open_router/request.pyto handle OpenRouter-specific parameters
DeepSeek Routing
The DeepSeekProvider in providers/deepseek/client.py functions as a minimal pass-through wrapper around the OpenAI-compatible client.
Key routing characteristics:
- Forwards requests without transformation using the standard OpenAI client configuration
- Expects model identifiers prefixed with
deepseek/ - Relies on the base class for all streaming and error handling
LM Studio Routing
The LMStudioProvider routes requests to locally running LM Studio instances rather than cloud APIs.
Key routing characteristics:
- Configures
ProviderConfigto usesettings.lm_studio_base_url(typicallyhttp://localhost:1234) - Uses a dummy API key value of
"lm-studio"for local authentication - Expects model identifiers prefixed with
lmstudio/
Complete Request Flow
When a client sends a POST request to /v1/messages, the following routing sequence executes:
-
FastAPI Entry Point: The
create_messagefunction inapi/routes.pyreceives the request and extracts the provider type usingSettings.parse_provider_type. -
Provider Instantiation: The factory function
get_provider_for_typeinapi/dependencies.pycreates the appropriate provider instance based on the parsed prefix. -
Request Building: The provider's
_build_request_bodymethod constructs the JSON payload specific to the target service (NIM fields for NVIDIA, reasoning hooks for OpenRouter, etc.). -
Upstream Streaming: The base class calls the OpenAI-compatible endpoint with
stream=Trueand processes chunks throughproviders/common/SSEBuilder.py. -
Client Response:
create_messagewraps the async generator in a FastAPIStreamingResponsewithtext/event-streamMIME type, delivering Claude-compatible events.
Practical Routing Examples
Route requests to specific providers using the model prefix notation:
Routing to NVIDIA NIM
curl -X POST https://my-proxy.example.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $PROXY_AUTH_TOKEN" \
-d '{
"model": "nvidia_nim/meta/llama-3.1-70b-instruct",
"messages": [{"role":"user","content":"Write a Python hello world"}]
}' \
--no-buffer
The nvidia_nim/ prefix triggers parse_provider_type to select the NVIDIA NIM provider, which handles model-specific parameters and retry logic for NIM endpoints.
Routing to OpenRouter
curl -X POST https://my-proxy.example.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $PROXY_AUTH_TOKEN" \
-d '{
"model": "open_router/deepseek/deepseek-chat",
"messages": [{"role":"user","content":"Explain recursion"}]
}' \
--no-buffer
The open_router/ prefix instantiates OpenRouterProvider, which maps the request to OpenRouter's model catalog and handles reasoning detail extraction.
Routing to DeepSeek
curl -X POST https://my-proxy.example.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $PROXY_AUTH_TOKEN" \
-d '{
"model": "deepseek/deepseek-chat",
"messages": [{"role":"user","content":"Analyze this code"}]
}' \
--no-buffer
The deepseek/ prefix routes through DeepSeekProvider with no request transformation, using standard OpenAI client configuration.
Routing to LM Studio
curl -X POST https://my-proxy.example.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $PROXY_AUTH_TOKEN" \
-d '{
"model": "lmstudio/qwen2.5-7b",
"messages": [{"role":"user","content":"Summarize the last paragraph"}]
}' \
--no-buffer
The lmstudio/ prefix selects LMStudioProvider, which forwards the request to the local LM Studio server configured in settings.lm_studio_base_url.
Summary
- Prefix-based routing: The
parse_provider_typefunction inconfig/settings.pyextracts provider identifiers from model strings using "/" as a delimiter. - Factory pattern:
get_provider_for_typeinapi/dependencies.pyinstantiates specialized providers (NvidiaNimProvider,OpenRouterProvider,DeepSeekProvider,LMStudioProvider) with appropriate configurations. - Unified interface: All providers inherit from
OpenAICompatibleProviderinproviders/openai_compat.py, ensuring consistent Claude-compatible streaming output regardless of the upstream backend. - Provider customization: Each provider implements specific request building and error handling (NIM strips invalid parameters on retry, OpenRouter handles reasoning details, LM Studio uses local endpoints).
Frequently Asked Questions
How does the proxy determine which provider to use for a request?
The proxy extracts the provider prefix from the model string by splitting on the "/" character. For example, a model name of nvidia_nim/meta/llama-3.1-70b-instruct returns nvidia_nim as the provider type, which the factory uses to instantiate the corresponding client class.
What happens if a provider-specific parameter causes an error?
The NvidiaNimProvider implements specific retry logic that catches HTTP 400 responses and automatically strips problematic parameters like reasoning_budget or chat_template before retrying the request. This handling is implemented in providers/nvidia_nim/client.py.
Can I run the proxy against a local LM Studio instance?
Yes. Set the lm_studio_base_url setting to your local LM Studio endpoint (typically http://localhost:1234), then prefix your model names with lmstudio/. The LMStudioProvider automatically uses a dummy API key of "lm-studio" and routes requests to your local server instead of cloud APIs.
How does the proxy handle streaming responses differently across providers?
All providers use the shared OpenAICompatibleProvider base class, which standardizes streaming through providers/common/SSEBuilder.py. Provider-specific implementations only customize the request payload construction via _build_request_body, while the base class handles the SSE formatting and Claude-compatible event generation consistently across all backends.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →