前言¶
DSH(DeepSeek Harness)的理念是「一切皆插件」,客戶端 UI 也走同一套路:內置能力只做必要的骨架,長尾需求靠插件補。這就帶來一個具體痛點:用戶往 Web 對話裏貼大段日誌或大文本時,一條消息就能佔滿整個會話視口,前面的上下文全被頂走。DSH 自帶的 Turn Process Folding 只摺疊過程行(tool-call / thinking),不折疊 user 消息正文,所以這塊一直是空缺。
下面介紹一個填這個空缺的客戶端插件:constraint21 維護的 dsh-long-message-fold。它把超長的用戶消息摺疊成固定高度(默認 360px,約 16 行),底部漸隱,並提供「展開全文 / 收起」切換;短消息一個像素都不變,裝上即生效。
這是什麼¶
一句話定位:一個純客戶端(Web 平臺)UI 插件,遮罩 shipped 的 PlainUserText 渲染器,把超長 user 消息正文摺疊成固定預覽高度。
- 維護者:constraint21
- 分類:客戶端(Client)
- 許可證:MIT(© 2026 constraint21)
- 包名/版本:
@local/dsh-long-message-fold,0.1.0,package.json裏private: true(刻意不發 npm,只走 git 或本地目錄安裝) - 目錄頁:https://www.skillhub.cn/plugins/constraint21/dsh-long-message-fold
- 倉庫:https://github.com/constraint21/dsh-long-message-fold
核心功能¶
1、超長用戶消息自動摺疊成固定高度(默認 MAX_HEIGHT = 360px,約 16 行),底部用 mask-image 漸隱。漸隱不猜背景色,因此在任意主題下都正確。
2、摺疊態下給出 pill 狀操作按鈕:「展開全文 · N 行」展開並顯示總行數;「收起」回到摺疊態。
3、拖動窗口寬度或側欄變寬後,原本溢出的消息會自動恢復成不折疊狀態,不需要手動操作。
4、短消息和未溢出的文本片段保持原樣。未溢出的渲染路徑返回與 shipped UserTextRun 等價的 <span style="font-size:inherit;line-height:inherit">,流式佈局與原來一致。
5、展開狀態有內存級記憶(模塊級 Map,鍵爲節點起止偏移 + 文本長度 + FNV-1a 哈希,最多 400 條),虛擬列表卸載再掛載同一行時狀態不丟;不寫 localStorage,刷新即復位。
6、沒有開關,裝上即生效。
關於「算不算超長」:插件不看文本長度,而是實測溢出。它通過 useLayoutEffect + ResizeObserver 測量:
- 內聯態取
getBoundingClientRect().height,能反映折行後的真實高度; - 已成塊態取
scrollHeight,摺疊與展開兩態下判定一致,不會來回抖動。
這個做法是必需的:conversation.user.text.node 這個 key 在 QueueDock 預覽和 submission echo 中也會被調用(ellipsis: true,父級是 white-space: nowrap),nowrap 下高度恆定爲 1 行,因此靠長度判會誤傷。ResizeObserver 掛到祖先鏈上最近一個有盒子的節點(bubble),所以側欄或詳情面板寬度變化時能雙向重算。
安裝¶
插件走 DSH 的 Plugin Manager 安裝,三種方式任選。
第一種,讓 agent 裝(README 標註爲推薦):
安裝插件 github:constraint21/dsh-long-message-fold
對 DSH 說出這句話即可,agent 會調用 plugin_manager → install_bundle,審批通過後生效。等價的顯式調用方式是:
plugin_manager → install_bundle → target: github:constraint21/dsh-long-message-fold
第二種,本地目錄:先把源碼取到本地,然後把 install_bundle 的 target 指向該目錄的絕對路徑。
第三種,手動(不推薦):把包放進 profile 的 node_modules,並在 cordis.patch.yml 裏 insert 一個 long-message-fold 條目。手工修改 profile 的 package.json 或 patch 容易與 Plugin Manager 的狀態打架,能用前兩種就別用這個。
安裝後要刷新 Web 頁面。插件是純客戶端 UI,不重啓 Host 也可以,但頁面資源需要重新加載。
卸載時在 Plugin Manager 裏移除 @local/dsh-long-message-fold(或執行 plugin_manager action: remove_bundle),刷新頁面後 user 消息立即恢復原樣。插件狀態只存在內存裏,無殘留。
典型用法¶
裝完刷新頁面後直接使用即可,沒有配置項需要打開。
1、往對話裏貼一段超過 360px 的用戶消息(例如日誌或長文)。
2、消息體現爲摺疊態:正文最高 360px、底部漸隱,下方有「展開全文 · N 行」按鈕。
3、點擊按鈕展開完整內容,按鈕文字變爲「收起」;再次點擊回到摺疊態。
4、把窗口或側欄拉寬,讓消息不再溢出,它會自行恢復成不折疊。
調參方式¶
參數是 client.js 頂部的四個常量,改完重新加載頁面即可,不需要重新安裝:
| 常量 | 默認 | 含義 |
|---|---|---|
MAX_HEIGHT |
360 |
摺疊後正文高度(px,約 16 行) |
FADE_HEIGHT |
48 |
底部漸隱高度 |
REMEMBER_LIMIT |
400 |
展開狀態記憶條數 |
OBSERVE_MIN_CHARS |
120 |
短於此長度的文本不掛 ResizeObserver |
實現要點(給要看源碼的人)¶
插件採用同 key 註冊的方式遮蓋 shipped 渲染器:爲 slot conversation.user.text.node 的 key 'text' 註冊自己的渲染器,外層氣泡、附件、各類控件全部保留。該 slot 在 catalog 裏聲明爲 replaceRisk: "shadows-shipped-ui";shipped 的 PlainUserText 以 priority: 100 註冊,動態安裝的插件條目由 runner 的 allocatePriority() 分到更小的數值,而數值更小者獲勝,所以同 key 註冊即取代,無需自己傳 priority。
README 記錄了幾個被否決的替代方案,理由是它們要求重寫整行或整塊(pending / echo / 時間 / 複製控件、userStack / 附件行 / bubble / JsonBlock),或者違反「不寫組件外 DOM、不讀別人 DOM」的插件紀律。
實現上的約束:文案走 Client locale service(ctx.locale.register(NS, { zh, en }),slot 註冊帶 locale: NS 以拿到框架注入的 t);配色只用 --dsw-alias-* 主題 token;不 require 任何 Harness Client 包。
兼容性方面:插件依賴 slot conversation.user.text.node 與 Client 包 @deepseek-ai/dsh-client-ui-conversation(見 package.json 的 dsh.client.inject),slot 或 shipped 實現大改時可能失效。退化是安全的:若上游把 'text' key 改名或不再有 occupant,框架會用 fallback 渲染原始文本,消息顯示不受影響,只是不再摺疊。插件只在 Web 平臺註冊(dsh.client.platform = "web"),Host 半的 index.js 是空實現。
適用場景與注意¶
適合:經常在 DSH Web 裏貼長日誌、長文本,且願意用插件補這塊空白的 DSH 用戶和智能體開發者;也適合想看「如何在客戶端用 slot 同 key 覆蓋 shipped 渲染器」這個做法的插件作者。
注意幾點:
1、插件以當前 DSH 進程權限運行。安裝前應打開源碼檢查一遍,並確認許可證(MIT)是否符合自身合規要求。
2、該倉庫目前 star 數爲 0,屬於很早期的個人項目。功能描述和參數以 README 爲準,缺少大規模使用反饋的跡象,建議當作小工具自用並在自己的 DSH 環境裏驗證。
3、它只處理 user 消息正文,不處理 assistant 輸出、tool-call 或 thinking 的過程行。
4、package.json 標了 private: true,所以不能通過 npm install 安裝,只能走 Plugin Manager 的 git 或本地目錄方式。
5、目錄頁(skillhub.cn)是獨立的社區站點,與 DeepSeek / 幻方無官方從屬關係,不是一個官方應用商店。
結尾¶
這個插件的價值很窄也很明確:把「貼大段日誌把上下文頂走」這件事用摺疊 + 漸隱 + 一鍵展開解決掉,同時不改變短消息和流式佈局。安裝一條命令、刷新頁面即生效,不寫 localStorage、卸載無殘留。目錄頁在 https://www.skillhub.cn/plugins/constraint21/dsh-long-message-fold,源碼與 README 在 https://github.com/constraint21/dsh-long-message-fold。