[Bug] rc.8: 空白会话切换 Agent Preset 后,旧 preset 的 agent-scoped 工具注册/restrict 残留形成杂交工具面;header agentPreset 与实际 mount 不符 #3615
Replies: 1 comment
|
We hit both symptoms on 0.1.1-rc.2 with concrete evidence, confirming this from a third-party plugin's perspective:
Happy to share logs/snippets if useful for reproduction. |
Uh oh!
There was an error while loading. Please reload this page.
TL;DR (EN): On a blank Web session, switching the agent preset does not tear down agent-scoped effects installed by the creation-time default preset — tool registrations made via
agent.ctx.tools.registerand whitelists viactx.tools.restrictfrom the old preset's local.mjsrows survive the switch. The newly selected preset mounts its persona/presentation, but the model-facing tool surface stays the old preset's (a hybrid mount). Additionally, the session header'sagentPresetfield records the creation-time default, not the actually mounted preset, so session logs misattribute the preset. Found via trajectory forensics on rc.8; details, evidence table, and repro below (in Chinese).环境
0.1.0-rc.8,macOS (arm64),dsh webGUIsettings.yaml:agent-presets: { default: pi-code }(自定义用户 preset)触发条件(自定义 preset 的关键行为)
默认 preset
pi-code含本地.mjs插件行,在agent/created里:read/edit/write,签名分别为read{path,offset,limit}/edit{path,edits[]}/write{path,content});ctx.tools.restrict({allow:["bash","skill"]})对 inherited/global catalog 做白名单收口。现象
同一时段 3 个 blank session 在 roster 上切换过 preset(有
agent-preset/selected事件)。对session.jsonl.zstd逐事件取证:agentPresetagent-preset/selectedpi-codepibash,edit,read,skill,write(与 pi 一致,不可判别是否残留)pi-codestandardbash,edit,read,skill,writepi-codestandardbash,edit,read,skill,writeB/C 是杂交 mount:persona 与呈现方式(native,无 code presentation)是 standard 的,但模型可见工具面完全是旧 preset 的——
edit{path,edits[]}、read{path,offset,limit}是旧 preset agent-scoped 注册的自定义工具签名(host 层并未全局挂载,已用--dump-config排除);write_todos/task/web_search等全部消失——被旧 preset 的tools.restrict白名单滤掉了。模型侧完全无感知,正常调用这五个工具并完成任务,症状非常隐蔽。
机制推测
agent/created只在 session 出生时 fire 一次,.mjs行的 agent-scoped 注册与 restrict 挂在 agent 生命周期上;blank session 切 preset 触发的 re-mount 只替换 generation 内的 prompt sections / tool-presentation / preset 工具行,不会 dispose agent-scoped 效果,于是新 preset 的声明面 = 新 preset 工具行 ∩ 旧 restrict 白名单 ∪ 旧 agent-scoped 注册。影响
agentPreset不能作为分析/审计的分组键。我们是在做多模型轨迹对比时,发现三个标着pi-code的 session 声明面互不相同,才追查出来的——一开始还把它误读成"模型绕开 Code Mode 的行为差异"。request/header的tools数组才能发现。复现步骤
.mjs行:agent/created里 agent scope 注册任意自定义工具 +tools.restrict白名单;settings.yaml将其设为agent-presets.default;dsh web新建 blank session,在 roster 上把该 session 切到出厂standard;session.jsonl.zstd,查看request/header事件的tools:为旧 preset 的工具面而非 standard 的目录。期望行为建议
agentPreset跟随实际 mount 更新(或新增一个记录实际 mount 的事件,含 preset id + generation);目前agent-preset/selected只记录了用户的切换动作,三方(header / selected / 实际声明面)可以互相矛盾。附带一个小观察(非 bug)
同一次取证中:Code Mode 下
deepseek-v4-flash曾把 SDK 函数名tools.write当作原生工具名发起调用,runtime 正确拒绝(Error: unknown tool "tools.write"),模型随后自行写探针代码恢复。说明 decl 面与 SDK 文档面的命名混淆对部分模型是现实风险,供 prompt/SDK 文案设计参考。All reactions