# Codex DeepSeek Responses Proxy

一个只监听本机的协议代理，使新版 Codex 以 OpenAI Responses API 访问仅提供
Chat Completions API 的 DeepSeek 服务。

```text
Codex /v1/responses
        ↓
Local proxy 127.0.0.1:15721
        ↓
DeepSeek /chat/completions
```

实现参考了 `cc-switch` 的 Codex Chat 转换思路，但代理本身是独立的
TypeScript 服务。当前实现只针对 DeepSeek 官方 Chat Completions API，
支持普通文本、reasoning、函数工具、自定义工具、并行工具调用、跨轮工具结果和
SSE 流式转换。

## 下载和运行

从 [GitHub Releases](https://github.com/flyeric0212/codex-deepseek-responses-proxy/releases)
下载对应平台的压缩包：

- macOS arm64 或 x64
- Linux arm64 或 x64
- Windows x64

```bash
./codex-deepseek-proxy init
```

Windows：

```powershell
.\codex-deepseek-proxy.exe init
```

该命令会在可执行文件旁创建 `config.env`。编辑并填写 API Key：

```dotenv
DEEPSEEK_API_KEY=sk-your-key
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_FLASH_MODEL=deepseek-v4-flash
DEEPSEEK_PRO_MODEL=deepseek-v4-pro
PROXY_HOST=127.0.0.1
PROXY_PORT=15721
UPSTREAM_TIMEOUT_MS=1200000
MAX_REQUEST_BODY_BYTES=10485760
LOG_LEVEL=info
```

然后以前台方式启动：

```bash
./codex-deepseek-proxy
```

发行版无需安装 Node.js 或 Bun。程序始终读取可执行文件所在目录的
`config.env`，因此可从任意工作目录启动。系统环境变量优先于配置文件；
也可使用 `--config /path/to/config.env` 指定其他路径。

常用命令：

```bash
./codex-deepseek-proxy status
./codex-deepseek-proxy --version
./codex-deepseek-proxy --help
```

在 1.0.0 之前，如果 `config.env` 不存在，程序会兼容读取同目录旧 `.env` 并提示迁移。

如果 DeepSeek 账户实际提供的模型 ID 与 Codex 菜单中的别名不同，通过
`DEEPSEEK_FLASH_MODEL` 和 `DEEPSEEK_PRO_MODEL` 映射，不需要修改模型目录。

## 从源码构建

源码开发要求 Node.js 22 或更高版本。发布构建使用项目固定的 Bun 1.3.14。

```bash
npm install
cp config.env.example config.env
npm run dev
```

编译后的 JavaScript：

```bash
npm run build
npm start
```

健康检查：

```bash
curl http://127.0.0.1:15721/health
```

为当前平台构建并验证独立可执行程序：

```bash
npm run release:build
BINARY_PATH=artifacts/codex-deepseek-proxy-darwin-arm64 npm run release:smoke
```

## 配置 Codex

将仓库中的配置合并到 `~/.codex/config.toml`。

也可以将配置保存为 Codex 命名 profile：

```bash
cp deepseek.config.toml ~/.codex/deepseek.config.toml
cp deepseek-model-catalog.json ~/.codex/deepseek-model-catalog.json
codex --profile deepseek
```

使用 profile 时，请将 `model_catalog_json` 改为复制后文件的绝对路径。Codex CLI
的 `--config` 参数只接受 `key=value` 覆盖项，不能接收 TOML 文件路径。

关键配置必须保持：

```toml
[model_providers.deepseek]
base_url = "http://127.0.0.1:15721/v1"
wire_api = "responses"
stream_idle_timeout_ms = 1200000
```

模型列表由 `deepseek-model-catalog.json` 提供。修改模型目录后需要重启 Codex。
DeepSeek 长时间排队或推理时，Codex 和代理的流空闲超时应保持一致；仓库默认均为
20 分钟。

## 校验与未签名程序

每个 GitHub Release 都包含 `SHA256SUMS.txt`。使用前请校验下载的压缩包：

```bash
# Linux
sha256sum codex-deepseek-proxy-*.tar.gz

# macOS
shasum -a 256 codex-deepseek-proxy-*.tar.gz
```

将输出结果与 `SHA256SUMS.txt` 中对应文件的一行进行比较。

首版 macOS 和 Windows 程序未进行正式代码签名。macOS 用户应先校验哈希，再执行：

```bash
xattr -d com.apple.quarantine ./codex-deepseek-proxy
```

Windows SmartScreen 可能需要选择“更多信息 → 仍要运行”。

## 验证

```bash
npm test
npm run check
npm run build
```

维护者发布版本时，先更新并提交 `package.json` 版本，再推送完全对应的标签，例如
`v0.3.0`。标签与包版本不一致时，发布工作流会直接失败。

## 限制

- 仅支持 DeepSeek 官方 Chat Completions 上游，不承诺兼容其他 OpenAI-compatible
  服务，也不包含供应商管理 UI、计费和故障转移。
- DeepSeek V4 是纯文本模型；包含图片的请求会返回明确的 400 错误。
- 工具历史保存在内存中。代理重启后应开启新的 Codex 会话。
- 不完整的流式工具参数会返回 `response.failed`，不会静默执行残缺参数。
- 代理默认只监听 `127.0.0.1`，不应直接暴露到公网。
- 发行程序以前台模式运行，暂不包含后台服务、自启动和自动更新。

## 流式与工具调用语义

- 上游缺少 `[DONE]` 但已发送 `finish_reason` 时，代理仍会正常结束 Responses 流。
- 纯文本流意外结束且已有有效内容时，返回 `status=incomplete`。
- 工具调用缺少 ID、名称或完整 JSON 参数时，整组工具调用返回
  `response.failed`，不会完成其中一部分。
- Codex 只发送 `previous_response_id + function_call_output` 时，代理会从内存历史
  恢复对应 assistant 工具调用及 `reasoning_content`。

## 排障

- 工具执行后无法继续：确认代理未重启，并从新的 Codex 会话重试；历史只保存在
  当前代理进程内。
- 长推理约 5 分钟后中断：确认实际使用的 Codex profile 中
  `stream_idle_timeout_ms` 已更新为 `1200000`。
- 返回 `response.failed`：优先查看事件中的 `error.type`。`stream_truncated`
  表示上游流提前结束，`invalid_tool_arguments` 表示工具 JSON 不完整。

## Attribution

参考来源和许可证见 [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md)。
