12 KiB
sub2api-overdraft 5h / 7d 额度透支定制记录
本文件是维护者实现与升级记录。面向部署者的完整安装、验证、升级和故障排查说明见 CODEX_OVERDRAFT_DEPLOYMENT_CN.md。
基本信息
- 当前官方合并基线:Sub2API
v0.1.179,upstream/main提交2bc139ab5 - 参考实现:https://github.com/Mxucc/cpa-account-config-manager
- 功能开关:
gateway.codex_quota_overdraft_enabled - 代码默认值:关闭;
deploy/config.example.yaml部署示例默认开启 - OpenAI 账号固定指纹开关:
gateway.openai_account_unique_fingerprint_enabled - 固定指纹开关默认开启;没有显式账号模式时按账号 ID 派生稳定设备指纹,账号 extra 中显式设置
codex_fingerprint_mode: off可单独关闭 - 账号编辑页新增
账号唯一设备(新增,推荐)选项,对应codex_fingerprint_mode: account_device;它只固定该账号的设备指纹,不改变会话/线程收敛 - Fork 版本文件:
FORK_VERSION - 更新源:
DeanZFC/sub2api-overdraft的codex-overdraft分支
Fork 更新检查
源码 Docker 构建会读取根目录的 FORK_VERSION,并以 BuildType=source 写入二进制。后台更新服务通过 GitHub Contents API 读取 Fork 分支上的同名文件,使用语义化版本比较判断是否有新版本。Redis 缓存同时记录仓库和构建类型,因此旧的官方更新缓存不会继续生效。
源码构建仅显示 git pull 更新提示,PerformUpdate、指定版本回退和在线回退列表均被禁用,防止官方二进制覆盖透支功能。维护者每次发布 Fork 更新都必须递增 FORK_VERSION;当前版本为 0.1.179-overdraft.3。
Sub2API v0.1.179 继续保留原生 remote compaction v2 在 /responses 路径。本定制同时检查旧 Compact 路径和原生 v2 请求信号,二者都不会开启额度透支调度或注入透支请求形态。
后台测试连接与残留限流修复
管理页面的 OpenAI OAuth 常规文本“测试账号连接”与真实业务请求使用相同策略:用量达到 95% 后注入;100% 时成功直接确认 passed,明确额度 429 直接确认 failed。API Key、Shadow、图片和 Compact 测试不启用该行为。
探测得到 passed,或额度周期进入 recovered 后,会清除仍残留的账号级 rate_limit_reset_at 以及本功能或额度阈值产生的暂停。这里不再要求当前重置时间与探测开始时记录的 observed_rate_limit_reset_at 完全相同,因为并发 429 可能在探测期间更新该字段;failed 状态不会清理限流。发生清理时记录 codex_quota_overdraft_stale_rate_limit_cleared。
PostgreSQL 兼容性修复
探测计划使用原子 claim 写入 accounts.extra。jsonb_build_object 的键参数必须显式
转换为 text,否则 PostgreSQL 会报 could not determine data type of parameter $1,导致
所有探测在启动前失败。对应 SQL 使用:
jsonb_build_object($1::text, $2::jsonb)
启用方式
在实际使用的 config.yaml 中加入:
gateway:
codex_quota_overdraft_enabled: true
openai_account_unique_fingerprint_enabled: true
修改配置后重启 sub2api。出现上游兼容问题时可改为 false 并重启,立即恢复官方调度和请求行为。
OpenAI 账号固定指纹
固定指纹行为覆盖 HTTP Responses、OpenAI 透传、Responses WebSocket 和账号测试/额度探测。
默认模式为 device:同一 OpenAI OAuth 账号的 x-codex-installation-id 在请求、重启和
重新构建后保持不变,不同账号按账号 ID 派生不同 UUID。已经配置 device、session、full
或 off 的账号保持原有显式配置优先级;全局开关关闭后,未显式配置模式的账号恢复原样。
老账号即使没有 codex_fingerprint_seed 也不需要立即执行迁移,运行时会使用账号 ID 派生稳定
种子;显式 device/session/full 模式仍要求账号已有有效种子。该功能只对 OpenAI OAuth/Codex
账号生效,不会改写 API Key 或其他平台账号。
完整行为
开启后,对 OpenAI OAuth 普通账号和 Agent Identity 账号生效,Shadow 账号除外。支持路径:
/v1/responses/v1/chat/completions转换到 Responses 的请求/v1/messages转换到 Responses 的请求- Responses WebSocket v2 首轮和后续轮
- 管理页面 OpenAI OAuth 常规文本“测试账号连接”
用量达到 95% 后,每次最终发往上游前,如果 input 最后一项是用户消息,则追加一对与参考项目相同的无操作 custom_tool_call 和 custom_tool_call_output。请求体超过 32 MiB、JSON 无效、形状不匹配或已经注入时保持原样。
5h 或 7d 额度达到 100%,或者收到包含明确额度证据的真实 429 时,执行以下混合判定:
- 实际注入的业务请求成功时直接判定
passed,账号继续调度并开始透支统计,不额外消耗探测请求。 - 实际注入的业务请求返回明确额度 429 时直接判定
failed,账号暂停到对应额度恢复时间并切号;5h 和 7d 同时耗尽时取最晚恢复时间。 - 如果没有可用的业务成功证据,同一额度周期仅启动 1 次独立 Responses 探测,最长 20 秒并优先使用当前业务模型。多实例使用 PostgreSQL 原子 claim 去重。
- 独立探测成功即判定
passed,明确quota_limited即判定failed;网络错误、超时、5xx、普通瞬时 429(包括error.type=rate_limit_error)和无效响应判定inconclusive,同周期不自动重试。 failed状态、临时暂停和调度 outbox 在同一数据库事务中提交。同周期failed为终态,晚到的业务成功或探测结果不能覆盖;业务明确额度 429 可以把并发产生的passed或inconclusive收敛为failed。- 401/403、账号停用等认证问题交给原有认证异常逻辑处理;400/404 判定为
inconclusive,不会暂停整个账号。 - 账号禁用、过载、代理/传输故障、模型级冷却及其他临时不可调度原因不被绕过。
- 额度恢复后状态改为
recovered,清理本功能或额度阈值产生的暂停;5h 与 7d 分别维护透支起点,不会因另一窗口后来耗尽而重置已有统计。
状态值包括 pending、passed、failed、inconclusive、recovered。账号用量页面显示探测状态、尝试次数、额度周期、透支期成功请求数、Token、账号金额及预计恢复时间。
不需要新增数据库表或执行数据库结构迁移(schema migration);周期状态保存在现有 accounts.extra JSONB 字段,透支统计读取现有 usage_logs。
/responses/compact、生图请求、Embedding、Count Tokens、Live 等端点不启用额度透支。
低冲突集成结构
从 0.1.177-overdraft.6 起,透支行为保持不变,但实现按“独立模块 + 固定钩子”组织,以减少同步官方更新时的冲突:
- 四个 PostgreSQL 原子状态方法及临时暂停查询扩展位于
backend/internal/repository/account_repo_codex_overdraft.go,account_repo.go不再承载大段透支 SQL。 - Gateway 通过
sync.Once懒加载并持有全进程唯一协调器;账号用量服务和账号测试服务从同一个 Gateway 获取实例,不再向 Wire 图添加 Fork 专用 Provider。 backend/cmd/server/wire_gen.go由官方 Wire 图正常生成,不包含透支专用变量或参数。- 调度、429、业务成功、用量快照和账号测试接线统一放在
openai_codex_quota_overdraft_hooks.go、openai_codex_quota_overdraft_integration.go和account_test_codex_overdraft.go;官方热点文件仅保留短调用。 - 前端状态徽标和透支统计分别位于
CodexOverdraftStatus.vue、CodexOverdraftStats.vue,官方账号用量组件仅负责传入原有数据。
这次调整没有修改 95% 注入门槛、Payload 内容、额度信号解析、429 分类、探测次数、状态转换、事务边界、暂停/恢复规则、统计口径或页面文案。升级时应优先保留独立文件,再逐一核对官方文件中的短钩子。
修改文件
后端配置、路由和调度:
backend/internal/config/config.gobackend/internal/handler/openai_chat_completions.gobackend/internal/handler/openai_gateway_handler.gobackend/internal/repository/account_repo.gobackend/internal/repository/account_repo_codex_overdraft.gobackend/internal/repository/account_repo_schedulable_projection_test.gobackend/internal/service/account_test_codex_overdraft.gobackend/internal/service/openai_account_runtime_block_fastpath.gobackend/internal/service/openai_account_scheduler.gobackend/internal/service/openai_codex_quota_overdraft.gobackend/internal/service/openai_codex_quota_overdraft_hooks.gobackend/internal/service/openai_codex_quota_overdraft_integration.gobackend/internal/service/openai_codex_quota_overdraft_probe.gobackend/internal/service/openai_codex_quota_overdraft_test.gobackend/internal/service/openai_codex_quota_overdraft_probe_test.gobackend/internal/service/openai_gateway_forward.gobackend/internal/service/openai_gateway_passthrough.gobackend/internal/service/openai_gateway_scheduling.gobackend/internal/service/openai_gateway_service.gobackend/internal/service/openai_gateway_usage.gobackend/internal/service/openai_ws_forwarder_ingress.gobackend/internal/service/openai_ws_forwarder_support.gobackend/internal/service/openai_ws_forwarder_v2.gobackend/internal/service/openai_ws_v2_passthrough_adapter.gobackend/internal/service/ratelimit_service.gobackend/internal/service/account_usage_service.gobackend/internal/service/account_test_service.gobackend/internal/service/account_test_service_openai_test.gobackend/internal/service/account_test_service_openai_compact_test.gobackend/internal/service/wire.go
前端、配置示例和测试:
frontend/src/types/index.tsfrontend/src/components/account/CodexOverdraftStats.vuefrontend/src/components/account/CodexOverdraftStatus.vuefrontend/src/components/account/UsageProgressBar.vuefrontend/src/components/account/AccountUsageCell.vuefrontend/src/components/account/__tests__/UsageProgressBar.spec.tsfrontend/src/components/account/__tests__/AccountUsageCell.spec.tsfrontend/src/i18n/locales/zh/dashboard.tsfrontend/src/i18n/locales/en/dashboard.tsdeploy/config.example.yaml
官方更新后的重新实施
普通 git pull 不会静默丢弃未提交修改:能自动合并时会保留,冲突时会停止。安装脚本若强制重置、删除目录后重拉或重新解压,则可能覆盖本定制。
- 更新前保存补丁:
git diff > codex-quota-overdraft.patch - 拉取官方代码并处理冲突。
- 尝试恢复补丁:
git apply --3way codex-quota-overdraft.patch - 无法自动应用时,按本文件“完整行为”和“修改文件”逐项重新接入。
- 在
backend执行go generate ./cmd/server,重新生成 Wire。 - 确认实际
config.yaml仍有gateway.codex_quota_overdraft_enabled: true。 - 运行验证:
cd backend
gofmt -w internal/service/openai_codex_quota_overdraft*.go
go test -tags=unit ./internal/repository ./internal/handler ./internal/service \
-run 'CodexQuotaOverdraft|AccountTestService_OpenAI|AccountSchedulingThreshold|SchedulerSnapshot|SchedulableAccountQueryScopesCodex' -count=1
go test ./internal/repository ./internal/handler ./internal/service ./cmd/server -run '^$' -count=1
cd ../frontend
pnpm install --frozen-lockfile
pnpm run typecheck
pnpm exec vitest run \
src/components/account/__tests__/UsageProgressBar.spec.ts \
src/components/account/__tests__/AccountUsageCell.spec.ts
cd ..
git diff --check
人工核对所有 Responses 出站路径仍在最终发送前注入,并检查日志关键字:
codex_quota_overdraft_probe_passed
codex_quota_overdraft_probe_failed
codex_quota_overdraft_probe_inconclusive
codex_quota_overdraft_probe_attempt
codex_quota_overdraft_business_passed
codex_quota_overdraft_business_exhausted
codex_quota_overdraft_pause_applied
codex_quota_overdraft_stale_rate_limit_cleared
数据库状态可这样检查:
SELECT id, name, extra->'codex_quota_overdraft_probe'
FROM accounts
WHERE platform = 'openai' AND type = 'oauth';