Replies: 3 comments
|
Your root-cause analysis holds, and it is still unfixed on master (c291e79), with one detail to update. Current state (verified in source):
So "delete the mode → sessions strand permanently" still holds. Recovery options today (pick one):
Upstream fix direction (as per your post): the resume path should surface the structured agent-preset-not-found({agentPreset, available}) instead of |
中文对上帖里的垫片片段,两点实测结论。均针对已安装的 harness、 1. 片段里的谓词现在已经匹配不到任何东西
于是 2. 只包
|
|
Both corrections accepted — you're right on both, and I withdraw my earlier
Also verified: your proxy mechanism note — the cordis traceable proxy's set Net effect on the upstream direction I listed: surfacing 中文要点:两条更正均成立,已按同一 checkout(c291e79)复核,并撤回我之前对原 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
中文
删除或修改模式(Agent Preset,agent 预设)后,使用该模式的会话在宿主重启后无法恢复
摘要
会话创建时记录所用模式,每次恢复都按记录重新挂载。当该模式后来从名册消失——
$DSH_HOME/.agent-presets下对应目录被删除、改名,或模式被修改后不再以原 id 出现在名册——宿主一旦重启,所有记录了该 id 的会话都以笼统的internal错误恢复失败,且没有任何受支持的手段让这些对话继续。同一进程内其实已经容忍删除:
AgentPresets.remove()会为已挂载会话保留 standing mount(见packages/preset/agent-presets/src/index.ts中remove()上方注释)。缺口只在冷恢复路径:宿主重启后,磁盘上已不存在的模式无法再被挂载。环境
0.1.1-rc.2(npm 全局安装),profilewebv24.19.0,Windows 11(10.0.26100)复现步骤
~/.dsh/.agent-presets/router-standard/agent.cordis.yml(拷贝任意内置预设即可);实际结果(本次复现,完整错误信息):
(
liangshen是该宿主上既有的用户模式,其余四个为内置预设。)同一消息也出现在 RPC 的error.message里:{ "ok": false, "error": { "code": "internal", "message": "resume failed for session \"session-2c50143f-cf3e-4236-a0ee-d462bb2e605e\": Error: agent-presets: preset \"router-standard\" not found (available: standard, code, minimal, cordis, liangshen)", "details": {} } }UI 仅弹出这个“模型操作失败”开头的笼统提示,该 id 下所有会话永久卡死。实测一个真实环境里 78 个持久会话中有 20 个因单个被删 id 而搁浅。
期望结果:要么会话仍可恢复(有文档化的降级),要么给出结构化、可行动的错误与恢复路径,而不是笼统
internal。根因
恢复链路:
api-proxy.ts的composeAgent(presetId)->presets.resolve(id)抛UnknownPresetError(preset.ts)-> 被packages/api/remotes/src/agent-lookup.ts的兜底捕获包装成{ code: 'internal' },丢弃了线协议已定义的agent-preset-not-found结构化细节({ agentPreset, available })。对比之下冷读历史已经优雅降级(
standingKeyFor失败被吞掉、历史仍可查看),唯独恢复硬失败,行为不一致且难排查。另外持久层已具备显式改绑的全部机制(agent-preset/selected事件、最新者胜),只是没有暴露给搁浅场景。修复方向建议
agent-preset-not-found(而非internal),客户端即可提供恢复入口;agent-preset/selected事件以改绑到现有模式——与空白期agentPreset.select同一持久化机制,扩展到搁浅场景;已验证的进程内 workaround
通过 home patch 层挂载的小插件包裹服务实例的
resolve:未知 id 返回默认模式行(保留 ghost id 作隔离键),全部消费路径随之降级,20 个搁浅会话无需重建任何目录即恢复。核心代码见英文节。已检索的既有报告
Discussions/Issues 中检索
preset not found、resume failed、“删除预设 会话”均无重复;最接近的是 #3018(改默认预设对复用空白会话不生效),同属预设生命周期领域但症状不同。English
Summary
A session records the agent preset it was composed under — the same thing the UI calls a "Mode" — and re-mounts that preset on every resume. When the preset later disappears from the roster (its user-authored directory deleted or renamed under
$DSH_HOME/.agent-presets, or the preset itself modified), every session recorded under that id fails to resume with a genericinternalerror after a host restart, and there is no supported way to keep those conversations alive.In-process behavior already tolerates deletion -
AgentPresets.remove()keeps standing mounts for joined sessions (packages/preset/agent-presets/src/index.ts, comment aboveremove()). The gap is only the cold-resume path: once the host restarts, nothing can re-mount a preset that no longer exists on disk.Environment
0.1.1-rc.2(npm global install), profilewebv24.19.0, Windows 11 (10.0.26100)Minimal reproduction
~/.dsh/.agent-presets/router-standard/agent.cordis.yml(a copy of any shipped preset works).~/.dsh/.agent-presets/router-standard/, or modify it so that id leaves the roster.Actual (verbatim from the affected host):
(
liangshenis an unrelated user preset already on that host; the other four are the shipped built-ins.) The same message arrives in the RPCerror.message:{ "ok": false, "error": { "code": "internal", "message": "resume failed for session \"session-2c50143f-cf3e-4236-a0ee-d462bb2e605e\": Error: agent-presets: preset \"router-standard\" not found (available: standard, code, minimal, cordis, liangshen)", "details": {} } }The UI surfaces only that generic
模型操作失败toast, and every session recorded under the missing id strands permanently. In one real deployment here, 20 of 78 persisted sessions stranded behind a single deleted id.Expected: either the session still resumes (documented fallback), or the failure is a structured, actionable error with a recovery path - not an opaque
internal.Root cause
Resume funnels through the recorded effective preset (newest
agent-preset/selectedevent, else the header -packages/preset/agent-presets/src/session.ts,resolveSessionPreset) into:packages/host/apiproxy/src/api-proxy.ts->composeAgent(presetId)->presets.resolve(id)-> throwsUnknownPresetError(packages/preset/agent-presets/src/preset.ts),{ code: 'internal' }(packages/api/remotes/src/agent-lookup.ts,resume failed for session ...), discarding the structuredagent-preset-not-founddetails ({ agentPreset, available }) that the wire protocol already defines.Notably, the cold transcript read already degrades gracefully:
standingKeyForfailures are swallowed so history stays viewable without the preset. Resume is the only path left failing hard, which makes the inconsistency easy to hit and confusing to diagnose.A session's preset is deliberately fixed at creation (
assertPresetUnchanged), and blank-session switches are recorded asagent-preset/selectedlog events where the newest wins - i.e. the persistence layer already has everything needed to re-point a session at another composition explicitly.Suggested directions (pick per taste)
agent-preset-not-foundinstead ofinternal(the RPC details map already carries{ agentPreset, available }). Clients could then offer recovery.agent-preset/selectedevent - same durability mechanismagentPreset.selectuses while blank, extended to the stranded case.Verified workaround (process-level plugin)
A home-patch plugin wrapping the live service instance keeps all 20 stranded sessions resumable with no directories recreated:
All consumers (create/resume/fork/cold read via
resolveMountable/standingKeyFor) degrade together because they funnel throughresolve()/this.resolve().Prior art checked
Searched Discussions & Issues for
preset not found,resume failed; no duplicate found. Closest: #3018 (default-preset change not applying to a reused blank session), same lifecycle area, different symptom.All reactions