# How to Add a New OpenAI-Compatible Provider to free-claude-code

> Add a new OpenAI compatible provider to free-claude-code by subclassing OpenAICompatibleProvider and integrating it into the factory. Learn the simple steps to extend your provider options.

- Repository: [Ali Khokhar/free-claude-code](https://github.com/Alishahryar1/free-claude-code)
- Tags: how-to-guide
- Published: 2026-04-24

---

**To add a new OpenAI-compatible provider to the free-claude-code project, you create a package under `providers/`, subclass `OpenAICompatibleProvider` from [`providers/openai_compat.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/openai_compat.py), implement a request-body builder using `build_base_request_body`, expose the class in [`providers/__init__.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/__init__.py), and wire it into the factory function in [`api/dependencies.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/api/dependencies.py).**

The free-claude-code repository by Alishahryar1 abstracts all LLM interactions behind a unified provider interface, allowing seamless integration of OpenAI-compatible endpoints such as OpenRouter, NVIDIA NIM, and DeepSeek. Adding a new OpenAI-compatible provider involves six concrete steps that leverage the shared logic in `OpenAICompatibleProvider` to handle streaming, rate limiting, and tool calling automatically. This guide provides the exact file paths, method signatures, and code patterns found in the source code.

## Understanding the Provider Architecture

### The Base Provider Contract

Every provider in free-claude-code inherits from `BaseProvider` defined in [`providers/base.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/base.py). This abstract base class defines the `ProviderConfig` dataclass and the core interface that all implementations must satisfy. The `ProviderConfig` carries authentication credentials, base URLs, rate limits, and timeout settings used across the application.

### The OpenAI-Compatible Abstraction

OpenAI-compatible providers share a common implementation in [`providers/openai_compat.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/openai_compat.py). The `OpenAICompatibleProvider` class extends `BaseProvider` and provides concrete methods for SSE streaming, retry logic, and Anthropic-to-OpenAI message conversion. When you add a new provider, you subclass `OpenAICompatibleProvider` and only need to implement the `_build_request_body` method to customize the JSON payload structure.

## Step-by-Step Implementation Guide

### Step 1: Scaffold the Provider Package

Create a new directory for your provider under the `providers/` folder. This package requires at minimum an [`__init__.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/__init__.py) file (which can be empty) and two Python modules: [`request.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/request.py) and [`client.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/client.py).

For example, to create a provider named **FooAI**:

```bash
mkdir providers/fooai
touch providers/fooai/__init__.py
touch providers/fooai/request.py
touch providers/fooai/client.py

```

### Step 2: Implement the Request Body Builder

In [`providers/fooai/request.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/fooai/request.py), import `build_base_request_body` from `providers.common.message_converter` to convert the internal Anthropic-style request into an OpenAI-compatible JSON payload. This helper handles message formatting, tool definitions, and thinking blocks.

```python
from typing import Any
from loguru import logger
from providers.common.message_converter import build_base_request_body

FOOAI_DEFAULT_MAX_TOKENS = 4096

def build_request_body(request_data: Any, *, thinking_enabled: bool) -> dict:
    """Convert internal Anthropic-style request to FooAI's OpenAI-compatible payload."""
    logger.debug(
        "FOOAI_REQUEST: start model={} msgs={}",
        getattr(request_data, "model", "?"),
        len(getattr(request_data, "messages", [])),
    )
    body = build_base_request_body(
        request_data,
        include_thinking=thinking_enabled,
        default_max_tokens=FOOAI_DEFAULT_MAX_TOKENS,
        include_reasoning_for_openrouter=thinking_enabled,
    )
    logger.debug(
        "FOOAI_REQUEST: done model={} msgs={} tools={}",
        body.get("model"),
        len(body.get("messages", [])),
        len(body.get("tools", [])),
    )
    return body

```

### Step 3: Create the Provider Class

In [`providers/fooai/client.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/fooai/client.py), define a class that inherits from `OpenAICompatibleProvider`. Implement `_build_request_body` to return the dictionary from your request builder. Optionally override `_handle_extra_reasoning` or `_get_retry_request_body` for provider-specific behavior.

```python
from typing import Any, Iterator
from providers.base import ProviderConfig
from providers.openai_compat import OpenAICompatibleProvider, SSEBuilder
from .request import build_request_body

class FooAIProvider(OpenAICompatibleProvider):
    """FooAI – an OpenAI-compatible endpoint."""

    def __init__(self, config: ProviderConfig):
        super().__init__(
            config,
            provider_name="FOOAI",
            base_url=config.base_url or "https://api.fooai.com/v1",
            api_key=config.api_key,
        )

    def _build_request_body(self, request: Any) -> dict:
        return build_request_body(
            request,
            thinking_enabled=self._is_thinking_enabled(request),
        )

    def _handle_extra_reasoning(
        self, delta: Any, sse: SSEBuilder, *, thinking_enabled: bool
    ) -> Iterator[str]:
        if not thinking_enabled:
            return
        details = getattr(delta, "reasoning_details", None)
        if details and isinstance(details, list):
            for item in details:
                txt = item.get("text", "")
                if txt:
                    yield from sse.ensure_thinking_block()
                    yield sse.emit_thinking_delta(txt)

```

### Step 4: Register the Provider

Export your provider class in [`providers/__init__.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/__init__.py) so it can be imported as `providers.FooAIProvider`. Append the class name to the `__all__` list.

```python
from .fooai import FooAIProvider

__all__.append("FooAIProvider")

```

### Step 5: Wire Into the Dependency Factory

Add a new branch to the `_create_provider_for_type` function in [`api/dependencies.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/api/dependencies.py). This maps the `PROVIDER_TYPE` environment variable value to your provider class and validates required settings.

```python
    if provider_type == "fooai":
        if not settings.fooai_api_key or not settings.fooai_api_key.strip():
            raise AuthenticationError(
                "FOOAI_API_KEY is not set. Add it to your .env file."
            )
        config = ProviderConfig(
            api_key=settings.fooai_api_key,
            base_url="https://api.fooai.com/v1",
            rate_limit=settings.provider_rate_limit,
            rate_window=settings.provider_rate_window,
            max_concurrency=settings.provider_max_concurrency,
            http_read_timeout=settings.http_read_timeout,
            http_write_timeout=settings.http_write_timeout,
            http_connect_timeout=settings.http_connect_timeout,
            enable_thinking=settings.enable_thinking,
            proxy=proxy,
        )
        return FooAIProvider(config)

```

### Step 6: Configure Environment Variables

Document the required environment variables in `.env.example` and your README. At minimum, define the API key variable and an optional proxy setting.

```dotenv

# FooAI

FOOAI_API_KEY=your-fooai-key
FOOAI_PROXY=

```

Once configured, users can activate the provider by setting:

```dotenv
PROVIDER_TYPE=fooai
FOOAI_API_KEY=your-key-here

```

## Optional: Provider-Specific Customizations

### Handling Extra Reasoning Fields

If your provider returns reasoning tokens in a custom field (such as `reasoning_details`), override the `_handle_extra_reasoning` method as shown in the FooAI example above. This method receives the raw delta object and an `SSEBuilder` instance to emit thinking blocks to the client.

### Custom Retry Strategies

For providers that require special retry logic or modified request bodies on retry attempts, implement the `_get_retry_request_body` method. The NVIDIA NIM provider in [`providers/nvidia_nim/client.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/nvidia_nim/client.py) demonstrates this pattern for handling rate-limit responses with adjusted token counts.

## Summary

- **Subclass `OpenAICompatibleProvider`** from [`providers/openai_compat.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/openai_compat.py) to inherit streaming, rate limiting, and tool-handling logic.
- **Implement `_build_request_body`** using `build_base_request_body` from `providers.common.message_converter` to handle Anthropic-to-OpenAI message translation.
- **Register exports** in [`providers/__init__.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/__init__.py) and add the factory case in [`api/dependencies.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/api/dependencies.py) to wire the provider to the `PROVIDER_TYPE` environment variable.
- **Validate credentials** in the factory function and document environment variables in `.env.example`.
- **Run the test suite** with `uv run pytest` and format code using `uv run ruff format` before committing.

## Frequently Asked Questions

### What base class must I extend to add a new OpenAI-compatible provider?

You must extend `OpenAICompatibleProvider` defined in [`providers/openai_compat.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/providers/openai_compat.py). This class inherits from `BaseProvider` and provides concrete implementations for HTTP streaming, SSE conversion, and OpenAI-compatible JSON formatting, requiring you only to implement the `_build_request_body` method for custom payload logic.

### How do I convert the internal Anthropic request format to OpenAI format?

Use the `build_base_request_body` function from `providers.common.message_converter` within your provider's request builder module. This utility converts Anthropic-style message lists and tool definitions into the OpenAI chat completions schema, handling thinking blocks and token limits automatically.

### Where should I validate environment variables for my custom provider?

Validate API keys and required settings inside the `_create_provider_for_type` function in [`api/dependencies.py`](https://github.com/Alishahryar1/free-claude-code/blob/main/api/dependencies.py) before instantiating your provider class. Raise an `AuthenticationError` if required variables like `FOOAI_API_KEY` are missing or empty, ensuring clear error messages for users.

### Can I add support for provider-specific response fields like reasoning tokens?

Yes. Override the `_handle_extra_reasoning` method in your provider class to parse custom fields such as `reasoning_details` from the API response delta. Yield thinking blocks using the `SSEBuilder` instance to stream these tokens to the client in the Anthropic-compatible format expected by free-claude-code.