dsh-answer-top:AI 回答結束後自動滾到回答開頭

前言

DSH (DeepSeek Harness) 裏跑智能體,長回答是常態。回答結束時頁面停留位置在末尾:要麼從末尾往上手動翻半天,要麼重新生成一次。dsh-answer-top 這個插件解決的就是這件事:AI 回答結束後,把滾動容器自動滾回到這一輪迴答的第一行。

下面介紹這個插件:它是誰維護的、裝上去之後具體做什麼、怎麼安裝、有哪些開關可以配置,以及在什麼場景下不要指望它。

這是什麼

dsh-answer-top 是 DSH 生態的客戶端插件,維護者是 DSH-USER-GTB。它不改變 DSH 的行爲,只監聽 DSH 客戶端渲染出來的對話 DOM,在檢測到「本輪迴答結束」時執行一次滾動。

一句話定位:回答結束 → 自動滾到這一輪迴答的第一行,不用每次往上翻。

它屬於客戶端插件:全部邏輯在瀏覽器側(lib/client.js),宿主端 lib/index.js 是空插件,apply 不做任何事。

核心功能

自動回滾的觸發條件

插件監聽 DSH 客戶端的 DOM 契約,判斷本輪迴答是否結束:

  • MutationObserver 監聽 document.body 上 data-actions-reveal 屬性的變化,另有 800ms 定時器兜底(漏事件或會話切換時補檢)。
  • [data-turn-tail] 元素出現 data-actions-reveal,說明這一輪迴答結束了。
  • 找出本輪第一個 [data-chat-flow-kind="assistant-step"] 節點,把 [data-conversation-scroll] 滾到它的頂部。

用到的 DOM 契約是從 DSH 客戶端裏逆向出來的:

[data-conversation-scroll]   滾動容器
[data-chat-turn="N"]         第 N 輪的所有流節點
[data-chat-flow-kind]        節點類型:user / assistant-step / tool-call / turn-process
[data-turn-tail]             輪次末尾容器
data-actions-reveal          該屬性存在 = 本輪已結束

各情況下的行爲:

情況 行爲
回答比一屏長 滾到回答開頭
回答短於 max(視口 25%, 80px) 不滾(避免頁面亂跳;閾值可調)
歷史消息加載 不滾(只對最後一輪生效)
turn 號識別失敗 不滾(不 fallback 到全部回答,避免誤滾到對話開頭)
流式輸出中 不滾(等真正結束才動)
啓動後首次進入會話 跳到最後一輪迴答開頭(整個頁面生命週期只一次,切會話不重複)

觸發閾值(v0.12.0+)

默認行爲是「回答短就不滾」,由兩條規定同時生效、取更高一條:回答高度低於 max(視口 × 25%, 80px) 時不滾。

閾值在 DSH 設置 → 左側導航「自動回滾」→「觸發閾值」兩個滑塊裏調,拖動立即生效並自動保存:

控件 範圍 默認 說明
最小回答高度 視口的 5%~100% 25% 回答低於「視口 × 該比例」時不滾
絕對下限 0~200px 80px 無論窗口多大,回答低於這個高度都不滾

設置持久化在瀏覽器 localStorage 的 dsh-answer-top:config 鍵裏,結構如下:

{
  "v": 1,
  "enabled": true,
  "sessions": {},
  "threshold": { "ratio": 0.25, "px": 80 }
}
字段 說明
v 配置版本,仍爲 1
enabled 總開關,默認 true
sessions 預留空對象,首版恆空
threshold.ratio 最小回答高度佔視口的比例,0.05~1,默認 0.25
threshold.px 絕對下限像素,0~200,默認 80

舊版本寫出的配置沒有 threshold 字段,讀取時自動回填 { ratio: 0.25, px: 80 },不改寫原存儲,下次拖動滑塊時才寫回。

總開關

默認開啓。關閉後完全不滾——不是滾少一點,是一次都不滾。開關放在 DSH 設置頁「自動回滾」分區,也可以在瀏覽器控制台執行:

__dshAnswerTop.setEnabled(false)   // 關閉
__dshAnswerTop.setEnabled(true)    // 打開
__dshAnswerTop.config()            // 看當前配置

改了立即生效,不用刷新。控制台裏改閾值也可以,但不持久化:

__dshAnswerTop.setThreshold(0.15, 40)

手動回滾按鈕(v0.12.0+)

輸入框下方的 dock(conversation.composer.dock)裏常駐一個「⤒ 回滾」小按鈕,始終顯示:

  • 點擊即滾到最後一輪迴答開頭,即使自動回滾關閉、或檢測到共存插件衝突;
  • 手動路徑跳過總開關、300ms 交互窗口和高度閾值;
  • DOM 標記:data-dsh-answer-top-manual="1",title="回滾到回答開頭"。

也可以用控制台手動觸發一次:

__dshAnswerTop.forceScroll()

與同類插件共存

如果同時啓用了同樣會「自動滾動/跳轉」的插件,兩個一起動會打架。插件讀 ctx.modules 的模塊名單(純內存,不走 loopback、不聯網):

// v0.12.0 起只把 dsh-chat-answer-anchor 視爲衝突
["dsh-chat-answer-anchor"]

命中後只關自動路徑:回答結束不再自動滾,設置頁顯示「檢測到 dsh-chat-answer-anchor,已暫停自動回滾」。手動按鈕和命令行 forceScroll() 不受影響。禁用 anchor 後會自動恢復。探測每 800ms 做一次輕量重檢;ctx.modules 不可用或形狀不符時保持上一次結論,寧可不動也不誤傷。dsh-jump-button 自 v0.12.0 起不再算衝突。

