ds4codex
ds4codex lets Codex use DeepSeek models through a small local proxy.
Codex talks to custom providers with the Responses API shape. DeepSeek exposes a Chat Completions compatible API. ds4codex sits between them and translates requests, responses, streaming events, tool calls, and thinking-mode options.
The package keeps the user-facing setup intentionally small:
- one human-edited config file:
~/.codex/config.toml - one generated model catalog for Codex
/model:~/.codex/ds4codex-model-catalog.json - two CLI commands:
ds4codex initandds4codex run
Install
Install from PyPI:
pip install ds4codex -i https://pypi.org/simple
For local development from this repository:
pip install -e .
Quick Start
Initialize Codex and write your DeepSeek API key into the managed provider block:
ds4codex init --apikey sk-your-deepseek-api-key
Start the local proxy:
ds4codex run
Keep ds4codex run running while using Codex. Codex will connect to http://127.0.0.1:8099/v1.
After initialization, start Codex and use /model to choose:
DeepSeek V4 FlashDeepSeek V4 Pro
What init Does
ds4codex init writes managed blocks into ~/.codex/config.toml and generates the model catalog JSON used by Codex /model.
Generated file:
~/.codex/ds4codex-model-catalog.json
Codex config blocks:
# BEGIN DS4CODEX ROOT
model = "deepseek-v4-flash"
model_provider = "ds4codex"
model_context_window = 1048576
model_catalog_json = "/home/you/.codex/ds4codex-model-catalog.json"
# END DS4CODEX ROOT
# BEGIN DS4CODEX SETTINGS
[ds4codex]
port = 8099
target_url = "https://api.deepseek.com/v1/chat/completions"
thinking = "disabled"
# END DS4CODEX SETTINGS
# BEGIN DS4CODEX PROVIDER
[model_providers.ds4codex]
name = "DeepSeek via ds4codex"
base_url = "http://127.0.0.1:8099/v1"
wire_api = "responses"
experimental_bearer_token = "sk-your-deepseek-api-key"
# END DS4CODEX PROVIDER
If ~/.codex/config.toml already exists, init preserves existing user config and only adds or refreshes the managed ds4codex blocks.
Useful options:
ds4codex init --port 9123
ds4codex init --apikey sk-your-deepseek-api-key
ds4codex init --force
ds4codex init --config-path /path/to/config.toml
ds4codex init --model-catalog-path /path/to/ds4codex-model-catalog.json
Model Catalog
The model catalog is required for a good Codex /model experience. It is a JSON file, not a directory.
ds4codex init points Codex at the catalog through:
model_catalog_json = "/home/you/.codex/ds4codex-model-catalog.json"
The catalog makes Codex aware of the two DeepSeek entries:
deepseek-v4-flashdeepseek-v4-pro
It also advertises Codex reasoning choices:
lowmediumhighxhigh
ds4codex first tries to reuse Codex's bundled model schema when the local codex executable is available. If codex is missing, not executable, or fails, ds4codex uses its own built-in template. This means ds4codex init does not require a working local codex binary.
Runtime Settings
The proxy reads runtime settings from the [ds4codex] section inside ~/.codex/config.toml:
[ds4codex]
port = 8099
target_url = "https://api.deepseek.com/v1/chat/completions"
thinking = "disabled"
~/.config/ds4codex/config.toml is not used.
Runtime values can also be overridden from the CLI:
ds4codex run --port 8099
ds4codex run --target-url https://api.deepseek.com/v1/chat/completions
ds4codex run --thinking high
or with environment variables:
DS4CODEX_PORT=8099 ds4codex run
DS4CODEX_TARGET_URL=https://api.deepseek.com/v1/chat/completions ds4codex run
DS4CODEX_THINKING=high ds4codex run
API Key Handling
The recommended path is:
ds4codex init --apikey sk-your-deepseek-api-key
This writes the token into:
[model_providers.ds4codex]
experimental_bearer_token = "sk-your-deepseek-api-key"
Codex sends that token to the local proxy as the incoming bearer token, and the proxy forwards it to DeepSeek.
Alternative runtime sources are also supported:
DS4CODEX_API_KEY=sk-your-deepseek-api-key ds4codex run
DEEPSEEK_API_KEY=sk-your-deepseek-api-key ds4codex run
ds4codex run --api-key sk-your-deepseek-api-key
Thinking Mode
thinking in [ds4codex] is only the default used when Codex does not send an explicit reasoning level.
Accepted practical values:
disabledenabledhighmax
Codex /model exposes these reasoning levels through the generated catalog:
lowmediumhighxhigh
DeepSeek currently documents high and max for reasoning effort, so ds4codex maps Codex-style values before forwarding upstream:
low,medium,minimal->highhigh->highxhigh->max
What's New in 0.1.6 — Tool Call Fixes
v0.1.6 fixes several critical tool-call issues discovered by comparing
ds4codex against the mature annodex translation layer. Without these
fixes, multi-turn tool use (especially with streaming) would silently fail
or produce incomplete results.
reasoning_contentinjection for DeepSeek tool calls — DeepSeek rejects assistant messages carryingtool_callswithoutreasoning_content. Everyfunction_callandcustom_tool_callnow includes the required placeholder.- Streaming tool-call deltas —
translate_streamnow processesdelta.tool_callsincrementally, emitting properresponse.output_item.added/function_call_arguments.delta/.doneevents. - Inline
<think>tag parsing — providers that embed reasoning inside<think>...</think>tags instead of using thereasoning_contentdelta field are now supported. - Namespace tool expansion —
type: "namespace"tool definitions (used by MCP servers) are flattened intonamespace__toolentries that Chat Completions APIs consume. custom_tool_call/custom_tool_call_outputsupport — previously dropped silently; now mapped to standard assistant/tool message format.
See CHANGELOG.md for full release history.
Why the Proxy Is Required
The proxy is still required even though configuration lives in ~/.codex/config.toml.
Codex custom providers use:
wire_api = "responses"
DeepSeek uses a Chat Completions compatible endpoint:
https://api.deepseek.com/v1/chat/completions
ds4codex translates between those two protocols.
Troubleshooting
Tool call errors
If tool calls fail silently or DeepSeek returns errors about missing fields
when Codex attempts tool use, upgrade to ds4codex >= 0.1.6:
pip install --upgrade ds4codex -i https://pypi.org/simple
If streaming tool calls stop mid-way or produce incomplete results, make sure you are on 0.1.6 or later. The streaming translator in earlier versions only forwarded text deltas and could not relay tool calls in streaming mode.
If /model does not show DeepSeek models, rerun:
ds4codex init --force
If you need a different local port, rerun:
ds4codex init --port 9123
Then confirm ~/.codex/config.toml contains model_catalog_json pointing to an existing ds4codex-model-catalog.json file.
If ds4codex init previously failed with PermissionError: [Errno 13] Permission denied: 'codex', upgrade to ds4codex >= 0.1.2. Current versions fall back to the built-in model template when local codex cannot be executed.
If DeepSeek returns messages[0].role: unknown variant developer, upgrade to ds4codex >= 0.1.3. Current versions map Codex developer messages to DeepSeek-compatible system messages.
If DeepSeek returns tools[0]: missing field function, upgrade to ds4codex >= 0.1.4. Current versions map Codex Responses-style function tools to the nested Chat Completions function shape DeepSeek expects.
If requests fail with an API-key error, check that one of these is true:
experimental_bearer_tokenin~/.codex/config.tomlcontains a real DeepSeek keyDS4CODEX_API_KEYis set when runningds4codex runDEEPSEEK_API_KEYis set when runningds4codex runds4codex run --api-key ...was used
Metadata
Release files for ds4codex 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ds4codex-0.1.6.tar.gz | 18.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ds4codex-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.4 kB
Release files / ds4codex-0.1.6.tar.gz
| Download URL | ds4codex-0.1.6.tar.gz |
|---|---|
| Size | 18.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b3256b36aa7195fa2c32f8dc8da32115cf9ba24ac92bc781b0dfc9734a755e2
|
|
BLAKE2b-256 checksum How to use checksums |
2933b3900245ff26b254f82354c5343745ea925fcf66c5aeef38a059d0e67916
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / ds4codex-0.1.6-py3-none-any.whl
| Download URL | ds4codex-0.1.6-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
78e10ebd2b2f1d7dd19c49c59d358976e07eab8a81ec2a5fd8fbed7be7237191
|
|
BLAKE2b-256 checksum How to use checksums |
73c896c4743af898dde2b75cbf4f6d537818d7b3ba58e3f83615e81964e6a69d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for ds4codex 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.