dsh-codex-handoff:把 Codex CLI 多輪會話接進 DeepSeek Harness

前言

在 DSH(DeepSeek Harness)裏做開發時,常見一種情況:兩邊都有命令行助手,DSH 跑 DeepSeek、本機還裝着 Codex CLI,但兩者的會話互不相通——這邊派一個任務過去,那邊答完就斷了,下一輪只能重貼上下文,模型選擇和工作強度也無法控制。

hato-24/dsh-codex-handoff(gpt_bridge)就是爲這個問題寫的客戶端插件:把本機 Codex CLI 的多輪會話接進 DSH,往來記錄在側欄可查,會話落庫後可以 resume 續接,模型與推理強度還能切換。下面介紹它的定位、安裝方式和實際用法。

這是什麼

一句話定位:Codex CLI 的多輪對話橋。插件裝上後,DSH 裏出現 GPT 對話面板,同時給 agent 註冊一個 codex_gpt 工具,GPT 因此能被當成子代理調用;會話默認持久化,可用 codex exec resume 續接同一條 thread。

  • 維護者:HATO-24
  • 分類:客戶端(同時含 Host 側與 Client 側組件)
  • 許可證:MIT

它解決的三件事:一是往來可見,每一輪問答在 DSH 側欄點開就能看;二是可續接,會話寫進 Codex 會話庫,換命令也能接着聊;三是可選檔位,模型和推理強度在界面上切換,而不是寫死在腳本里。

核心功能

插件由三部分組成:

