Files
cpa-plugin/docs/operations.md
T

228 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLIProxyAPI 升级、构建与部署记录
## 当前基线
| 项目 | 当前值 |
|---|---|
| CLIProxyAPI Tag | `v7.2.135` |
| submodule 提交 | `ee2c494788f8a089c58f7ae9aa6ebd1b422211cb` |
| patched 构建版本 | `v7.2.135-dev` |
| Native ABI | `1` |
| RPC schema | `4` |
| Go | `1.26.6` |
| 本地运行目录 | `.runtime` |
| 本地管理页面 | `http://127.0.0.1:8317/management.html` |
| 远端目录 | `root@akko.pchuan.top:/root/cpa` |
DeepSeek 必须配置在 CPA 的 `codex-api-key` 通道,`base-url` 使用 `https://api.deepseek.com`。不要把该凭证配置为 `openai-compatibility`。Windows Codex CLI 连接本地 CPA 时,provider 的 `base_url` 使用 `http://127.0.0.1:8317/v1``wire_api` 使用 `responses`
当前本地测试状态保存在被 Git 忽略的 `.runtime`
- CPA 配置:`.runtime/config.yaml`
- billing 数据库:`.runtime/data/billing.db`
- 管理 Key 和默认下游 Key`000000`
- 测试模型:`deepseek-v4-flash`
- 默认额度:`$10`,最大并发数:`4`
- 当前价格是本地验收价格,不作为生产价格依据。
升级宿主或插件时保留配置和数据库,不重复初始化 Key、价格和额度。
## 已知上游测试失败
CLIProxyAPI `ee2c4947` 在 Debian WSL 中运行 `go test ./... -count=1` 时有以下失败:
| 测试 | 实际值 | 期望值 |
|---|---|---|
| `TestApplyClaudeHeaders_DisableDeviceProfileStabilization` | `X-Stainless-Os=MacOS` | `Linux` |
| `TestApplyClaudeHeaders_LegacyModePreservesConfiguredUserAgentOverrideForClaudeClients` | `X-Stainless-Os=MacOS` | `Linux` |
| `TestClaudeExecutor_NonClaudeRequestUsesClaudeCode220CLIFingerprint` | `X-Stainless-Os=MacOS` | `Linux` |
2026-08-18 已在未应用任何 billing 补丁的纯上游 `ee2c4947` 临时 worktree 中复现相同结果。三项补丁没有修改 `internal/runtime/executor`,因此同一提交、同一 WSL 环境、同一失败内容再次出现时,直接记为已知上游失败,不再创建干净 worktree复测。
出现以下任一情况时重新验证:
- submodule 提交不再是 `ee2c4947`
- 上游修改了 `internal/runtime/executor/claude_executor_test.go``claude_executor_request.go``helps/claude_device_profile.go`
- 失败测试、行号、实际值或期望值发生变化;
- 三项补丁开始修改 `internal/runtime/executor`
## submodule 升级
当前 submodule 工作区包含三项已应用补丁。升级前必须按反方向撤销,再切换上游提交:
```bash
git -C .externals/CLIProxyAPI apply --reverse ../../patch/cli-proxy-api-request-lifecycle-cancel.patch
git -C .externals/CLIProxyAPI apply --reverse ../../patch/cli-proxy-api-usage-identity.patch
git -C .externals/CLIProxyAPI apply --reverse ../../patch/cli-proxy-api-usage-context.patch
git -C .externals/CLIProxyAPI fetch --tags --prune origin
git -C .externals/CLIProxyAPI switch --detach origin/main
```
重新应用补丁:
```bash
git -C .externals/CLIProxyAPI apply ../../patch/cli-proxy-api-usage-context.patch
git -C .externals/CLIProxyAPI apply ../../patch/cli-proxy-api-usage-identity.patch
git -C .externals/CLIProxyAPI apply ../../patch/cli-proxy-api-request-lifecycle-cancel.patch
git -C .externals/CLIProxyAPI diff --check
```
应用后 submodule 显示 `dirty` 是预期结果。根仓库提交新的 gitlink 指针和必要的 `patch/` 更新,不在 submodule 中创建派生提交。
## 测试顺序
WSL 使用以下环境。Go bootstrap 可能低于 `1.26.6`,有效 toolchain 由 Go 自动下载;`gofmt` 位于有效 `GOROOT/bin`,因此需要补充 `PATH`
```bash
export GOPROXY=https://goproxy.cn,direct
export PATH="$(go env GOROOT)/bin:$PATH"
go version
gofmt -h >/dev/null
```
从 PowerShell 调用包含 Bash 变量、命令替换或多层引号的命令时,把内容写入 `.runtime/tmp/*.sh` 后交给 WSL 执行。`.runtime/tmp` 不提交。
每次升级执行以下检查:
```bash
cd .externals/CLIProxyAPI
go test -race ./internal/pluginhost ./sdk/api/handlers ./sdk/cliproxy/usage -count=1
go test ./... -count=1
cd ../..
go test ./... -count=1
go test -race ./... -count=1
```
补丁正确性的最低标准如下:
- 三项补丁按顺序应用成功,`git diff --check` 通过;
- `internal/pluginhost``sdk/api/handlers``sdk/cliproxy/usage` race 测试通过;
- billing 全量测试和全量 race 测试通过;
- CPA 全量测试除已记录的纯上游失败外通过;
- CPA 和 billing 均可编译。
## 构建
CPA 版本必须使用当前最新 Tag 加 `-dev`,提交取 submodule HEAD
```bash
cd .externals/CLIProxyAPI
version=v7.2.135-dev
commit="$(git rev-parse --short=8 HEAD)"
build_date="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
CGO_ENABLED=1 go build -buildvcs=false \
-ldflags="-s -w -X main.Version=$version -X main.Commit=$commit -X main.BuildDate=$build_date" \
-o ../../.runtime/bin/cli-proxy-api.new ./cmd/server/
../../.runtime/bin/cli-proxy-api.new -h >/dev/null
```
`-h` 会在第一行输出完整版本。上游没有 `--version` 参数,不要使用该参数核对版本。
构建插件:
```bash
cd ../..
bash scripts/build.sh
cp bin/billing.so .runtime/plugins/billing.so.new
sha256sum bin/billing.so .runtime/plugins/billing.so.new
```
两个插件哈希必须一致。
## 本地替换与验收
本地 CPA 只使用 `.runtime`。替换前停止进程并保存旧产物:
```bash
bash scripts/stop-test-host.sh
backup=".runtime/backups/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup"
cp .runtime/bin/cli-proxy-api "$backup/"
cp .runtime/plugins/billing.so "$backup/"
mv .runtime/bin/cli-proxy-api.new .runtime/bin/cli-proxy-api
mv .runtime/plugins/billing.so.new .runtime/plugins/billing.so
bash scripts/run-test-host.sh
```
启动后检查:
1. `/healthz` 返回 `status=ok`
2. `/v0/management/plugins` 中 billing 的 `registered``enabled``effective_enabled` 都为 `true`
3. 日志版本与构建参数一致,且没有插件错误或 panic;
4. 无下游 Key 的请求返回 401;
5. 有效 billing Key 的 `/v1/responses` 请求返回 200
6. 请求只新增一条明细,包含唯一 Request ID 和 Token
7. 额度只扣减一次,`active_requests` 回到 0。
本地 CPA 通过 WSL localhost 转发供 Windows 使用。取消链路测试需要在 WSL 内直连 `127.0.0.1:8317`,避免 Windows localhost 转发延迟传递断开。
## 远端发布
核心升级使用 PowerShell 脚本:
```powershell
./scripts/push.ps1
```
脚本默认执行以下操作:
- fetch `origin/main` 并要求 submodule HEAD 与其一致;
- 要求 submodule 修改文件集合与 `patch/*.patch` 声明一致;
- 运行三个补丁相关包的 race 测试;
- 使用最新 Tag 加 `-dev` 和当前提交、构建时间编译核心;
- 生成 gzip 最高压缩级别的核心包和 SHA-256;
- 上传后在远端重新校验压缩包、版本和核心哈希;
- 等待 billing `active_requests=0`,备份后只替换 CPA 核心;
- 核对配置、所有插件动态库、插件注册状态和独立 keeper;
- 失败时恢复旧核心并按部署前状态启动 CPA Manager Plus。
只执行本地构建、测试和打包,不上传或部署:
```powershell
./scripts/push.ps1 -WhatIf
```
复用已有核心时使用 `-SkipBuild -BinaryPath <path>`;跳过补丁相关 race 测试使用 `-SkipTests`;部署锁定但不是当前 `origin/main` 的提交时显式使用 `-SkipUpstreamCheck`。请求排空默认等待 120 秒,可通过 `-DrainTimeoutSeconds``-DrainPollSeconds` 调整。
远端只部署本项目的 billing 和已要求启用的 keeper。发布步骤如下:
1. 本地完成真实模型请求、协议、计费和取消链路验收;
2. 对 CPA 二进制和插件计算 SHA-256
3. 使用 gzip、tar.gz 或 `scp -C` 上传;
4. 停止 `/root/cpa/cpa.sh` 管理的进程;
5. 把旧 CPA、billing、keeper 和 `data/cpa-ext.db*` 保存到 `/root/cpa/backups/<timestamp>/`
6. 替换二进制和插件,保留配置及 secret 文件;
7. 启动进程并检查健康状态、版本、插件注册状态和日志;
8. 启动失败时恢复同一备份目录中的文件并重启。
远端不发送 `/v1/responses``/v1/chat/completions` 或 compact 请求。管理密钥和下游 Key 在远端脚本内部从 secret 文件或管理 API 读取,不输出到终端和普通日志。
`cpa.sh start` 会先把管理 Key 同步到 `config.yaml`,CPA 启动后会重新保存该字段的哈希,因此每次启动后 `config.yaml` 的原始 SHA-256 可能变化。部署校验应把 `remote-management.secret-key` 的值归一化后比较其余配置内容,不得因为原始配置哈希变化回滚核心。
远端存在持续请求时,在远端部署脚本内部先完成压缩包和插件检查,再每 5 秒读取 billing `active_requests`。检测到 0 后立即停止 CPA,避免在本地轮询与远端执行之间出现新请求。
## 2026-08-18 验证记录
`v7.2.135` / `ee2c4947` 已完成以下验证:
- 三项补丁重新应用成功,共修改 11 个文件,增加 289 行,删除 10 行;
- 补丁相关三个包的 race 测试通过;
- billing 全量测试和全量 race 测试通过;
- CPA 和 billing Linux amd64 产物编译成功;
- CPA 运行版本为 `v7.2.135-dev / ee2c4947`
- billing `0.1.0` 加载并注册;
- DeepSeek Codex `/v1/responses` 返回 200 和 `CODEX_READY`
- 该请求记录 129 Token,只产生一条计费记录,`active_requests=0`
- 本地替换前产物保存在 `.runtime/backups/20260818-154252-v7.2.135/`
同日已完成远端核心升级:
- 只替换 `/root/cpa/bin/cli-proxy-api`,插件、配置、数据库和独立 keeper 未替换;
- 远端运行版本为 `v7.2.135-dev / ee2c4947`,核心 SHA-256 为 `d702d8d65a06911b5bec78476d84e228bcfb57e03c511b4c1d89df8f460c41fd`
- CPA PID 为 `278177`,独立 keeper PID 保持为 `230299`
- billing 和 keeper `0.1.0` 均已加载、注册和启用;
- `/healthz` 正常,启动日志没有 panic 或插件错误;
- 未向远端模型端点发送验收请求;
- 升级前文件保存在 `/root/cpa/backups/20260818T081102Z-core-v7.2.135/`