Skip to content

v2.4.0 — 会话身份头、模型清单解冻、中文路由可存

Choose a tag to compare

@XDTrees XDTrees released this 21 Oct 03:10
· 30 commits to main since this release

这一版收的是「用着用着就报错」的那一类问题:调用被网关判成非法渠道、国际版模型清单停在开机那一刻、中文名字的路由点了保存却没存下、上下文一选就弹回第一项。都不新增界面,全是把已经该work的事情修回来。

先看这一版修掉了什么

九个问题,按你遇到它的顺序排:

你看到的 真实原因
聊天突然报 400 / 11128 Illegal API invocation from an unapproved channel,看着像密钥失效 网关要一组「这一轮对话属于谁」的身份头,缺一个就整轮拒绝。不是密钥的问题
国际版的模型清单永远停在启动那一刻,「重新获取模型」点了没反应 模型数组在创建时被快照,刷新时复用了同一个对象,宿主按对象身份记忆化,新清单从没送出去
中文名字的路由,点了保存,列表里没有 链名 slug 只认 a-z0-9,中文名被压成空 id,规范化时当作无效条目静默丢弃
上下文大小选了「完整」,选中态立刻弹回第一项 「从未保存过预算」被当成「已收窄到 200K」显示,清空后该行又算回 200K
国际版 Deepseek-V4.1-Flash 只能选 High 一档 兜底表把这批模型的思考档位写成了单档
同一个人,账号池里显示成两个,各带一部分模型 桌面凭据带 uin+uid、扫码渠道只带 uid,池 id 按 uin 优先哈希
「重新检测账号」永远没结果,扫码账号也进不了池 listAllAccounts 漏了 await,拿到 Promise 后 .filter 抛错并被 catch 吞掉

会话身份头:11128 的真身

网关对「这一轮对话属于谁」有一组身份头,缺一个就整轮拒绝,报 11128 Illegal API invocation from an unapproved channel。这个文案会让人以为密钥失效,其实是新会话没自报身份。按官方客户端的契约补齐:

  • 会话稳定三头(同一会话内不变):X-Conversation-ID、X-Conversation-Request-ID、acp-connection-id
  • 每请求两头(逐次随机):X-Conversation-Message-ID、X-Request-ID
  • 另附 X-Agent-Intent、X-Agent-Purpose、x-codebuddy-request、X-Private-Data、X-Product 与 W3C/B3 追踪族

实测口径:三个稳定头缺任一个即 400 11128,齐全即 200;值本身不校验(非 UUID 字符串也过)。池车道(WorkBuddy 国内/国际)与扫码渠道两条路径都接上了。

顺带修掉同源的一处:role: "developer" 的消息在国内网关同样触发 11128,现统一上送为 system。

国际版模型清单不再冻结

createProvider 的 models 是创建 provider 时快照下来的数组,而原来的 invalidate() 只重排了 profile、复用了同一个 provider 对象。宿主按对象身份记忆化 current(),于是新拿到的清单永远送不到选择器。

现在每次 invalidate() 重建 provider 与 profile 两个对象,并通过 adapter handle 的 replace() 重新登记路由,由宿主自己发出 llm/adapters-updated。

顺便核查了一处怀疑:国际版本来就有独立的 modelSelectionGlobal 键,与国内白名单分开读写,这一处无需改动。

中文路由名现在存得下

链名 slug 原来是 [^a-z0-9]+ → '-',中文名整串被压成空 id。改为 Unicode 感知的 slug(\p{L} / \p{N}),拉丁名形态完全不变(comboId('Write Then Fallback') 仍是 combo:write-then-fallback),已存的路由 id 继续可解析。

上下文大小:选中态不再一选就弹回

渠道卡把「从未保存过预算」当成了「已收窄到 200K」,用户点「完整」清空预算后,该行又算回 200K,选中态立刻跳回第一项。

现在未保存过预算就显示完整窗口;清空预算时同时保留 nativeContextWindow,radio 组不会在指针底下消失。

思考档位:不再只认一档

pack 兜底表把十几个模型的 reasoningEfforts 写成了单档(["medium"] / ["high"]),于是国际版 Deepseek-V4.1-Flash 只能选 High。

逐模型实测(两个网关、五档全跑)后按真实能力补齐:凡是能调通的模型,五档都接受,且各档 reasoning_content 长度不同。两个例外如实留在表里:

  • gpt-5.3-codex 五档皆 200,但 reasoning_content 恒为空——档位合法而不可观测,已在表内注明
  • gemini-3.5-flash 与 primary-model 五档全 400,model [X] is not allowed for user type [personal]——这是账号套餐权限,与档位无关,未动

同一个人不再显示成两个

桌面端凭据同时带数字 uin 与 UUID uid,扫码渠道只带 uid,而账号 id 是按 uin 优先哈希的。同一个人走两条登录路径就整出两个池条目,各自带一部分模型——这正是长期反馈的「重复账号」。

现在按 uid 建次级索引合并到同一个池条目。刻意不改哈希:冷却、失效标记、忽略名单、持久化快照全部按旧 id 归档,改了一次性作废。也与凭据到达的先后顺序无关。

「重新检测账号」不再静默失败

listAllAccounts 漏了 await,拿到的是一个 Promise,随后的 .filter 抛 is not a function 并被外层 try/catch 吞掉。表现是扫码账号全部并不进池、重新检测永远没结果。

其余

  • 测试:新增会话身份头与中文路由名的回归用例,全套 68 文件 / 910 用例通过。
  • 版本:2.3.0 → 2.4.0(POOL_VERSION 同步,有测试守着它不许漂移)。

升级

dsh plugin add dsh-xdpool@2.4.0

装完重启一次 DSH:身份头与模型清单的修复都在后端侧,热重载拿不到。


完整改动:2def4d0...933a5c3 · 逐条说明:CHANGELOG.md