本文档只处理一个专题:当账号额度接近或显示耗尽时,Helper 应在什么时候切换账号,才能既避免任务中断,又充分使用当前账号在正在执行轮次中的可用尾部额度。
这项能力是商业可靠性门槛,但不应挤占整体产品化目标的主线。总目标只需引用本文档并把验收作为发布阻断条件。
Codex 存在一个重要运行特性:即使额度界面已经显示接近耗尽或耗尽,只要当前轮任务仍在执行,生成、工具调用和收尾动作可能继续进行,直到当前轮自然结束、上下文压缩、明确错误或其它中断事件发生。
因此,最后 1% 不是简单的“立即不可用”信号。它可能承载一个相当长的在途任务。如果系统仅根据额度阈值或过早的额度错误提示立即写入新 auth 并重启 Codex,会产生以下损失:
- 正在执行的任务被中断,用户看见无故换号或工作断流。
- 当前账号仍能完成的在途轮次被浪费。
- 新账号额度被更早消耗,账号池总有效工作量下降。
- 审计将“保护任务”与“消耗额度”混成一次简单切换,无法解释损失原因。
目前 Helper 已有任务保护骨架:
native-helper/CodexPlusLocalHelper.cs中的自动切换循环先得到 usage 或运行日志触发,再调用IsSafeToAutoSwitch(...);自动切换配置模型位于native-helper/AutoSwitchConfig.cs。CodexLogRuntimeMonitor会读取 Codex 日志,识别active、cooling、idle、unknown与待处理触发。quota、auth、account_disabled当前都属于硬触发;在cooling状态下,硬触发可以继续进入换号路径。- Worker 负责确认切换条件、选候选账号和保存审计;真正写 auth、重启 Codex 的动作在 Helper。
这说明代码已在尝试避免任务中切换,但仍需专门验证并修正一个核心语义:
额度信号只能说明“需要准备换号”,不能单独证明“当前轮已不能继续运行”。
- 自动切换必须发生在安全轮次边界,而不是单纯发生在额度阈值命中时。
- 正在产生有效输出或执行工具的任务,默认不因额度低、额度为零或用量接口异常而被强制切换。
auth已明确失效且当前请求已经失败结束时,可以尽快切换;仍不能通过破坏在途任务来推测其已失败。- 状态不确定时采用保守策略:延后自动切换,并允许用户手动确认。
- 用户必须能看懂为什么仍未切换、什么时候会切换、最终节约或消耗了什么。
实现调整前,应通过真实 Codex 桌面运行和可重复测试获取以下证据,不凭关键词猜测:
- 当额度为
1%、0%或用量接口返回限流时,当前轮是否仍持续产生输出、工具调用或完成事件。 - 额度耗尽提示与
response.completed、response.failed、turn.completed、上下文压缩、用户中止之间的事件顺序。 - app-server 状态、
logs_2.sqlite状态与窗口可见任务状态在长任务期间是否一致。 - 当前实现发生误切时,Helper 判定的
state、triggerType、pendingSwitchAt、SafeToSwitch和实际写 auth 时间。 - 是否存在日志静默间隔,使一个仍会继续执行的任务被误判为
cooling或idle。
所有排查记录不得包含 access token、refresh token 或完整 auth 内容。
自动切换应将“触发”与“执行”彻底分开。
| 状态 | 含义 | 允许动作 |
|---|---|---|
healthy |
当前额度和任务状态正常 | 周期检查,不写切换审计流水 |
tail_observing |
额度低于预警阈值,但没有确定失败 | 显示预警,准备候选,不切换 |
switch_pending |
已出现额度耗尽、限流或授权异常信号 | 记录待切原因,持续观察当前轮 |
draining_active_turn |
待切状态下当前任务仍活跃或可能继续 | 禁止自动写 auth 与重启 |
boundary_confirming |
检测到轮次结束或明确失败,正在短时确认稳定边界 | 再次核验当前 auth、任务状态和候选 |
switching |
边界已确认,开始切换 | 执行 payload、写 auth、恢复 Codex |
held_unknown |
无法可靠判断轮次边界 | 不自动切,提示用户检查或手动操作 |
cooldown |
已切换或用户取消后保护期 | 阻止重复换号 |
fiveHourThreshold与oneWeekThreshold只进入tail_observing或switch_pending,不得直接成为写 auth 的充分条件。- 额度接近阈值时可预取候选摘要,但不得提前下发可写入的明文 auth,也不得提前更新
last_switch_at。
- 发现额度耗尽、
429或标准 usage-limit 信号时,记录待切原因。 - 若当前轮仍是
active、工具执行中、流式输出中或状态无法确认,则进入draining_active_turn。 - 只有出现可信的任务完成、任务失败、用户中止或已证实不再可继续的边界事件,并通过短时间稳定确认后,才允许自动切换。
- 可见的额度提示、usage 百分比或短暂日志静默,不能单独作为轮次结束证据。
- 授权失效、账号停用属于更高优先级触发,但仍应先确认当前轮已经结束或失败。
- 若错误事件自身明确结束当前请求,例如可信的
response.failed,则可以在短确认期后进入切换。 - 若只是后台预检查失败,不得中断正在成功运行的当前轮。
- 用户主动点击切换时,如存在活跃任务,先给出明确提示:“当前任务仍在运行,立即切换可能中断本轮并浪费剩余额度”。
- 提供“等待当前任务完成后自动切换”和“仍然立即切换”两个清晰选择。
- 强制切换必须记录为用户动作,不能伪装成智能切换策略执行。
设置页可在“智能切换”中增加高级项,默认值保护任务连续性:
switchTimingMode:after_turn|immediate_when_idle|manual_confirmprotectActiveTailUsage: 默认true,表示额度耗尽后仍等待当前轮结束。boundaryConfirmSeconds: 安全边界稳定确认时间,默认建议15至30秒,需基于真实测试确定。unknownStateAction:hold|notify_only,默认hold。allowManualForceSwitch: 默认true,但必须展示风险确认。
after_turn 应为默认和推荐模式。不能把“立即切换”作为普通用户无感知的默认行为。
Helper 主窗口和云控制台应显示可理解的阶段,而不是笼统的“切换中”:
额度接近上限,继续观察当前任务额度已耗尽,正在保护当前运行任务任务已结束,正在确认安全切换时机状态无法确认,自动切换已暂停安全边界已确认,正在切换账号
界面应展示:
- 待切原因,例如
5H 额度耗尽、授权失效。 - 当前保护状态,例如
当前轮仍在执行,不会打断。 - 待切开始时间和最近一次可信任务事件。
- 实际切换发生时间与目标账号。
账号详情不应展示每次轮询检查;只展示一次触发、一次延后摘要和最终切换结果。
新增或规范化审计事件,保证运营侧能判断是否误切:
auto-switch-armed: 达到触发条件,仅建立待切计划。auto-switch-deferred-active-turn: 因当前轮仍活跃而延后,按一次保护周期聚合,不按轮询频率刷屏。auto-switch-boundary-confirmed: 已找到可信安全边界。auto-switch-switched: 实际完成切换,携带触发类型和保护持续时长。auto-switch-manual-forced: 用户明确强制切换。auto-switch-held-unknown: 无法判断状态而暂停。
需要记录但可脱敏的字段:
accountId、deviceKeyHint、triggerType、triggerAtruntimeState、runtimeSource、lastTaskEvent、boundaryEvidenceprotectedDurationMs、switchedAt、targetAccountId
严禁记录 token、完整 auth payload 或第三方响应中的秘密数据。
- 将现有“硬触发在
cooling时可切换”的判定重构为安全边界判定,不把 quota 信号本身视为已安全。 - 扩展
CodexLogRuntimeMonitor,明确标记在途轮次、结束边界和不确定状态的证据来源。 - 将 pending switch 持久化到本机配置或状态文件,Helper 重启后不丢失待切原因,但仍要重新核验任务状态。
- 切换前再核验当前 auth、目标账号、Codex 状态与触发有效性。
- 将“触发资格”和“切换提交”分离:Worker 可以确认候选,但只有 Helper 报告安全边界并执行成功后才记录切换完成。
- 对延后事件做去重和聚合,避免 D1 审计被轮询写满。
- 返回候选时保留触发和边界证据字段,以便审计追踪。
- 设置页暴露切换时机策略与任务保护开关。
- Helper 诊断区展示
保护当前任务、等待安全边界和状态未知暂停。 - 设备页自动切换阶段卡已落地:基于 Helper 上报的
pending_switch_reason、safe_to_switch、最近任务事件和auto_switch.last_result,展示触发、边界证据、最近结果和下一步动作,不新增后台轮询或 D1 写入。 - 手动切换保护弹窗已接入账号详情、账号列表和智能选择入口:当 Helper 上报
safe_to_switch === false时默认拦截切换,用户可选择等待安全边界后自动切换,或明确强制立即切换;强制路径会写入manualForce审计元数据。 - Helper
0.4.7已将待切原因、触发类型、来源、开始时间和本机 auth 指纹持久化到本机配置;Helper 重启后控制台显示“恢复待切计划”,但持久记录不会直接授权换号,必须通过新一轮实时额度和安全边界核验后才可写入 auth。 - 运行记录按业务语义展示聚合结果,不把预警显示成已切换。
必须覆盖真实运行验证与自动测试。
- 额度剩余约
1%时启动长输出任务,确认触发后仍不会中断当前轮。 - 额度显示
0%但流式输出或工具调用仍继续,确认 Helper 只进入保护状态。 - 当前轮自然完成后,确认只切换一次并恢复 Codex。
- 当前轮因可信 usage-limit 或 auth 错误明确失败后,确认能够尽快切换。
- 上下文压缩、用户中止、工具等待确认、日志短暂静默等场景不发生误切。
- Helper 重启或离线恢复后,待切状态可解释且不会重复消耗账号。
- 状态机单元测试:事件序列输入后只能在安全边界输出
shouldSwitch=true。 - 回归测试:阈值命中、usage 错误、
response.completed、response.failed、未知状态、手动强制切换。 - Worker 审计测试:延后去重、完成切换后才写成功、没有 token 泄露。
- UI 测试:保护状态、风险确认、聚合审计文案可见且不刷屏;
scripts/verify-panels-ui.cjs覆盖保护当前任务、安全边界已确认和自动切换失败三类阶段。
- 额度低或显示耗尽时,正在执行的当前轮默认不会被自动切换打断。
- 只有可信轮次边界确认后,自动切换才改写 auth 并重启 Codex。
- 状态无法确认时不会冒险切换,用户可看见暂停原因和手动选项。
- 真实测试证明最后尾部额度能被当前任务继续使用,不因提前换号浪费。
- 自动切换相关日志、审计和界面文案能区分触发、保护、确认边界和完成切换。
- 高频状态检查不会污染账号详情或运营审计。