# How Ouroboros Provider Adapters Interface with LiteLLM, Anthropic, and Claude Code

> Learn how Ouroboros Provider Adapters unify LiteLLM, Anthropic, and Claude Code for streamlined LLM request handling, retries, and error normalization. Simplify your AI integrations.

- Repository: [Q00/ouroboros](https://github.com/Q00/ouroboros)
- Tags: how-to-guide
- Published: 2026-03-14

---

**Ouroboros unifies LiteLLM, Anthropic, and Claude Code behind a single `LLMAdapter` protocol that standardizes request handling, retry logic, and error normalization across every supported model.**

The Q00/ouroboros repository defines a clean abstraction layer that allows developers to switch between language models without changing application code. By implementing the `LLMAdapter` protocol, Ouroboros Provider Adapters translate unified configuration objects into provider-specific API calls while normalizing responses and failures. This architecture separates model orchestration from provider implementation details.

## The LLMAdapter Protocol Foundation

Every adapter conforms to the `LLMAdapter` protocol defined in [`src/ouroboros/providers/base.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/base.py). This contract requires a single `complete(messages, config)` coroutine that accepts a list of `Message` objects and a `CompletionConfig`, returning a `Result[CompletionResponse, ProviderError]`.

The protocol enforces a unified data model across all providers. **Message**, **CompletionConfig**, **CompletionResponse**, and **UsageInfo** are defined once in [`base.py`](https://github.com/Q00/ouroboros/blob/main/base.py) and reused by every adapter. This ensures that tools and agents built on Ouroboros remain agnostic to whether they are calling GPT-4 via OpenRouter or Claude via the Agent SDK.

Error handling is similarly normalized. All adapters convert native exceptions into the `ProviderError` class from [`src/ouroboros/core/errors.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/core/errors.py), using the `_extract_provider` helper to label the error source (e.g., `"openrouter"` or `"anthropic"`).

## LiteLLMAdapter: Unified Multi-Provider Gateway

The **LiteLLMAdapter** in [`src/ouroboros/providers/litellm_adapter.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/litellm_adapter.py) acts as a universal gateway, leveraging the `litellm` library to support hundreds of models through a single interface.

### Model Selection and API Resolution

Model selection is driven by the `model` field of `CompletionConfig`. Values like `openrouter/openai/gpt-4` are passed directly to `litellm.acompletion`. API key resolution follows a precedence hierarchy:

1. An explicit `api_key` argument overrides everything.
2. If omitted, the adapter inspects environment variables (`OPENROUTER_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) based on the prefix of the model string.

### Request Construction

The `_build_completion_kwargs` method constructs the payload dictionary with `model`, `messages`, `temperature`, `max_tokens`, and `top_p` (omitted for Anthropic models). It optionally injects `stop` sequences, `response_format`, and a custom `api_base`.

### Resilience with Stamina

Transient failures are handled automatically via the `@stamina.retry` decorator. The adapter retries `litellm` exceptions including `RateLimitError`, `ServiceUnavailableError`, `Timeout`, and `APIConnectionError` up to `max_retries` (default **3**). All failures are converted to `ProviderError` before returning to the caller.

## ClaudeCodeAdapter: Agent SDK Integration

The **ClaudeCodeAdapter** in [`src/ouroboros/providers/claude_code_adapter.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/claude_code_adapter.py) interfaces with the Claude Agent SDK, enabling access to Claude Code's capabilities through the same `LLMAdapter` surface.

### CLI Path and Authentication

Unlike other adapters, this implementation does not require per-provider API keys. It relies on the user's Claude Code Max-Plan subscription. A custom CLI binary can be supplied via the `cli_path` parameter, which resolves from the `OUROBOROS_CLI_PATH` environment variable or [`config.yaml`](https://github.com/Q00/ouroboros/blob/main/config.yaml).

### Prompt Engineering and Options

The adapter transforms the message list into a single string via `_build_prompt`. It constructs a `ClaudeAgentOptions` object containing allowed/disallowed tools, `max_turns`, `permission_mode`, `cwd`, and optional `system_prompt`. When a JSON schema is requested, it sets the `output_format` accordingly.

### Manual Retry Logic

Rather than using `stamina`, this adapter implements **manual exponential backoff** with `_MAX_RETRIES = 5`. It detects retryable conditions by matching error messages against `_RETRYABLE_ERROR_PATTERNS` or catching unknown SDK message types. After the generator finishes, the adapter walks through SDK messages (`AssistantMessage`, `ToolUseBlock`, `ResultMessage`) to assemble the final `CompletionResponse`.

## AnthropicAdapter Direct Integration

While not detailed in the primary excerpts, the **AnthropicAdapter** follows the same architectural pattern. It targets the `anthropic/*` model namespace, pulling `ANTHROPIC_API_KEY` from the environment unless overridden. It builds request payloads according to Anthropic's native specification and uses the `stamina` decorator for retry logic on rate-limit and service-unavailable errors.

## Shared Architectural Patterns

All Ouroboros Provider Adapters share three critical design traits:

- **Unified data model** – Types defined in [`base.py`](https://github.com/Q00/ouroboros/blob/main/base.py) ensure consistency across LiteLLM, Claude Code, and direct API implementations.
- **Result wrapper** – Every `complete` call returns `Result[CompletionResponse, ProviderError]`, enabling callers to handle success and failure uniformly without try-catch blocks.
- **Provider detection** – The `_extract_provider` utility parses model identifiers to ensure accurate error attribution and logging.

## Implementation Examples

The following examples demonstrate instantiating adapters with environment-driven or explicit configuration.

```python

# LiteLLMAdapter with OpenRouter

from ouroboros.providers.litellm_adapter import LiteLLMAdapter
from ouroboros.providers.base import Message, MessageRole, CompletionConfig

adapter = LiteLLMAdapter()  # Resolves API key from env vars

cfg = CompletionConfig(
    model="openrouter/openai/gpt-4",
    temperature=0.5,
    max_tokens=512,
)

messages = [
    Message(role=MessageRole.USER, content="Explain Ouroboros architecture in 2 sentences.")
]

result = await adapter.complete(messages, cfg)
if result.is_ok:
    print(result.value.content)
else:
    raise result.error

```

```python

# ClaudeCodeAdapter with custom CLI path

from ouroboros.providers.claude_code_adapter import ClaudeCodeAdapter
from ouroboros.providers.base import Message, MessageRole, CompletionConfig

adapter = ClaudeCodeAdapter(cli_path="/usr/local/bin/claude")
cfg = CompletionConfig(
    model="claude-sonnet-4-6",
    temperature=0.0,
    max_tokens=256,
)

messages = [
    Message(role=MessageRole.USER, content="Generate a Mermaid diagram for a binary tree.")
]

result = await adapter.complete(messages, cfg)
if result.is_ok:
    print(result.value.content)
else:
    raise result.error

```

## Summary

- The `LLMAdapter` protocol in [`src/ouroboros/providers/base.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/base.py) defines the `complete()` coroutine that all adapters must implement.
- **LiteLLMAdapter** leverages `litellm.acompletion` for broad model support and uses the `stamina` library for automatic retries on transient errors.
- **ClaudeCodeAdapter** integrates the Claude Agent SDK, folds message lists into strings via `_build_prompt`, and implements custom exponential backoff with `_MAX_RETRIES = 5`.
- All adapters return `Result[CompletionResponse, ProviderError]` for uniform error handling across the Ouroboros codebase.
- Provider detection via `_extract_provider` ensures errors are accurately attributed to their source (e.g., `"openrouter"` or `"anthronic"`).

## Frequently Asked Questions

### What is the primary interface for Ouroboros Provider Adapters?

The primary interface is the `LLMAdapter` protocol defined in [`src/ouroboros/providers/base.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/base.py). It requires a single async method `complete(messages, config)` that accepts a list of `Message` objects and a `CompletionConfig`, returning a `Result` type containing either a `CompletionResponse` or a `ProviderError`.

### How does LiteLLMAdapter handle API authentication?

**LiteLLMAdapter** resolves API keys through a cascading strategy. An explicit `api_key` argument takes highest precedence. If omitted, the adapter examines environment variables such as `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY` based on the provider prefix in the model identifier (e.g., `openrouter/` or `anthropic/`).

### Why does ClaudeCodeAdapter use manual retry logic instead of stamina?

The **ClaudeCodeAdapter** integrates with the Claude Agent SDK, which streams messages via a generator pattern rather than simple HTTP requests. This requires custom logic to detect retryable conditions by matching error strings against `_RETRYABLE_ERROR_PATTERNS` and implementing exponential backoff manually across up to five attempts, rather than using the `stamina` decorator designed for standard async function calls.

### Can I add a custom provider adapter to Ouroboros?

Yes. Create a new class that implements the `LLMAdapter` protocol from [`src/ouroboros/providers/base.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/providers/base.py). Your implementation must accept `List[Message]` and `CompletionConfig` in its `complete` method and return `Result[CompletionResponse, ProviderError]`. Follow the patterns in [`litellm_adapter.py`](https://github.com/Q00/ouroboros/blob/main/litellm_adapter.py) for HTTP-based providers or [`claude_code_adapter.py`](https://github.com/Q00/ouroboros/blob/main/claude_code_adapter.py) for SDK-based integrations to ensure proper error normalization and retry behavior.