Product one-shot subagents use generic background Jobs
产品 one-shot subagent 使用通用后台 Job
The Codex and Claude Code providers already run one self-contained task and return one final answer, while `dsh-tool-subagent` already adapts any one-shot provider to the generic background Job runtime. The shipped product-tool rows disabled that route, so an agent could only wait for the product answer even when the delegation was independent of its next action. Exposing background execution must not add a product s
English
Problem
The Codex and Claude Code providers already run one self-contained task and return one final answer, while dsh-tool-subagent already adapts any one-shot provider to the generic background Job runtime. The shipped product-tool rows disabled that route, so an agent could only wait for the product answer even when the delegation was independent of its next action.
Exposing background execution must not add a product session, product-specific job state, another cancellation owner, or another result protocol. The same provider run must remain responsible for one native process or query and one final answer, while the existing Job registry remains responsible for ids, collection, cancellation, owner cleanup, and completion notices.
Decision
Production dsh does not install the optional product providers. A Profile that opts in installs the needed dsh-subagent-codex or dsh-subagent-claude-code packages and mounts the required provider instances on the host plane. The standard, code, and cordis Agent Presets configure the corresponding dormant tool rows with backgroundMode: one-shot; removing a row's disabled field exposes the existing optional run_in_background argument to agents composed from that preset. Omission or false waits in the foreground; explicit true returns a parent-owned Job id after synchronous Job preflight and registration, without waiting for provider startup or completion.
The named-instance decision allows multiple rows for either product. Each additional host provider row has its own providerName, and each exposed preset tool row binds that exact name through provider while keeping a unique toolName; the foreground/background scheduling choice does not constrain the number of instances.
The generic one-shot background adapter owns background registration and settlement. It starts the same SubagentRun, uses a Job-owned cancellation signal across provider startup and execution, waits for run.result and run.dispose(), maps the terminal result and optional safe diagnostic into the Job, and lets job_output, job_list, job_kill, and the existing completion notice expose that state. The product provider decision continues to own native protocols, answer selection, local cancellation, and process-tree quiescence; the non-interactive permissions decision owns each product Provider's Profile configuration and diagnostic production.
This scheduling decision adds no provider configuration, service interface, event, wire field, persistence format, or product identifier. A Provider may define its own Profile configuration independently; foreground and background still differ only in which existing consumer waits for the same one-shot run.
Ownership and lifecycle
product tool call
-> omitted / false: tool call waits -> final answer or error -> run disposal
-> true: Job preflight + owner cleanup
-> starter begins provider startup under Job-owned signal
-> Job record/id published and returned (startup remains pending)
-> provider result + run disposal -> Job settlement + notice
-> job_output reads / job_kill cancels
-> parent disposal: Job owner cleanup cancels -> run disposal -> process exit
| Fact or resource | Owner | Product-tool responsibility | Observable result |
|---|---|---|---|
| Product provider installation and registration | Explicit Profile | Install the optional provider package and mount the required named instances on the host plane | The provider names are available without adding the package to every production dsh install |
| Product selection and exposure | Agent Preset | Bind one fixed tool name to one fixed provider | Enabling one row exposes only that product tool |
| Foreground or background choice | dsh-tool-subagent | Resolve run_in_background under one-shot policy | Omission is foreground; explicit true returns a Job id |
| Job id, state, output, cancellation, and notice | ctx.jobs and dsh-tool-jobs | Register and present the existing one-shot run | Generic job tools collect or stop the run for the exact parent |
| Native result, optional diagnostic, and process quiescence | Product provider and dsh-subprocess | Produce one final result and release one process tree | Job settlement and foreground return consume the same result and both wait for disposal |
Published composition
The production base keeps both optional product providers out of its dependency closure. An opting-in Profile installs the needed packages and mounts the required provider instances on the host plane. Each full preset keeps both product-tool rows disabled and contributes the generic Job controls to its own agent scope, while the base host owns the shared Job registry. A user copies a preset and removes disabled from the matching product rows after the Profile providers are present; no product process starts during composition.
A standalone custom composition that enables one-shot background execution must provide the product provider plus the complete generic Job capability: dsh-jobs-local as the Job provider and dsh-tool-jobs as the model-facing consumer. A Profile based on dsh-base already has the Job capability and adds only the optional product provider before enabling the preset tool row. A product tool without the Job runtime can still execute in the foreground, but an explicit background request fails the existing Job preflight instead of publishing an uncollectable id.
The ACP product compositions use the same fixed product rows and generic job controls. Their keyless schema snapshots expose description, prompt, and optional run_in_background for each enabled product tool without invoking Codex, Claude Code, or an external model.
Verification
The Web composition test explicitly mounts both optional providers from the repository examples dependency anchor, then boots four user-preset variants—neither product, Codex, Claude Code, and both—and checks that each enabled product tool exposes run_in_background alongside job_output, job_list, and job_kill. The two package-owned Loader compositions run with an empty PATH, inspect the same schemas and controls, and prove that explicit provider loading starts no product process. ACP keyless snapshots pin the assembled explicit product schemas, while the existing dsh-tool-subagent and job suites pin foreground defaulting, Job registration, final-output collection, shared diagnostic presentation, cancellation, completion notices, owner disposal, and provider disposal. The two real product-provider suites independently prove that their native permission failures enter that same shared result before either scheduling path consumes it.
Alternatives considered
Keep the product tools foreground-only. This preserves the smallest schema but prevents agents from scheduling independent product work even though the generic one-shot Job adapter already owns the required lifecycle.
Make product delegations background by default. A one-shot Job requires later collection, unlike a continuable child with its own durable conversation id and settlement delivery. Foreground remains the compatible default, and background remains an explicit scheduling choice.
Use Codex or Claude Code native session state as the background owner. That would create provider-specific ids, status, cancellation, and recovery semantics beside the generic Job registry. The providers remain one-shot result producers and keep native ids private.
Add product-specific output, wait, or kill tools. Separate controls would duplicate the generic job protocol and teach a different collection workflow for each provider. The existing job_* tools already cover the required operations.
Add continuable product sessions at the same time. Resume, follow-up, progress, and persisted product sessions require new product contracts and lifecycle ownership. This decision exposes only the already implemented one-shot background route.
Consequences
Agents can continue useful work while Codex or Claude Code handles an independent one-shot task, then collect the final answer or cancel it through the same Job controls used by other background producers. Foreground and one-shot background consumers present the same safe Provider diagnostic when a failed result supplies one.
Every product delegation still starts a fresh native process or query, produces final assistant text as its only assistant payload, and ends with provider disposal and whole-tree exit. A failed result may separately carry a safe diagnostic. A background call additionally exposes the generic Job id, status, completion notice, and collection or cancellation results. Background Jobs are process-local and parent-owned: they do not survive parent disposal, do not expose intermediate product activity, and do not make a product conversation resumable. Production installs do not pay for either product integration unless a Profile explicitly installs it; any composition that exposes the background argument must also keep the generic Job provider and controls available.
中文
问题
Codex 与 Claude Code 提供方已经能够运行一项自包含任务并返回一个最终回答,而 dsh-tool-subagent 也已经能够把任意 one-shot 提供方接入通用后台 Job 运行时。随附产品工具行禁用了这条路径,因此即使委托与 agent 的下一步操作彼此独立,agent 也只能等待产品回答。
公开后台执行不得增加产品会话、产品专属作业状态、另一取消责任方或另一结果协议。同一个提供方运行必须继续负责一个原生进程或 query 和一个最终回答,而现有作业注册表继续负责 id、收集、取消、owner 清理与完成通知。
决策
生产 dsh 不安装可选产品提供方。选择启用产品集成的 Profile 会安装所需的 dsh-subagent-codex 或 dsh-subagent-claude-code 包,并在 host plane(宿主平面)挂载所需的提供方实例。standard、code 与 cordis Agent Preset 使用 backgroundMode: one-shot 配置相应的休眠工具行;删除某一行的 disabled 字段后,现有可选参数 run_in_background 会向由该 preset 组装的 agent 公开。省略该参数或传入 false 时会在前台等待;显式传入 true 时会在同步完成 Job 预检与登记后返回由父级拥有的 Job id,而不会等待提供方启动或完成。
命名实例决策允许两个产品分别拥有多个配置项。每个新增宿主提供方配置项都有独立的 providerName,每个公开的 preset 工具配置项都通过 provider 绑定该名称并保持唯一的 toolName;前台或后台调度选择不会限制实例数量。
通用 one-shot 后台适配器负责后台登记与结算。它会启动同一个 SubagentRun,让 Job 自有的取消信号覆盖提供方启动与执行,等待 run.result 和 run.dispose(),把终态结果与可选安全诊断映射进 Job,并由 job_output、job_list、job_kill 与现有完成通知公开该状态。产品提供方决策继续负责原生协议、答案选择、本地取消与进程树完全停稳;非交互权限决策负责各产品提供方的 Profile 配置与诊断生产。
本调度决策不新增提供方配置、服务接口、事件、协议字段、持久化格式或产品标识符。提供方可以独立定义自己的 Profile 配置;前台与后台的区别仍然只在于由哪个现有消费方等待同一个 one-shot 运行。
归属与生命周期
product tool call
-> omitted / false: tool call waits -> final answer or error -> run disposal
-> true: Job preflight + owner cleanup
-> starter begins provider startup under Job-owned signal
-> Job record/id published and returned (startup remains pending)
-> provider result + run disposal -> Job settlement + notice
-> job_output reads / job_kill cancels
-> parent disposal: Job owner cleanup cancels -> run disposal -> process exit
| 事实或资源 | 责任方 | 产品工具职责 | 可观察结果 |
|---|---|---|---|
| 产品提供方安装与登记 | 显式 Profile | 安装可选提供方包,并在 host plane 挂载所需的命名实例 | 提供方名称可用,但不会让每次生产 dsh 安装都包含该包 |
| 产品选择与公开 | Agent Preset | 把一个固定工具名绑定到一个固定提供方 | 启用一行只会公开对应产品工具 |
| 前台或后台选择 | dsh-tool-subagent | 按 one-shot 策略解析 run_in_background | 省略参数时在前台运行;显式传入 true 时返回 Job id |
| Job id、状态、输出、取消与通知 | ctx.jobs 与 dsh-tool-jobs | 登记并展示现有 one-shot 运行 | 通用作业工具为准确父级收集或停止运行 |
| 原生结果、可选诊断与进程完全停稳 | 产品提供方与 dsh-subprocess | 产生一个最终结果并释放一棵进程树 | Job 结算与前台返回消费同一结果,且都会等待资源释放 |
发布组装
生产 base 不让两个可选产品提供方进入依赖闭包。选择启用产品集成的 Profile 会安装所需包,并在 host plane 挂载所需的提供方实例。每个完整 preset 让两个产品工具行保持禁用,并把通用 Job 控制工具贡献到自身 agent 作用域;base host 负责共享 Job 注册表。Profile 提供方实例存在后,用户复制一个 preset,再从对应产品行删除 disabled;组装期间不会启动产品进程。
独立自定义组装若启用 one-shot 后台执行,就必须同时提供产品提供方与完整通用 Job 能力:由 dsh-jobs-local 充当 Job 提供方,由 dsh-tool-jobs 充当面向模型的消费方。基于 dsh-base 的 Profile 已具备 Job 能力,只需在启用 preset 工具行前新增可选产品提供方。没有 Job 运行时的产品工具仍可在前台执行,但显式后台请求会在现有 Job 预检中失败,不会发布无法收集的 id。
ACP 产品组装使用相同的固定产品行与通用作业控制工具。其无密钥 schema 快照会为每个已启用产品工具公开 description、prompt 和可选的 run_in_background,而不会调用 Codex、Claude Code 或外部模型。
验证
Web 组装测试会从仓库 examples 依赖锚点显式挂载两个可选提供方,再启动四种用户 preset 变体——不启用产品、只启用 Codex、只启用 Claude Code,以及同时启用两者——并检查每个已启用产品工具都会与 job_output、job_list 和 job_kill 一起公开 run_in_background。两个由包负责的 Loader 组装会在空 PATH 下运行,检查相同 schema 与控制工具,并证明显式加载提供方不会启动产品进程。ACP 无密钥快照会固定显式组装后的产品 schema,而现有 dsh-tool-subagent 与作业测试套件会固定前台默认值、Job 登记、最终输出收集、共享诊断呈现、取消、完成通知、owner 资源释放与提供方资源释放。两个真实产品提供方测试套件还会分别证明各自的原生权限失败先进入同一个共享结果,再由任一调度路径消费。
曾考虑的替代方案
让产品工具继续只支持前台运行。 这种方案保留最小 schema,却会阻止 agent 调度独立产品工作,即使通用 one-shot Job 适配器已经负责所需生命周期。
让产品委托默认在后台运行。 one-shot Job 需要后续收集,这不同于拥有自身持久会话 id 与结算交付的可续接子级。前台继续作为兼容默认值,后台继续作为显式调度选择。
让 Codex 或 Claude Code 原生会话状态负责后台生命周期。 这会在通用作业注册表之外建立提供方专属 id、状态、取消与恢复语义。提供方继续只产生 one-shot 结果,并把原生 id 保持为私有事实。
增加产品专属 output、wait 或 kill 工具。 独立控制工具会复制通用作业协议,并为每个提供方教授不同的收集工作流。现有 job_* 工具已经覆盖所需操作。
同时增加可续接产品会话。 恢复、后续交互、进度与持久化产品会话需要新的产品约定和生命周期归属。本决策只公开已经实现的 one-shot 后台路径。
后果
agent 可以在 Codex 或 Claude Code 处理独立 one-shot 任务时继续推进其他工作,随后通过其他后台 producer 共用的 Job 控制工具收集最终回答或取消运行。若失败结果提供了安全的提供方诊断,前台与一次性后台消费方会呈现同一内容。
每次产品委托仍会启动一个全新的原生进程或 query,把最终 assistant 文本作为唯一 assistant 载荷,并以提供方资源释放和整棵进程树退出结束。失败结果可以另行携带安全诊断。后台调用还会额外公开通用 Job id、状态、完成通知以及收集或取消结果。后台 Job 仅存在于当前进程且由父级拥有:它不会在父级资源释放后继续存活,不会公开产品中间活动,也不会让产品对话变得可恢复。只有 Profile 显式安装产品集成时,生产安装才承担对应成本;公开后台参数的任何组装还必须让通用 Job 提供方与控制工具保持可用。