Skip to content

feat(command): 新增实验性 Command Code 渠道(走 CLI 的 /alpha/generate,支持所有档位) - #230

Merged
caigee-cmd merged 5 commits into
caigee-cmd:mainfrom
BrianBoyCN:feat/command-code-go-provider
Sep 25, 2026
Merged

caigee-cmd merged 5 commits into
caigee-cmd:mainfrom
BrianBoyCN:feat/command-code-go-provider

Conversation

@BrianBoyCN

@BrianBoyCN BrianBoyCN commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Refs #226

概述

新增实验性 Command Code(commandcode.ai)in-process 渠道,模板参照 Devin 适配器(不起子进程、不复用 worker 生命周期)。

Command Code 有三个生成面:

路径 协议形状 档位
POST /provider/v1/messages 标准 Anthropic Messages 仅 Pro+
POST /provider/v1/chat/completions 标准 OpenAI Chat Completions 仅 Pro+
POST /alpha/generate CLI 自用 envelope 任意档位

$1 Go 档下两个 /provider/v1/* 生成路径返回 403 upgrade_required;/alpha/generate 是 cmd CLI 每轮都在用的端点、不受档位限制,因此适配层始终走它 —— 所有档位都能用,且覆盖整个模型目录。属于「上游协议适配」,不是再造一个 OpenAI 网关。

具体实现:

  • 认证:仅一把 user_… Bearer key(CLI 与 API 共用,无 OAuth / 回环 / device seed)。复用现有 PAT 页签粘贴;control.LoginPAT 为 in-process 适配器补齐 login/pat,因此不需要新登录流程,Qoder 的 worker 路径不受影响。
  • 模型目录:GET /provider/v1/models(匿名可读),带 TTL 缓存。
  • 聊天:请求转换为严格的 config envelope + Vercel AI SDK ModelMessage[](tool-call / tool-result / role:"tool",既非 Anthropic blocks 也非 OpenAI tool messages);非流式聚合;NDJSON → OpenAI SSE 流式改写;tool 往返(含 id 与 toolCallId 的坑);inputTokens 含缓存 token 的口径处理。
  • 错误分类:映射到 accounts taxonomy(upgrade_required → invalid_request、insufficient_credit → quota、401 → auth …)。
  • 用量:GET /alpha/billing/credits —— 由 planId 推导的月套餐窗口,以及滚动的 5 小时 / 周 windowLimits;另有 /alpha/whoami 就绪探针。
  • 推理:仅对已验证支持 reasoning_effort 的模型(DeepSeek V4 Pro/Flash)声明档位,适配层绝不自行注入档位。

版本耦合:/alpha/generate 未公开且以 x-command-code-version 为键,故 CLI 版本在 constants.go 中钉死,不匹配时明确报错(可用 CMD_CLI_VERSION 覆盖)。

架构:只新增一个包 + descriptor/注册,app.go 一行,外加 control 里一个小的 login/pat 分支。未改动 gateway / console / server / executor / store / runtime;internal/providers/command 不引入任何被禁包(TestImportConstraints 通过,command 已加入 concrete-provider 守卫)。协议事实来自 safzanpirani/pi-commandcode-provider(MIT),出处见 internal/providers/command/NOTICE。

实验性 —— /alpha/generate 未公开、可能漂移,不承诺生产可用。

Test plan

  • go test ./...
  • go vet ./...
  • cd worker && npm test
  • cd frontend && npm run build && npm run lint
  • 已添加 changelog/unreleased/command-code-provider.md,或本 PR 无用户可见变更
  • diff 中无 token、鉴权 blob、原始抓包或主机信息

本地另跑:go test -race ./...、TestImportConstraints / TestDutyBoundaries、release-notes.py validate、gitleaks(无发现)、Windows/arm64 交叉编译。新增单测覆盖凭证导入、目录解析、envelope/消息转换、NDJSON 聚合、SSE 改写、错误分类与额度窗口。

真账号验收已完成:本分支已构建为镜像在本地单容器部署(v0.6.5-command-test3),用真实 Go 档 user_… key 完成多轮长对话实测,流式、工具往返、长上下文与版本头(x-command-code-version)均正常。仍保留 experimental 标注,原因是 /alpha/generate 为未公开端点、存在漂移风险,与验收无关。

BrianBoyCN and others added 2 commits September 24, 2026 10:27
Command Code's /provider/v1/messages and /provider/v1/chat/completions
require the Pro plan or higher and return 403 upgrade_required on the $1 Go
plan. /alpha/generate is the undocumented envelope the `cmd` CLI itself uses
on every turn; it is not plan-gated and serves the whole model catalog, so
this adapter always speaks it.

- internal/providers/command: in-process adapter (constants, credential,
  catalog, payload -> Vercel ModelMessage[] envelope, chat non-stream +
  NDJSON->SSE stream rewrite, errors -> accounts taxonomy, probe via
  /alpha/whoami, credits via /alpha/billing/credits). Modelled on the Devin
  adapter; imports no executor/store/HTTP packages.
- registry + app: register the global in-process descriptor (PAT auth).
- control: LoginPAT wires the existing paste-key tab for in-process PAT
  adapters (Qoder keeps its worker login path).
- frontend: provider mark, labels/hints, PAT-tab default for a provider with
  no browser login.
- README/AGENTS/CONTRIBUTING + bilingual changelog fragment.

The /alpha/generate schema is strict and version-coupled (x-command-code-
version), so the CLI version is pinned and fails loudly rather than degrading
silently. Reasoning is only advertised for models with verified
reasoning_effort support (DeepSeek V4 Pro/Flash). Experimental; not
production-ready.

Protocol facts derived from safzanpirani/pi-commandcode-provider (MIT); see
internal/providers/command/NOTICE.
The credits endpoint returns the rolling usage windows at the response root
(`windowLimits.fiveHour` / `windowLimits.weekly` with `used`/`cap`/`resetAt`)
plus `credits.planId`. The adapter ignored both, so the account card showed a
single monthly meter pinned at 0%.

- Parse `windowLimits` -> 5-Hour Limit and Weekly Limit windows (used/cap
  percentage, millisecond resetAt -> reset countdown), with a nested fallback if
  the shape moves into `credits`.
- Derive the Monthly Limit window from `planId` via the same plan allowance
  table the CLI uses (go 10 / goat 70 / pro 30 / pro-v1 80 / provider 15 /
  max 150 / ultra 300 / teams-pro 40); unknown plans leave it unset rather than
  fabricating a total.
- Label: the provider speaks the CLI's /alpha/generate protocol, which is not
  plan-gated and works on every plan, so drop the "(Go plan)" suffix from the
  account type, hints, README, and changelog.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@BrianBoyCN

BrianBoyCN commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

关联 #226 —— 本 PR 落实了那里的范围问题:直接实现 /alpha/generate 这条路。它是唯一有独家价值的部分(Go 档唯一可用的生成面,且不受档位限制)。如果你更想分批评审,我可以拆成三支:descriptor+credential+catalog+非流式、流式+tool 往返、前端+额度。

@BrianBoyCN BrianBoyCN changed the title feat(command): add experimental Command Code provider via /alpha/generate feat(command): 新增实验性 Command Code 渠道(走 CLI 的 /alpha/generate,支持所有档位) Sep 24, 2026
@BrianBoyCN

Copy link
Copy Markdown
Contributor Author

补充:真账号验收已完成。本分支已构建并部署为本地单容器实例(版本号 v0.6.5-command-test3,即本 PR 的 a6c4b5f),用真实 Go 档 user_… key 跑了多轮长对话,/alpha/generate 的流式、工具往返、长上下文以及 x-command-code-version: 1.65.0 版本头均正常。所以 PR 描述里"验收待定"一条已移除;experimental 标注保留,是针对未公开端点的漂移风险,不是验收状态。

BrianBoyCN and others added 2 commits September 24, 2026 11:48
The cross-provider pool lets a client pin a provider with a leading
"<provider>/" model id, but ProviderPrefix() only knew qoder/workbuddy/trae/
devin. A "command/deepseek/deepseek-v4-pro" request therefore never had its
prefix stripped, could not match the command catalog, and failed with
"model route unavailable" — even though the account was ready and the model
was listed.

- Add command/ to the prefix set (and the console's model-setting prefix
  parser), with a regression test that also asserts a bare org-namespaced id
  ("deepseek/…", "moonshotai/…") is not misread as a provider.
- Refresh the provider-prefix hint in both locales.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
A real /alpha/generate stream sends two terminal events: `finish-step` with
`usage`, then `finish` with `totalUsage` (no `usage`). Both hit the same
switch arm, so handling `finish` set usage from a nil `event.Usage` and wiped
the numbers from `finish-step`. Streaming requests — all real traffic —
therefore recorded no prompt/completion/cache tokens at all.

- Read `usage` with a `totalUsage` fallback, and never overwrite a known
  usage with nil, in both the SSE writer and the non-stream aggregate.
- Regression tests for finish-step+finish, finish-only, and the SSE usage
  chunk.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@BrianBoyCN

Copy link
Copy Markdown
Contributor Author

补充:用真实 Go 档账号跑下来发现并修了两个只有实测才会暴露的问题(均已补回归测试):

  1. command/ 前缀路由失败(ed22072):跨渠道模型池下,客户端发 command/deepseek/deepseek-v4-pro 时,executor.ProviderPrefix() 的前缀白名单只有 qoder/workbuddy/trae/devin,前缀没被剥离 → 落到 model route unavailable。已补 command/,并加断言防止把裸的组织命名空间 id(deepseek/…、moonshotai/…)误判成 provider。

  2. 流式用量全部丢失(11af021):真实 /alpha/generate 一次响应会发两个终态事件 —— finish-step(带 usage)和 finish(带 totalUsage,无 usage)。两者落进同一个 switch 分支,处理 finish 时用 nil 覆盖了刚拿到的用量,导致所有流式请求(即全部真实流量)的 prompt/completion/cache token 都没记录。已改为 usage 优先、totalUsage 兜底,且不用 nil 覆盖已知值。

实测验证后,request_logs 里 command 渠道的用量已正常(例如 prompt_tokens=411301 / completion_tokens=381 / cache_read_tokens=410880 / usage_source=upstream,与 inputTokens 含缓存的 Vercel 口径一致)。

这两条也正是"实验性、未公开端点"风险的体现,PR 描述里的 experimental 标注依然成立。

@BrianBoyCN

Copy link
Copy Markdown
Contributor Author

新增的 ed22072 / 11af021 两个提交会重新触发 CI,但来自 fork 的推送需要重新批准一次才会跑(上一个 run 35951038614 是批准后全绿的)。麻烦再点一次 Approve and run。本地对应校验我都过了:go test ./...、-race、go vet、frontend build+lint、gitleaks 均绿。

@caigee-cmd
caigee-cmd merged commit 0c0f6d0 into caigee-cmd:main Sep 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants