Skip to content

Commit a9be460

Browse files
authored
Merge pull request #45 from FammasMaz/feature/anthropic-endpoints
Anthropic endpoint for claude code
2 parents 088180f + 1798e75 commit a9be460

File tree

12 files changed

+1956
-26
lines changed

12 files changed

+1956
-26
lines changed

DOCUMENTATION.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The project is a monorepo containing two primary components:
1010
* **Batch Manager**: Optimizes high-volume embedding requests.
1111
* **Detailed Logger**: Provides per-request file logging for debugging.
1212
* **OpenAI-Compatible Endpoints**: `/v1/chat/completions`, `/v1/embeddings`, etc.
13+
* **Anthropic-Compatible Endpoints**: `/v1/messages`, `/v1/messages/count_tokens` for Claude Code and other Anthropic API clients.
1314
* **Model Filter GUI**: Visual interface for configuring model ignore/whitelist rules per provider (see Section 6).
1415
2. **The Resilience Library (`rotator_library`)**: This is the core engine that provides high availability. It is consumed by the proxy app to manage a pool of API keys, handle errors gracefully, and ensure requests are completed successfully even when individual keys or provider endpoints face issues.
1516

@@ -816,6 +817,108 @@ When a custom cap triggers a cooldown longer than the exhaustion threshold, it a
816817

817818
**Defaults:** See `src/rotator_library/config/defaults.py` for all configurable defaults.
818819

820+
### 2.21. Anthropic API Compatibility (`anthropic_compat/`)
821+
822+
A translation layer that enables Anthropic API clients (like Claude Code) to use any OpenAI-compatible provider through the proxy.
823+
824+
#### Architecture
825+
826+
The module consists of three components:
827+
828+
| File | Purpose |
829+
|------|---------|
830+
| `models.py` | Pydantic models for Anthropic request/response formats (`AnthropicMessagesRequest`, `AnthropicMessage`, `AnthropicTool`, etc.) |
831+
| `translator.py` | Bidirectional format translation functions |
832+
| `streaming.py` | SSE format conversion for streaming responses |
833+
834+
#### Request Translation (`translate_anthropic_request`)
835+
836+
Converts Anthropic Messages API requests to OpenAI Chat Completions format:
837+
838+
**Message Conversion:**
839+
- Anthropic `system` field → OpenAI system message
840+
- `content` blocks (text, image, tool_use, tool_result) → OpenAI format
841+
- Image blocks with base64 data → OpenAI `image_url` with data URI
842+
- Document blocks (PDF, etc.) → OpenAI `image_url` format
843+
844+
**Tool Conversion:**
845+
- Anthropic `tools` with `input_schema` → OpenAI `tools` with `parameters`
846+
- `tool_choice.type: "any"``"required"`
847+
- `tool_choice.type: "tool"``{"type": "function", "function": {"name": ...}}`
848+
849+
**Thinking Configuration:**
850+
- `thinking.type: "enabled"``reasoning_effort: "high"` + `thinking_budget`
851+
- `thinking.type: "disabled"``reasoning_effort: "disable"`
852+
- Opus models default to thinking enabled
853+
854+
**Special Handling:**
855+
- Reorders assistant content blocks: thinking → text → tool_use
856+
- Injects `[Continue]` prompt for fresh thinking turns
857+
- Preserves thinking signatures for multi-turn conversations
858+
859+
#### Response Translation (`openai_to_anthropic_response`)
860+
861+
Converts OpenAI Chat Completions responses to Anthropic Messages format:
862+
863+
**Content Blocks:**
864+
- `reasoning_content` → thinking block with signature
865+
- `content` → text block
866+
- `tool_calls` → tool_use blocks with parsed JSON input
867+
868+
**Field Mapping:**
869+
- `finish_reason: "stop"``stop_reason: "end_turn"`
870+
- `finish_reason: "length"``stop_reason: "max_tokens"`
871+
- `finish_reason: "tool_calls"``stop_reason: "tool_use"`
872+
873+
**Usage Translation:**
874+
- `prompt_tokens` minus `cached_tokens``input_tokens`
875+
- `completion_tokens``output_tokens`
876+
- `prompt_tokens_details.cached_tokens``cache_read_input_tokens`
877+
878+
#### Streaming Wrapper (`anthropic_streaming_wrapper`)
879+
880+
Converts OpenAI SSE streaming format to Anthropic's event-based format:
881+
882+
**Event Types Generated:**
883+
```
884+
message_start → Initial message metadata
885+
content_block_start → Start of text/thinking/tool_use block
886+
content_block_delta → Incremental content (text_delta, thinking_delta, input_json_delta)
887+
content_block_stop → End of content block
888+
message_delta → Final metadata (stop_reason, usage)
889+
message_stop → End of message
890+
```
891+
892+
**Features:**
893+
- Accumulates tool call arguments across chunks
894+
- Handles thinking/reasoning content from `delta.reasoning_content`
895+
- Proper block indexing for multiple content blocks
896+
- Cache token handling in usage statistics
897+
- Error recovery with proper message structure
898+
899+
#### Client Integration
900+
901+
The `RotatingClient` provides two methods for Anthropic compatibility:
902+
903+
```python
904+
async def anthropic_messages(self, request, raw_request=None, pre_request_callback=None):
905+
"""Handle Anthropic Messages API requests."""
906+
# 1. Translate Anthropic request to OpenAI format
907+
# 2. Call acompletion() with translated request
908+
# 3. Convert response back to Anthropic format
909+
# 4. For streaming: wrap with anthropic_streaming_wrapper
910+
911+
async def anthropic_count_tokens(self, request):
912+
"""Count tokens for Anthropic-format request."""
913+
# Translates messages and tools, then uses token_count()
914+
```
915+
916+
#### Authentication
917+
918+
The proxy accepts both Anthropic and OpenAI authentication styles:
919+
- `x-api-key` header (Anthropic style)
920+
- `Authorization: Bearer` header (OpenAI style)
921+
819922
### 3.5. Antigravity (`antigravity_provider.py`)
820923

