codex-deepseek
中文
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.
Quick Start
cp .env.example .env
Edit .env with your API key and optional settings (see Configuration).
2. Start
./start.sh
Or with uv directly:
uv run python -m src.main
The proxy listens at http://127.0.0.1:11435.
Configuration
| 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_model note: 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-pro for both official API and third-party (when model is a routing identifier like deepseek-ai/DeepSeek-V4-Pro).
Supported Providers
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 thinking parameter. If the model recognizes thinking: {type: "enabled"}, you can keep is_deepseek=true.
How It Works
Codex speaks OpenAI Responses API. Most AI model providers speak Chat Completions API.
This proxy translates between the two protocols in real time.
Request chain
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
input items into Chat Completions messages
- 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
Translation coverage
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) |
reasoning_content recovery
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.
Identity injection
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.
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.
Setup
1. Start the proxy:
./start.sh
2. 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.json on startup. Copy it to ~/.codex/model-catalogs/ and configure the model_catalog_json path.
Note: Codex requires a non-empty OPENAI_API_KEY in ~/.codex/auth.json to pass its client-side check, but the actual upstream authentication is handled by this proxy’s own .env — so any placeholder value works in auth.json.
3. Restart your terminal for changes to take effect.
Files
| 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 |
Scripts
./start.sh # Start the proxy server
./test.sh # Run unit tests
Troubleshooting
Codex’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.json
Step 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_json must be at the root level of config.toml, not inside [model_providers.xxx]. [model_properties] does not work in Codex 0.141+.
Stream disconnection (DeepSeek V4 long thinking)
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 minutes
Startup prints recommended config
The proxy detects missing configuration on startup and prints only what needs to be added.
License
MIT
评论