dsh-if:給 DSH 加一條先判斷條件、成立才發送指令的 /if 命令

前言

在 DSH 裏編排智能體時,經常需要“先確認條件再動手”:上一輪是否報錯、用戶是否確認了某個方案、測試是否通過。把判斷寫進提示詞,判斷過程會佔用主上下文;判斷服從規則、命令參數等還可能改寫後續請求的緩存前綴。dsh-if 把這件事收成一條自定義 /if 命令:判斷交給一個繼承當前會話上下文的 fork 子代理,條件成立時才把 /if 下方的指令作爲一條普通用戶消息發給主 agent,不成立則什麼都不做。

下面介紹它的能力、安裝、用法與需要注意的約束。

這是什麼

  • 插件名:dsh-if,倉庫 tlewa/dsh-if,npm 包名 dsh-if。
  • 維護者:TLEWA,許可證 MIT。
  • 分類:工作流;社區目錄頁登記爲 GitHub 1 stars。
  • 定位:給 DeepSeek Harness 加一條 /if 斜槓命令,用 LLM 判斷一個條件,成立時才發送指令。

判斷器是一個 fork 子代理,繼承當前會話的工具、system prompt 與消息歷史,只在末尾追加一條判斷指令。判斷請求與主會話下一次請求共享逐字節一致的 tools → system → messages 前綴,因此可以複用 provider 的 prompt cache / KV cache。

涉及英文原文的表述摘自該插件的 GitHub README;目錄頁與維護者信息來自其社區目錄條目。

核心功能

下面按 README「功能」一節逐條列出,均爲已覈實能力。

  1. 上下文條件判斷。判斷器繼承當前會話的工具、system prompt 與歷史消息,按條件回答 YES 或 NO。
  2. 複用 KV 緩存。fork 子代理只追加一條尾部 user 消息,前綴與主會話一致,可命中 provider 前綴緩存。
  3. 只讀判斷。工具目錄保持不變,執行期 guard 只放行 read / glob / grep / web_search / web_fetch / skill 等只讀工具,寫入、修改、執行命令、子代理一律拒絕。
  4. 與普通消息同隊列。/if 作爲一條普通消息進入輸入框上方的隊列面板,可編輯、刪除、↑ 插話;回合開始時才判斷,成立就把這條消息原地換成指令。
  5. 兩種排隊模式。默認 message,即與普通消息同隊列;background 保留 0.2.x 行爲,命令立即返回,判斷在後臺跑。
  6. 條件成立才發送。只有 YES 才把指令作爲用戶消息發給主 agent;NO 完全不觸發主 agent。
  7. 判斷不進上下文。判斷在獨立子會話完成,不寫主會話事件,不調用 agent.inject。
  8. 命令不泄露參數。recordInput: false,log-only 的 command/run 也不記錄條件或指令。
  9. 多行條件。第一行是條件,其餘行是指令;條件有多行時用單獨一行 --- 分隔。
  10. 自動回退。host 沒有可繼承上下文的 fork provider 時,回退到一次性 ctx.llm.stream + 約 24k 字符純文本記錄。
  11. 防止誤發。條件爲空、指令爲空、判斷輸出不是 YES / NO、或判斷超時,都返回錯誤且不發送。

安裝與啓用

環境要求:

  1. DSH 0.2.1-rc.5 或更新版本。
  2. Node.js 20.3 或更新版本(使用 AbortSignal.any / AbortSignal.timeout)。

從 npm 安裝(推薦)

  1. 打開側邊欄「插件」頁 →「安裝插件」。
  2. 輸入包名並確認:
dsh-if
  1. 安裝完成後重啓 DSH(host 插件在 profile 啓動時加載)。

固定版本:

dsh-if@0.3.4

命令行等價寫法:

dsh plugin --profile desktop add dsh-if@0.3.4

從 GitHub 安裝

lib/ 是可直接運行的源碼,不需要本地構建:

https://github.com/TLEWA/dsh-if

固定到標籤或 Release 附件:

dsh plugin --profile desktop add github:TLEWA/dsh-if#v0.3.4
https://github.com/TLEWA/dsh-if/releases/download/v0.3.4/dsh-if-0.3.4.tgz

從源碼安裝

git clone https://github.com/TLEWA/dsh-if.git
cd dsh-if
npm test
dsh plugin --profile desktop add .

重啓 DSH 後,在輸入框輸入 /if,斜槓面板會出現該命令。

典型用法

基本形式:第一行是條件,其餘行是指令。

/if 1+1=2
請只回復 OK

條件本身有多行時,用單獨一行 --- 分隔:

/if 用戶已經確認方案 A
並且測試已經通過
---
請開始執行方案 A

也可以只寫一行條件和一個單行指令,/if 後面的第一個換行就是分隔點。

分隔符優先:只要出現過單獨一行的 ---,它右邊的部分一定全是指令。所以指令正文裏不要單獨成行寫 ---(Markdown 水平線),否則它前面的內容會被當成條件的一部分。

判斷語義

  1. 判斷由當前會話配置的模型完成,不是 JavaScript 或數學求值器。1+1=2 只是最小示例,條件可以是“用戶是否已經確認方案”“上一條回覆是否包含錯誤”等。
  2. 判斷器只被要求輸出 YES 或 NO;輸出裏沒有可識別結果時按判斷失敗處理,不發送指令。
  3. 判斷器可以只讀地查看文件、檢索代碼來確認事實,但不能做任何修改。
  4. 條件需要的信息在當前上下文裏找不到、或條件含糊無法確定時,判爲不成立:寧可不動,也不誤發指令。
  5. UI 只顯示通用結果,不回顯條件、指令或判斷原文。

工作方式

README 把實現拆成九步,摘要如下。

  1. 通過 ctx.effect(() => ctx.commands.register(...)) 註冊 /if,並設置 recordInput: false;註冊掛在插件 fiber 上,停用時一併註銷。
  2. 入隊。message 模式把原文 /if <條件>\n<指令> 作爲普通 user 消息 agent.followup() 到會話隊列,進的是宿主 durable inbox,客戶端排隊面板照常顯示、可編輯、可刪除、可插話。
  3. 輪次邊界攔截。回合開始時宿主按 agent/pre-step waterfall 領取這批消息,插件把以 /if 開頭的條目挑出來先在原地判斷:成立就把 content 換成指令,不成立就從批次刪除。判斷失敗時該條同樣刪除,並在會話裏記一張「【/if 未執行】」錯誤命令卡片,可用卡片右側「取回 /if」一鍵放回。
  4. 首選 fork 子代理判斷。用 ctx.subagents.getProvider('fork') 取 provider(要求 inheritsParentContext === true),再以 startActivation({ provider: 'fork', childId, request: { parent, agentOptions, prompt }, delivery: 'caller' }) 啓動判斷子會話。
  5. 丟掉繼承來的待辦。fork 的種子會帶回父會話入隊的 next-turn 消息和未領走的 next-step 插話,插件在拿到子 agent 時把這兩條隊列中除自己判斷 prompt 以外的待辦全部 remove,父會話隊列不受影響。
  6. 執行期只讀限制。ctx.tools.guard 僅對判斷子會話生效,只讀工具放行,寫入、命令、子代理被拒;工具目錄不裁剪,緩存前綴不變。
  7. 判斷超時 60 秒;只有 YES 時把指令作爲帶 id 和 role: 'user' 的已識別消息交給主 agent。
  8. 回退路徑。宿主沒有可繼承上下文的 fork provider 時,historyTranscript() 讀取 agent.session.deriveMessages(),只保留 user / assistant / tool 消息,生成最多約 24k 字符純文本記錄(每條最多 3k 字符,保留頭尾),再用 ctx.llm.stream() 發起一次性判斷請求;該請求不帶主會話 sessionId,命中不了主緩存。
  9. background 模式跳過上面的入隊與輪次攔截兩步,命令立即返回“已排隊”,判斷由後臺任務完成;多個 /if 按發送順序串行判斷。

配置

配置寫在 profile 的 cordis.patch.yml:

# profile 的 cordis.patch.yml
- id: if-command
  name: 'dsh-if'
  config:
    mode: message     # 默認。background = 0.2.x 的老行爲
  • mode: message(默認):/if 先作爲普通用戶消息排隊,輪次開始時再判斷。條目內容是 /if <條件> + 指令原文,出現在隊列面板裏,編輯它即等同於改條件與指令。
  • mode: background:0.2.x 行爲。命令立即返回“已排隊”,判斷交給後臺任務,不佔隊列位置。判斷失敗時會在會話裏記一張 if 命令卡片說明原因。

也可以不改文件:插件 → dsh-if → 配置 裏有「判斷方式」下拉框,切換即時生效(mode 聲明爲 volatile 字段,設置頁直接改寫運行中的配置)。插件用 Config(@deepseek-ai/schemastery)描述該字段,mode 缺省即爲 message,未知字段被忽略。

KV 緩存與上下文隔離

這部分是刻意的設計約束,不是可選項。

  1. /if 命令、條件、指令、判斷 prompt、判斷結果都不寫入主會話;command/run 和 command/done 都是 log-only 事件。
  2. 判斷在 fork 子代理裏完成,tools、system prompt、歷史消息全部繼承,只在末尾追加一條 user 消息,因此前綴與主會話下一步逐字節一致,provider 的 prefix cache / KV cache 可以直接複用。
  3. 判斷子會話是獨立會話,不追加主會話的 session 事件,只讀歷史;工具目錄不裁剪,裁剪反而會改變前綴、破壞緩存。
  4. 代價是透明的:每次判斷都會把整段上下文重發一次,token 計數按全量算,命中緩存的部分按 provider 的緩存價計費;會話越長,單次判斷的絕對 token 數越大。
  5. 條件不成立時主會話沒有任何變化;條件成立時唯一改動是在歷史末尾追加一條普通用戶消息,已有前綴不變,不會調用 agent.inject,也不會編輯、替換或刪除已有 session 事件。

適用場景與注意

適合需要在主流程裏插入條件門控的場景:方案確認後執行、測試通過後再繼續、上一輪有錯時再補一條指令。判斷會消耗一次上下文重發,長會話下絕對 token 數不小,適合低頻、條件明確的門控,不適合把每個判斷都鋪到高頻路徑。

注意兩點:

  1. 插件以當前 dsh 進程的權限運行,相關判斷邏輯在 lib/ 中是可直接運行的源碼,安裝前建議檢查源碼與許可證;該插件爲 MIT 許可。
  2. 判斷依賴宿主提供的 fork provider 與 ctx.tools.guard,缺失時自動回退到 transcript 判斷,該退路命中不了主緩存。其他 host 能力邊界請對照 README 的「兼容性」一節。

結尾

dsh-if 的價值在於把“判斷條件”和“執行指令”分開:判斷髮生在獨立子會話,不污染主上下文,成立時只追加一條普通消息,從而保住主請求的可複用前綴。它定位明確、約束寫在明面上,適合需要條件門控的 DSH 工作流。

  • 目錄頁:https://www.skillhub.cn/plugins/TLEWA/dsh-if
  • GitHub:https://github.com/TLEWA/dsh-if

社區目錄是獨立站點,與 DeepSeek、幻方無官方從屬關係。

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

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

小夜