[技术调研] 借鉴 OpenCodex 补齐多协议 provider adapter 与请求级诊断
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 401
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
## 背景
调研项目:[lidge-jun/opencodex](https://github.com/lidge-jun/opencodex),代码快照为 `165f1a83a89e6d31084f012f9663e221fd2d6ab8`(2026-07-21)。
OpenCodex 不是另一个 agent framework,而是放在 Codex / Claude Code 前面的本地多协议网关:
- 以 OpenAI Responses 作为 Codex 入站协议;
- 用少量 adapter 转到 Anthropic Messages、Google Gemini、Azure、OpenAI Responses、OpenAI Chat Completions;
- 通过数据化 provider preset 支撑 40+ 上游;
- 同时提供模型目录、OAuth/API Key、请求日志、TTFT、tok/s、费用估算和部分账号池能力。
调研时项目创建约一个月,已有约 900 stars、5k/周 npm 下载,main 跨平台 CI 通过;但主要贡献高度集中、发版频率很高,仍属于快速演进项目。
**结论:不建议把 OpenCodex 作为 Cindy 的运行时依赖或直接 fork;最值得借鉴的是“少量 wire adapter + 数据化 provider preset”以及请求级可观测性。**
## 与 Cindy 当前能力的对照
Cindy 已有较好的基础:
- `@lizi/model-providers` 已把 provider、per-runtime 模型、鉴权和路由收敛为 SSoT;
- 自定义供应商已有 per-runtime base URL、模型发现、API Key / 通用 OAuth、测试连接;
- `anthropic-compat-proxy` 已支持 per-request route、字段恢复、SSE 透明转发;
- `anthropic-responses-bridge` 已完整处理 Anthropic Messages → OpenAI Responses,包括 tool、reasoning、usage 和 SSE 时序;
- Codex 使用隔离 `CODEX_HOME` 和进程级 `-c` override,不修改用户全局 `~/.codex`,这一点应保持。
当前最明确的缺口:
1. [`BridgeWireProtocol`](https://github.com/makecindy/cindy-temp/blob/main/packages/anthropic-responses-bridge/src/types.ts#L136-L164) 目前只有 `openai-responses`,源码已经明确预留但尚未实现 `openai-chat`。
2. [`CustomProviderRuntimeConfig`](https://github.com/makecindy/cindy-temp/blob/main/packages/model-providers/src/types.ts#L364-L381) 没有显式 wire protocol;协议由 runtime 隐式决定:
- Claude Code 默认假设 Anthropic Messages;
- Codex 默认假设 OpenAI Responses。
3. [provider connection probe](https://github.com/makecindy/cindy-temp/blob/main/apps/desktop/src/main/maker-host/provider-diagnostics.ts#L72-L113) 同样固定为 `/v1/messages` 或 `/responses`。
4. 现有 `UsageTracker` 和 session cost 能回答“会话用了多少”,但还不能让用户快速回答“这次请求最终路由到哪里、首 token 多久、为什么重试/失败”。
相关现有问题:
- makecindy/cindy#98:LiteLLM provider-specific 字段导致续请求协议不兼容;
- makecindy/cindy#101:自定义供应商模型缺少 capability 护栏。
这两个问题都说明 provider 接入正在从“能转发”进入“需要明确协议和能力契约”的阶段。
## 建议路线
### P0:显式建模 upstream wire protocol,并优先补 `openai-chat`
给 `CustomProviderRuntimeConfig` / `RoutingDescriptor` 增加可选 `wireProtocol`,建议初始取值:
- `anthropic-messages`
- `openai-responses`
- `openai-chat`
兼容默认值保持现状:
- `claude-code` 缺省为 `anthropic-messages`;
- `codex` 缺省为 `openai-responses`。
第一阶段只实现 Codex Responses → OpenAI Chat Completions adapter,即可让现有自定义 provider/preset 直接覆盖大量只提供 Chat Completions 的端点,例如 Ollama、vLLM、部分 OpenRouter/LiteLLM/DeepSeek/Groq 配置。
实现原则:
- adapter 负责构造上游请求,并把上游流解析为中性的 text / thinking / tool lifecycle / usage / error 事件;
- 保证 parallel tool-call delta、取消、断流和错误状态不丢失、不乱序;
- 先以 sibling adapter 落地,不为“统一”立即重写现有 bridge;
- 等第二个 adapter 稳定后,再判断是否提取共享 request/event IR。
### P1:增加 provider 请求级诊断
在 main 进程维护有上限的 request ring buffer;聚合数据需要长期展示时再追加持久化层。
建议记录:
- agent runtime / provider / selected model;
- 最终 resolved upstream(展示时脱敏);
- HTTP 状态、结构化错误类别;
- TTFT、总耗时;
- recovery / retry / failover 原因;
- usage 是 reported、estimated 还是 unavailable;
- cache read / write(上游有报告时)。
默认禁止记录:
- prompt / message 正文;
- Authorization、API Key、OAuth token;
- 完整原始响应体;
- 可识别账号身份。
用户侧目标是能在设置页或会话错误详情里直接回答:“请求去了哪里、卡在哪一阶段、为什么失败”。
### P1:建立跨 provider 协议兼容 fixture 矩阵
至少覆盖:
- 并行 tool-call delta 交错;
- tool call / tool result 悬空或被用户消息打断;
- provider 私有 reasoning signature 跨 provider 隔离;
- headers 已开始发送后的流式错误;
- SSE 意外 EOF、stall watchdog、client cancel;
- 图片输入与结构化输出;
- usage/cache 字段缺失或不同语义;
- 上游 400 恢复后不得无限重试。
OpenCodex 可作为案例来源和差分参照,但测试应按 Cindy 自己的契约重写,不直接绑定其内部实现。
### P2:显式 capability fallback
OpenCodex 用 sidecar 给不支持搜索/图片的模型补能力。Cindy 可以结合现有 `CatalogModel.modalities/capabilities` 做显式 fallback planner,但必须满足:
- 用户知道内容会发送到第二个模型;
- 明确额外费用和隐私边界;
- 能关闭;
- 不靠 prompt 自行判断路由。
这不是当前优先级,应在协议和诊断面稳定后再评估。
## 明确不做
- 不引入 OpenCodex 的 Bun daemon / 系统 service;
- 不让第三方组件修改全局 `~/.codex`;
- 暂不实现 ChatGPT 多账号池、额度轮转或共享订阅;
- 不照搬依赖隐藏参数、prompt 注入或客户端内部 wire hack 的跨模型 sub-agent 方案;
- 不按 provider 名称逐个硬编码特例,继续坚持“少量 adapter + 数据化 preset”。
OpenCodex 自身的 [#92](https://github.com/lidge-jun/opencodex/issues/92) 仍受 Codex 加密任务体限制,说明跨 provider 的客户端内部协议 hack 很脆弱;Cindy 仍应优先用代码和显式契约保证确定性。
## 建议拆分
这是调研/架构 umbrella issue,实施时至少拆为:
1. `wireProtocol` 类型、持久化兼容与设置 UI;
2. Codex Responses → OpenAI Chat adapter;
3. adapter 流式/工具/reasoning/错误 fixture;
4. provider request diagnostics 数据模型与 main 侧采集;
5. 用户可见诊断 UI;
6. capability fallback 的独立产品评估。
## 第一阶段验收建议
- 老自定义供应商无迁移操作即可继续使用;
- 新建 Codex 自定义供应商可选择 `OpenAI Responses` 或 `OpenAI Chat Completions`;
- OpenAI Chat provider 能完成文本、流式输出、单/并行工具调用、usage 和错误映射;
- client cancel 能中止上游;
- reasoning/tool 私有状态不会跨 provider 回放;
- 不记录 prompt 或密钥;
- 现有 Responses / Anthropic 路径行为不回退。
## 参考
- [OpenCodex system overview](https://github.com/lidge-jun/opencodex/blob/165f1a83a89e6d31084f012f9663e221fd2d6ab8/structure/00_overview.md)
- [OpenCodex transports and sidecars](https://github.com/lidge-jun/opencodex/blob/165f1a83a89e6d31084f012f9663e221fd2d6ab8/structure/04_transports-and-sidecars.md)
- [OpenCodex normalized AdapterEvent](https://github.com/lidge-jun/opencodex/blob/165f1a83a89e6d31084f012f9663e221fd2d6ab8/src/types.ts#L192-L238)
Contributor guide
Research direction
This is an architecture umbrella issue, not a single newcomer-sized task. Start with packages/anthropic-responses-bridge/src/types.ts, packages/model-providers/src/types.ts, and apps/desktop/src/main/maker-host/provider-diagnostics.ts, then review the six proposed implementation tracks. Done means splitting the work into focused issues with their own tests and acceptance criteria, while preserving existing protocol behavior and avoiding prompt or credential logging.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, observability, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100