Repository navigation
feat(acp-bridge): session/new 透传 toolAllowlist/toolDenylist - #53
Conversation
… 实测)
问题 (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。
|
感谢这个增量——动机踩得很准(plan 模式是 advisory 的痛点本仓在 README「重要限制」里也有记录)。结论:修后可合并(两条 P1 是同一处校验语义的正面缺口,改动量小)。以下是维护者侧独立审查;独立代码审查 agent 的意见见下一评论。 核心声明活体验证(本机 0.16.9 官方 app-server)
意见应修(合并前):
建议:
合并顺序本 PR 叠在 #52 上:先合 #52,本 PR rebase 后再走(若 #52 按审查意见修改,本 PR 需要跟着动 |
结论:修后可合并(无 P0;2 条 P1 校验语义 + 5 条 P2 文档/验证) 一、对作者声明的引擎侧核实(bundle 证据)
二、问题清单P1(应修)
P2(建议)
P3(提示)
未发现问题的维度:性能(O(n) 单遍归一);注入(工具名作数据下发,日志只记数量不泄内容);崩溃/边界(非 dict/缺键/空列表不抛异常);向后兼容的「缺省」分支经 C5a 与代码核实成立。 亮点:增量 commit 隔离干净;「缺省绝不改变旧行为」用 C5a 多形态断言钉死,超出常见测试质量;日志只输出条目数;对引擎行为的调研基本可被 bundle 证实(strict schema、工具集级硬过滤)——对首个外部 PR 而言证据意识很强。 给贡献者的一句话:这是一份调研扎实、测试自觉的高质量 PR——增量隔离清楚、兼容性有断言护住,感谢把引擎行为吃透后再动手;需要补齐的是把「名单是安全原语」贯彻到非法输入与空输入的处理(fail-closed 而非静默放行),并把 README/SKILL.md 与 precedence、Node REPL 提示一起补上,改完即可合。 |
在 jasonQin6 PR tizerluo#52 基础上按 R1 审查清单修复, 保持原方案 (setModel 对象 形态 + session/new 可选 model) 不变, 只修审查指出的问题。 A (P1 孤儿会话): - model 形状校验前移到 session/create 之前 — 非法形态本地 -32602 且不 触碰后端, 不再先真实建会话再报错; - create 后失败 (catalog 未命中/不可用、setModel 失败、setModel 超时) 的错误文案带已创建的 sessionId (「已创建会话 <sid> 但 model 未生效: <原因>」) 供客户端收编; 后端无会话删除方法, 不尝试回收; - session_map 注册后移到 model 应用成功之后, 失败会话不登记、不能被 session/prompt 使用。消费方确认: session/prompt/session/cancel 用 .get(acp_sid) 严格取, 扩展 handler 用 .get(acp_sid) or acp_sid 兜底; acp_sid 恒等于 zcode_sid 且登记先于响应返回, 移位对成功路径无行为差异; - _on_session_new docstring 同步失败语义。 B (P3): - 对象形态 providerId/modelId 须为非空字符串 (本地 -32602, 消除透传后端 -32602 被 _passthrough_error 改写成 -32603 的不一致); - catalog 条目/ref/reasoning 加 isinstance 守卫 (畸形条目不抛 AttributeError); - 「catalog 不可用」与「未命中」文案区分; - _passthrough_error 加 prefix 参数 + docstring 注记 session/new 嵌套 setModel 是核心 handler 走本 helper 的例外场景; - _on_session_set_model docstring 改写 (需要按 catalog 解析的调用方应在 session/new 指定; 本方法要求调用方提供完整对象)。 C (文档): - README 版本兼容性加注: setModel 对象形态仅 0.16.x 验证 (0.16.9 实测), ≤0.15 未验证; - README/SKILL 的 session/new 说明: 「补默认 reasoningLevel」条件化为 「catalog 条目带 reasoning.defaultLevel 时补」, 补 model:null 语义; - agent-help key_methods: setModel 参数改对象形态 + 0.16 注记; - docs/recheck-3.14.0.md 追加补遗 (旧形态 -32602 原文/新对象形态实测/ create 快照 catalog 形态/空参探存活的方法论教训)。 D (测试 547→551): - C4/C4a/C4b 补 sessionId 断言; C4d 补 setModel 文案 + 超时分支 + 失败 不登记; C4e 锁定 create 参数逐字段不变; - 新增 C4g (嵌套 setModel -32601 → 「已移除 (session/setModel)」文案)、 C4h (对象缺字段 → 本地 -32602 且不发起后端调用)、C4i (catalog 不可用 文案)、C4j (畸形 catalog 条目不抛); - C4c/C4f 补「不发起 create」「不登记 session_map」断言。 验证: python3 -m unittest discover -s tests → 551 passed; ruff check 干净。
0.16 stdio 下 mode=plan 是 advisory (工具照常自动执行, 实测), 快照 diff 只是 事后发现; 引擎 session/create 的 toolAllowlist/toolDenylist 映射 引擎的工具集注册级硬 allow/deny (先于权限层、与 mode 无关), 是会话级前置只读手段。非空字符串数组 原样透传 (空条目剔除), 缺省/空数组/非数组时 create 参数与旧版逐字一致。 C5/C5a 回归用例; 全套 549 passed + 34 subtests。 R2 审查修复: 严格校验 fail-closed / 空数组透传 / 文档与测试同步 — - 键存在 → 必须为字符串数组且每个元素 strip 后非空, 非法 (含显式 null/ 非数组/元素非字符串/空串) 本地 -32602 且不触碰后端; 删除 str() 强转与 非数组静默忽略路径; 键缺省 → 不写入 create 参数 (与旧行为逐字节一致); - 字面空数组 [] 原样透传 (引擎语义: 空 allowlist = 全部禁用, 空 denylist = 无限制), 不再静默丢弃; - docstring/README/SKILL 同步: 机制归属修正为工具集注册级物理过滤 (先于 权限层、与 mode 无关; 非 PermissionService 映射), allow+deny 同传 = 交集且 deny 优先, 只读监督建议同时 deny Node REPL 族; - 测试改写为 C5/C5a-C5e (归一/缺省兼容/空数组透传/非法 fail-closed/单边/ 与 model 并存), 全套 557 passed; ruff check 干净。
20fa2b0 to
446737c
Compare
|
感谢这个增量,同样先道个歉:搁了近两周才被看到是我们的问题;为不再耽误,我们在你的分支上直接代为修复后合并了(rebase 到 #52 的修复版之上,你的提交经 amend 保留了你的作者署名, 处理经构
贡献记录你的提交以原始作者署名保留在 main 历史(合并提交 欢迎继续贡献,后续不会再让 PR 晾着。 |
基于 #52(session/new model 钉定)之上的增量提交,只评审最后一个 commit(20fa2b0)。
动机
0.16 stdio 下
mode=plan是 advisory——工具照常自动执行,调用方只能在事后(快照 diff)发现越界。会话级前置只读目前没有手段:引擎session/create的toolAllowlist/toolDenylist映射PermissionService的硬 deny/allow,不经过权限模式判断、hook 也不能覆盖,正是这个缺口需要的原语。变更
session/new新增可选toolAllowlist/toolDenylist(非空字符串数组,空条目剔除)原样并入session/create参数。缺省、空数组或非数组时 create 参数与旧版逐字一致(向后兼容:不传名单的调用方行为不变;传了名单而后端拒收未知字段时,create 的报错如实透出)。测试
pytest tests/ -q→ 549 passed + 34 subtests