Python port of ccswitch-deepseek — a protocol translation proxy that converts OpenAI Responses API to Chat Completions API, enabling Codex to use DeepSeek or any OpenAI-compatible model via cc-switch.
Zero external dependencies — Python standard library only.
Thanks to the original ccswitch-deepseek project for the design and protocol research.
cp .env.example .envEdit .env with your API key and optional settings (see Configuration).
./start.shOr with uv directly:
uv run python -m src.mainThe proxy listens at http://127.0.0.1:11435.
| Variable | Default | Description |
|---|---|---|
api_key |
— | API key (required) |
base_url |
https://api.deepseek.com |
API base URL |
model |
deepseek-v4-pro |
Model name |
port |
11435 |
Server listen port |
timeout |
30 |
Upstream API timeout in minutes |
is_deepseek |
true |
Set to false if not using a DeepSeek model |
multimodal |
false |
Set to true if the model supports image inputs |
identity_model |
(empty) | Fill in official model name to enable identity injection, empty skips |
identity_modelnote: Fill in the official model name to enable identity injection. Leave empty to skip. Whether using the official API or a third-party platform, you must set this to inject. Example:deepseek-v4-profor both official API and third-party (whenmodelis a routing identifier likedeepseek-ai/DeepSeek-V4-Pro).
This proxy works with any model provider that offers an OpenAI-compatible Chat Completions API. Just configure base_url, model, and api_key accordingly.
Tip: Some third-party model providers also support the DeepSeek-format
thinkingparameter. If the model recognizesthinking: {type: "enabled"}, you can keepis_deepseek=true.
Codex speaks OpenAI Responses API. Most AI model providers speak Chat Completions API. This proxy translates between the two protocols in real time.
Codex (app or CLI) ──▶ cc-switch ──▶ proxy :11435 ──▶ Upstream API
- Codex sends a request to cc-switch (its configured provider endpoint)
- cc-switch routes the request to this proxy at
/responses - The proxy translates Responses API
inputitems into Chat Completionsmessages - The translated request is forwarded to
{base_url}/chat/completions - The upstream API's SSE streaming response is translated back into Responses API events and returned
Input (Responses → Chat Completions)
| Source | Target |
|---|---|
input_text / output_text / reasoning_text |
message text content |
function_call item |
assistant tool_calls |
function_call_output item |
tool role message |
reasoning item |
skipped; reasoning_content retained on adjacent message |
developer role |
system role |
input_image / input_file / input_audio |
skipped with stats |
instructions |
prepended system message |
temperature / top_p / max_output_tokens |
passthrough |
tools / tool_choice |
translated to Chat Completions format |
thinking / reasoning |
thinking mode control (DeepSeek format) |
Output (Chat Completions SSE → Responses SSE)
| Chat Completions SSE event | Responses API event |
|---|---|
| first delta | response.created + response.in_progress |
delta.content |
response.output_text.delta / done |
delta.reasoning_content |
response.reasoning_text.delta / done |
delta.tool_calls |
response.function_call_arguments.delta / done |
| stream end | response.output_item.done × N + response.completed (with usage) |
DeepSeek omits reasoning_content on tool-call assistant messages in multi-turn conversations.
The proxy automatically remembers reasoning from the previous turn and restores it on the next,
so the reasoning chain stays intact across function calls.
A system message is prepended to every request telling the model its true identity,
preventing conflicting identity claims from Codex or other tools.
Set identity_model in .env to the model's official name to enable injection; leave empty to skip.
Integration with cc-switch
cc-switch is a cross-platform AI CLI management tool that handles provider configuration and request routing. This proxy is an independent service; cc-switch routes Codex requests to it.
1. Start the proxy:
./start.sh2. Add a new Codex provider in cc-switch:
cc-switch manages Codex's config files (~/.codex/config.toml and ~/.codex/auth.json).
Fill in these fields when adding the provider:
| Field | Value |
|---|---|
| name | codex-deepseek |
| base_url | http://127.0.0.1:11435 |
| wire_api | responses |
| requires_openai_auth | true |
The resulting ~/.codex/config.toml will look like:
model_provider = "custom"
model = "deepseek-v4-pro"
model_reasoning_effort = "high"
model_context_window = 262144
model_supports_reasoning_summaries = true
model_reasoning_summary = "none"
model_catalog_json = "~/.codex/model-catalogs/deepseek.json"
[model_providers.custom]
name = "codex-deepseek"
base_url = "http://127.0.0.1:11435"
wire_api = "responses"
requires_openai_auth = true
stream_idle_timeout_ms = 1800000| New Field | Description |
|---|---|
model_context_window |
Informs Codex of context window size for correct compaction |
model_supports_reasoning_summaries |
Declares the model supports reasoning |
model_reasoning_summary = "none" |
DeepSeek returns reasoning_content natively; no extra summary needed |
stream_idle_timeout_ms |
30-minute stream idle timeout, prevents Codex from disconnecting during DeepSeek V4 long thinking |
model_catalog_json |
Points to a model catalog JSON to fix "model metadata not found" warnings |
Note: The proxy auto-generates
codex-deepseek-catalog.jsonon startup. Copy it to~/.codex/model-catalogs/and configure themodel_catalog_jsonpath.
Note: Codex requires a non-empty
OPENAI_API_KEYin~/.codex/auth.jsonto pass its client-side check, but the actual upstream authentication is handled by this proxy's own.env— so any placeholder value works inauth.json.
3. Restart your terminal for changes to take effect.
| File | Description |
|---|---|
src/main.py |
HTTP server (stdlib http.server) |
src/log.py |
Colored ANSI logging |
src/translate.py |
Input translation (Responses → Chat) |
src/sse.py |
SSE event translation (Chat → Responses) |
src/recover.py |
reasoning_content auto-restore |
tests/test_translate.py |
28 unit tests |
./start.sh # Start the proxy server
./test.sh # Run unit testsCodex's built-in model registry lacks DeepSeek model info. Create a model catalog JSON and reference it in config.toml.
Step 1: The proxy auto-generates codex-deepseek-catalog.json on startup. Copy it to your Codex directory:
mkdir -p ~/.codex/model-catalogs
cp codex-deepseek-catalog.json ~/.codex/model-catalogs/deepseek.jsonStep 2: Add to the root level of ~/.codex/config.toml (not inside the provider section):
model_catalog_json = "~/.codex/model-catalogs/deepseek.json"Important:
model_catalog_jsonmust be at the root level of config.toml, not inside[model_providers.xxx].[model_properties]does not work in Codex 0.141+.
DeepSeek V4 may produce no output for extended periods during reasoning. Codex's default stream idle timeout can cause disconnections. Add to the provider config:
[model_providers.custom]
stream_idle_timeout_ms = 1800000 # 30 minutesThe proxy detects missing configuration on startup and prints only what needs to be added.
MIT