組件 作用
Host 側 lib/index.js 調 codex exec、維護 .bridge 存儲、提供 /api/codex-bridge/* 路由、註冊 codex_gpt 工具
Client 側 lib/client.js 側欄「GPT 對話」入口 + 主面板(會話列表、逐輪提問/回覆)
gpt_bridge.ps1(升級版) 命令行橋,默認持久化會話、記錄 thread_id、支持 -Resume

數據落在工作區的 <workspace>/.bridge/,與 gpt_bridge.ps1 共用同一套目錄,所以升級前的舊記錄也能看到。

安裝與啓用

前置條件:本機已安裝 DSH,且 Codex CLI 已登錄、可正常調用。插件會自動在 %LOCALAPPDATA%\OpenAI\Codex\bin\*\codex.exe、CODEX_BIN、PATH 裏找 codex 可執行文件。

dsh-codex-handoff@0.1.1

兩種方式安裝,任選其一:

1、界面操作:插件 頁 → 添加 → 輸入 dsh-codex-handoff

2、工具安裝:plugin_manager → install_bundle,target 填 dsh-codex-handoff@0.1.1

說明:這裏的版本號按 README 安裝章節原文填寫;倉庫 package.json 中聲明的版本是 0.1.3。

裝好後界面會出現三處入口:

  • 左下角(Settings 旁、催更姬旁邊)新增 GPT 按鈕,點擊在 DSH 右側欄打開對話面板
  • 右側欄頂部出現 GPT 對話 標籤(和「開始」並列)
  • 會話標題欄最右側的對話氣泡按鈕,作爲快捷入口

兩個注意點:

  • Client 插件改了 inject 後要重啓 DSH,新配置纔會被解析;
  • 本地改代碼後,在插件頁把該插件禁用 → 啓用即可重載,不用重啓 DSH。

另外,左側欄圖標不能用作入口:它會切走當前 conversation,導致 sidebarRight.mounted 變空,openResource 拋 sidebarRight: no session surface is mounted,這是 DSH 的機制限制。

在側欄查看記錄與發消息

點左下角的 GPT 按鈕(或會話頭部氣泡按鈕),右側欄展開「GPT 對話」標籤。右側欄可拖動分隔條調寬度,主面板不受影響,對話照常進行。

面板底部是發送區:

  • 輸入框 Enter 發送、Shift+Enter 換行;
  • 模型下拉來自 codex debug models 列出的全部 10 個模型(GPT-6.1-Sol、GPT-6-Astra、GPT-6.1 Terra、GPT-6-Sol 等);
  • 推理下拉跟着所選模型支持的檔位走(low/medium/high/xhigh/max/ultra);
  • 選中某段會話時,兩個下拉自動回填該會話上次用的模型與推理強度,直接發送即沿用;切換會話才重置。

記錄的是「實際用了什麼」:每輪結束後插件會讀 rollout 裏 turn_context 的真實 model 與 effort,寫進 inbox/<id>.json 的 actualModel/actualEffort,不傳模型時也不會顯示空值。README 裏的實測對照如下(請求參數 model=gpt-6.1-sol, reasoning=high):

來源 model effort
請求參數 gpt-6.1-sol high
橋記錄 actualModel gpt-6.1-sol high
rollout turn_context gpt-6.1-sol high

卡片和會話頭部因此能區分 gpt-6.1-sol 與 gpt-6-sol,這兩個是不同模型,前者默認推理是 low,後者是 medium。

會話標識規則:選中某段會話時發送等於續接那個 Codex 會話,沒選中則新開一段;發送完會自動選中新會話並刷新列表。

讓 GPT 當子代理:codex_gpt 與多輪續接

DSH agent 會看到新工具 codex_gpt,參數是 message(必填)、conversationId/threadId(二選一)、model、reasoning:

codex_gpt({ message: "審查 docs/plan.md 的里程碑,找不可執行之處", reasoning: "high" })
→ { conversationId: "c-...", threadId: "01a1...", reply: "..." }

第二輪傳同一個 conversationId,即續接同一個 Codex 會話,不用重發上下文:

codex_gpt({ conversationId: "c-...", message: "第 2 點展開,給具體改法" })

也可以直接續接任意 Codex thread:

codex_gpt({ threadId: "01a1ac8e-01a4-79a2-a70d-855254e70751", message: "繼續上次的方案" })

兩個坑值得寫在前面:

  1. 推理檔位統一是 low / medium / high / xhigh / max / ultra,沒有 minimal 也沒有 none;傳給舊腳本習慣的 minimal 會直接 turn.failed。
  2. model/reasoning 不傳就用 Codex 配置默認,傳了會走 -m 與 -c model_reasoning_effort=…,README 實測生效。

HTTP 接口

路由前綴 /api/codex-bridge,默認端口 http://127.0.0.1:12530:

方法 路徑 作用
GET /list 會話列表(含老記錄)+ 當前默認配置
GET /read?id=<id> 某段會話的逐輪提問與回覆 + Codex 側原文
GET /status 工作區、codex 路徑、隔離開關
GET /models 可用模型目錄(slug / 顯示名 / 支持的推理檔位)
POST /send 發一輪真實對話,body:{message, conversationId?, threadId?, model?, reasoning?}
POST /promote 把一段會話標記成 Codex App 可見,body:{threadId} 或 {conversationId}

發送一輪:

$body = @{ message = "只回復兩個字:收到"; reasoning = "low" } | ConvertTo-Json -Compress
Invoke-WebRequest -Uri "http://127.0.0.1:12530/api/codex-bridge/send" -Method POST `
  -Body $body -ContentType "application/json" -UseBasicParsing -TimeoutSec 900
# → {"conversationId":"c-...","threadId":"01a1...","reply":"收到"}

需要留意兩點:POST /send 會真實消耗 Codex 額度,而且是同步等待,README 實測一次 low 推理約 58 秒;另外路由用了 Node 原生 handler 而非 resource,因爲 resource 路由只放行 GET/HEAD,POST 會被平臺層直接 405。

上下文與隔離:GPT 能看到什麼

這是本插件最初要回答的問題。README 用零額度的方式實測:codex debug prompt-input "test" 會把模型實際收到的輸入原樣打印成 JSON 數組,逐條看,模型看到的東西遠超橋發過去的那一段 prompt。

注入項 實測證據 大小/內容
全局人設指令 developer message 第 1 條 ~/.codex/config.toml 裏 model_instructions_file 指向的 prompts/gpt-with-taste/main.md,24,461 字符
skills 清單 developer message 第 2 條 <skills_instructions> 4,897 字符,列出 ~/.codex/skills/.system、plugins/cache/openai-bundled 等 skill roots,GPT 看到路徑就能自己讀 SKILL.md
MCP 工具 工具表 mcp__cua_repl.js 等,來自 config.toml 的 [mcp_servers.node_repl]
插件推薦列表 developer message <recommended_plugins> 876 字符,16 個「可用未安裝」插件
多代理系統提示 developer message <multi_agent_role> / <multi_agent_mode> 2,400 + 271 字符
環境上下文 user message <environment_context> cwd、shell、日期、時區、文件系統權限根
Codex 記憶 config.toml 的 [features] memories = true / [memories] use_memories = true 會讀取 memories_1.sqlite / memories_v2_1.sqlite

結論:橋只負責發一段 prompt,其餘全是 Codex 自己加載的。想讓上下文更乾淨,可以開本插件的隔離開關 DSH_CODEX_BRIDGE_ISOLATE=1(或命令行 -Isolate),默認關閉。更徹底的隔離手段是 Codex CLI 自身的參數,README 給了三檔:

# 1) 完全隔離:不加載 ~/.codex/config.toml(auth 仍用 CODEX_HOME)
codex exec --ignore-user-config -m gpt-6-sol ...

# 2) 只關插件推薦
codex exec --disable plugins ...

# 3) 只關 MCP
codex exec -c 'mcp_servers={}' ...

注意 --ignore-user-config 同時會丟掉 model 等配置,隔離時要顯式傳 -m。

適用場景與注意

適合這幾類用法:想讓 GPT 以子代理身份參與 DSH 裏的多輪協作;想讓 Codex 的會話在 Codex 桌面版或 CLI 裏繼續,而不是用完即散;需要按任務切換模型和推理強度並留檔。

上手前需要確認幾件事:

  • 插件以當前 DSH 進程的權限運行,能讀到 Codex CLI 的環境與配置,未覈實的源碼建議安裝前自行過一遍,許可證爲 MIT。
  • 會話會消耗 Codex 賬號額度,建議先用 codex debug prompt-input 和隔離開關確認上下文範圍,再決定是否定向提問。
  • 老記錄來自 outbox/*.prompt.md 與 inbox/<id>.json、logs/<id>.stdout.jsonl,thread_id 能從這兩處回撈;README 實測升級前的 3 條老記錄全部列出,其中 2 條成功恢復 thread_id,另 1 條是模板沒寫回復的空記錄。

結尾

這個插件把「用過即棄」的 Codex CLI 對話變成了 DSH 工作流裏可查、可續、可調檔位的一環,改造集中在側欄面板、codex_gpt 工具和 HTTP 路由三處,改動面不大但樁點明確。社區插件目錄頁:https://www.skillhub.cn/plugins/HATO-24/dsh-codex-handoff ;源碼:https://github.com/HATO-24/dsh-codex-handoff 。該目錄是獨立站點,與 DeepSeek / 幻方無官方從屬關係。

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

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

小夜