看探測結果:

__dshAnswerTop.info().coexistence     // { anchor, checked, probe }
__dshAnswerTop.diagnose().coexistence
__dshAnswerTop.moduleIds()            // 覈對目標插件 id 是否帶 /client 後綴

數據與隱私

插件不聯網、不上傳。源碼裏沒有任何 fetch / XMLHttpRequest / WebSocket / sendBeacon,不向 DSH、GitHub 或第三方發送數據。

只在本機 localStorage 寫兩個鍵:dsh-answer-top:config(設置)和 dsh-answer-top:events(脫敏事件日誌,最多 200 條 / 50KB,超出丟最舊)。事件日誌只記布爾或枚舉字段(errorType、at、v、count、anchor、probe 等),不記消息正文、會話 id、用戶輸入、文件路徑、URL、頁面內容、截圖和原始錯誤文本。清理方式:

localStorage.removeItem('dsh-answer-top:events')    // 只清日誌
localStorage.removeItem('dsh-answer-top:config')    // 連設置一起重置
location.reload()

安裝與啓用

插件是鏈接安裝串(link)形式,裝完需要重啓 DSH(bundle 層插件)。在 DSH 裏進入 設置 → 插件 → 添加插件,輸入本地目錄的 link 安裝串:

link:<你的插件目錄>

命令行等價寫法:

dsh plugin --profile desktop add link:<你的插件目錄>

卸載:

dsh plugin --profile desktop remove dsh-answer-top

下載途徑:社區目錄頁 https://www.skillhub.cn/plugins/DSH-USER-GTB/dsh-answer-top 和源碼倉庫 https://github.com/DSH-USER-GTB/dsh-answer-top。本地開發用同一條 link 命令,重新添加時保持目錄不變即可。

package.json 裏的版本是 0.12.1,許可證 MIT。按包內聲明,dsh.client.inject 是 [],但 client 端運行時代碼的 exports.inject 必須聲明爲 ["slots", "modules"] 才能拿到 ctx.modules,否則共存探測不可用。

典型用法

1、裝好插件,啓動 DSH。
2、打開任意會話,發一條會觸發長回答的請求。
3、回答結束後,頁面自動回到這一輪迴答的第一行;如果回答短於 max(視口 25%, 80px),則停在末尾不動。
4、想臨時調閾值,在控制台執行 __dshAnswerTop.setThreshold(0.15, 40)(不持久化)。
5、想長期調整,在設置頁「自動回滾 → 觸發閾值」裏拖兩個滑塊。
6、自動回滾被共存插件暫停時,點輸入框下方的「⤒ 回滾」按鈕手動跳一次。

適用場景與注意

適合:以長回答爲主的 DSH 對話場景,特別是每次回答結束都要從頭讀一遍的用戶;以及想改成手動控制、只要一個常駐按鈕的用戶。設置頁開關和手動按鈕是兩個獨立槽位,開關切首選/備選位置時手動按鈕不受影響。

需要注意:

  • 插件以當前 dsh 進程權限運行,安裝前應打開源碼倉庫覈對代碼與許可證(MIT)。
  • 只對最後一輪生效,翻歷史消息時不會跟着滾。
  • 依賴 DSH 的 DOM 契約。升級 DSH 後如果失效,多半是屬性名變了——先按下面的方法確認契約元素是否存在。
  • v0.12.x 起滾動是瞬時跳轉(直接賦值 scrollTop),在 DSH 的新滾動容器上 smooth 動畫不生效。

調試

如果沒生效,在瀏覽器控制台逐條確認契約元素:

// 看契約元素在不在
document.querySelector('[data-conversation-scroll]')
document.querySelectorAll('[data-chat-turn]').length
document.querySelectorAll('[data-turn-tail]').length

// 看最後一輪結束沒
const tails = document.querySelectorAll('[data-turn-tail]');
tails[tails.length-1].hasAttribute('data-actions-reveal')

元素都在但不滾,看控制台報錯。設置頁裏看不到開關時,v0.9.1 起可以用一條命令定位問題在哪一層:

__dshAnswerTop.diagnose()
輸出 含義 下一步
injectCallbackRuns: 0 slot 還沒被聲明,注入回調沒跑 確認 DSH 版本里 settings.section 仍存在
injectCallbackRuns: 1, registerRuns: 0 回調跑了但註冊失敗 看 registerError
slotEntryCount: 0 註冊了但列表裏沒有 看 registerError / 是否被 abdicate
slotEntryCount: 1, slotMounted: 0 已註冊,只是沒打開對應分區 打開 設置 →「自動回滾」
slotEntryCount: 1, slotMounted: 1 一切正常 看組件是否被 CSS 隱藏

注意 teardown() 會註銷 slot,之後必須刷新頁面纔會重新註冊。

總結

dsh-answer-top 是一個功能單一的客戶端插件:自動回滾、閾值可調、有手動按鈕兜底、不聯網不落敏感數據。裝好重啓 DSH 即可用;如果以後 DSH 改了 DOM 契約導致失效,先在控制台覈對上面那幾個契約元素是否存在。目錄頁:https://www.skillhub.cn/plugins/DSH-USER-GTB/dsh-answer-top ;源碼:https://github.com/DSH-USER-GTB/dsh-answer-top 。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