821924
The most sophisticated provider implementation, supporting Google's internal Antigravity API for Gemini 3 and Claude models (including **Claude Opus 4.5**, Anthropic's most powerful model).

README.md

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44

55
**One proxy. Any LLM provider. Zero code changes.**
66

7-
A self-hosted proxy that provides a single, OpenAI-compatible API endpoint for all your LLM providers. Works with any application that supports custom OpenAI base URLs—no code changes required in your existing tools.
7+
A self-hosted proxy that provides OpenAI and Anthropic compatible API endpoints for all your LLM providers. Works with any application that supports custom OpenAI or Anthropic base URLs—including Claude Code, Opencode, and more—no code changes required in your existing tools.
88

99
This project consists of two components:
1010

11-
1. **The API Proxy** — A FastAPI application providing a universal `/v1/chat/completions` endpoint
11+
1. **The API Proxy** — A FastAPI application providing universal `/v1/chat/completions` (OpenAI) and `/v1/messages` (Anthropic) endpoints
1212
2. **The Resilience Library** — A reusable Python library for intelligent API key management, rotation, and failover
1313

1414
---
1515

1616
## Why Use This?
1717

18-
- **Universal Compatibility** — Works with any app supporting OpenAI-compatible APIs: Opencode, Continue, Roo/Kilo Code, JanitorAI, SillyTavern, custom applications, and more
18+
- **Universal Compatibility** — Works with any app supporting OpenAI or Anthropic APIs: Claude Code, Opencode, Continue, Roo/Kilo Code, Cursor, JanitorAI, SillyTavern, custom applications, and more
1919
- **One Endpoint, Many Providers** — Configure Gemini, OpenAI, Anthropic, and [any LiteLLM-supported provider](https://docs.litellm.ai/docs/providers) once. Access them all through a single API key
20+
- **Anthropic API Compatible** — Use Claude Code or any Anthropic SDK client with non-Anthropic providers like Gemini, OpenAI, or custom models
2021
- **Built-in Resilience** — Automatic key rotation, failover on errors, rate limit handling, and intelligent cooldowns
2122
- **Exclusive Provider Support** — Includes custom providers not available elsewhere: **Antigravity** (Gemini 3 + Claude Sonnet/Opus 4.5), **Gemini CLI**, **Qwen Code**, and **iFlow**
2223

@@ -177,12 +178,57 @@ In your configuration file (e.g., `config.json`):
177178

178179
</details>
179180

181+
<details>
182+
<summary><b>Claude Code</b></summary>
183+
184+
Claude Code natively supports custom Anthropic API endpoints. The recommended setup is to edit your Claude Code `settings.json`:
185+
186+
```json
187+
{
188+
"env": {
189+
"ANTHROPIC_AUTH_TOKEN": "your-proxy-api-key",
190+
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8000",
191+
"ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini/gemini-3-pro",
192+
"ANTHROPIC_DEFAULT_SONNET_MODEL": "gemini/gemini-3-flash",
193+
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "openai/gpt-5-mini"
194+
}
195+
}
196+
```
197+
198+
Now you can use Claude Code with Gemini, OpenAI, or any other configured provider.
199+
200+
</details>
201+
202+
<details>
203+
<summary><b>Anthropic Python SDK</b></summary>
204+
205+
```python
206+
from anthropic import Anthropic
207+
208+
client = Anthropic(
209+
base_url="http://127.0.0.1:8000",
210+
api_key="your-proxy-api-key"
211+
)
212+
213+
# Use any provider through Anthropic's API format
214+
response = client.messages.create(
215+
model="gemini/gemini-3-flash", # provider/model format
216+
max_tokens=1024,
217+
messages=[{"role": "user", "content": "Hello!"}]
218+
)
219+
print(response.content[0].text)
220+
```
221+
222+
</details>
223+
180224
### API Endpoints
181225

182226
| Endpoint | Description |
183227
|----------|-------------|
184228
| `GET /` | Status check — confirms proxy is running |
185-
| `POST /v1/chat/completions` | Chat completions (main endpoint) |
229+
| `POST /v1/chat/completions` | Chat completions (OpenAI format) |
230+
| `POST /v1/messages` | Chat completions (Anthropic format) — Claude Code compatible |
231+
| `POST /v1/messages/count_tokens` | Count tokens for Anthropic-format requests |
186232
| `POST /v1/embeddings` | Text embeddings |
187233
| `GET /v1/models` | List all available models with pricing & capabilities |
188234
| `GET /v1/models/{model_id}` | Get details for a specific model |

0 commit comments

Comments
 (0)