Repository navigation
[bug] DSH 0.2.1-rc.5:Web GUI 改模型配置必报 profile reload requires the root Include entry #11853
Replies: 4 comments 1 reply
|
运行 |
|
哦,我 dsh-web 运行环境是在 ubuntu 上 |
|
Follow-up: I've opened a dedicated proposal with concrete patch sketches for this failure class — #12076. TL;DR of the proposal:
@tianyicui @LegGasai @imccyu — the proposal is ready to be picked up directly if the team agrees with the direction. |
|
补充两个从 一个 30 秒判别步骤:先区分「双模块实例」与「ctx 归属」
# 临时把 profile 的 node_modules 挪走,重启 dsh web
mv ~/.dsh/profiles/web/node_modules /tmp/nm-backup
# 如果设置写入立刻恢复正常 → 是「profile 里装了重复的 @deepseek-ai 包」导致的双模块实例
# 如果仍然报同样的错 → 才是 ctx 归属 / 配置损坏方向的问题我用运行时插桩(在
错误文案本身在误导排查方向
完整修复提案我把根因分析、插桩证据和三组可直接采纳的代码方案整理成了独立提案:#12076( (环境: |
Uh oh!
There was an error while loading. Please reload this page.
1. 一句话结论
dsh web下,在 Settings → Models 页面修改任一模型配置,请求都会被dsh-config-editor的持久化回调拒绝:重启进程后 100% 复现,与浏览器访问地址、运行时长、网络路径完全无关。根因是
ConfigEditor.edit()内部把被编辑条目自己的 entry context(this.ownerContext.root)当作"根上下文"传给reconcileProfilePatches(),而bootstrapIncludes这个 WeakMap 的 key 是应用根 Context(boot()里new Context()那个),两者永远不相等。2. 环境
3. 复现步骤
systemctl --user restart dsh-web,从日志取新 URL(dsh web: http://127.0.0.1:19387/?token=...),浏览器打开。已验证排除的因素:
socat转发的10.10.10.105:19388 → 127.0.0.1:19387表现一致。systemctl --user status显示启动时间为刚刚,PID 为新值(如 1764215,since Mon 2026-11-02 15:50:23 CST),ss -ltnp确认 19387 只有这一个 node 进程,19388 只是 socat。4. 根因分析(已逐行核对 rc.5 发布产物)
4.1 报错点
@deepseek-ai/dsh-app-boot/lib/index.js:boot()中:所以 只有 boot 时那个应用根 Context 才能取到 entry。
4.2 触发路径
@deepseek-ai/dsh-config-editor/lib/index.js:其中
this.ownerContext是ConfigEditor构造时注入的插件条目作用域 ctx:Cordis 语义:
ctx.root是"应用根上下文(every child context shares it)",不论调用方处于哪个插件条目作用域,ctx.root都应解析到 boot 的根 Context。而 DSH 的 WeakMap 却以"传入的那个 Context 对象"为 key。这两者在ConfigEditor里对不上。4.3 为什么
dsh-hmr没报同样的错@deepseek-ai/dsh-hmr/lib/index.jsL1359 调用recomposeProfile(this.ownerContext.root, ...)却能工作——这与上面"应该恒等"的预期相矛盾,说明问题出在ownerContext的来源或某个 scoped context 上,而不是ctx.root本身:ConfigEditor实例是在某个 Loader 条目(internal/loader/entry)或 group 的 scoped ctx 上实例化的,ownerContext.root会指向该 scoped context 的真实根(例如ctx.createPlugin(...)时传入的this.ctx),而不是 boot 的实例根;mountRootInclude登记的是 boot 的实例根。因此建议修正方向(二选一,任一即可修复):
mountRootInclude除了bootstrapIncludes.set(ctx, entry),还应对ctx.root、ctx[Context.isolate]的根标签等所有等价根建立别名映射;recompose()/reconcileProfilePatches()里回退查找:当bootstrapIncludes.get(ctx)为空时,沿ctx.root/ctx.root.root链、以及loader.entries()中parent.tree.ctx.fiber.entry?.id === "include"的条目反查根 Include entry,找不到才抛错;ConfigEditor显式持有 boot 根:ConfigEditor构造时用ctx.root之外的可靠来源(例如通过profileContext一并带过来,或新增一个bootstrapContext服务)保存真正的应用根。5. 影响
configEditor.edit()/settings.write()的字段全部失败(settings.write()→configEditor.edit())。cordis.patch.yml+systemctl --user restart dsh-web(本文档的环境即如此绕过)。!!js表达式写坏的风险(这点需要单独验证)。6. 期望行为
点击保存后配置应原子落盘并热重载,不应抛出"requires the root Include entry";若确实无法找到根 Include,应给出一句可操作的诊断(例如"配置编辑器所处的 context 不是应用根,请报告该条目的 ownerContext 链"),而不是让用户以为配置文件写坏了。
7. 临时绕过(供其他用户参考)
~/.dsh/profiles/web/cordis.patch.yml(注意:id定向覆盖会替换整个config,必须重述原字段;!!js表达式原样保留)。systemctl --user restart dsh-web,从journalctl --user -u dsh-web取新 token URL 打开。0.2.2-alpha.2属于未验证路径(本次未测试)。All reactions