Skip to main content

A lightweight proxy server that converts Anthropic Messages API to OpenAI API

Project description

local-openai2anthropic

Python 3.12+ License: Apache 2.0 PyPI

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 PassthroughPOST /v1/chat/completions forwards requests as-is with zero conversion overhead. All upstream fields preserved.
  • OpenAI Responses API BridgePOST /v1/responses accepts the Responses API format and translates to /v1/chat/completions for backends that only implement chat completions. Lets Responses SDK clients talk to any vLLM/SGLang backend.
  • Server-Side Web Search — Built-in Tavily / TongXiao search. Give any model internet access without client-side changes.
  • Interleaved Thinking — Full support for thinking blocks with chat_template_kwargs and reasoning_effort. DeepSeek V4 and other reasoning models work out of the box.
  • Streaming, Tools & Vision — SSE real-time streaming, Claude tool_use conversion, multi-modal image input. Full API surface coverage.
  • Model Name Mapping — Wildcard rules map Anthropic model names to backend models automatically.
  • Daemon + Web Dashboardoa2a start/stop/logs for one-command management. Built-in web UI for request monitoring.

What This Does

Three 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
Responses Bridge POST /v1/responses OpenAI Responses SDK clients talking to chat-completions-only backends

Architecture


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.

OpenAI Responses API Bridge

Method Path Description
POST /v1/responses OpenAI Responses-format request, translated to chat/completions upstream

Accepts the Responses API request shape (input, instructions, reasoning.effort, tools of type function, max_output_tokens, …) and translates it to a /v1/chat/completions call against the upstream backend. The upstream chat completion is translated back into a Responses Response object. Both streaming and non-streaming modes are supported — streaming emits the full Responses SSE event sequence (response.createdresponse.output_text.deltaresponse.completed).

Server-side web search: when the request includes a web_search / web_search_preview tool and a search provider is configured (Tavily or 通晓/TongXiao), the proxy runs the search loop locally. The web_search tool is exposed to the model as a function tool, executed via the configured provider when called, and the results are fed back so the model can answer with up-to-date information. The Responses output includes one web_search_call item per executed search. Configure search the same way as for the Anthropic path:

tavily_api_key = "tvly-xxx"
# or
tongxiao_api_key = "xxx"
websearch_provider = "tavily"       # "tavily", "tongxiao", or "both"
websearch_max_uses = 5
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="any")
resp = client.responses.create(
    model="your-model",
    input="Hello!",
    instructions="Be concise",
)
print(resp.output_text)

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_url content blocks
  • Thinking / Reasoning — Supports thinking blocks with chat_template_kwargs (vLLM/SGLang) and output_config.effort to reasoning_effort mapping 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

local_openai2anthropic-0.7.0.tar.gz (5.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

local_openai2anthropic-0.7.0-py3-none-any.whl (875.4 kB view details)

Uploaded Python 3

File details

Details for the file local_openai2anthropic-0.7.0.tar.gz.

File metadata

  • Download URL: local_openai2anthropic-0.7.0.tar.gz
  • Upload date:
  • Size: 5.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for local_openai2anthropic-0.7.0.tar.gz
Algorithm Hash digest
SHA256 70654ca6504f1921c85a274713d587febfbed8e154e8f0976e087109b7f6f13f
MD5 b83fb23f0ab4e4bb45fa31cc17ab555c
BLAKE2b-256 bf7a49029f184dfdf6f0fe3e7ddd4ea3735fec64e98e379787feb48e7abf47f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for local_openai2anthropic-0.7.0.tar.gz:

Publisher: publish.yml on dongfangzan/local-openai2anthropic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file local_openai2anthropic-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for local_openai2anthropic-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 316d1bd4d8a8314ee625e62a95947cd409d2646c5214c299abc279ed6788f56b
MD5 149f343cd26908c1abd03599ff7ee4e3
BLAKE2b-256 a0b5961ac8ce3381f9f402e708b68f158b3c6cb85b0a02ce60d2267ab382383c

See more details on using hashes here.

Provenance

The following attestation bundles were made for local_openai2anthropic-0.7.0-py3-none-any.whl:

Publisher: publish.yml on dongfangzan/local-openai2anthropic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page