# Agent Note: 后台 subagent 任务

Status: implemented

[English](2026-07-08-background-subagent-tasks.md) | 中文

## 问题

[subagent seam](2026-06-21-subagent-capability-seam.md) 会返回 `SubagentRun`，但原先面向模型的工具会同步收集每一次运行。因此，各自独立的慢速委派要么一直占用父调用，要么按串行方式运行。

subagent 需要与其他长时间运行的工具相同的启动、收集、列出、停止、归属、通知和清理行为，但不应采用进程流语义。子会话仍是详细记录；父级只需最终答案和任务状态。后台子级的存活时间还会超过启动它的工具调用，因此必须明确其取消和拥有者资源释放契约。

## 决策

每个 `dsh-tool-subagent` 实例都可以公开 `run_in_background`，由 `enableRunInBackground` 控制，且默认启用。禁用该功能的实例不包含此参数，并会在执行时拒绝强制传入的后台参数。提供方选择仍属于部署配置，因此一个实例仍然只为一个提供方注册一个名称可区分的工具。

后台 subagent 使用[通用后台任务运行时](../architecture/2026-06-20-generic-long-running-tool-runtime.md)。`task_output`、`task_list` 和 `task_kill` 负责收集、列出、取消、完成通知和提示词引导；系统不提供 subagent 专用的配套工具。

前台调用保留其同步契约：等待提供方启动和 `run.result`；仅当状态为 `completed` 时返回最终文本；将其他终止原因映射为出错的工具结果；并且始终在返回前释放该运行。

对于后台调用，工具会验证父级，并在调用 `ctx.tasks.start()` 前拒绝已中止的执行信号。任务运行时会在调用生产者启动器前，预检控制接口和拥有者清理。该启动器创建独立的 `AbortController` 并启动 `ctx.subagents.start()`；返回 id 之后，工具调用的信号不再拥有该子级。

任务注册按以下方式映射 subagent seam：

- `kind` 为 `subagent`，`label` 为模型提供的描述，`owner` 为父 agent（智能体）。
- `cancel(reason?)` 中止任务自有的控制器。同一个信号同时覆盖尚未完成的提供方启动和已就绪的子级。
- `done` 等待提供方启动、子级结果和 `run.dispose()`。已完成的运行返回最终文本，已中止的运行变为 `killed`，其他停止原因变为 `failed`。启动、结果和资源释放失败会转换为失败结果，而不是被拒绝的任务 Promise。
- `readOutput` 不存在。任务存活期间，`task_output` 只返回状态；结算后，它以幂等方式返回最终输出。中间的子级活动仍保留在子会话中。

## 生命周期

后台 subagent 归属于其父 agent，不会在拥有者关闭后持久存续。任务运行时将清理附加到对应拥有者的确切作用域。agent 资源释放会取消任务，并在 `AgentHandle.dispose()` 完成前等待启动回滚或子级资源释放，避免泄漏子 agent 和会话。

完成通知会发送给启动时捕获的确切拥有者。如果拥有者清理过程已经释放了注入目标，该通知将被丢弃；生命周期保证是清理，而不是通知。

## 模型引导

通用任务提示词教会模型一套共享的做法：保留 id；继续独立工作，而不是忙等轮询；在回答前收集相关任务；终止无关工作。subagent schema 只补充说明：后台模式返回 task id，且 `task_output` 用于收集结果。无论模型是否遵循提示词，授权和拥有者清理都会强制执行运行时边界。

## 备选方案

### subagent 专用的等待、输出和停止工具

能力专用工具会重复任务协议，再教一套收集与停止习惯，并增加多个提供方实例的复杂度。通用运行时在不改变工具「每个实例对应一个提供方」形态的前提下，提供了所需行为。

### 在拥有者关闭后存续

该方案需要持久化的任务状态、子会话恢复、延迟结果交付通道，以及对被遗弃拥有者的处理策略。以拥有者为作用域的清理为进程内工作界定了明确生命周期。持久作业需要单独设计。

### 隔离客户端不做拥有者检查

agent 和日志可能以会话为作用域，但任务注册表和可预测 id 属于运行时全局范围。因此，通用拥有者防线同样适用于 subagent 和所有其他生产者。

### 增量子 transcript 输出

将子级历史以流式方式写入父级，会模糊日志边界，并使提供方行为分化。此接口只公开最终输出；更丰富的观察应由会话或 UI 工具承担。

## 测试

单元测试覆盖固定了停止原因映射、在报告前释放资源、启动与结果失败、对预中止的拒绝、从启动调用信号分离、在提供方就绪前后取消、通过真实任务工具收集、无控制接口的预检防线、运行时缺失失败，以及每实例 schema 开关。快照覆盖固定了面向模型的 schema。

## 影响

父级可以并行分派慢速委派任务，并通过与 bash 共用的任务控制来收集结果。子级工作不再占用启动它的工具调用，但在收集、终止或拥有者释放之前可以继续消耗资源。提示词引导鼓励收集；拥有者清理则提供硬性生命周期边界。需要同步委派的部署可以按工具实例禁用后台模式。
