Repository navigation
session event "system/message" is not surface-eligible and cannot carry surfaceOp —— 成因、排查方法与修复
#6274
XingbinChen
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
以下由DeepSeek-V4.1-Flash分析并生成。
1. 现象
升级dsh版本后,在
dsh --profile web的浏览器 UI 中(以及终端日志里)出现:无法查看旧的对话记录,而且无法选择模型。
环境:
dsh --version→0.1.5-rc.1npm i -g @deepseek-ai/dsh,安装在%USERPROFILE%\..\nodejs(普通 Node 全局目录)webprofile;此前用 marketplace 装过若干 out-of-tree 插件(dsh-context、dsh-better-sidebar、@linxin666/dsh-client-ui-git-graph、dsh-client-ui-skill-explorer),报错发生在插件装卸期间 / host 升级前后dsh --profile web --no-open --port 8099无报错、UI 正常加载、控制台 0 error),错误只在插件参与时才出现2. 这条报错的确切来源
全仓库只有一处抛出该字符串(
packages/core/session/src/surface.ts,surfaceOpOf()):validateSurfaceMetadata()(同文件)由这些路径调用:Session.append()与 seed/restore 校验:packages/core/session/src/index.tsfoldSurface():会话回放 / snapshot / session-querypackages/api/session-controller/src/client/session-wire-event.ts(浏览器端历史分页与 live 帧)结论:抛出这句话的那个
@deepseek-ai/dsh-session副本,其SURFACE_EVENT_TYPES里没有system/message。 也就是说——事件本身没写错,是读取/校验它的那份库太旧。3.
system/message什么时候变成 surface 事件的system/message是在 commitee956c720d(2026-09-06,"refactor(session): represent the system prompt as surface node zero") 才加入SurfaceEventType的(设计说明:.agents/notes/implemented/architecture/2026-09-02-system-prompt-as-surface-node.md)。在那之前,系统提示词存放在 log-only 的request/header.system里,system/message根本不存在。已发布版本的运行时集合(核对各 tag 的
packages/core/session/src/surface.ts):SURFACE_EVENT_TYPES0.1.1-rc.2、0.1.2-rc.1、0.1.3-alpha.1/2及更早user/message、assistant/message、tool/result(3 个)0.1.5-alpha.1、0.1.5-alpha.2、0.1.5-rc.1、0.1.5-rc.2system/message(4 个)所以:旧库读到新 host 写出的
system/message(带surfaceOp)时,必然抛这句。4. 排查方法(逐步可复现)
4.1 先确认 host 本身是新的
如果 host 已是
0.1.5-*,那问题就不在安装本身,而在第二份旧副本。4.2 枚举机器上所有
dsh-session副本及其版本本次排查结果(问题实例):
注意:
%USERPROFILE%\.dsh\profiles\<profile>\node_modules里还有整套同代的旧依赖(dsh-llm、dsh-settings、dsh-invariants、dsh-brand、dsh-scope… 均为0.1.2-rc.1),不只是dsh-session。4.3 直接验证哪份副本会抛错
确认旧副本里没有
system/message:再用它跑一次最小复现(
<copy>= 上面那个目录):输出:
同一份副本用新版(
0.1.5-rc.2)跑则不会抛错——至此定位完成。4.4 确认插件解析路径是否被 profile 目录遮盖
问题状态下指向
...\profiles\web\node_modules\...(旧),修复后指向安装目录(新)。4.5 查 marketplace 的兼容性日志(成因佐证)
%USERPROFILE%\.dsh\profiles\web\.dsh-market\log.ndjson:{"level":"warn","event":"install-compat","detail":"dsh-context: introduced host-compatibility risks — @deepseek-ai/dsh-session@>=0.1.2-rc.1 vs 0.1.1-rc.2; @deepseek-ai/dsh-settings@>=0.1.2-rc.1 vs 0.1.1-rc.2"} {"level":"warn","event":"update-compat","detail":"dsh-better-sidebar@0.19.0 declares ^0.1.5-rc.1; this host is 0.1.2-rc.1 — refused before installing"} {"level":"warn","event":"update-compat","detail":"dsh-better-sidebar: introduced host-compatibility risks — @deepseek-ai/dsh-session@^0.1.5-rc.1 vs 0.1.2-rc.1; ..."}日志明确显示:装插件时 host 还是
0.1.1-rc.2/0.1.2-rc.1,而插件声明的依赖是>=0.1.2-rc.1/^0.1.5-rc.1,于是插件把一整代旧的dsh-session拉进了 profile。5. 根因
插件私有依赖闭包与 host 版本错配,且旧副本在 profile 目录里
shadow掉了安装里的新副本。完整链条:
system/message只在 host ≥0.1.5-alpha.1时才是 surface 事件;旧版@deepseek-ai/dsh-session(≤0.1.3-alpha.2)的SURFACE_EVENT_TYPES只有 3 个类型。dsh-session装进%USERPROFILE%\.dsh\profiles\<profile>\node_modules;插件代码从该目录解析模块,优先拿到这一份。0.1.1-rc.2→0.1.2-rc.1→0.1.5-rc.1的迁移),开始按新规则写/发system/message(surface node 0,带surfaceOp)。dsh-session,validateSurfaceMetadata/foldSurface/ wire 校验拒绝system/message+surfaceOp→ 抛出该错误。profiles\web\node_modules里的旧代闭包原地留存(pnpm-lock.yaml的 importers 已经是空的,但目录还在,旁边还留着 npm 的package-lock.json),于是即便插件已卸载,后续任何从 profile 目录解析dsh-session的代码仍会踩到旧副本。为什么会出现"另装一份旧版"而不是复用 host 的:semver prerelease 规则。
^0.1.3-alpha.2只匹配0.1.3-alpha.2及之后同一major.minor.patch元组的预发布版本,不匹配0.1.5-rc.2。所以按旧范围解析时只能下载旧的同代版本,形成新旧共存。补充说明:机器上并不存在"多个 dsh 安装"。
D:\Environments\nodejs只是 nvmD:\Programs\nvm\v24.15.0的 junction,指向同一个安装;真正多出来的只是 profile 目录里的那份插件依赖。6. 解决方案
6.1 立即修复:清掉 profile 里的旧依赖残留
插件已经卸载(
package.json/ patch 里都没有引用了),node_modules属可再生状态,直接删:若插件仍在使用,正确做法是让整棵树同代:先
dsh plugin --profile web prune(转发到 pnpm),或直接删掉 profile 的node_modules后重装插件。6.2 验证修复
本次实测:清理后只剩一份
0.1.5-rc.2;profile 解析指向安装目录;dsh --profile web启动正常,浏览器打开 UI 并切换 workspace,控制台 0 error。6.3 日常更新顺序(避免复发)
npm i -g @deepseek-ai/dsh@<channel>(latest/next/alpha),重启 dsh。refused before installing/host-compatibility risks是保护,不是 bug —— 出现就先去升 host。node_modules,不要让两代共存。%USERPROFILE%\.dsh\profiles\<profile>\.dsh-market\log.ndjson。附:一句话结论
system/message是0.1.5-alpha.1起才进入 surface 的事件类型;当 profile 目录里残留着旧代@deepseek-ai/dsh-session(本例0.1.2-rc.1)时,插件会优先加载旧库,用旧规则校验新 host 写出的事件,于是抛出not surface-eligible and cannot carry surfaceOp。删掉%USERPROFILE%\.dsh\profiles\<profile>\node_modules里的旧依赖闭包即可,之后保持 host 先于插件更新。All reactions