wilshi/dsh-external-api:給 DSH Desktop 加一個可選的對外 HTTP API

前言

DSH Desktop 本身是交互式客戶端,”讓別的程序也能驅動它”通常要麼改客戶端源碼,要麼直接在宿主環境裏塞自寫腳本,維護成本都不低。WilShi/dsh-external-api 走另一條路:在 DSH 進程內掛一個可選的 HTTP 服務,默認關閉、默認只監聽 127.0.0.1,用 Bearer Token 鑑權,對外暴露會話、Run、SSE 事件這些能力。維護者是 WilShi。下面是介紹。

這是什麼

一句話定位:DSH Desktop 的可選外部 HTTP API,面向本機與可信局域網的集成場景。

插件包名爲 dsh-external-api,當前版本 0.2.4,MIT 許可證,Node 要求 ^22.19.0 || ^24.0.0。它兼容 DSH 0.2.1-rc.5(Host protocol v4)與 Cordis 4.0.5,插件形態是 Bundle(dsh.bundle.patch)加 Client inject(settings.section 槽位),也就是安裝後要在 DSH 設置頁裏點啓用,而不是改配置文件。

它不新開一套宿主環境。所有 @deepseek-ai/* 宿主包都聲明爲 peerDependencies,由 DSH 運行時提供;插件自身不安裝、也不會帶出第二套 cordis 單例。必需的宿主服務(inject)有 sessionController、workspaceController、agentPresets、sessionSkillCatalog、webServer。運行時依賴只有 @deepseek-ai/dsh-atomic-write(原子寫)和 @deepseek-ai/schemastery(配置 schema)。

核心功能

1、默認關閉。服務沒有啓用前不監聽任何端口。
2、默認只監聽本機。啓用後 host 默認是 127.0.0.1,只有本機能訪問;改成 0.0.0.0 或某個局域網地址纔對網絡開放,此時啓動日誌會打印一條網絡暴露告警。
3、Bearer Token 鑑權。除健康檢查和 CORS 預檢外,所有接口都要求 Authorization: Bearer <token>。
4、資源模型是 Session / Run / 事件流:列會話、建會話、發起 Run、查 Run 狀態、訂閱 SSE、取消 Run。
5、Token 級隔離。每個 Token 只能訪問自己創建的 Session、Run 和 SSE 流。
6、可訂閱的事件類型固定:run.queued、run.started、run.cancelling、message.delta、message.completed、tool.started、tool.completed、run.completed、run.cancelled、run.failed,SSE 支持 Last-Event-ID 斷線續傳。
7、能力探測接口。/api/v1/capabilities 返回當前 Token 能看到什麼,調用方可以先讀它再決定後續請求。
8、撤銷即失效。Token 撤銷會立即斷開它的 SSE 連接、嘗試取消活動 Run,並刪除其會話歸屬記錄。

安裝與啓用

安裝命令只有一條,來自 README:

dsh plugin --profile web add dsh-external-api

安裝後重啓 DSH,然後在「設置 → API 服務」裏啓用。之後按頁面提示填端口(默認 47831),爲調用方創建獨立 Token,並立即保存只顯示一次的明文。

開頭先驗證一下服務

端口按默認 47831,Token 已寫入環境變量 DSH_API_TOKEN。這一步的作用是確認 Listener 已起來、Token 有效,並看清這個 Token 具備哪些權限。

curl.exe http://127.0.0.1:47831/api/v1/capabilities `
  -H "Authorization: Bearer $env:DSH_API_TOKEN"

創建一個會話併發起一次 Run

最省事的路徑是 POST /api/v1/responses:一次請求同時建會話、發 Run。下面用 Windows PowerShell 演示,局域網設備把 127.0.0.1 換成 DSH 主機的局域網 IPv4。

$body = @{ input = '請概括當前項目的結構' } | ConvertTo-Json -Compress
Invoke-RestMethod `
  -Method Post `
  -Uri 'http://127.0.0.1:47831/api/v1/responses' `
  -Headers @{ Authorization = "Bearer $env:DSH_API_TOKEN" } `
  -ContentType 'application/json' `
  -Body $body

響應狀態是 202,裏面包含 session、run 和 eventsUrl。下一步拿這個 Run ID 去讀實時事件:

curl.exe -N http://127.0.0.1:47831/api/v1/runs/RUN_ID/events `
  -H "Authorization: Bearer $env:DSH_API_TOKEN"

接口與 Scope

完整接口表(README 原文,Scope 名稱照抄):

方法 路徑 作用 所需 Scope
GET / HEAD /api/v1/health Listener 健康檢查 無
GET /api/v1/capabilities 能力、限制和當前 Token 權限 capabilities:read
GET /api/v1/workspaces Token 可使用的工作區 capabilities:read
GET /api/v1/agents Token 可使用的 Agent Preset capabilities:read
GET /api/v1/models?sessionId=... 會話可用模型 capabilities:read
GET /api/v1/skills?sessionId=... 會話可用技能 capabilities:read
GET /api/v1/sessions 列出當前 Token 創建的會話 sessions:read
POST /api/v1/sessions 創建會話 sessions:write
GET /api/v1/sessions/:id/messages 獲取脫敏後的消息歷史 sessions:read
POST /api/v1/sessions/:id/messages 發起 Run runs:write
POST /api/v1/sessions/:id/runs 發起 Run(語義等同上一項) runs:write
POST /api/v1/responses 創建會話併發起 Run sessions:write、runs:write
GET /api/v1/runs/:id 查詢 Run 狀態 runs:read
GET /api/v1/runs/:id/events 訂閱 Run 的 SSE 事件 runs:read
POST /api/v1/runs/:id/cancel 取消 Run runs:write

創建會話時可以指定白名單裏的 workspaceId 和 agentPreset:

{
  "workspaceId": "workspace-id",
  "agentPreset": "agent-preset-id"
}

發起 Run 的請求體:

{
  "input": "分析這個問題",
  "clientTimeZone": "Asia/Shanghai"
}

瀏覽器端訂閱 SSE

瀏覽器原生的 EventSource 不能設置 Bearer Header,需要改用 fetch 流。注意:瀏覽器還必須位於服務允許的 Origin 白名單中,而當前設置頁尚未開放這項配置,普通網頁默認會被拒絕;下面代碼只適用於已經由發行版或受控配置啓用對應 Origin 的環境。

const response = await fetch(`${baseUrl}/api/v1/runs/${runId}/events`, {
  headers: { Authorization: `Bearer ${token}` },
})
if (!response.ok || !response.body) throw new Error(`HTTP ${response.status}`)

const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()
for (;;) {
  const { value, done } = await reader.read()
  if (done) break
  console.log(value) // 正式客戶端應按 SSE 幀解析,而不是假定一次讀取就是一個事件
}

錯誤格式

外部接口使用穩定的 JSON 錯誤結構,不回傳內部異常或宿主錯誤詳情。客戶端應以 HTTP 狀態碼和 error.code 作爲程序判斷依據。

{
  "error": {
    "code": "AUTH_INVALID",
    "message": "The bearer token is invalid.",
    "requestId": "..."
  }
}

安全邊界

這一節建議先讀完再決定要不要改監聽地址。

1、默認只綁定 127.0.0.1。顯式把 host 設爲 0.0.0.0(或某個局域網地址)纔會對網絡開放。它不復用、也不轉發 DSH 主站的 /api 路由。
2、Token 明文只在創建時返回一次,持久化配置裏只保存 SHA-256 摘要。
3、工作區與 Agent Preset 默認不允許調用方自行指定,需要顯式加入 Token 白名單;白名單非空時,創建 Session 必須顯式指定被允許的 workspaceId / agentPreset,省略即 403。
4、對外開放範圍有明確上限:Slash Command、任意內部 RPC、工具參數、工具結果正文、系統提示和推理內容都不會對外開放。
5、Host 必須與客戶端實際訪問的 IPv4 和端口一致;Origin、Fetch Metadata、請求體大小、請求速率、併發 Run 和 SSE 連接數也都有限制。活動 Run 默認上限是每 Token 10 個、全局 20 個;舊版精確的 2/4 默認組合會在啓動時自動升級,其他自定義組合不變。
6、管理接口只掛在 DSH 自身的隨機迴環端口,並校驗同源瀏覽器請求,用於防止網頁跨站調用;它不把同一系統賬戶下的惡意本機進程當作可隔離的安全邊界。
7、管理接口寫入的配置保存在 $DSH_HOME/external-api/config-v1.json(目錄權限 0700、文件 0600),與 Token 歸屬記錄 ownership-v1.json 分開存放;加載器通過 cordis.patch.yml 下發的 config 作爲基礎層,管理頁的編輯覆蓋其上。
8、外部 API 是明文 HTTP。只在受信任的專用網絡中啓用,用系統防火牆把入站來源限制到所需私網;不要把端口直接映射或暴露到公網。跨不受信任網絡接入時,應使用 VPN 或受信任的 TLS 反向代理並限制來源網絡。

適用場景與注意

適合的場景:想在本機給 DSH Desktop 接一個外部編排腳本、Web 前端或局域網內的另一臺設備,並且希望按 Token 粒度控制誰能建會話、誰能跑 Run。

需要留意的地方:

1、插件以當前 DSH 進程的權限運行,能訪問會話、工作區和工具執行結果,等於擁有該進程的同等能力。安裝前先讀源碼,確認 MIT 許可證與你的分發方式兼容,再看 cordis.patch.yml 下發了哪些配置。
2、它不是官方產品,目錄頁是社區站點,與 DeepSeek / 幻方沒有官方從屬關係。
3、從 0.2.1-rc.5 起的 DSH Host protocol v4 纔在這個兼容範圍內,用在其他版本上需要先確認。
4、Token 明文只顯示一次,創建時丟失只能重新生成。

結尾

這套接口的價值在於把”驅動 DSH”變成一次普通的 HTTP 調用,同時用默認本機綁定、Token 級隔離和明確的對外暴露上限把風險壓在可控範圍裏。目錄頁在 https://www.skillhub.cn/plugins/WilShi/dsh-external-api,倉庫在 https://github.com/WilShi/dsh-external-api。

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

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

小夜