Skip to content

feat(acp-bridge): session/new 可选 model 锁定会话模型 + setModel 对象形态修复 (0.16 实测) - #52

Open
jasonQin6 wants to merge 1 commit into
tizerluo:mainfrom
jasonQin6:feat/acp-session-model-selection
Open

jasonQin6 wants to merge 1 commit into
tizerluo:mainfrom
jasonQin6:feat/acp-session-model-selection

Conversation

@jasonQin6

Copy link
Copy Markdown

问题(0.16.1–0.16.9 实测, App 3.14.0/CLI 0.16.9)

1. setModel 透传形态与 0.16 后端 schema 不匹配

桥的 _on_session_set_model{sessionId, modelId: "<string>"},而 0.16 后端 zod schema 要 model 对象,实测必报:

-32602 Invalid params — model: Invalid input: expected object, received undefined;
(root): Unrecognized key: "modelId"

即 0.16 时代 ACP 面的 session/setModel 从未真正可用(即使参数名对上,注册表里没有该 provider 也会报 Provider Registry 中不存在 Model)。

2. client 无法按会话指定模型(headless 刚需)

headless spawn 的 app-server,模型解析跟随 personal provider registry / App「上次使用」默认;config.json 静态 provider 不进注册表,凭证 env 三件套在 personal registry 存在时被无视。结果:App 里选了什么模型,脚本/编辑器拉起的会话就默认用什么,client 无从覆盖。

修复/新增

  • setModel:改为 {sessionId, model} 原样透传 ModelSelection 对象 {providerId, modelId, options?: {reasoningLevel}}。旧 modelId 字符串形态移除(在 0.16 后端从未通过 schema,保留只会让调用方误以为已生效)。
  • session/new 新增可选 model:
    • 字符串形态("GLM-5.3"):按 create 快照 settings.model.available catalog 解析,补 reasoningLevel = reasoning.defaultLevel;
    • 对象形态:原样透传;
    • create 成功后经 session/setModel 应用,失败则 session/new 整体报错(客户端明确知道模型没生效)。
    • 刻意不透传给 create 本身:0.16.9 实测 create 的初始 model 形参接受对象但丢 options,turn 阶段报 ModelProtocolError: Reasoning level is required for <provider>/<model>;setModel 路径无此问题。

实测(ZCode App 3.14.0 / CLI 0.16.9, personal provider bigmodel-api)

场景 结果
session/new {model: "GLM-5.3"}session/prompt stopReason=end_turn,流式文本正常
session/new 素建 + session/setModel {model: {providerId, modelId, options:{reasoningLevel:max}}} → prompt setModel ok,turn end_turn
setModel 缺 options(reasoning 必需的模型) turn 阶段 ModelProtocolError(与 catalog defaultLevel 补齐后通过)
{modelId} 形态 桥本地 -32602(替代原先透传后端必败)

测试

  • M5 改写:model 对象透传 / 缺参与非法形态 -32602(含旧 modelId 形态显式拒绝)
  • 新增 C4 系列 7 例:字符串 catalog 解析(补 defaultLevel)/无 reasoning 条目/对象透传/未知 modelId 不发 setModel/setModel 失败连带 new 失败/不带 model 向后兼容(零 setModel 调用)/非法类型
  • python3 -m pytest tests/ -q547 passed, 34 subtests passed

兼容性说明

  • {modelId}{model} 是破坏性 ACP 参数变更,但旧形态对 0.16 后端本来就 100% 失败,无实际可用性损失;≤0.15 后端未验证(0.16 用户不受影响,老版本用户如需可反馈再兼容)。
  • 不带 model 的 session/new 行为逐字节不变(C4e 锁定)。

… 实测)

问题 (0.16.1-0.16.9 实测):
1. setModel 透传形态与 0.16 后端 schema 不匹配: 桥发 {sessionId, modelId}
   字符串, 后端要 model 对象 → 必报 -32602 "expected object, received
   undefined; Unrecognized key: modelId"。即 0.16 时代 setModel 从未真正
   可用, ACP client 无法切换会话模型。
2. headless 场景模型解析跟随 personal provider registry / App「上次使用」,
   client 无法按会话指定模型: App 里选了什么, spawn 出的引擎就默认用什么
   (provider 目录不含 config.json 静态 provider, env 三件套在 personal
   registry 存在时被无视)。

修复/新增:
- setModel: 改为 {sessionId, model} 原样透传 ModelSelection 对象
  {providerId, modelId, options?: {reasoningLevel}}。旧 modelId 形态移除
  (在 0.16 后端从未通过 schema, 保留只会让调用方误以为已生效)。
- session/new 新增可选 model:
  * 字符串形态 ("GLM-5.3"): 按 create 快照 settings.model.available 的
    catalog 解析, 补 reasoningLevel=reasoning.defaultLevel;
  * 对象形态: 原样透传;
  * create 成功后经 session/setModel 应用, 失败则 session/new 整体报错。
  刻意不透传给 create 本身: 0.16.9 实测 create 的初始 model 形参接受对象
  但丢 options, turn 阶段报 ModelProtocolError "Reasoning level is
  required for <provider>/<model>"; setModel 路径无此问题。

实测 (ZCode App 3.14.0 / CLI 0.16.9, personal provider bigmodel-api):
- session/new {model: "GLM-5.3"} → session/prompt → stopReason=end_turn;
- setModel {model: {providerId, modelId, options:{reasoningLevel:max}}} →
  ok → prompt → end_turn;
- setModel 缺 options (无 reasoning 的模型除外) → turn 失败, 与 catalog
  defaultLevel 补齐后通过。

测试: M5 改写 (对象透传/缺参 -32602/旧形态拒绝) + C4 系列 7 例 (字符串
catalog 解析/无 reasoning 条目/对象透传/未知 modelId/setModel 失败连带
new 失败/不带 model 向后兼容/非法形态)。547 passed + 34 subtests。
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