前言¶
在 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: "继续上次的方案" })
两个坑值得写在前面:
- 推理档位统一是
low / medium / high / xhigh / max / ultra,没有minimal也没有none;传给旧脚本习惯的minimal会直接turn.failed。 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 / 幻方无官方从属关系。