Merge pull request #2374 from deepseek-harness/codex/product-subagent-one-shot-background

feat(agent-presets): enable background Codex and Claude Code subagent tasks
This commit is contained in:
pku-xht
2026-08-14 15:49:58 +08:00
committed by GitHub
39 changed files with 403 additions and 139 deletions

View File

@@ -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 packages/subagent/subagent-claude-code/README.md
README.md: 17b14e847baea3eadda7129b5e49f5e65b668cc8
README.zh.md: 5c970f623c794e91ec2c4a6b2c71c6b28c887485
README.md: 1a0d6e32b8610769dcc5d8342a4fe88d0c884085
README.zh.md: 78dab14e5eaddc06ccd07b69dc952a09380e0428

View File

@@ -31,7 +31,9 @@ The provider advertises no optional start-time capabilities and reports `inherit
Production resolves `claude` from the subprocess execution world's credential-scrubbed `PATH`, with explicit `env` entries applied, and passes the resulting path to the SDK as `pathToClaudeCodeExecutable`. On Windows, a resolved `.cmd` or `.bat` path is carried as a quoted, per-spawn environment value that `cmd.exe /v:off` expands once, so valid path metacharacters remain data. The pinned SDK's fixed flags then occupy cmd's command tail and contain no cmd metacharacters; they are not ordinary Windows argv. Native settings and authentication remain authoritative. The plugin does not install another CLI, select a model, create a product home, log in, or probe an account. Credential-shaped ambient variables are removed before the explicit `env` overlay is applied, so an API key or token intended for the child must be supplied there. Non-credential endpoint variables such as `ANTHROPIC_BASE_URL`, along with ordinary ambient values such as `PATH` and `HOME`, remain inherited unless overridden.
Shipped profiles load this provider once on the host and start no Claude process until a tool call. Full Agent Presets carry the tool row below with `disabled: true`; copy a preset and remove that field to expose `subagent_claude_code` only to agents composed from the copy. A custom host composition can still use both rows directly.
Production `dsh` does not install or mount this optional provider. A Profile that opts in must install `@deepseek-ai/dsh-subagent-claude-code` and mount it once on the host plane; loading the provider starts no Claude process until a tool call. Full Agent Presets carry a matching product tool row with `disabled: true`; copy a preset and remove that field to expose `subagent_claude_code` only to agents composed from the copy. Its `one-shot` policy keeps omitted or `false` `run_in_background` calls in the foreground, while explicit `true` returns a parent-owned Job id for `job_output` or `job_kill`. The base host and full presets already provide the generic Job registry and controls.
The standalone composition below shows the complete explicit capability. A Profile based on `@deepseek-ai/dsh-base` keeps its existing Job rows, adds the product provider row, and enables the preset tool row instead of mounting duplicate Job services.
```yaml
- id: subagent-claude-code
@@ -40,13 +42,18 @@ Shipped profiles load this provider once on the host and start no Claude process
env:
ANTHROPIC_API_KEY: !!js process.env.ANTHROPIC_API_KEY
- id: jobs
name: '@deepseek-ai/dsh-jobs-local'
- id: tool-jobs
name: '@deepseek-ai/dsh-tool-jobs'
- id: tool-subagent-claude-code
name: '@deepseek-ai/dsh-tool-subagent'
disabled: true
config:
provider: claude-code
toolName: subagent_claude_code
enableRunInBackground: false
backgroundMode: one-shot
maxDepth: provider-managed
```
@@ -72,19 +79,19 @@ The child pays for an independent Claude Code context and query. Child tokens do
Independent of the parent request cache. Reuse depends only on Claude Code's own model, instructions, tools, native settings, and fresh query.
### Parent tool result, indirectly
### Parent scheduling and results, indirectly
#### What the model sees
Through `dsh-tool-subagent`, the parent sees only the strict final Claude Code answer or the consumer's exact error for a non-completed result. Claude Code reasoning, tool activity, intermediate messages, stderr, workspace diffs, usage, and product ids are not copied into the parent Session.
Through `dsh-tool-subagent`, a foreground call gives the parent the strict final Claude Code answer or the consumer's exact error for a non-completed result. A background call first returns a Job id; the generic job controls later deliver a completion notice, expose the final answer and status through `job_output`, and let `job_kill` request cancellation. Claude Code reasoning, tool activity, intermediate messages, stderr, workspace diffs, usage, and product ids are not copied into the parent Session.
#### Token effect
Parent input grows only by the final answer or error retained in the tool result. This provider adds no parent tool schema by itself.
Foreground input grows by the retained final answer or error. Background input also includes the start acknowledgement, completion notice, and any `job_output`, `job_kill`, or later status results; child tokens still do not enter the parent context. This provider adds no parent tool schema by itself.
#### KV Cache effect
Append-only: the new tool result follows the reusable parent request prefix.
Append-only: foreground adds one result after the reusable parent prefix, while background appends the Job acknowledgement, notice, and later control or collection results. Background scheduling can add a notice-driven turn, but none of these messages rewrites the earlier prefix.
## Known Limitations and Deferred Work
@@ -93,6 +100,6 @@ Append-only: the new tool result follows the reusable parent request prefix.
- **Product installation and account state remain native** — a missing or incompatible `claude`, configuration error, or authentication failure is surfaced as a startup or run error; the plugin provides no installer or login flow.
- **The SDK platform CLI remains in the install closure** — production ignores it in favor of the host `claude`, but the current SDK optional dependency is still installed and supplies the keyless compatibility fixture. Removing that payload belongs to the separate product installation-closure follow-up.
- **No human interaction path** — `AskUserQuestion` is disabled and other interactive callbacks are absent, so tasks requiring new approval or input fail instead of suspending.
- **Final text only** — reasoning, intermediate messages, tool traffic, usage, stderr, and workspace diffs remain product-local.
- **Product payload is final text only** — reasoning, intermediate messages, tool traffic, usage, stderr, and workspace diffs remain product-local; generic Job ids, notices, and status come from the shared job runtime.
- **No optional shared capabilities** — output schemas, child personas, tool filtering, and harness depth enforcement are rejected by the shared service for this provider.
- **No wall-clock timeout or side-effect rollback** — the caller cancels long work, and files or external systems changed before cancellation are not restored.

View File

@@ -31,7 +31,9 @@ SDK 接收由文本块原样拼接成的任务。提供方会完整迭代 SDK
生产环境从子进程执行世界清除凭证后的 `PATH` 解析 `claude`,再应用显式 `env` 条目,并把所得路径作为 `pathToClaudeCodeExecutable` 交给 SDK。在 Windows 上,解析到的 `.cmd``.bat` 路径会作为带引号、仅供本次 spawn 使用的环境值交给 `cmd.exe /v:off` 展开一次,因此合法路径中的元字符仍只是数据。锁定版本的 SDK 随后把固定命令行选项放在 cmd 的命令尾部;这些选项不含 cmd 元字符,也并不是普通的 Windows argv。原生设置与身份验证继续是权威来源。本插件不安装另一份 CLI、不选择模型、不创建产品主目录、不执行登录也不探测账户。具有凭证特征的环境变量会在显式 `env` 覆盖生效前被清除,因此供子进程使用的 API 密钥或 token 必须在该配置中显式提供。除非被覆盖,`ANTHROPIC_BASE_URL` 等非凭证端点变量以及 `PATH``HOME` 等普通环境变量仍会被继承。
随附 profile 会在宿主上加载一次该提供方,而且在工具调用前不会启动 Claude 进程。完整 Agent Preset 携带下列工具行并设置 `disabled: true`;复制一个 preset 后删除该字段,即可只向由该副本组装的 agent 暴露 `subagent_claude_code`自定义宿主组装仍可直接使用两条配置行
生产 `dsh` 不会安装或挂载这个可选提供方。选择启用它的 Profile 必须安装 `@deepseek-ai/dsh-subagent-claude-code`,并在 host plane宿主平面挂载一次加载提供方本身不会在工具调用前启动 Claude 进程。完整 Agent Preset 携带对应的产品工具行并设置 `disabled: true`;复制一个 preset 后删除该字段,即可只向由该副本组装的 agent 暴露 `subagent_claude_code``one-shot` 策略会让省略 `run_in_background` 或传入 `false` 的调用继续在前台等待,而显式传入 `true` 会返回由父 agent 拥有的 Job ID`job_output``job_kill` 使用。base host基础宿主与完整 preset 已提供通用作业注册表和控制工具
下列独立组装展示完整的显式能力。基于 `@deepseek-ai/dsh-base` 的 Profile 保留已有 Job 行,只新增产品提供方行并启用 preset 工具行,禁止重复挂载 Job 服务。
```yaml
- id: subagent-claude-code
@@ -40,13 +42,18 @@ SDK 接收由文本块原样拼接成的任务。提供方会完整迭代 SDK
env:
ANTHROPIC_API_KEY: !!js process.env.ANTHROPIC_API_KEY
- id: jobs
name: '@deepseek-ai/dsh-jobs-local'
- id: tool-jobs
name: '@deepseek-ai/dsh-tool-jobs'
- id: tool-subagent-claude-code
name: '@deepseek-ai/dsh-tool-subagent'
disabled: true
config:
provider: claude-code
toolName: subagent_claude_code
enableRunInBackground: false
backgroundMode: one-shot
maxDepth: provider-managed
```
@@ -72,19 +79,19 @@ Claude Code 子级会在一个全新的 SDK query 中接收独立文本任务。
这与父请求缓存相互独立。能否复用只取决于 Claude Code 自身的模型、指令、工具、原生设置和全新 query。
### 父级工具结果(间接)
### 父级调度与结果(间接)
#### 模型看到的内容
通过 `dsh-tool-subagent`,父级模型只会看到符合严格成功条件的 Claude Code 最终答案或者在结果未完成时看到消费方给出的原样错误。Claude Code 的推理、工具活动、中间消息、stderr、工作区差异、用量信息和产品标识符均不会复制到父会话。
通过 `dsh-tool-subagent`前台调用会让父级模型看到符合严格成功条件的 Claude Code 最终答案,或者在结果未完成时看到消费方给出的原样错误。后台调用会先返回 Job id随后通用作业控制面会送达完成通知通过 `job_output` 公开最终答案与状态,并允许 `job_kill` 请求取消。Claude Code 的推理、工具活动、中间消息、stderr、工作区差异、用量信息和产品标识符均不会复制到父会话。
#### 对 token 的影响
父级输入会增加工具结果中保留的最终答案或错误内容。本提供方自身不添加父级工具 schema。
前台输入会增加工具结果中保留的最终答案或错误内容。后台输入还会包含启动确认、完成通知,以及 `job_output``job_kill` 或后续状态结果;子任务 token 仍不会进入父级上下文。本提供方自身不添加父级工具 schema。
#### 对 KV Cache 的影响
仅追加:新的工具结果接在可复用的父请求前缀后。
仅追加:前台会在可复用的父请求前缀后增加一个结果,后台则会继续追加 Job 启动确认、通知以及后续控制或收集结果。后台调度可能增加一个由通知唤醒的轮次,但这些消息都不会改写更早的前缀
## 已知限制与后续工作
@@ -93,6 +100,6 @@ Claude Code 子级会在一个全新的 SDK query 中接收独立文本任务。
- **产品安装与账户状态仍由原生机制管理**`claude` 缺失或不兼容、配置错误或身份验证失败都会呈现为启动错误或运行错误;本插件不提供安装程序或登录流程。
- **SDK 平台 CLI 仍在安装闭包内**:生产环境会忽略它,改用宿主提供的 `claude`,但当前 SDK 的可选依赖仍会安装,并提供无密钥兼容性 fixture。移除该载荷属于独立的产品安装闭包后续项。
- **没有人工交互路径**`AskUserQuestion` 被禁用,其他交互回调也不存在,因此需要新审批或输入的任务会失败而不会挂起。
- **仅返回最终文本**推理、中间消息、工具通信、用量信息、stderr 和工作区差异仍只保留在产品内部。
- **产品载荷仅包含最终文本**推理、中间消息、工具通信、用量信息、stderr 和工作区差异仍只保留在产品内部;通用 Job id、通知与状态来自共享作业运行时
- **没有可选的共享能力**:对于本提供方,共享服务会拒绝输出 schema、子任务角色设定、工具筛选和 harness 深度强制约束。
- **没有按实际经过时间触发的超时或副作用回滚**:长时间运行的工作由调用方取消,且取消前已更改的文件或外部系统不会恢复原状。

View File

@@ -15,7 +15,7 @@ const configPath = join(fixtureDir, 'cordis.yml')
const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url))
describe('product-provider public Loader composition', () => {
it('loads both opt-in packages and foreground tools without starting either product', async () => {
it('loads both opt-in packages, one-shot task tools, and job controls without starting either product', async () => {
const { stdout, stderr } = await runLoaderSmoke({
label: 'product-provider Loader composition',
tempDirPrefix: 'dsh-product-provider-loader-',
@@ -57,15 +57,16 @@ describe('product-provider public Loader composition', () => {
tools: [
{
name: 'subagent_codex',
parameterNames: ['description', 'prompt'],
parameterNames: ['description', 'prompt', 'run_in_background'],
required: ['description', 'prompt'],
},
{
name: 'subagent_claude_code',
parameterNames: ['description', 'prompt'],
parameterNames: ['description', 'prompt', 'run_in_background'],
required: ['description', 'prompt'],
},
],
jobTools: ['job_kill', 'job_list', 'job_output'],
starts: 0,
})
}, LOADER_SMOKE_TEST_TIMEOUT_MS)