Skip to content

[Bug] 批注块不随消息发送:DSH 0.1.6-alpha.2 移除了 sessions.list.current(1.4.10 / 1.4.11-preview.1 均受影响) #64

Description

@wkeking

TL;DR:DSH 在 commit 6830e1460d(首个发布的版本是 dsh-v0.1.6-alpha.2)把 SessionListState.current 移除了。插件从 ctx.sessions.list.getSnapshot().current 取当前会话 id,于是恒为 undefined;attachAndSend() 在 current === undefined 处静默 return false(早于自身的 try/catch),批注块从不进草稿,也无任何提示。1.4.10 与 1.4.11-preview.1 均受影响(我核对了 preview 的 tarball,同一写法仍有 9 处)。0.1.6-alpha.2 起内核也没有为页面级插件提供"当前会话"的公开读取面。

环境

  • 插件:@changfenhuang/dsh-annotation@1.4.10(npm latest);另核对 1.4.11-preview.1,受影响
  • 宿主:DSH 0.1.6-alpha.2(tag dsh-v0.1.6-alpha.2,commit ddefc45fbc,源码 checkout 构建)
  • 形态:Web GUI(dsh web)

现象

选中助手文字 → 添加批注 →「批注 ×N」标签正常出现 → 回车发送:

  • 消息里没有批注块,模型只收到正文;
  • Console 没有 [annotation] 批注块已拼入草稿,回车将随消息发送(N 条);
  • 没有任何 toast 或报错(选区、高亮、编号脚标、标签全部正常,只有"发送"这一环失效)。

根因

1.4.10 的 client.js 在 7 处读取 sessions.list.getSnapshot().current:第 879 / 1146 / 1518 / 1799 / 1802 / 2205 / 2208 行。

DSH commit 6830e1460d(refactor(session-controller): own Client Session generations,2026-09-17)把 current 从 SessionListState 移除:

内核版本 SessionListState.current 插件表现
dsh-v0.1.5-rc.2(1.4.10 的验收宿主) 存在 正常
dsh-v0.1.6-alpha.1(1.4.11-preview.1 的验收宿主) 存在 正常
dsh-v0.1.6-alpha.2 已移除 批注不发送

attachAndSend() 的写法是先静默返回、后进 try/catch,所以整条链路没有任何提示:

function attachAndSend(e) {
  var current = sessions.list.getSnapshot().current
  if (current === undefined) return false      // ← 命中这里:无 toast、无日志
  var scoped = sessions.scope(current)
  ...
  try { ... shell.setDraft(block + ...) } catch (err) { showToast(t('toast.attachFail')) }
}

同一原因还波及(可用同一种修法一起解决):

  • submitAttached():Cmd/Ctrl+Enter 发纯批注同样提前返回;
  • watchInputDraft():以"草稿由有变空"作为已发送的清理权威,现在每秒重试、永不挂上;
  • writeCurrentPendingQuotes() / readPendingQuotes():按会话持久化的 key 恒为 undefined,读写都失效;
  • 会话切换检测:选择态已移出 list store,sessions.list.subscribe(...) 不再于切换时触发(跨会话保留未发送批注的特性失效)。

内核侧没有公开替代读面

  • 新的选中态在 packages/client/ui-workspace/src/client/navigation.ts 的 private readonly selection(持久化键 dsh.sessions.current);UiWorkspace 公开接口只有 openSession / startSession / archiveSession 这类动作,没有任何读取成员。
  • ISessions(packages/api/session-controller/src/client/contract/sessions.ts)也没有等价读取:scope(id) / scopeOf(ctx) 都需要你先知道 id,或已处于该会话的 ctx。
  • 已核对 dsh-v0.1.7-alpha.2 与 master(2026-09-22):SessionListState 仍无 current,selection 仍为私有;0.1.7 还把 subagentsByParent / jobsBySession 换成了 projectionsBySession。

即:页面级(非 slot 内)插件目前没有任何官方途径知道"当前是哪个会话"。这也是本 issue 建议内核侧补齐的部分。

最小复现

手工:

  1. DSH 0.1.6-alpha.2 + 插件 1.4.10;
  2. 选中助手回复里一段文字 → 添加批注(内容可留空);
  3. 输入框写一句话 → 回车;
  4. 看消息内容与 Console:批注块缺失,且没有 [annotation] 批注块已拼入草稿… 日志。

代码级(沿用插件自带夹具的抽取方式,只把假内核换成 0.1.6 的真实形状):

var sessions = { list: { getSnapshot: () => ({ ids: ['session-a'], byId: {}, phase: 'ready' }) }, scope: () => ({}) }

attachAndSend({}) 返回 false,草稿保持原样。

建议修法

首选(内核侧):给页面级插件一个公开的只读选中态——例如把 uiWorkspace.selection 暴露为只读快照源,或在 ISessions 上恢复等价能力。这样插件只需改一处 id 来源,也不会再因内核内部重构而断裂。

临时(插件侧):读 localStorage['dsh.sessions.current'] 的 sessionId,再走 sessions.scope(id)。我在本地按此思路打了补丁并验证通过,改动共 3 处:

       var sessions = ctx.sessions
+      // ---- 兼容 DSH 0.1.6-alpha.2+(内核 commit 6830e1460d 移除了 sessions.list.current)----
+      // 当前会话改由 uiWorkspace 的私有 selection store 持有,内核未提供公开读取面;
+      // 该 store 以 'dsh.sessions.current' 键持久化到 localStorage,故在此退化为读它。
+      function currentSessionId() {
+        try {
+          var raw = localStorage.getItem('dsh.sessions.current')
+          if (raw === null) return undefined
+          var parsed = JSON.parse(raw)
+          return parsed !== null && typeof parsed === 'object'
+            && typeof parsed.sessionId === 'string' ? parsed.sessionId : undefined
+        } catch (_) { return undefined }
+      }

另两处:7 个调用点 sessions.list.getSnapshot().current → currentSessionId();会话切换检测改为 sessions.list.subscribe(fn) + setInterval(fn, 300),并在已有清理函数里 clearInterval。

注意这是权宜之计:它依赖内核内部持久化键名,键名或持久化方式再变即失效。长期仍建议内核提供公开读面。

测试夹具需要同步(不是行为回归)

  • test/message-block.test.mjs 的 harness 把假内核硬编码为 { list: { getSnapshot: () => ({ current: 'session' }) } },并把函数单独 eval:换成读 helper 后,抽出的 attachAndSend 会报 currentSessionId is not defined,导致 4 项测试变红(需把 helper 一并注入 harness)。
  • test/pending-clear.test.mjs 的"会话切换作废旧会话未消费的发送暂存数据"依赖 sessions.list.subscribe(function () { 这一写法,改具名函数后该项变红。

相关但不同(避免混淆)

验证记录

同一夹具 + 真实 0.1.6 内核形状(list 快照无 current),打补丁前后对照:

attachAndSend() 返回 草稿是否含批注 sessions.scope() 收到
原始 1.4.10 false 否 从未调用
打过补丁 true 是(且保留原问题) "session-a"

其余:node --check 通过;8 处 currentSessionId 引用经括号作用域分析全在 apply() 内;重复调用不重复拼稿;硬刷新后 Console 出现 [annotation] 批注块已拼入草稿,回车将随消息发送(1 条),模型按 Annotation 1:… 逐条回应。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions