Skip to content

fix(orcaterm):凭证续期三处失能 —— JWT 过期后账号永久 502 - #317

Open
chjiron wants to merge 1 commit into
aimod-cc:betafrom
chjiron:upstream-pr/orcaterm-refresh
Open

chjiron wants to merge 1 commit into
aimod-cc:betafrom
chjiron:upstream-pr/orcaterm-refresh

Conversation

@chjiron

@chjiron chjiron commented Oct 17, 2026

Copy link
Copy Markdown

现象

OrcaTerm 账号导入约两小时后,该账号的所有模型一律返回 502;同一时间官方客户端本身一切正常。requests.attempt_details 里的真实报错(四种模型同一句):

OrcaTerm 建会话失败(code=-1:Invalid or expired AccessToken)

时间线:16:36 / 16:37 / 18:34 测试通过 → 19:41 起及次日全部 502。JWT 时效约 2 小时(见 providers/orcaterm/credentials 模块头),失效时刻吻合。

根因:三处叠加,导致「过期即永久 502」

1. tokenExpireAt 单位错位 —— 主动续期从未触发

账号记录存毫秒(导入与续期回写都是 expires_at * 1000,见 account_store::orcaterm_accounts),读取侧却把它塞进按秒理解的 OrcatermCredentials::expires_at(该字段语义是 JWT exp,is_expiring() 用 now_ms()/1000 相减)。毫秒值当秒读比 now 大三个数量级,is_expiring() 于是恒返回 false:

  • 临期续期(chat::run_chat / balance)
  • 定时凭证维护(credential_maintenance)
  • 面板「刷新临期凭证」

三条自动路径全部静默失能。

2. 凭证失效的口径没被翻译 —— 自愈链只认 401

上游用 HTTP 200 + code=-1 表达凭证失效,create_conversation 把它一律映射成 502;而建会话 / 开流两处自愈链(refresh_for_retry)的触发条件是 status_code == 401。这条信号因此永远触发不了强制续期。

3. 面板「刷新 Token」的分派表漏登记 OrcaTerm

api::accounts::refresh_account 的按 provider 分派覆盖了其余带 refreshToken 的家,但没有 OrcaTerm,会落到 workbuddy 兜底链路(该函数文档把这条列为「加带 refreshToken 的家时必须一起加」)。手动救回账号的通路因此也缺。

改动(3 文件,+145 / −6)

  • providers/orcaterm/credentials.rs:新增 expires_at_seconds(),在读取侧把毫秒归一到秒(落点选读取侧,因为 tokenExpireAt 的毫秒口径是面板「到期时间」展示依赖的)。
  • providers/orcaterm/chat.rs:新增 is_credential_rejection(),把凭证类业务码翻译成 401(判据收窄:须同时提到 token 与 invalid/expired/失效/过期),让既有自愈链生效;非凭证类业务码维持 502。
  • api/accounts.rs:补上 OrcaTerm 的强刷分派分支。
  • 另加 5 项回归测试(单位归一、判不出时回落 JWT exp、10 分钟临期窗口开合、凭证失效判据的宽窄两面)。

验证

612 项后端测试通过(另 6 项 ignored),其中新增 5 项。已在 upstream/main 与 upstream/beta 上分别试摘,均无冲突。

🤖 本条回复由 AI Agent 生成

- 修复 tokenExpireAt 单位错位:账号记录存**毫秒**(导入与续期回写都是
  expires_at * 1000),读取侧却塞进按**秒**理解的 OrcatermCredentials::expires_at,
  比 now 大三个数量级,is_expiring() 于是恒返回 false —— 临期续期
  (chat / balance)、定时凭证维护、面板「刷新临期凭证」三条自动路径全部静默
  失能。落点在读取侧归一(tokenExpireAt 的毫秒口径是展示层依赖的,改写入会
  顺手改坏面板「到期时间」那个读数)。
- 修复凭证失效的口径没翻译:上游用 HTTP 200 + code=-1 表达(实测原文
  Invalid or expired AccessToken),被 create_conversation 一律映射成 502,
  而建会话 / 开流两处自愈链只认 401 —— 这条信号永远触发不了强制续期,账号一旦
  过期就没有自愈出口。现按收窄判据(同时提到 token 与 invalid/expired 等)
  识别凭证类业务码并翻译成 401(新增 is_credential_rejection);非凭证类
  业务码维持 502,不白刷 token。
- 修复 refresh 分派表漏登记 OrcaTerm:面板「刷新 Token」不认这家,会落到
  workbuddy 兜底链路并返回腾讯鉴权端点的错 —— 与 Antigravity / Trae /
  Command Code 漏登记时同一性质(refresh_account 的文档把这条列为
  「加带 refreshToken 的家时必须一起加」)。
- 新增回归测试:单位归一(含判不出时回落 JWT 的 exp)、10 分钟临期窗口的
  开合、凭证失效判据的宽窄两面。

症状与定位依据:2026-10-17 实测,账号导入约两小时后四种模型的测试全部 502,
requests.attempt_details 同一句 code=-1:Invalid or expired AccessToken;
用户侧 OrcaTerm 客户端一切正常(客户端自续自己那份,网关这份自导入起未被
更新过)。612 项后端测试通过(另 6 项 ignored),其中新增 5 项。
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.

1 participant