Repository navigation
Replies: 2 comments
|
丢消息这条链路你说对了,但有两处要修正: 链路成立
对照一下正常领取: 修正一:回执已经有,缺的是消费者
每条被丢掉的消息都会发一个实时事件。问题是只有三个地方订阅它: 所以正确的说法不是"没有任何回执",而是"事件发了,UI 没接"。诉求也就更清楚了:让客户端订阅 修正二:
|
|
+1 |
|
丢消息这条链路你说对了,但有两处要修正: 链路成立
对照一下正常领取: 修正一:回执已经有,缺的是消费者
每条被丢掉的消息都会发一个实时事件。问题是只有三个地方订阅它: 所以正确的说法不是"没有任何回执",而是"事件发了,UI 没接"。诉求也就更清楚了:让客户端订阅 修正二:
|
|
+1 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
0. 一句话
我在一个回合运行中安装本地插件(= 改
<profile>/package.json的dsh.profile.bundles),约 2.8 秒后正在跑的回合被中止,同时我排队的那条消息无声消失:会话日志里它被移除、只带outcome: "canceled",界面上没有任何提示。我当时的判断是"我的消息被取消了",但实际上我没有取消过——"canceled"这个词在代码里跟用户操作无关。这条报告的主体是"丢消息",重载只是触发器。1. 环境
dsh/package.json→"name": "@deepseek-ai/dsh-desktop-runtime","version": "0.2.0-rc.2",exe FileVersion 同),win32/x64,nodeVersion 24.18.1、pnpmVersion 11.7.0,更新通道 nightlydesktop(DSH_HOME=C:\Users\WINDOWS\.dsh)session-7036c050-c6b0-4833-8446-169ee768345e,工作区C:\Users\WINDOWS\Documents\deepseek-harness\default-workspace2. 现象(重点:丢消息)
回合执行中,往
<DSH_HOME>\profiles\desktop\package.json的dsh.profile.bundles末尾追加一项后约 2.8 秒:turn/end→{"reason":{"kind":"aborted","reason":{"kind":"disposed"}}};该回合的全部输出从未送达用户(不是发送失败,是这轮结果根本不存在了);{"removedCount":1,"inserted":[],"outcome":"canceled"},界面没有任何提示;3. 复现
<DSH_HOME>\profiles\<profile>\package.json的dsh.profile.bundles(追加/删除任意一项);等价操作:在插件页安装/卸载一个插件(GUI 走同一条重载路径,见 §4.4);4. 代码级因果链
@deepseek-ai/dsh-hmr监听 profile manifest 与两个 profile 级补丁文件:dsh-hmr/lib/index.js:353const manifestPath = join(profile.dir, "package.json");:376await this.watchConfig(manifestPath, () => refresh(true));chokidarawaitWriteFinish: true(2 s 窗口)+debounce: 100正好解释 2.77 s。:359的if (manifestOnly && bundles === lastBundles) return,于:370await reconcileProfilePatches(this.ownerContext.root, patches, "dsh")。reconcileProfilePatches(dsh-app-boot/lib/index.js:3468-3495)重算 patch 集合、entry.update(...),然后:3488await Promise.allSettled(previousFibers.map(({ fiber }) => fiber.await()))—— 等待所有旧 fiber 结算;patch 子树重建,归属其中的 agent fiber 被 dispose。dsh-plugin-manager/lib/index.js:2031-2034reload()→ 同一个reconcileProfilePatches;change(...)(:2035-2057)在withFileLock(join(profile.dir,"package.json"), …)内执行并置application: hmr !== undefined ? "applied" : "restart-required"(:2042)。machine.cancel({ kind: "disposed" })(dsh-agent-loop/lib/index.js:1688;dispose 触发点:1713-1721),而cancel()(dsh-agent-loop/lib/index.js:815-821)先inbox.clear()再 abort——一次 dispose 同时产出「清收件箱」与「abort」,且被丢弃的条目没有任何用户可见的回执。dsh-agent-loop/lib/index.js:195const outcome = discardRemoved && actualDeleteCount > 0 ? "canceled" : void 0——只要有条目被丢弃就写canceled,与「用户点了取消」无关。正常消费走claim()(discardRemoved: false),因此正常投递的移除事件没有outcome字段(本会话实测:#6、[bug] SQLite scanRows torn-tail tolerance deletes valid events together with the bad row #675、[Feature Request] TUI支持 #842、插件写入自定义 session 事件类型会让会话永久无法恢复 #918、[Bug Report] Web UI 弹层:焦点可逃逸出 `aria-modal` 对话框,一次 Escape 同时关闭多层弹层(各弹层独立监听、无 stack 协调) #943 均无 outcome;只有被丢弃的那次 npx @deepseek-ai/dsh web failed with node-pty #835 有)。agent.cancel({ kind: "user" })(dsh-api-session-controller/lib/index.js:998),日志里会显示user;本例是disposed。session/end-seed属正常事件(dsh-session/lib/index.js:1351-1352)。插件管理器自身没有文件 watcher。5. 会话日志证据(原始 JSONL)
证据:
<DSH_HOME>\sessions\--C-Users-WINDOWS-Documents-deepseek-harness-default-workspace--\session-7036c050-c6b0-4833-8446-169ee768345e\session.v4.jsonl.zstd(多帧 zstd,需zstd -dc)tool/calledit写<DSH_HOME>\profiles\desktop\package.json(dsh.profile.bundles末尾追加插件名)agent/inbox/spliced{"target":"next-turn","start":0,"removedCount":1,"inserted":[],"outcome":"canceled"}← 排队消息在此消失turn/end{"turn":1,"reason":{"kind":"aborted","reason":{"kind":"disposed"}}}session/end-seed写盘 43.708 → 丢消息/abort 46.480 = 2.77 s。
(该排队消息的原文与三次编辑都在更早的
agent/inbox/spliced事件里——即内容确实存在于日志中,但从未进入模型上下文,用户界面也无从知晓。)6. 期望行为(Expected behavior)
outcome: "canceled"换成不会误导责任方的值;(具体实现建议见 §8。)
7. 已证实 vs 未隔离(诚实标注)
已证实(本机实测 + 代码引用)
outcome:"canceled"(§5);cancel()先inbox.clear()(dsh-agent-loop/lib/index.js:815-821);outcome的判定只看「有没有条目被丢弃」(:195);dsh-hmr监听<profile>/package.json(dsh-hmr/lib/index.js:353-376),bundles 变化触发reconcileProfilePatches(:359、:370),后者await所有旧 fiber(dsh-app-boot/lib/index.js:3488);dsh-plugin-manager/lib/index.js:2031-2057)。未隔离(推论 / 未能复现)
DSH_HOME的测试 profile 上用探针插件(ctx.effect打日志)观察:修改 profile 的cordis.patch.yml、以及向 bundles 追加一个能实际加载的新 bundle,都没有观察到无关插件 fiber 被 dispose(两次实验里都没有第二个回合在跑)。所以触发条件的精确边界待上游确认;但真实那一次的事件序列、时间戳、reason: disposed与上述代码路径完全一致。8. 建议
inbox.clear()之前把被丢弃的条目落一条显式事件 + 界面提示(「因配置重载,N 条排队消息被丢弃」),或者让排队队列跨 abort 保留、由用户决定重发;outcome: "canceled"拆成能区分「用户取消」与「系统丢弃」的值(例如discarded),避免把责任误导到用户;reconcileProfilePatches前检查是否有活跃回合/排队消息,若有则提示确认或推迟到空闲(插件管理器已有withFileLock与hmr.runExclusive,加一个「回合空闲」条件是自然扩展;与 建议:插件重载与宿主重启——已加载产物身份 / 单插件重载 / 人确认重启 #8470 的方向一致);dsh-hmrREADME 的「已知限制」补一条——profile manifest / 补丁文件变化会重载 patch 子树,可能打断进行中的回合并丢弃排队消息。9. 相关讨论(发帖时交叉引用)
cordis.patch.yml会杀死在跑回合)、[Bug] Live profile reload leaves session-scoped services unavailable: session/follow fails with gateway/service-unavailable #9100、【Bug】live 重载 profile 补丁后,在途会话工具目录静默塌缩(47 → 14),模型陷入幽灵工具调用循环 #7519、Editing a profile patch layer while DSH is running strips the agent's tools from live sessions #8635、[Bug] Native HMR starts replacement activation before asynchronous disposal finishes #6883prepareRequest抛错时永久丢失)、中断之后,排队消息只剩「编辑/删除」:唯一的发送按钮被 running 门挡成灰色 #8018(中断后排队消息只剩编辑/删除)All reactions