
【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址https://gitcode.com/gh_mirrors/ope/opencodex点击查看免费下载导读opencodex 是一个通用的 Provider 代理Universal provider proxy允许 Codex CLI、Codex App、SDK 以及 Claude Code 通过统一入口使用 Claude、Gemini、Grok、DeepSeek 等任意 LLM 服务。本篇以开发日志 devlog/_fin/241_umans-provider-cleanup/00_note.md 为骨架完整还原将 Umans AI Coding Plan 接入为 key-login 型 Anthropic 兼容 Provider这一工作包括 Provider 注册条目、模型种子数据、key-login 保存时的运行时元数据保留、以 Anthropic Messages API 形态校验 API Key以及为网关转义内置工具名cx_前缀并在回传前剥离前缀。读完本文你将掌握在 opencodex 中新增/理解一个 Anthropic 兼容 key-login Provider 所需的全部配置要点与底层实现路径。背景PR #14/#19 合并审计中的工作树清理该开发日志记录了一个典型的工程实践场景在PR #14/#19 本地开发合并停机审计local dev merge stop audit过程中工作树里出现了一个与本次合并无关的Umans provider 半成品WIP。虽然 PR #14/#19 的提交本身已经过验证但脏工作树dirty tree意味着 dev 分支尚未为后续的 main 合并决策做好准备——这正是把 Umans 相关的零散改动整理成一个独立、可验证、可合入单元的直接动因。该工作的范围被明确界定为五件事将Umans AI Coding Plan添加为 key-login 型 Anthropic 兼容 Provider在保存 API-key 登录时保留 Provider 运行时元数据模型列表、上下文窗口、输入模态、推理档位、无视觉模型列表等以Anthropic Messages API 形态而非/models列表探测校验 Anthropic 兼容 API Key对需要该能力的网关转义内置工具名并在将工具调用返回给 Codex 前剥离前缀在 README 与 docs-site 各语言文档页中记录新增的 Provider/配置标志。以下各节将逐一对应源码展开。Provider 注册条目Umans 在目录中的完整声明Umans AI Coding Plan 的注册条目位于 src/providers/registry/entries-core.ts{ id: umans, label: Umans AI Coding Plan, adapter: anthropic, baseUrl: https://api.code.umans.ai, authKind: key, featured: true, dashboardUrl: https://app.umans.ai/billing, defaultModel: umans-coder, models: UMANS_MODELS, modelContextWindows: UMANS_MODEL_CONTEXT_WINDOWS, modelInputModalities: UMANS_MODEL_INPUT_MODALITIES, note: Coding plan via Anthropic Messages, modelReasoningEfforts: { umans-coder: UMANS_REASONING_EFFORTS, umans-kimi-k2.7: UMANS_REASONING_EFFORTS, umans-flash: UMANS_REASONING_EFFORTS, umans-glm-5.3: UMANS_GLM_53_REASONING_EFFORTS, umans-glm-5.3-flash: UMANS_GLM_53_REASONING_EFFORTS, umans-glm-5.2: UMANS_GLM_REASONING_EFFORTS, umans-glm-5.1: UMANS_GLM_REASONING_EFFORTS, umans-qwen3.6-35b-a3b: UMANS_REASONING_EFFORTS, }, noVisionModels: UMANS_TEXT_ONLY_MODELS, escapeBuiltinToolNames: true, },逐字段解读字段值含义adapteranthropic走 Anthropic Messages 适配器上游端点按/v1/messages处理authKindkeykey-login 型 Provider通过粘贴 API Key 登录而非 OAuth 设备码流程featuredtrue在 GUI Add provider 选择器中置顶展示defaultModelumans-coder默认模型同时作为 API Key 校验时探测的模型baseUrlhttps://api.code.umans.aiUmans 网关地址docs-site 的 provider 汇总表也收录了该地址见 docs-site/src/content/docs/guides/providers.mddashboardUrlhttps://app.umans.ai/billing用量/账单控制台escapeBuiltinToolNamestrue触发内置工具名转义逻辑详见下文工具名转义一节注意modelReasoningEfforts是按模型配置的GLM 家族与 Kimi/通用模型使用不同的推理档位集合说明网关对同系列不同模型开放的reasoning effort档位并不一致——注册时不能一刀切。模型种子数据Umans 的完整模型目录Umans 的模型清单与元数据集中在 src/providers/registry/model-seeds.tsexport const UMANS_MODELS [ umans-coder, umans-kimi-k2.7, umans-flash, umans-glm-5.3, umans-glm-5.3-flash, umans-glm-5.2, umans-glm-5.1, umans-qwen3.6-35b-a3b, ]; export const UMANS_REASONING_EFFORTS [low, medium, high, xhigh, max]; export const UMANS_GLM_REASONING_EFFORTS [high, xhigh, max]; // 260814: Z.AI folds GLM-5.3 efforts into low/high/maxlow 是真实档位xhigh 与 max 不区分 export const UMANS_GLM_53_REASONING_EFFORTS [low, high, max]; // umans-glm-5.3-flash 不在此列Z.AI 将其列为 VLM 文档原生支持图像 export const UMANS_TEXT_ONLY_MODELS [umans-glm-5.3, umans-glm-5.2, umans-glm-5.1]; export const UMANS_MODEL_CONTEXT_WINDOWS: Recordstring, number { umans-coder: 262_144, umans-kimi-k2.7: 262_144, umans-flash: 262_144, umans-glm-5.3: 405_504, umans-glm-5.3-flash: 405_504, // 与同系列兄弟模型一致Umans 未单独公布 flash 档位 umans-glm-5.2: 405_504, umans-glm-5.1: 202_752, umans-qwen3.6-35b-a3b: 262_144, }; export const UMANS_MODEL_INPUT_MODALITIES: Recordstring, string[] Object.fromEntries( UMANS_MODELS.map(id [id, UMANS_TEXT_ONLY_MODELS.includes(id) ? [text] : [text, image]]), );几个值得注意的细节源码注释直接印证上下文窗口并非统一GLM-5.x 系列为 405,504 token其中 GLM-5.1 为 202,752其余模型统一 262,144 token。若注册时给所有模型套同一个窗口Codex 侧会按保守的 128k 兜底从而浪费真实可用上下文——这正是该数据被显式声明的意义。umans-glm-5.3-flash不在纯文本列表Z.AI 将 glm-5.3-flash 文档化在 VLM 指南下原生接受图像因此不需要走代理的视觉 sidecar。源码注释还诚实记录了一次seed 分类按家族名误判、后续只修正了部分 Provider的教训。输入模态按模型推导非纯文本模型默认[text, image]纯文本模型为[text]。该推导式Object.fromEntries(...)在测试中同样被断言例如modelInputModalities[umans-glm-5.2]必须等于[text]。key-login 保存运行时元数据如何被完整保留这是本工作的核心工程点通过 CLI 以 API Key 登录并保存 Provider 行时绝不能丢目录中声明的运行时元数据。实现位于 src/oauth/login-cli.ts 的providerConfigFromKeyLoginProviderexport function providerConfigFromKeyLoginProvider(def: KeyLoginProvider, key: string, baseUrlOverride?: string): OcxProviderConfig { return { adapter: def.adapter, baseUrl: baseUrlOverride ?? def.baseUrl, apiKey: key, ...(def.apiKeyTransport ! undefined ? { apiKeyTransport: def.apiKeyTransport } : {}), ...(def.defaultModel ? { defaultModel: def.defaultModel } : {}), ...(def.models ? { models: [...def.models] } : {}), ...(def.contextWindow ! undefined ? { contextWindow: def.contextWindow } : {}), ...(def.modelContextWindows ? { modelContextWindows: { ...def.modelContextWindows } } : {}), ...(def.modelMaxInputTokens ? { modelMaxInputTokens: { ...def.modelMaxInputTokens } } : {}), ...(def.defaultMaxOutputTokens ! undefined ? { defaultMaxOutputTokens: def.defaultMaxOutputTokens } : {}), ...(def.modelMaxOutputTokens ? { modelMaxOutputTokens: { ...def.modelMaxOutputTokens } } : {}), ...(def.modelInputModalities ? { modelInputModalities: cloneRecordOfArrays(def.modelInputModalities) } : {}), ...(def.reasoningEfforts ? { reasoningEfforts: [...def.reasoningEfforts] } : {}), ...(def.modelReasoningEfforts ? { modelReasoningEfforts: cloneRecordOfArrays(def.modelReasoningEfforts) } : {}), ...(def.reasoningEffortMap ? { reasoningEffortMap: { ...def.reasoningEffortMap } } : {}), ...(def.modelReasoningEffortMap ? { modelReasoningEffortMap: cloneNestedRecord(def.modelReasoningEffortMap) } : {}), ...(def.noVisionModels ? { noVisionModels: [...def.noVisionModels] } : {}), ...(def.noReasoningModels ? { noReasoningModels: [...def.noReasoningModels] } : {}), ...(def.noTemperatureModels ? { noTemperatureModels: [...def.noTemperatureModels] } : {}), ...(def.noTopPModels ? { noTopPModels: [...def.noTopPModels] } : {}), ...(def.noPenaltyModels ? { noPenaltyModels: [...def.noPenaltyModels] } : {}), ...(def.autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels: [...def.autoToolChoiceOnlyModels] } : {}), ...(def.preserveReasoningContentModels ? { preserveReasoningContentModels: [...def.preserveReasoningContentModels] } : {}), ...(def.requiresReasoningPlaceholderModels ? { requiresReasoningPlaceholderModels: [...def.requiresReasoningPlaceholderModels] } : {}), ...(def.escapeBuiltinToolNames ! undefined ? { escapeBuiltinToolNames: def.escapeBuiltinToolNames } : {}), }; }三个值得展开的实现要点① 全程防御性拷贝defensive clone数组字段用[...arr]普通记录用{ ...record }嵌套数组记录用cloneRecordOfArrays深层嵌套用cloneNestedRecord。这是刻意的设计——保存的 Provider 行是独立快照此后修改其models、modelContextWindows等字段不得反向污染目录里的共享常量。测试umans-provider.test.ts中专门验证了这一点对 OpenAI API-key 条目克隆出的modelMaxInputTokens写入新值后源对象source.modelMaxInputTokens[gpt-5.6-sol]仍保持 922_000。② 保留apiKeyTransport某些 Anthropic 兼容网关要求Authorization: Bearer而非x-api-key。字段存在即透传测试CLI key-login save payload preserves apiKeyTransport when configured用{...KEY_LOGIN_PROVIDERS.umans, apiKeyTransport: bearer}验证保存后仍为bearer。③ 保留空数组语义requiresReasoningPlaceholderModels若为显式[]用户主动关闭占位策略展开后仍是[]而不是被undefined吞掉导致回退默认策略。测试用[deepseek-reasoner]与[]两种预设分别断言两者都原样保留。保存时的 operator 字段合并providerConfigFromKeyLoginProvider产出的是预设行而落盘时还需与既有行合并避免把 operator 手动配置的字段覆盖掉。同一文件中的 mergeKeyLoginProviderRow 目前专门保留modelCosts覆盖用户配置的模型成本估算这样轮换 API Key 不会静默把 Logs/Usage 的成本估算回退成目录价格随后 commitKeyLoginProvider 把合并行写盘并推送给运行中的代理保证磁盘配置与运行时代理配置不产生漂移。API Key 校验改用 Anthropic Messages 形态而非/models传统 OpenAI 兼容 Provider 的 Key 校验方式是GET /models探测。但 Anthropic 兼容网关如 Umans用/models往往拿不到有效的鉴权语义因此 src/oauth/key-providers.ts 的validateApiKey对adapter anthropic走专用分支if (provider.adapter anthropic) { const base provider.baseUrl.replace(/\/v1\/?$/, ); const res await fetch(${base}/v1/messages, { method: POST, headers: anthropicKeyValidationHeaders(provider, key), body: JSON.stringify({ model: provider.defaultModel ?? claude-haiku-4-5, max_tokens: 1, messages: [{ role: user, content: ping }], }), redirect: error, signal: AbortSignal.timeout(8000), }); if (res.ok) return true; if (res.status 401 || res.status 403) return false; return unknown; }要点请求形态POST {base}/v1/messagesbody 为最小 Messages 请求——model缺省回退claude-haiku-4-5、max_tokens: 1、单条userping 消息。8 秒超时禁止跟随重定向。三态结果ok → true401/403 → false其他状态码返回unknown保持尽力而为的登录流程可用但不把不确定的结果写成验证通过。无状态语义函数开头的provider.apiKeyValidation unknown早退同样返回unknown——公共模型目录无法证明某个 Key 有效时不产生假阳性。传输方式可切换anthropicKeyValidationHeaders根据apiKeyTransport选择x-api-key: key或Authorization: Bearer key。测试 tests/providers/umans-provider.test.ts 对两种模式均有断言默认模式请求头含x-api-key且无authorizationbearer模式则相反且都携带anthropic-version: 2023-06-01。内置工具名转义cx_前缀的上线与回传剥离这是 Umans 条目escapeBuiltinToolNames: true的底层实现位于 src/adapters/anthropic.ts 与 buildToolNameTransformsconst COMPAT_TOOL_PREFIX cx_; function buildToolNameTransforms(provider: OcxProviderConfig): { toWire: (name: string) string; fromWire: (name: string) string } { if (provider.authMode oauth) { return { toWire: applyClaudeToolPrefix, fromWire: stripClaudeToolPrefix }; } if (provider.escapeBuiltinToolNames true) { return { toWire: (name) name.startsWith(COMPAT_TOOL_PREFIX) ? name : COMPAT_TOOL_PREFIX name, fromWire: (name) name.startsWith(COMPAT_TOOL_PREFIX) ? name.slice(COMPAT_TOOL_PREFIX.length) : name, }; } return { toWire: (name) name, fromWire: (name) name }; }为什么需要转义部分 Anthropic 兼容网关会保留一组同名的内置工具如web_search。如果 opencodex 把 Codex 侧的web_search原样发给该网关网关可能无法区分来自客户端的工具声明与自身内置工具导致冲突或工具调用异常。cx_前缀相当于命名空间隔离上行时给工具名加前缀幂等已带前缀的不重复加下行解析工具调用时再剥掉前缀把干净的web_search交还给 Codex。测试如何验证这条链路tests/providers/umans-provider.test.ts 用 mock fetch/流式响应完整覆盖了该行为请求构造buildRequest后断言req.url https://api.code.umans.ai/v1/messages、POST、x-api-key生效、anthropic-beta缺省请求体中工具名已变为cx_web_searchtool_choice同步为{ type: tool, name: cx_web_search }system 提示中含Valid tool names for this turn are exactly \cx_web_search.。Responses 风格 allowed_tools 过滤两个工具web_search与run_tests仅allowedTools: [web_search]时上行tools只剩cx_web_searchtool_choice归一为{ type: any }。流式回传剥离mock SSE 流中content_block_start携带name: cx_web_search解析出的首个事件必须是{ type: tool_call_start, id: toolu_1, name: web_search }前缀已剥离。非流式回传剥离parseResponse对 JSON 响应中tool_use块做同样处理且最终必须产出done事件。模型成本与推理档位语义的严谨性Umans 条目中还体现了一类证据边界纪律umans-glm-5.3-flash的上下文窗口直接复用同系列兄弟模型的 405,504源码注释明确说明Umans 没有单独公布 flash 档位断言一个不同的数字就是猜测。同理GLM-5.3 的档位按 Z.AI 最新文档折叠为[low, high, max]并注明日期。这类宁可镜像已知事实、不虚构未知数据的处理方式是 Provider 目录维护中值得借鉴的准则。验证命令与文档同步该工作收尾时通过以下命令门禁见 00_note.mdbun run typecheck bun test tests/umans-provider.test.ts tests/provider-registry-parity.test.ts bun test tests bun run build:guitests/umans-provider.test.ts是本次新增的专项测试上文各节引用的断言均出自于此tests/providers/provider-registry-parity.test.ts用于保证目录条目与其他来源如 models.dev 同步数据、上游模型元数据的一致性全量bun test tests与bun run build:gui防止该改动波及 GUI 构建与既有测试。文档同步方面Provider 汇总表已在 docs-site/src/content/docs/guides/providers.md 及各语言页fr/ja/ko/ru/tr/zh-cn/zh-tw 对应文件登记 Umans 的 base URLGUI 侧featured: true让该条目在 Add provider 选择器置顶展示。README 亦同步记录新增 Provider 与escapeBuiltinToolNames配置标志方便新用户直接搜索到。小结从一次合并审计中揪出的无关 WIP到最终落地的完整 Provider 支持241_umans-provider-cleanup展示了 opencodex 接入 Anthropic 兼容 key-login Provider 的标准姿势目录注册entries-core.ts→ 模型种子model-seeds.ts→ key-login 元数据保留login-cli.ts→ Messages 形态 Key 校验key-providers.ts→ 工具名转义anthropic.ts→ 专项测试与文档同步。对想要理解或新增类似 Provider 的读者沿着umans字符串在 src/providers/registry/entries-core.ts、src/providers/registry/model-seeds.ts、src/oauth/login-cli.ts、src/oauth/key-providers.ts 与 src/adapters/anthropic.ts 中的引用链即可复现这条完整的接入路径。赞分享【免费下载链接】opencodexUniversal provider proxy for OpenAI Codex Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code项目地址https://gitcode.com/gh_mirrors/ope/opencodex点击查看免费下载相关推荐DeepSeek Harness Workspace 注册删除深度解析仅删除注册记录、保留数据的安全语义设计DeepSeek Harness Workspace 注册删除深度解析仅删除注册记录、保留数据的安全语义设计 导读 本文聚焦 DeepSeek Harness人工智能AI AgentAgent 框架DeepSeekCargo Login 命令完全指南注册表认证令牌的保存与 Credential Provider 机制Cargo Login 命令完全指南注册表认证令牌的保存与 Credential Provider 机制 cargo login 是 CargoThe Ru开发工具包管理器CLI构建工具OpenSSL EVP_SKEY 元数据机制为 PKCS12 对称密钥保留别名、Local Key ID 与算法标识OpenSSL EVP_SKEY 元数据机制为 PKCS 12 对称密钥保留别名、Local Key ID 与算法标识 OpenSSL 正在将对称密钥纳入 P密码学网络安全通信创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考