deepseek-harness-studio/packages/subagent/subagent-codex

403Star43Fork2Issue2Watching

让 DSH 在委托会话里一次性无人工地拉起官方 Codex 子代理:通过 app-server 协议把一条纯文本任务交给 Codex 跑并按严格成功条件回传最终答案。

语言
TypeScript
License
MIT
分支
main
ai-agentdeepseekdeepseek-harnessdeepseek-harness-studiodesktop-appdeveloper-toolsdshdsh-plugin

安装

$ dsh plugin --profile web add github:fufankeji/deepseek-harness-studio/packages/subagent/subagent-codex

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

一句话定位

subagent-codex 让 DSH 会话在需要的时候临时拉起一个独立的 Codex 子进程来跑一段纯文本任务:每次都开新的 app-server、不需要人按键审批、跑完把最终答案或失败诊断交给上游;它不改写你的 Codex 账户和设置,只是把官方 app-server 协议接到 DSH 的 subagent 服务上。

核心能力

  • 在委托 Session 的工作目录里拉起官方 Codex 的 app-server --stdio 子进程,进程归 dsh-subprocess 的进程树统一管控(src/run.ts:236-249 / src/run.ts:185-217)
  • 一次性文本任务:只接受非空纯文本块,Codex 必须返回带 phase: "final_answer" 的 agentMessage,没明确 final phase 时回退到最后一条 phase: null 的消息;空回答也会判为错误(README.md:11 / src/run.ts:162-177)
  • 无人值守审批:命令/文件审批一律走 Codex 的 thread/start 配置,三种 permissionMode 都不会触发 DSH 交互;未知 server request 直接失败关闭(src/wire.ts:25-36, 86-94 / README.md:13)
  • 失败带诊断:把 lifecycle 阶段(initialize / thread-start / turn-start / turn / process / teardown)、Codex 错误分类、HTTP 状态码、子进程退出码/信号拼成失败摘要,写到 SubagentResult.diagnostic(src/run.ts:84-114 / src/run.ts:358-365)
  • 不继承父会话:明确 inheritsParentContext: false,父会话的对话、角色、工具过滤、深度策略都不会下发到子 Codex(src/index.ts:62 / README.md:21)
  • 安装/卸载通过 Profile Bundle:安装才让宿主上多出一个休眠 provider,卸载后下次启动就连同其私有运行时一起撤回(README.md:44 / cordis.patch.yml:1-5)

