fix(subagent): keep Codex provider opt-in

This commit is contained in:
pku-xht
2026-08-04 18:00:09 +08:00
parent d7ee0e798a
commit 8e4a1b3396
8 files changed
+4 -35

No files matched your search

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/proposed/feature/2026-08-04-claude-code-and-codex-subagent-backends.md
2026-08-04-claude-code-and-codex-subagent-backends.md: 52181edba816f651877eac2c616cf67191f7e550
2026-08-04-claude-code-and-codex-subagent-backends.zh.md: bde24eb8939b10c10916dab93effd3b94cbc7e1b
2026-08-04-claude-code-and-codex-subagent-backends.md: 37f45f844c9411af0467397272649533ed4d44cc
2026-08-04-claude-code-and-codex-subagent-backends.zh.md: dcd7b90231bdaed47435c27deef413d20f0b7f28
@@ -16,7 +16,7 @@ The harness provides two sibling one-shot providers behind two fixed model-facin
The Codex provider is implemented against Codex 0.146.0. The Claude Code provider remains unimplemented. This Note remains proposed until both siblings and their combined evidence are present.
Both providers report `inheritsParentContext: false`, advertise no optional start capabilities, and pass the parent Session cwd without copying the parent conversation. Their fixed tools use `maxDepth: 'provider-managed'` because each out-of-process product owns any delegation budget inside its own harness; the parent sends no recursion cap that the provider cannot enforce. Every call creates a fresh product process and a non-resumable product conversation. The shared subagent service continues to own request resolution, lifecycle events, result settlement, and foreground collection; the shared subprocess service owns credential scrubbing, process-tree termination, and whole-tree exit observation.
Both providers report `inheritsParentContext: false`, advertise no optional start capabilities, and pass the parent Session cwd without copying the parent conversation. Every call creates a fresh product process and a non-resumable product conversation. The shared subagent service continues to own request resolution, lifecycle events, result settlement, and foreground collection; the shared subprocess service owns credential scrubbing, process-tree termination, and whole-tree exit observation.
```text
fixed tool → shared subagent service → product provider → official product process
@@ -37,8 +37,6 @@ fixed tool → shared subagent service → product provider → official product
`@deepseek-ai/dsh-subagent-codex` registers the fixed `codex` provider and always starts `codex app-server --stdio` from `PATH`. Its public configuration contains only an explicit `env` overlay and a positive finite `disposeGraceMs`. Installation, login, `CODEX_HOME`, model selection, base URL, sandbox, approval policy, and product-session settings remain native Codex or deployment responsibilities.
The shipped `apps/cli/config/base.cordis.yml` loads this provider and a fixed `subagent_codex` tool by default, while `apps/cli/package.json` carries the provider package in the CLI dependency closure. Loading the base does not probe the Codex binary or authentication; missing native availability fails only when the tool is called.
Before publication, the provider validates a non-empty text-only task, starts the managed app-server in the parent workspace, completes `initialize``initialized`, and creates an `ephemeral: true` thread. The published run owns exactly one `turn/start`; its thread and turn ids remain private and are never persisted in the parent Session.
`turn/completed` is the authoritative remote terminal fact. The latest nonblank `agentMessage` with `phase: "final_answer"` wins. When the product emits no explicit final phase, the latest message with `phase: null` is the compatibility fallback; commentary never replaces either answer. A completed turn without an answer, a failed or interrupted remote turn, malformed wire data, protocol closure, early process exit, or unknown server request becomes `error`. Local cancellation wins its race and remains `aborted`.
@@ -16,7 +16,7 @@ harness 在两个固定的面向模型工具背后提供两个一次性兄弟提
Codex 提供方基于 Codex 0.146.0 实现。Claude Code 提供方仍未实现。在两个兄弟提供方及其组合证据全部具备之前,本 Agent Note 将保持提案状态。
这两个提供方都报告 `inheritsParentContext: false`,不声明任何可选的启动时功能,并传递父会话 cwd,但不会复制父级对话。固定工具使用 `maxDepth: 'provider-managed'`,因为每个进程外产品都负责其自身 harness 内部的委派预算;父级不会传入提供方无法执行的递归上限。每次调用都会创建一个全新的产品进程和一次不可续接的产品对话。共享 subagent 服务继续负责请求解析、生命周期事件、结果结算和前台收集;共享子进程服务负责凭证清洗、进程树终止以及整棵进程树的退出观测。
这两个提供方都报告 `inheritsParentContext: false`,不声明任何可选的启动时功能,并传递父会话 cwd,但不会复制父级对话。每次调用都会创建一个全新的产品进程和一次不可续接的产品对话。共享 subagent 服务继续负责请求解析、生命周期事件、结果结算和前台收集;共享子进程服务负责凭证清洗、进程树终止以及整棵进程树的退出观测。
```text
fixed tool → shared subagent service → product provider → official product process
@@ -37,8 +37,6 @@ fixed tool → shared subagent service → product provider → official product
`@deepseek-ai/dsh-subagent-codex` 注册固定的 `codex` 提供方,并始终启动 `codex app-server --stdio`,该命令从 `PATH` 解析。其公开配置仅包含显式的 `env` 覆盖项和须为正有限值的 `disposeGraceMs`。安装、登录、`CODEX_HOME`、模型选择、基础 URL、沙箱、审批策略和产品会话设置仍由 Codex 原生机制或部署环境负责。
正式发布的 `apps/cli/config/base.cordis.yml` 默认加载这个提供方和固定的 `subagent_codex` 工具,而 `apps/cli/package.json` 将提供方包纳入 CLI 依赖闭包。加载基础配置时不会探测 Codex 二进制程序或身份验证;缺少原生可用条件只会在工具实际调用时失败。
发布前,提供方会验证非空的纯文本任务,在父级工作区中启动受管的 app-server,完成 `initialize``initialized` 握手,并创建一个 `ephemeral: true` 线程。已发布的运行只拥有一次 `turn/start`;其线程 ID 与轮次 ID 保持私有,绝不会持久化到父会话。
`turn/completed` 是权威的远端终止事实。以最后一条非空白的 `agentMessage` 为准,但它必须带有 `phase: "final_answer"`。若产品没有发出明确的最终阶段,则以最后一条 `phase: null` 的消息作为兼容性回退;过程说明绝不会取代上述任一答案。轮次完成却没有答案、远端轮次失败或中断、协议数据格式错误、协议关闭、进程提前退出或未知的服务器请求,都会产生 `error`。本地取消在竞态中胜出并保持为 `aborted`
-6
View File
@@ -94,8 +94,6 @@ flowchart LR
cfg --> plugin_dsh_base_subagent_spawn
plugin_dsh_base_subagent_fork["subagent-fork<br/>@deepseek-ai/dsh-subagent-fork"]
cfg --> plugin_dsh_base_subagent_fork
plugin_dsh_base_subagent_codex["subagent-codex<br/>@deepseek-ai/dsh-subagent-codex"]
cfg --> plugin_dsh_base_subagent_codex
plugin_dsh_base_tool_subagent_control["tool-subagent-control<br/>@deepseek-ai/dsh-tool-subagent-control"]
cfg --> plugin_dsh_base_tool_subagent_control
plugin_dsh_base_tool_subagent_list_agents["tool-subagent-list-agents<br/>@deepseek-ai/dsh-tool-subagent-control/list-agents"]
@@ -104,8 +102,6 @@ flowchart LR
cfg --> plugin_dsh_base_tool_subagent
plugin_dsh_base_tool_subagent_fork["tool-subagent-fork<br/>@deepseek-ai/dsh-tool-subagent"]
cfg --> plugin_dsh_base_tool_subagent_fork
plugin_dsh_base_tool_subagent_codex["tool-subagent-codex<br/>@deepseek-ai/dsh-tool-subagent"]
cfg --> plugin_dsh_base_tool_subagent_codex
plugin_dsh_base_tool_subagent_report["tool-subagent-report<br/>@deepseek-ai/dsh-tool-subagent-report"]
cfg --> plugin_dsh_base_tool_subagent_report
plugin_dsh_base_workflow_workerthread["workflow-workerthread<br/>@deepseek-ai/dsh-workflow-workerthread"]
@@ -195,12 +191,10 @@ flowchart LR
| `subagent` | `@deepseek-ai/dsh-subagent` |
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
| `subagent-fork` | `@deepseek-ai/dsh-subagent-fork` |
| `subagent-codex` | `@deepseek-ai/dsh-subagent-codex` |
| `tool-subagent-control` | `@deepseek-ai/dsh-tool-subagent-control` |
| `tool-subagent-list-agents` | `@deepseek-ai/dsh-tool-subagent-control/list-agents` |
| `tool-subagent` | `@deepseek-ai/dsh-tool-subagent` |
| `tool-subagent-fork` | `@deepseek-ai/dsh-tool-subagent` |
| `tool-subagent-codex` | `@deepseek-ai/dsh-tool-subagent` |
| `tool-subagent-report` | `@deepseek-ai/dsh-tool-subagent-report` |
| `workflow-workerthread` | `@deepseek-ai/dsh-workflow-workerthread` |
| `tool-workflow` | `@deepseek-ai/dsh-tool-workflow` |
-11
View File
@@ -254,9 +254,6 @@
config:
providerName: fork
- id: subagent-codex
name: '@deepseek-ai/dsh-subagent-codex'
# Continuable background children are selected per delegation tool. The
# separately loaded follow-up tool registers the one global `send_message`.
- id: tool-subagent-control
@@ -279,14 +276,6 @@
toolName: subagent_fork
backgroundMode: continuable
- id: tool-subagent-codex
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: codex
toolName: subagent_codex
enableRunInBackground: false
maxDepth: 'provider-managed'
# Optional direct-child return channel; absent from roots and one-shot agents.
- id: tool-subagent-report
name: '@deepseek-ai/dsh-tool-subagent-report'
-1
View File
@@ -98,7 +98,6 @@
"@deepseek-ai/dsh-storage-domain": "workspace:^",
"@deepseek-ai/dsh-storage-json": "workspace:^",
"@deepseek-ai/dsh-subagent": "workspace:^",
"@deepseek-ai/dsh-subagent-codex": "workspace:^",
"@deepseek-ai/dsh-subagent-fork": "workspace:^",
"@deepseek-ai/dsh-subagent-spawn": "workspace:^",
"@deepseek-ai/dsh-subprocess-local": "workspace:^",
-6
View File
@@ -85,7 +85,6 @@ function startRawLifecycle(fixture: RawLifecycleFixture) {
env: {
DSH_HOME: fixture.home,
DSH_TELEMETRY_DISABLED: '1',
PATH: fixture.home,
RAW_READY_FILE: fixture.ready,
RAW_SETTLED_FILE: fixture.settled,
RAW_DISPOSED_FILE: fixture.disposed,
@@ -164,11 +163,6 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)',
expect(stdout).toContain("name: '@deepseek-ai/dsh-agent-loop'")
expect(stdout).toContain('agents: []')
expect(stdout).toContain('# == base.cordis.yml')
expect(stdout).toContain("name: '@deepseek-ai/dsh-subagent-codex'")
expect(stdout).toContain('provider: codex')
expect(stdout).toContain('toolName: subagent_codex')
expect(stdout).toContain('enableRunInBackground: false')
expect(stdout).toContain('maxDepth: provider-managed')
}, 30_000)
it('composes the required raw overlay directly over the base', async () => {
-3
View File
@@ -377,9 +377,6 @@ importers:
'@deepseek-ai/dsh-subagent':
specifier: workspace:^
version: link:../../packages/subagent/subagent
'@deepseek-ai/dsh-subagent-codex':
specifier: workspace:^
version: link:../../packages/subagent/subagent-codex
'@deepseek-ai/dsh-subagent-fork':
specifier: workspace:^
version: link:../../packages/subagent/subagent-fork