A lightweight proxy server that converts Anthropic Messages API to OpenAI API
Project description
local-openai2anthropic
English | 中文
A lightweight proxy that bridges Anthropic and OpenAI ecosystems — run Claude SDK apps on any OpenAI-compatible backend, or use OpenAI clients directly with zero conversion overhead.
Why OA2A
- Bidirectional Protocol Conversion — Anthropic Messages API ↔ OpenAI Chat Completions API. Run Claude SDK / Claude Code on any OpenAI-compatible backend (vLLM, SGLang, cloud APIs).
- OpenAI-Native Passthrough —
POST /v1/chat/completionsforwards requests as-is with zero conversion overhead. All upstream fields preserved. - Server-Side Web Search — Built-in Tavily / TongXiao search. Give any model internet access without client-side changes.
- Interleaved Thinking — Full support for
thinkingblocks withchat_template_kwargsandreasoning_effort. DeepSeek V4 and other reasoning models work out of the box. - Streaming, Tools & Vision — SSE real-time streaming, Claude
tool_useconversion, multi-modal image input. Full API surface coverage. - Model Name Mapping — Wildcard rules map Anthropic model names to backend models automatically.
- Daemon + Web Dashboard —
oa2a start/stop/logsfor one-command management. Built-in web UI for request monitoring.
What This Does
Two modes of operation:
| Mode | Endpoint | Use Case |
|---|---|---|
| Anthropic Proxy | POST /v1/messages |
Claude SDK / Claude Code apps talking to any OpenAI backend |
| OpenAI Passthrough | POST /v1/chat/completions |
OpenAI-native clients bypassing conversion entirely |
Quick Start
pip Install
pip install local-openai2anthropic
First run launches an interactive setup wizard:
oa2a start
Or run in foreground:
oa2a
Docker
docker run -d --name oa2a -p 8080:8080 \
-e OA2A_OPENAI_API_KEY=your-key \
-e OA2A_OPENAI_BASE_URL=http://host.docker.internal:8000/v1 \
dongfangzan/local-openai2anthropic:latest
Usage Example
import anthropic
client = anthropic.Anthropic(base_url="http://localhost:8080", api_key="any")
message = client.messages.create(
model="your-model",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
print(message.content[0].text)
Daemon Management
oa2a start # Start in background
oa2a stop # Stop background server
oa2a restart # Restart background server
oa2a status # Check if running
oa2a logs # Show recent logs
oa2a logs -f # Follow logs in real-time
Configuration
Config file: ~/.oa2a/config.toml (auto-created)
Core Settings
| Option | Required | Default | Description |
|---|---|---|---|
openai_api_key |
Yes | — | API key for the upstream backend |
openai_base_url |
Yes | https://api.openai.com/v1 |
Upstream backend URL |
openai_org_id |
No | — | OpenAI Organization ID |
openai_project_id |
No | — | OpenAI Project ID |
host |
No | 0.0.0.0 |
Server bind address |
port |
No | 8080 |
Server port |
api_key |
No | — | Auth key for this proxy (Bearer token) |
request_timeout |
No | 300.0 |
Upstream request timeout in seconds |
log_level |
No | INFO |
DEBUG, INFO, WARNING, ERROR |
Model Name Mapping
Map Anthropic model names to backend model names with wildcard support:
default_model = "kimi-k2.5"
[[model_mapping]]
from = "sonnet"
to = "kimi-k2.5"
[[model_mapping]]
from = "*opus*"
to = "deepseek-v4"
from supports * and ? wildcards. default_model is the fallback when no rule matches.
Web Search
Supports two search providers: Tavily and TongXiao (通晓).
tavily_api_key = "tvly-xxx"
tongxiao_api_key = "xxx"
websearch_provider = "tavily" # "tavily", "tongxiao", or "both"
websearch_max_uses = 5
tavily_max_results = 5
tongxiao_max_results = 5
CORS
cors_origins = ["*"]
cors_credentials = true
cors_methods = ["*"]
cors_headers = ["*"]
API Endpoints
Anthropic-Compatible
| Method | Path | Description |
|---|---|---|
POST |
/v1/messages |
Create a message (streaming via stream: true) |
GET |
/v1/models |
List available models (proxied) |
POST |
/v1/messages/count_tokens |
Count tokens (local tiktoken estimation) |
GET |
/health |
Health check |
OpenAI-Native Passthrough
| Method | Path | Description |
|---|---|---|
POST |
/v1/chat/completions |
OpenAI-format chat completions (streaming & non-streaming) |
The passthrough endpoint forwards requests directly to the upstream — no validation, no conversion, no model mapping. All fields (including chat_template_kwargs, reasoning_effort, etc.) are preserved as-is.
Features
- Streaming — SSE real-time token streaming in both Anthropic and OpenAI modes
- Tool Calling — Claude-compatible tool use (
tool_use/tool_result) converted to OpenAI function calls - Vision — Multi-modal image input via
image_urlcontent blocks - Thinking / Reasoning — Supports
thinkingblocks withchat_template_kwargs(vLLM/SGLang) andoutput_config.efforttoreasoning_effortmapping for DeepSeek V4 - Web Search — Server-side web search via Tavily or TongXiao (通晓), usable with any model
- Model Mapping — Wildcard-based model name resolution
- API Auth — Optional Bearer token authentication for the proxy itself
- Web Dashboard — Built-in web UI at
/for monitoring request statistics - Daemon Mode — Background service management (start/stop/restart/status/logs)
Using with Claude Code
Docker (Recommended)
The repo includes a docker-compose.yml with both OA2A proxy and Claude Code pre-configured:
cat > .env << 'EOF'
OA2A_OPENAI_API_KEY=your-api-key
OA2A_OPENAI_BASE_URL=http://host.docker.internal:8000/v1
CLAUDE_MODEL=your-model-name
EOF
docker-compose up -d
docker-compose exec claude-code claude --dangerously-skip-permissions
Local Installation
Configure ~/.claude/settings.json:
{
"env": {
"ANTHROPIC_BASE_URL": "http://localhost:8080",
"ANTHROPIC_API_KEY": "any",
"ANTHROPIC_MODEL": "your-model",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "your-model",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "your-model",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "your-model"
}
}
Then start the proxy (oa2a start) and launch Claude Code (claude).
Supported Backends
| Backend | Status |
|---|---|
| vLLM | Fully supported |
| SGLang | Fully supported |
| Any OpenAI-compatible API | Should work |
Ollama natively supports the Anthropic API format — point Claude SDK directly to
http://localhost:11434/v1, no proxy needed.
Development
git clone https://github.com/dongfangzan/local-openai2anthropic.git
cd local-openai2anthropic
pip install -e ".[dev]"
pytest # 445+ tests, >80% coverage
License
Apache License 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file local_openai2anthropic-0.6.6.tar.gz.
File metadata
- Download URL: local_openai2anthropic-0.6.6.tar.gz
- Upload date:
- Size: 5.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
418310713c5217a73928116b246c59e1fb5d25d20acabd29b0f065f75873d666
|
|
| MD5 |
9403275397a3972982d106e8d277ea15
|
|
| BLAKE2b-256 |
2b5d26f99002fba9d9b1061d6ccabe52c280220843c92ecfdd080b287542f38e
|
Provenance
The following attestation bundles were made for local_openai2anthropic-0.6.6.tar.gz:
Publisher:
publish.yml on dongfangzan/local-openai2anthropic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
local_openai2anthropic-0.6.6.tar.gz -
Subject digest:
418310713c5217a73928116b246c59e1fb5d25d20acabd29b0f065f75873d666 - Sigstore transparency entry: 1448349122
- Sigstore integration time:
-
Permalink:
dongfangzan/local-openai2anthropic@579c7d4bc655cbdb1859143dfd5c0069be050578 -
Branch / Tag:
refs/tags/v0.6.6 - Owner: https://github.com/dongfangzan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@579c7d4bc655cbdb1859143dfd5c0069be050578 -
Trigger Event:
push
-
Statement type:
File details
Details for the file local_openai2anthropic-0.6.6-py3-none-any.whl.
File metadata
- Download URL: local_openai2anthropic-0.6.6-py3-none-any.whl
- Upload date:
- Size: 859.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
381f62f92bd172f0749fa991183e949d43078500039acb533d0abe32bc26e133
|
|
| MD5 |
7792f733757c6c7895f2f0c8fe328f19
|
|
| BLAKE2b-256 |
caa6ca050584700ac82af65dfc6254aeb54cf8b5f843bb40483f08755c1d3b4b
|
Provenance
The following attestation bundles were made for local_openai2anthropic-0.6.6-py3-none-any.whl:
Publisher:
publish.yml on dongfangzan/local-openai2anthropic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
local_openai2anthropic-0.6.6-py3-none-any.whl -
Subject digest:
381f62f92bd172f0749fa991183e949d43078500039acb533d0abe32bc26e133 - Sigstore transparency entry: 1448349232
- Sigstore integration time:
-
Permalink:
dongfangzan/local-openai2anthropic@579c7d4bc655cbdb1859143dfd5c0069be050578 -
Branch / Tag:
refs/tags/v0.6.6 - Owner: https://github.com/dongfangzan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@579c7d4bc655cbdb1859143dfd5c0069be050578 -
Trigger Event:
push
-
Statement type: