tool-deadline-guard:爲未聲明 timeoutMs 的工具調用補上部署級 deadline

前言

在 DeepSeek Harness(dsh)裏跑長任務時,常見一種現象:界面上的 turn 一直顯示 running,日誌和輸出裏卻沒有任何報錯。模型側有流式 idle 超時(DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000,由 idleWatchdog 按 chunk 重載),因此「長時間無輸出」往往指向工具調用卡住,而不是模型卡住。社區討論 #7339 描述的就是這類 long-horizon 任務靜默掛起。

根因之一在於工具定義:ToolDefinition.timeoutMs 是可選字段,說明爲「Cooperative tool-call timeout budget in milliseconds. Omit for no deadline」。核心策略包 @deepseek-ai/dsh-tool-call-timeout-policy 在 timeoutMs === undefined 時直接 return next(),不會掛定時器、不會發信號、也不會寫診斷。在 dsh v0.1.6-alpha.2 中,調用 defineTool( 的 40 個非測試源文件裏,有 26 個完全沒有 timeoutMs,其中包括 tool-subagent、tool-terminal、mcp-resources 以及若干 fs 與工作流相關工具——恰恰是委託子進程、跨網絡 MCP 等容易長時間阻塞的路徑。

下面介紹社區 Cordis 插件 @argszero/cordis-plugin-tool-deadline-guard(GitHub:argszero/cordis-plugin-tool-deadline-guard),它在 tools/execute 與 tools/pre-execute 瀑布上爲「未自行聲明 deadline」的調用補上可配置的部署級預算,超時後把靜默掛起變成模型可見的結構化錯誤,便於重試或改策略。

這是什麼

@argszero/cordis-plugin-tool-deadline-guard 由維護者 argszero 發佈,分類屬於 DSH 生態中的工作流向插件(SkillHub 目錄:argszero/cordis-plugin-tool-deadline-guard)。它不替換工具自身實現的 timeoutMs,而是在 harness 未武裝任何 deadline 時爲工具執行體與派發前階段分別計時;到期則返回插件自有錯誤碼,與核心策略的 TOOL_TIMEOUT 區分開,便於區分「工具聲明瞭預算卻超時」與「部署策略補上的預算超時」。

核心功能

執行體階段(tools/execute)

插件掛在與核心 timeout policy 相同的公開 seam tools/execute 上。對每個 dispatch:

  1. 通過 ctx.tools.get(exec.name, exec.agent) 解析工具定義,決定是否武裝 deadline;未知工具仍由 registry 處理(UNKNOWN_TOOL)。
  2. 武裝一個 timer 與一個 AbortController,經 exec.signal 向工具提供 AbortSignal.any([caller, own]),與核心 policy 的做法一致。
  3. 在 finally 中恢復調用方 signal,避免後續 wrapper 看到本 mount 可能已 abort 的 signal。
  4. 僅當本 mount 的 timer 先觸發時才替換結果;在預算內正常結束則原樣返回工具結果,不二次 dispatch。
  5. 超時結果形態爲 isError: true,且 error.info.code === 'TOOL_DEADLINE_EXCEEDED'(非核心的 TOOL_TIMEOUT),模型側可據此行動。README 中的示例如:對 subagent 的調用在超過 600000ms 且工具未聲明 timeoutMs 時,返回明確說明 deadline 來源的錯誤文本。

默認情況下,凡未在工具定義裏寫 timeoutMs 的調用,會被 bound 在 10 分鐘(600000 ms);已聲明 timeoutMs 的工具在默認 applyTo: undeclared 下仍交給核心 policy,本插件不改動。

派發前階段(tools/pre-execute,0.2.0)

timeoutMs 只約束工具體;tools/pre-execute 瀑布在覈心 tools/execute wrapper 之前完成。若某 listener 在此階段 await 無界工作,整個 session 的工具調用都會堵在後面,而只掛在 tools/execute 上的 deadline structurally 看不到該階段。README 以 @deepseek-ai/dsh-workspace-changes 在 pre-execute 中等待 turn recorder 快照隊列爲例,並指向討論 #9515。

0.2.0 起,同一插件也掛載 tools/pre-execute。該階段超時使用不同錯誤碼 TOOL_PRE_EXECUTE_DEADLINE_EXCEEDED,形態爲 deny(調用未被 dispatch),與執行體超時區分:便於判斷是「跑太久」還是「根本沒跑起來」。

配置項

無配置時:對所有未聲明 timeoutMs 的工具使用 10 分鐘默認預算,其餘調用原樣放行。

field default meaning
mode auto auto 武裝 deadline;observe 只報告將會 bound 的內容並原樣 dispatch;off 不註冊
defaultTimeoutMs 600000 未聲明 timeout 的工具的預算(10 分鐘)
perTool {} 按解析後的工具名覆蓋預算,優先於 defaultTimeoutMs
exempt [] 永不 bound 的工具名
applyTo undeclared undeclared 不碰已聲明 timeoutMs 的工具;all 對所有已知工具 bound
onExpiry cooperative 到期行爲;README 指向 Honest limits 小節
preExecute true 是否 bound 派發前階段
preExecuteTimeoutMs defaultTimeoutMs 派發前階段預算
warnLimit 5 每個 mount 發出的診斷條數;0 關閉

預算須爲正有限數且 ≤ 2147483647(setTimeout 飽和上限);更大值會立即觸發,因此「無 deadline」應通過 exempt 或 mode: off 表達,而非設極大數值。

安裝與啓用

先在項目中安裝 npm 包(版本以 registry 爲準;package.json 中當前爲 0.2.0):

npm install @argszero/cordis-plugin-tool-deadline-guard

在 cordis.yml 或 profile bundle 中增加一行(也可合併包內自帶的 cordis.patch.yml,內容等價):

- insert:
    - id: tool-deadline-guard
      name: '@argszero/cordis-plugin-tool-deadline-guard'

安裝後無需額外配置即可生效:未聲明 timeoutMs 的工具默認 10 分鐘上限。需要更長或更短等待時,在 Cordis 插件配置裏調整 defaultTimeoutMs 或 perTool;對必須允許長時間阻塞的工具(例如特定 MCP),將其名加入 exempt。

上線前可用 mode: observe 觀察本 mount 將會 bound 哪些調用,確認名單後再切回 auto。

典型用法示例

僅收緊 subagent 與 terminal,其餘仍用默認 10 分鐘:

在插件實例上配置(字段名以 README 爲準):

defaultTimeoutMs: 600000
perTool:
  subagent: 900000
  terminal: 300000
exempt:
  - ask-user

關閉派發前階段 bound(只 guard 執行體):

preExecute: false

對某第三方 MCP 工具完全豁免:

exempt:
  - mcp_some_server_long_poll

超時後模型會看到類似 README 中的 tool_result [error],其中說明 exceeded 的毫秒數與 deadline 來自 tool-deadline-guard mount,而不是工具自帶的 timeoutMs。

適用場景與注意

適合誰: 在生產或長時間自動化任務中使用 dsh,且依賴 subagent、終端、MCP、工作流類工具;希望 turn 不會因單個 wedged 調用無限 running,又需要與核心 TOOL_TIMEOUT 區分運維語義(部署策略 vs 工具自聲明預算)的團隊。

協作式默認: onExpiry 默認爲 cooperative;README 強調插件不會強行拋棄工具本身不願結束的調用,並在可選 replace 模式下明確說明限制。需要更激進行爲時應閱讀 README 的 Honest limits。

權限與安全: 插件隨當前 dsh 進程權限運行,掛載在 harness 公開 waterfall 上,不單獨降權。安裝前請閱讀 GitHub 倉庫 源碼與 MIT 許可證,確認與您的合規要求一致。peer 依賴範圍在 package 說明中審計爲 dsh 0.1.2-rc.1 至 0.2.1-alpha.2 的 npm/pnpm prerelease 讀法;與您實際 dsh 版本不匹配時應在測試環境驗證。

生態說明: DSH 採用「一切皆插件」的 Cordis 組合方式;SkillHub 等社區目錄獨立於 DeepSeek / 幻方,並非官方應用商店。本插件星標數爲 0(截至目錄抓取),選用時以 README 與 issue 跟蹤維護狀態即可。

結尾

tool-deadline-guard 解決的是 harness 對「未聲明 timeoutMs」工具默認不設 deadline 的空白:把靜默 wedged 的工具調用轉成 TOOL_DEADLINE_EXCEEDED 或 TOOL_PRE_EXECUTE_DEADLINE_EXCEEDED,讓模型和運維都能看見原因。目錄頁:https://www.skillhub.cn/plugins/argszero/cordis-plugin-tool-deadline-guard;源碼與完整配置說明:https://github.com/argszero/cordis-plugin-tool-deadline-guard。

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

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

小夜