Files
ModelRouter/internal/lua
JianFeeeee 893857464d feat(channels): TRAE callback 真实移植 —— token 直传 + ExchangeToken(照参考逐行)
此前 oauth_callback 是通用 OAuth 形态(直接拿 code 当凭据),与 TRAE 真实
行为不符。参考实现 trae-oauth.ts 的回调是 **token 直传**,本次照其行为移植:

parseTraeCallbackDetailed(决策表 5 行):
  行1 refreshToken 直传(或 userJwt.RefreshToken 回退)→ ExchangeToken 换新
      access(请求体 ClientID/RefreshToken/ClientSecret:'-'/UserID 照抄,
      响应取 Token)→ 凭据 = 新 access
  行2 无 refreshToken 但有 userJwt.Token → 直接兜底,**不打** ExchangeToken
  行3 只有 code/authCodeInfo → PKCE 流,明确报"暂不支持"而非含糊失败
      (参考注释强调:判为无效会让用户往错误方向排查)
  行4 全空 → 报"回调未携带 refreshToken / userJwt.Token / code"
  行5 ExchangeToken HTTP 失败 → 错误指明 ExchangeToken 阶段

配套:
- PLATFORMS.trae 增加 callback = {mode="trae", exchange_url, exchange_body};
- oauth_callback 按平台 callback.mode 分派(nil→code 旧路径不变,googleish 不受影响);
- traeCallback/jsonField 新函数;set_endpoints 支持 callback.exchange_url 覆盖
  (既是运维能力也是测试缝,与 device 端点同语义);
- TestTraeCallbackBehavior:5 行决策表 + 行1 断言凭据来自假上游新 Token
  (防"把回调原值当凭据")、行2 断言 ExchangeToken 零调用(防多余上游请求)。

回归:channels/trae/device 变异/压力/legacy/保险库/e2e 全绿。
2026-10-11 22:35:18 +08:00
..