诉求
想加一个 provider:Command Code (commandcode.ai,CLI 是 npm 上的 command-code,命令名 cmd)。
先问一句「要不要收」,不是催实现 —— 实现我来 ,想先确认这是否落在项目定位内、以及你要哪个范围。
TL;DR:Command Code 的高价档位本身就是标准 OpenAI/Anthropic API ,接进去价值有限;真正有独家价值的是 $1 Go 档 —— 它没有 API 访问,只能走 CLI 自用的 alpha/generate(自定义 envelope + NDJSON),而这恰好是「上游协议适配」而不是「再做一个 OpenAI 网关」。想问的是:只收 Go 档这层适配,还是整个渠道都收?
上游事实(本机实测,非照抄文档)
认证只有一把 user_… Bearer key,同一个 key 同时用于 CLI 与 API,没有 OAuth、没有浏览器回环、没有 WASM/machineId 。
四个流量面:
Path
协议形状
档位
POST /provider/v1/chat/completions
已是标准 OpenAI Chat Completions
GOAT / Pro / Max / Team / Provider
POST /provider/v1/messages
已是标准 Anthropic Messages
同上
GET /provider/v1/models
标准列表,匿名可访问 (实测 200,15,696 字节;80 个模型,其中 9 个声明 /messages、63 个声明 /responses)
同上
POST /alpha/generate
自定义 envelope(Vercel AI SDK ModelMessage[] + NDJSON,不是 SSE )
任意档位,含 $1 Go 档
两个细节对我们的适配层很关键:
models 每项带 supported_endpoints,Claude 系只有 ["/messages"],非 Anthropic 是 ["/chat/completions","/responses"];把 Claude 发给 /chat/completions 直接 400。这相当于天然的 per-model endpoint 路由 ,形状和 ModelInfo.Scene(feat(trae): PKCE login, scene routing, max-mode tiers; devin quota layout; workbuddy check-in retry #223 刚给 Trae 做的那套 scene routing)完全一致,不需要新机制。
官方也有 /responses,所以 gateway 现有的 /v1/chat/completions、/v1/messages、/v1/responses 三个面在 GOAT+ 档位上基本是薄透传 。
错误分类表同样干净,Classify() 不用猜:401 authentication_error / 403 upgrade_required(Go 档专属) / 422 cmd_zdr_no_providers / 429 rate_limit_error / 5xx server_error。
alpha/generate 的协议已被别人逆向并有可用实现 ,不是我要从零猜:safzanpirani/pi-commandcode-provider(附 docs/wire-protocol.md,含完整 NDJSON 事件表与 usage 口径)、thaolaptrinh/commandcode-api-proxy(37⭐,9 月还在动,npx 直接跑)。所以 B 范围的不确定性主要在「跟版」,不在「能不能通」。
为什么想放进 cli2api,而不是直连
这大概是第一个会被问的问题,先答:
直连官方 API 就能用的场景(单把 GOAT/Pro key)确实不需要这里。动机全部集中在低价档位的「组池」上 :
订阅档位是 5 小时 / 周 / 月三重滚动窗口 (GOAT:$14 / $35 / $70;Go:约 $3 / $6 / $10)。月积分没打满,但 5h 窗口先撞墙是常态 —— 这正是 QuotaWindow + 日/周窗口渲染(feat: show Devin daily and weekly quota windows #208 、v0.6.3)和按模型冷却该解决的问题。
$1 Go 档没有 API 访问 (403 upgrade_required),只能走 alpha/generate。这个 envelope 不对外承诺、客户端专用,恰好属于「上游协议适配」而不是「再做一个 OpenAI 网关」 ;把它翻译成 OpenAI 形状 + 多把 key 组池轮换,是 cli2api 的价值,直连做不到。
客户端侧我这边已有 Qoder/WorkBuddy 一把 key 接 Codex/Claude Code 的习惯,想把这个渠道并进同一个入口、同一套日志和额度视图,不想再多起一个进程。
如果你认为「卖 API 的上游」不符合项目定位(AGENTS.md 里写着调度保持在个人账号路由、不做商业网关特性),这条我完全接受,见最后一节。
实现边界(我打算怎么走,先确认不越线)
按 in-process adapter ,模板是 internal/providers/devin/,不起子进程、不复用 Qoder worker 生命周期:
internal/providers/command/
constants.go # base、paths、CredentialFormat = "command-key-v1"
credential.go # Bearer key 校验
catalog.go # GET /provider/v1/models,把 supported_endpoints 映射成 Scene
payload.go # ChatRequest → alpha/generate 的 config envelope(范围 B 才需要)
chat.go # 非流式 + 流式;错误 → accounts taxonomy
rewrite.go # NDJSON → OpenAI SSE,io.Pipe 自造 http.Response(范围 B)
status.go # 三窗口 QuotaWindow(若上游有额度端点,没有就先只做 used/total)
errors.go # Classify
client.go # Adapter() 组装
既有文件只动三处:providers/registry.go 加 descriptor(RuntimeInProcess、AuthTypes{AuthPAT}、PATLogin: true、Login/Checkin/ImportExport 留 nil)+ registry map + List();app/app.go 里一行 Register();前端 lib/provider.ts / ProviderMark.tsx / AddAccountModal.tsx / i18n/messages.ts,然后 npm run sync。
已确认 AddAccountModal.tsx:181 是 pat_login !== false,所以直接走现成的粘贴 key 页签,不需要新的登录流程 。gateway / console / server / executor / control / runtime 全部不碰,注册只在 app.go —— TestImportConstraints 这关我先本地跑。
想请你定的三件事
范围要 A 还是 B?
A(薄) :只支持 GOAT/Pro/Max/Team/Provider 档,上游已是标准 OpenAI/Anthropic 形状,adapter 主要是贴 header + 按 supported_endpoints 选路 + catalog + 额度。代码量小、漂移风险低,但对「官方已有兼容 API」这个质疑,价值确实主要是组池和统一入口。
B(含 Go 档) :额外逆 alpha/generate(config envelope 字段全必填、messages 是 ModelMessage[] 既非 Anthropic blocks 也非 OpenAI tool messages、响应是 NDJSON 逐行、tool-call 终态用 toolCallId 而 delta 用 id)。真正独家价值,但它是未公开端点,上游改版就得跟版。
我倾向 A 先落地、B 作为独立后续 PR ,但如果你想收的只有 B 的独家能力,我就直接写 B。
x-command-code-version 这类版本耦合放哪? alpha/generate 需要带 CLI 版本号,陈旧会被拒。npm 上 command-code 现在 1.64.0,而协议逆向资料还停在 0.52.1 —— 漂移是真的。我倾向照 worker/src/compat.mjs 的做法:显式钉一个版本 + 不匹配就 fail loudly 并在错误里说清去改哪 ,而不是静默降级。这个约定你觉得 OK 吗(尤其 provider 包里不引 Node 侧 pinned 常量,钉版值放哪合适)?
额度端点要不要一起进范围? 目前没找到公开的「查我的 5h/周/月窗口」端点。如果拿不到,我先只做 catalog + chat,卡片额度显示 unknown(不假装可用),后续再补。这算你能接受的「实现完成但额度验收未完成」状态吗?
我会负责的部分
按 3 个小 PR 走,不甩一个 600 行的:① descriptor + credential + catalog + 非流式;② 流式 + tool roundtrip;③ 前端 + 额度窗口。
每个 PR 带 changelog/unreleased/<slug>.md 双语 fragment,不动 CHANGELOG.md。
测试用脱敏 fixture(照 devin/testdata/devin_models.sample.json 的做法),不提交真实 key / raw capture ;go test ./...、-race、go vet、worker npm test、frontend build+lint、git diff --check 我本地全跑齐再提。
README / README_EN 里和 Devin 同口径标注:experimental,不承诺生产可用。
后续上游漂移的跟版我来做。
如果你近期没精力 review 新渠道,或者觉得这类「上游本身在卖 API」的渠道不该进项目,直接关掉这条就行 —— 我自己 fork 出去维护,将来如果方向和你想的一致再重新提。要不要顺手在 README 的支持列表里加一行,也听你的。
诉求
想加一个 provider:Command Code(
commandcode.ai,CLI 是 npm 上的command-code,命令名cmd)。先问一句「要不要收」,不是催实现 —— 实现我来,想先确认这是否落在项目定位内、以及你要哪个范围。
上游事实(本机实测,非照抄文档)
认证只有一把
user_…Bearer key,同一个 key 同时用于 CLI 与 API,没有 OAuth、没有浏览器回环、没有 WASM/machineId。四个流量面:
POST /provider/v1/chat/completionsPOST /provider/v1/messagesGET /provider/v1/models/messages、63 个声明/responses)POST /alpha/generateModelMessage[]+ NDJSON,不是 SSE)两个细节对我们的适配层很关键:
models每项带supported_endpoints,Claude 系只有["/messages"],非 Anthropic 是["/chat/completions","/responses"];把 Claude 发给/chat/completions直接 400。这相当于天然的 per-model endpoint 路由,形状和ModelInfo.Scene(feat(trae): PKCE login, scene routing, max-mode tiers; devin quota layout; workbuddy check-in retry #223 刚给 Trae 做的那套 scene routing)完全一致,不需要新机制。/responses,所以 gateway 现有的/v1/chat/completions、/v1/messages、/v1/responses三个面在 GOAT+ 档位上基本是薄透传。错误分类表同样干净,
Classify()不用猜:401 authentication_error/403 upgrade_required(Go 档专属) /422 cmd_zdr_no_providers/429 rate_limit_error/5xx server_error。alpha/generate的协议已被别人逆向并有可用实现,不是我要从零猜:safzanpirani/pi-commandcode-provider(附docs/wire-protocol.md,含完整 NDJSON 事件表与 usage 口径)、thaolaptrinh/commandcode-api-proxy(37⭐,9 月还在动,npx 直接跑)。所以 B 范围的不确定性主要在「跟版」,不在「能不能通」。为什么想放进 cli2api,而不是直连
这大概是第一个会被问的问题,先答:
直连官方 API 就能用的场景(单把 GOAT/Pro key)确实不需要这里。动机全部集中在低价档位的「组池」上:
QuotaWindow+ 日/周窗口渲染(feat: show Devin daily and weekly quota windows #208、v0.6.3)和按模型冷却该解决的问题。403 upgrade_required),只能走alpha/generate。这个 envelope 不对外承诺、客户端专用,恰好属于「上游协议适配」而不是「再做一个 OpenAI 网关」;把它翻译成 OpenAI 形状 + 多把 key 组池轮换,是 cli2api 的价值,直连做不到。如果你认为「卖 API 的上游」不符合项目定位(
AGENTS.md里写着调度保持在个人账号路由、不做商业网关特性),这条我完全接受,见最后一节。实现边界(我打算怎么走,先确认不越线)
按 in-process adapter,模板是
internal/providers/devin/,不起子进程、不复用 Qoder worker 生命周期:既有文件只动三处:
providers/registry.go加 descriptor(RuntimeInProcess、AuthTypes{AuthPAT}、PATLogin: true、Login/Checkin/ImportExport留 nil)+registrymap +List();app/app.go里一行Register();前端lib/provider.ts/ProviderMark.tsx/AddAccountModal.tsx/i18n/messages.ts,然后npm run sync。已确认
AddAccountModal.tsx:181是pat_login !== false,所以直接走现成的粘贴 key 页签,不需要新的登录流程。gateway / console / server / executor / control / runtime全部不碰,注册只在app.go——TestImportConstraints这关我先本地跑。想请你定的三件事
supported_endpoints选路 + catalog + 额度。代码量小、漂移风险低,但对「官方已有兼容 API」这个质疑,价值确实主要是组池和统一入口。alpha/generate(config envelope 字段全必填、messages 是ModelMessage[]既非 Anthropic blocks 也非 OpenAI tool messages、响应是 NDJSON 逐行、tool-call终态用toolCallId而 delta 用id)。真正独家价值,但它是未公开端点,上游改版就得跟版。x-command-code-version这类版本耦合放哪?alpha/generate需要带 CLI 版本号,陈旧会被拒。npm 上command-code现在 1.64.0,而协议逆向资料还停在 0.52.1 —— 漂移是真的。我倾向照worker/src/compat.mjs的做法:显式钉一个版本 + 不匹配就 fail loudly 并在错误里说清去改哪,而不是静默降级。这个约定你觉得 OK 吗(尤其 provider 包里不引 Node 侧 pinned 常量,钉版值放哪合适)?我会负责的部分
changelog/unreleased/<slug>.md双语 fragment,不动CHANGELOG.md。devin/testdata/devin_models.sample.json的做法),不提交真实 key / raw capture;go test ./...、-race、go vet、worker npm test、frontend build+lint、git diff --check我本地全跑齐再提。如果你近期没精力 review 新渠道,或者觉得这类「上游本身在卖 API」的渠道不该进项目,直接关掉这条就行 —— 我自己 fork 出去维护,将来如果方向和你想的一致再重新提。要不要顺手在 README 的支持列表里加一行,也听你的。