技术实现

  • 语言: TypeScript(ESM,发布产物 lib/index.jslib/types/*.d.ts,见 package.json:13-27)。
  • 关键依赖: @openai/codex@0.147.0(官方 SDK,含六个平台子包携带 app-server 2.1.220 的 JavaScript wrapper 与原生 codex 二进制)、@deepseek-ai/dsh-subagent(共享任务接缝与结果结算)、@deepseek-ai/dsh-subprocess(负责真 CLI 进程的进程树托管)、@deepseek-ai/dsh-timeoutMAX_TIMER_DELAY_MS 上限校验)(package.json:49-53 / src/run.ts:9-29 / src/index.ts:11)。
  • 架构模式: 函数插件 + Profile Bundle——src/index.ts 命名导出 name/inject/Config/applyapply(ctx, config) 把一个 CodexProvider 注册到 ctx.subagents,由 cordis.patch.yml 顺势注入 dsh-base 之上。运行时通过 createRequire 解析 @openai/codex/package.jsonbin.codex,用当前 Node 可执行文件拉起 wrapper;JSON-RPC 帧层由 dsh-sdk-protocol 提供,wire.ts 只负责产品方法、当前 thread/turn 关联、无人值守审批应答和最终答案选择(src/index.ts:30-32, 113-135 / cordis.patch.yml:1-5 / src/run.ts:43-52, 132-134 / src/wire.ts:9-14)。
  • 入口文件: src/index.ts(Cordis 注册入口)、src/run.ts(一次性任务生命周期与 run spec)、src/wire.ts(Codex app-server 0.147.0 协议适配器)。

适用场景

把"我不想动手、就让 Codex 自己去干"的一段独立任务交给子 Agent,常见做法是让 DSH 主对话里的模型在工具白名单里看到 subagent_codex 后按需触发,比如一次性生成长文档、批量改文件、或让 Codex 自己拉一份现状总结再带回主对话。本包不适合需要持续对话、要看中间步骤、或者要求 Codex 一路弹交互确认的场景——这些需求跟"一次性、无人工、只读最终答案"的定位天然冲突。

前置依赖与兼容性

依赖最低版本说明
DSH(launcher)0.1.0-rc.8本包和同仓库其它包同版本(package.json:4),作为 Profile Bundle 注入 dsh-base 上层(cordis.patch.yml:1-5)。
Node.js^22.19.0 || >=24.0.0仓库根 engines.node 约束,subagent-codex 自身未声明独立范围(仓库根 package.json:8-10)。
平台跨平台(macOS / Windows / Linux)实际可执行的 app-server 由 @openai/codex@0.147.0 的六个平台子包按系统/CPU 自带;省略 optional dependencies、不被支持的系统、载荷文件缺失都会让 provider 注册能成功但第一次委派在 app-server 启动边界失败(README.md:97-101)。
Codex app-server0.147.0(随 @openai/codex 平台包)0.147.0 锁定,不依赖宿主 codex;本包也不查 PATH、不做平台选择、不回退到宿主二进制(README.md:42 / src/run.ts:43-52)。
原生模块codex / codex-code-mode-host / rg / zsh(darwin-arm64 平台包自带)安装后由 Codex 平台包携带,DSH 这边不再引入新的原生模块;其它平台载荷可能不同(README.md:97)。
disposeGraceMs 上限MAX_TIMER_DELAY_MS(2 147 483 647)apply() 启动时校验,正有限值且不得超过仓库 dsh-timeout 共享上限(src/index.ts:120-129 / packages/util/timeout/src/index.ts:25)。

安装方式

dsh plugin --profile web add github:fufankeji/deepseek-harness-studio/packages/subagent/subagent-codex

配置项

配置类型说明默认值
providerName字符串(非空)ctx.subagents 上的注册名,同时给 dsh-tool-subagent 工具行的 provider 字段引用;同一个 Profile 挂多份实例时需要互不重复(src/index.ts:38, 51 / README.md:27)。codex
env对象(Record<string, string>显式透传给 Codex app-server 子进程的环境变量,叠在父环境已被共享机制清掉凭证后的子集上;想让子进程拿到 OPENAI_API_KEY 时必须在这里显式声明(src/index.ts:43, 52 / src/run.ts:241 / README.md:42)。{}
permissionMode枚举:never / approve-for-me / dangerously-bypass-approvals-and-sandbox选定这个 provider 实例的 Codex 原生非交互权限与沙箱模式;never 表示不发审批请求、approve-for-me 走 Codex 自动评审、dangerously-bypass-approvals-and-sandbox 会同时关掉审批和沙箱(src/run.ts:55-68 / README.md:32-36)。never
disposeGraceMs数字(毫秒,正有限值)共享进程树主人在各终止 tier 之间的等待时长,随后要等到整棵进程树退出才算清场(src/index.ts:47, 55, 120-129 / src/run.ts:240)。3000

常见问题

Q: 跟直接接 Codex API 有什么区别?是不是更简单的接入?

A: 不一样。这个包是 dsh 的"subagent 供应商"角色,承接 dsh-tool-subagent 那边发来的一次性请求,每次启全新的 Codex app-server 进程跑完就结束;它不替 Codex 选模型、不持久化 Codex 会话、不复制 Codex settings。dsh-base 里默认的 deepseek 入口是主对话模型,跟这个 provider 在进程级别就是独立的两条线(README.md:42, 135)。

Q: env 是不是只放 OPENAI_API_KEY?别的变量怎么传?

A: 不是只能放 key,但请把 key 放在这里。父进程里任何被判定为凭证形态的环境变量在传给子进程前都会被 dsh-subprocess 剥掉。HOMECODEX_HOME 这种非凭证变量会被自然继承,要在 env 里显式覆盖也可以。DSH 这边不会创建账户、不会登录 Codex、不会改 settings 文件;登录态和有效 key 都得由 Codex 那一侧自己保证存在(README.md:42 / src/run.ts:241)。

Q: 安装好之后,模型怎么才知道有 subagent_codex 这个工具?

A: 并不知道,要靠你的 Agent Preset。full Preset 默认把对应的 tool 行设成 disabled: true,需要先复制 Preset 再去掉这一字段;起一个基于复制品的新 Session 时,模型才会看到那个静态工具名。每个 dsh-tool-subagent 行需要一个独立 toolName 暴露给模型,因此同 Profile 下挂多份 provider 时也要给每个工具起不同的名字(README.md:52)。

Q: 子进程里跟 Codex 的设置文件是怎样生效的?

A: 走原生 Codex 配置的相对路径,本包既不指定 CODEX_HOME、也不去 copy / 过滤 settings 文件。所以在父会话的工作目录下会按 Codex 自家的 project / user 三层去找配置和登录态。也就是说你能在项目里放一份 .codex/settings.json 影响这个 provider,而卸载本包不会动到你这些文件(README.md:42)。

Q: 怎么从失败里看出到底是 Codex 报错还是子进程没起来?

A: 看 SubagentResult.diagnostic 里的 stage 段:initialize / thread-start 多半是启动期问题(比如平台包找不到、载荷缺失),turn-start / turn 是 Codex 协议层出错,process 是 CLI 已经退出但没正常出结果,teardown 是清理阶段 sub-process 退出失败。同时出现的 exit code / signal 行就是进程层的真实退出原因;HTTP 状态码只在 Codex 提供时才会出现在诊断里。原始的产品层或 Host 错误永远在 Error 的 cause 链里,不会直接进入这条 diagnostic(src/run.ts:84-114, 358-365 / src/wire.ts)。

Q: permissionMode 的三个值该怎么选?

A: 不想弹任何审批框就用默认的 never,Codex 对没预先授权的操作会直接拒绝;想让 Codex 改文件但仍然不让它问人就把 permissionMode 换成 approve-for-me,这时 Codex 会走自动评审而不是 DSH 弹窗;dangerously-bypass-approvals-and-sandbox 是把原生审批与沙箱同时关掉,让 Codex 像脱缰一样能在任何路径下做任何事,原则上只在受控 / 沙箱环境里用。DSH 这边三种模式都不会创建交互通道,所有审批都走 Codex 自身的设置(README.md:34-40 / src/wire.ts:25-36)。

Q: 我能让一个工具实例同时支持 foreground 和后台跑吗?

A: 可以,但需要分两个工具行。dsh-tool-subagentbackgroundModeone-shot 时,省略 run_in_background 或传 false 走前台(同步阻塞);传 true 则立刻返回一个由父 Agent 拥有的 Job id,配合 dsh-tool-jobs 提供的 job_output / job_kill 后续拉。前提是你的 Profile 已经装好本地作业服务(@deepseek-ai/dsh-jobs-local / dsh-tool-jobs)(README.md:52)。

Q: 卸载这个包会不会带走什么副作用?

A: 没有持久副作用。卸载后下一次 Profile 启动就把这个 provider 注销,本包没有任何独立磁盘写入或独立账户创建;登录态、Codex settings 文件、缓存都还在 Codex 那一侧独立保留(README.md:44 / README.md:144)。

上手难度

进阶 —— 需要先看懂 dsh 的 Profile Bundle 模型、cordis patch 注入顺序、dsh-tool-subagent 与 job 的接缝,并且要会自己配置 Codex 那边的 settings 和 key 才能让子进程跑通;如果只想"插上去就能用"会觉得整条链路偏长。

已知问题与限制

  • 每次运行都新建一个 app-server、一个 Codex 线程和一个 turn:不支持续接、resume、池化、进度流、产品会话持久化(README.md:135)
  • 实例选择是静态的:Profile 行固定 provider 名与工具绑定;模型不能在调用时挑 provider,每个对外工具必须有唯一 toolName(README.md:136)
  • 宿主 Codex settings 始终是权威:本包不提供"经过筛选或与宿主环境隔离"的生产模式,项目和用户层 settings 能改模型、provider、MCP、hook、skill 等(README.md:42, 137)
  • 认证与账户状态由 Codex 原生侧管理:本包不创建账户、不登录、不改 settings;配置或认证失败会以生命周期阶段 + unknown 回退报出来(README.md:137)
  • 委派时必须有 Codex 平台载荷:可选依赖被跳过、平台不被支持、平台载荷缺失或损坏都会在首次 initialize 失败,不存在"宿主 CLI 回退"路径(README.md:138 / src/run.ts:243-248)
  • 兼容性由 0.147.0 协议基线锁定:升级 Codex 必须重新生成上游 schema 证据并重跑握手 / 答案选择 / 审批 / 取消 / 真实产品测试(README.md:139)
  • 不存在人工审批路径:已知无人值守审批请求会被拒绝,未知 server request 会以默认拒绝方式让运行失败;三种 permissionMode 都不会创建 DSH 交互通道或逐次调用 allow 策略(README.md:140 / src/wire.ts:38-51)
  • assistant 载荷仅含最终文本:推理 / 过程说明 / 中间消息 / 工具调用 / 用量 / 进程 stderr / 工作区差异都不会进入父会话;失败时按需多带一段独立安全诊断(README.md:141)
  • 不支持可选共享能力:共享 subagent 服务会拒掉本 provider 的输出 schema、子角色、工具筛选、harness 深度强制(README.md:142)
  • 没有按经过时长触发的超时或副作用回滚:调用方主动 abort 才会停;停之前子进程已经写过、改过、调过外部接口的状态不会被自动还原(README.md:143)