diff --git a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.i18n.yaml index 44a8fbf89f..a5bde488e1 100644 --- a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.i18n.yaml @@ -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/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md -2026-08-10-fork-children-stay-one-shot.md: 0edf6ca9347dcf57313365e570daed22589f69fd -2026-08-10-fork-children-stay-one-shot.zh.md: c2e3504bd21ec6dd6b3feba4ed8abdaec3ee45a4 +2026-08-10-fork-children-stay-one-shot.md: 27f5a4101f2ffac494d923cc82a4a5759e6db30f +2026-08-10-fork-children-stay-one-shot.zh.md: 6f0b632744c9e5530c09fb31ff6e9cf6f18f53aa diff --git a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md index 0edf6ca934..27f5a4101f 100644 --- a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md +++ b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md @@ -14,7 +14,7 @@ The earlier shipped composition avoided this mismatch by keeping forked children The model-facing `send_message` tool is registered globally for every Agent in a composition. A continuable forked child therefore receives the same tool name, description, schema, and ordering as its parent. Its initial task is appended after the inherited Session seed, and the task includes the direct parent id plus guidance to return results with `send_message({ agent_id, message })` when that tool is visible to the child. -The base and headless compositions retain one-shot fork as their conservative lifecycle policy. The `cordis`, `standard`, and `ptc` CLI presets may bind fork to the continuable lifecycle because that binding no longer inserts child-only request-head fields. `ForkInProcessProvider.prepareContinuable()` and `ctx.subagents.startContinuable()` remain the implementation seam for those presets. +The base bundle and the `cordis`, `standard`, and `ptc` CLI presets bind fork to the continuable lifecycle. Base-backed profiles, including headless, inherit that default. `ForkInProcessProvider.prepareContinuable()` and `ctx.subagents.startContinuable()` preserve the same request-prefix behavior across these compositions. Byte-identical prefix reuse is qualified by explicit deployment choices. A fork delegation that applies a child persona or `toolFilter` may still change the request head. In particular, filtering out `send_message` removes both the schema and the return guidance from the child; the runtime does not bypass an explicit allow-list. @@ -32,7 +32,7 @@ Byte-identical prefix reuse is qualified by explicit deployment choices. A fork - Parent and continuable-fork child expose byte-identical ordered tool schemas when the delegation does not request a persona or tool filter. - The inherited Session seed precedes the child's initial task and return guidance. -- The base and headless profiles keep one-shot fork, while selected CLI presets exercise continuable fork without a child-only request-head addition. +- The base bundle and full CLI presets default to continuable fork without a child-only request-head addition; explicit foreground calls still use the one-shot path. - A child sends zero or more messages to its direct parent explicitly; its final answer is not implicitly copied. The manager-owned settlement notice remains unconditional and separate. - Keyless snapshots and package tests pin schema equality, inherited-history ordering, parent-id guidance, and child-to-parent delivery through the same `send_message` operation used in the other direction. diff --git a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md index c2e3504bd2..6f0b632744 100644 --- a/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md @@ -14,7 +14,7 @@ fork 与 spawn 的差异在于:fork 会用 parent 已完成轮次的前缀作 面向模型的 `send_message` 工具在组合中的每个 Agent 上全局注册。因此,可继续 fork child 获得与 parent 相同的工具名称、描述、schema 和顺序。其初始任务追加在继承的 Session 种子之后;当 child 可以看到该工具时,任务还会包含直接 parent id,以及使用 `send_message({ agent_id, message })` 返回结果的指引。 -base 与 headless 组合保留 one-shot fork 作为其保守生命周期策略。`cordis`、`standard` 和 `ptc` CLI preset 可以把 fork 绑定为可继续生命周期,因为该绑定不再插入 child-only 请求头字段。`ForkInProcessProvider.prepareContinuable()` 与 `ctx.subagents.startContinuable()` 仍是这些 preset 使用的实现 seam。 +base 组合包与 `cordis`、`standard` 和 `ptc` CLI preset 将 fork 绑定为可继续生命周期。基于 base 的 profile(包括 headless)继承这一默认值。`ForkInProcessProvider.prepareContinuable()` 与 `ctx.subagents.startContinuable()` 在这些组合中保持相同的请求前缀行为。 逐字节相同的前缀复用受显式部署选择约束。配置 child persona 或 `toolFilter` 的 fork 委派仍可能改变请求头。尤其是过滤掉 `send_message` 时,child 会同时失去该 schema 与返回指引;运行时不会绕过显式 allow-list。 @@ -32,7 +32,7 @@ base 与 headless 组合保留 one-shot fork 作为其保守生命周期策略 - 未请求 persona 或工具过滤时,parent 与可继续 fork child 暴露逐字节相同且顺序一致的工具 schema。 - 继承的 Session 种子位于 child 初始任务及其返回指引之前。 -- base 与 headless profile 保持 one-shot fork;选定的 CLI preset 会在没有 child-only 请求头增量的前提下使用可继续 fork。 +- base 组合包与完整 CLI preset 默认使用可继续 fork,不增加 child-only 请求头字段;显式前台调用仍使用 one-shot 路径。 - child 显式向直接 parent 发送零条或多条消息;最终回答不会被隐式复制。管理器负责的结算通知仍然无条件执行,并且与 Agent 消息分离。 - keyless snapshot 与包测试固定 schema 相等性、继承历史顺序、parent-id 指引,以及通过同一个 `send_message` 操作完成的 child-to-parent 投递。 diff --git a/packages/bundle/base/README.i18n.yaml b/packages/bundle/base/README.i18n.yaml index 292f948500..d8b1ef6cc4 100644 --- a/packages/bundle/base/README.i18n.yaml +++ b/packages/bundle/base/README.i18n.yaml @@ -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/bundle/base/README.md -README.md: f9cc3e4d03a0d71d1f598d97633c0f89f7700b42 -README.zh.md: 2e98bb710502b62ad87f04ae768833487b4b5787 +README.md: d6aee588dee09600c27d602e9ad25c4fde8d370a +README.zh.md: 7bce05e7b79518b3f7c951f1ac29141ac24e2d3a diff --git a/packages/bundle/base/README.md b/packages/bundle/base/README.md index f9cc3e4d03..d6aee588de 100644 --- a/packages/bundle/base/README.md +++ b/packages/bundle/base/README.md @@ -49,6 +49,8 @@ Run `dsh --profile my-profile "your task"` and you get a working agent with mode Out of the box, every profile built on this core provides: a DeepSeek model connection (the provider and model are configurable, and you can enable extra providers from your settings), the full tool set — file editing, shell commands, web search, public HTTP(S) fetch, subagents, task and goal tracking — durable sessions that survive restarts, and the default permission policy that confines file writes to your workspace and asks before risky actions. Web fetch runs without per-call approval; its provider rejects non-public destinations. Feedback stays in the Session log. [OTel session upload](../../session/session-telemetry-otel/README.md) defaults to `FEEDBACK_ONLY` for all users, including `deepseek-official`: new text feedback, message ratings, edits, and withdrawals release the complete canonical prefix through that event, including context. Later records wait for the next explicit feedback; sending an authorized batch needs no further interaction or model call. `DISABLED` prevents OTel capture. The default-on [DeepSeek session-log contributor](../../session/session-log-deepseek/README.md) remains a separate request path. +Both `subagent` and `subagent_fork` default to continuable background children. They return a child id for later `send_message` calls; explicit `run_in_background: false` still waits for a one-shot result. [Delegation-tool behavior](../../subagent/tool-subagent/README.md) describes both paths. + Default file editing uses `read`, `write`, and `edit`. The `str_replace_editor` tool remains available as an explicit opt-in. To add it to a base-backed profile, put this entry in the profile, home, or invocation patch: ```yaml diff --git a/packages/bundle/base/README.zh.md b/packages/bundle/base/README.zh.md index 2e98bb7105..7bce05e7b7 100644 --- a/packages/bundle/base/README.zh.md +++ b/packages/bundle/base/README.zh.md @@ -49,6 +49,8 @@ kind: "package-bundle" 开箱即用,基于本核心构建的每个 profile 都提供:DeepSeek 模型连接(提供方与模型可配置,你还可以在设置中启用额外提供方)、完整工具集——文件编辑、shell 命令、web 搜索、公开 HTTP(S) 抓取、subagent、任务与目标跟踪——可跨重启存活的持久会话,以及默认权限策略:把文件写入限制在工作区内,危险操作前征询许可。Web 抓取无需逐次审批,其提供方会拒绝非公开目的地址。反馈保存在会话日志中。[OTel 会话上传](../../session/session-telemetry-otel/README.zh.md)对所有用户默认使用 `FEEDBACK_ONLY`,包括 `deepseek-official`:新的文本反馈、消息评分、编辑与撤回会释放截至该事件的完整规范会话日志前缀,包含上下文。后续记录等待下一次显式反馈;发送已授权批次无需进一步交互或模型调用。`DISABLED` 阻止 OTel 捕获。默认开启的 [DeepSeek 会话日志贡献器](../../session/session-log-deepseek/README.zh.md)仍是独立的请求路径。 +`subagent` 与 `subagent_fork` 都默认创建可继续对话的后台子 agent,并返回 child id,供后续 `send_message` 调用使用;显式传入 `run_in_background: false` 仍会等待一次性结果。[委派工具行为](../../subagent/tool-subagent/README.zh.md)说明了这两条路径。 + 默认文件编辑使用 `read`、`write` 和 `edit`。`str_replace_editor` 工具仍可显式启用。要将它加入基于 base 的 profile,请在 profile、home 或逐次调用 patch 中添加以下条目: ```yaml diff --git a/packages/bundle/base/cordis.patch.yml b/packages/bundle/base/cordis.patch.yml index 1aaf9da6b4..860dd2d912 100644 --- a/packages/bundle/base/cordis.patch.yml +++ b/packages/bundle/base/cordis.patch.yml @@ -361,9 +361,8 @@ backgroundMode: continuable # Fork omits model selection so provider/model stay equal to the parent and - # the inherited history remains eligible for KV Cache reuse. This base row - # stays one-shot; preset layers may select continuable mode without adding a - # child-only system-prompt section or tool schema ahead of that history. + # the inherited history remains eligible for KV Cache reuse. Parent and child + # share the messaging tools; return guidance follows the inherited history. # See .agents/notes/implemented/feature/2026-08-18-model-selected-subagent-routes.md # and .agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md. - id: tool-subagent-fork @@ -371,7 +370,7 @@ config: provider: fork toolName: subagent_fork - backgroundMode: one-shot + backgroundMode: continuable - id: ptc-runtime name: '@deepseek-ai/dsh-ptc-runtime-node' diff --git a/packages/subagent/subagent-fork-in-process/README.i18n.yaml b/packages/subagent/subagent-fork-in-process/README.i18n.yaml index ab0bb07299..692666ac68 100644 --- a/packages/subagent/subagent-fork-in-process/README.i18n.yaml +++ b/packages/subagent/subagent-fork-in-process/README.i18n.yaml @@ -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-fork-in-process/README.md -README.md: 0c8ff5372717b26a4e5ee556655094a74c9d6dda -README.zh.md: c1098825dc0d27f854e7c4d283670d84a507999d +README.md: 6796e1e79c45fa9c282219c2e9c2e0eeb9b38d8f +README.zh.md: 0359ee2083bd2d79a99c09776401cc169f311151 diff --git a/packages/subagent/subagent-fork-in-process/README.md b/packages/subagent/subagent-fork-in-process/README.md index 0c8ff53727..6796e1e79c 100644 --- a/packages/subagent/subagent-fork-in-process/README.md +++ b/packages/subagent/subagent-fork-in-process/README.md @@ -84,7 +84,7 @@ On `start`, the prefix is sliced from the parent's event log up to and including ### Lifecycle binding -The base bundle and ACP/headless examples bind this provider to `backgroundMode: one-shot`, while the CLI presets select `continuable`. Both preserve the inherited request prefix: parent and child receive the same messaging tool definition and ordering, and the continuable child's parent id and return guidance live in its initial user task after inherited history ([cache-preserving fork Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md)). +The base bundle and full CLI presets bind this provider to `backgroundMode: continuable`; explicit foreground calls and one-shot compositions remain supported. Both preserve the inherited request prefix: parent and child receive the same messaging tool definition and ordering, and the continuable child's parent id and return guidance live in its initial user task after inherited history ([cache-preserving fork Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md)). @@ -93,14 +93,14 @@ The base bundle and ACP/headless examples bind this provider to `backgroundMode: ## Further Exploration -Read these pages when the package-level contract is not enough; they move from the shared subagent model to the sibling backends and the design evidence for the one-shot binding. +Read these pages when the package-level contract is not enough; they move from the shared subagent model to the sibling backends and the design evidence for preserving the inherited request prefix. - [Subagent subsystem](../../../docs/subsystems/subagent.md) — start requests, results, provider contract, and in-process depth and seed. - [dsh-subagent-in-process-driver](../subagent-in-process-driver/README.md) — the shared run driver this backend calls. - [dsh-subagent-spawn-in-process](../subagent-spawn-in-process/README.md) — the fresh-child sibling backend. - [dsh-tool-subagent](../tool-subagent/README.md) — the model-facing delegation tool that reaches this provider. - [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-subagent-fork-in-process) — every accepted config field and its source declaration. -- [Fork children stay one-shot](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md) — why shipped compositions bind fork to one-shot. +- [Forked children preserve the parent request prefix](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md) — why continuable fork preserves the inherited request prefix. ----- @@ -143,7 +143,7 @@ Append-only; newly visible content follows the reusable request prefix and does These limits define when the backend is the wrong choice; they are current package constraints. - **The seed is a one-time snapshot** — the child sees the parent's completed turns as of the fork and nothing the parent logs afterwards; there is no live context sharing. -- **Fork lifecycle policy differs by composition** — the base bundle and ACP/headless examples use one-shot fork, while the CLI presets use continuable fork. Both keep the inherited prefix eligible for reuse because parent and child messaging definitions match byte for byte; explicit persona, tool filtering, generated-SDK, or route changes can still break equality. Rationale: the [cache-preserving fork Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md). +- **Prefix reuse depends on matching request inputs** — parent and child messaging definitions match byte for byte in both lifecycle modes; explicit persona, tool filtering, generated-SDK, or route changes can still break equality. Rationale: the [cache-preserving fork Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.md). - **Shipped fork tools do not expose child LLM route selection** — they inherit the parent's provider and model so the copied history remains eligible for KV Cache reuse. Route selection stays disabled until a change can preserve reuse or expose a bounded recomputation cost; the [model-selected route Agent Note](../../../.agents/notes/implemented/feature/2026-08-18-model-selected-subagent-routes.md) owns that restriction. diff --git a/packages/subagent/subagent-fork-in-process/README.zh.md b/packages/subagent/subagent-fork-in-process/README.zh.md index c1098825dc..0359ee2083 100644 --- a/packages/subagent/subagent-fork-in-process/README.zh.md +++ b/packages/subagent/subagent-fork-in-process/README.zh.md @@ -84,7 +84,7 @@ kind: "package-reference" ### 生命周期绑定 -base 组合包与 ACP(Agent Client Protocol)/headless 示例在委派工具上把本提供方绑定为 `backgroundMode: one-shot`,CLI(命令行界面)预设则选择 `continuable`。两者都保留继承的请求前缀:父级与子级获得定义和顺序相同的消息工具,可继续子级的父级 ID 与返回指导位于继承历史之后的初始用户任务中(见[保持 fork 缓存的 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md))。 +base 组合包与完整 CLI(命令行界面)预设在委派工具上把本提供方绑定为 `backgroundMode: continuable`;仍支持显式前台调用与一次性组合。两者都保留继承的请求前缀:父级与子级获得定义和顺序相同的消息工具,可继续子级的父级 ID 与返回指导位于继承历史之后的初始用户任务中(见[保持 fork 缓存的 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md))。 @@ -93,14 +93,14 @@ base 组合包与 ACP(Agent Client Protocol)/headless 示例在委派工具 ## 进一步探索 -当包级约定不够用时阅读以下页面;它们从共享 subagent 模型进入兄弟后端,以及一次性绑定的设计证据。 +当包级约定不够用时阅读以下页面;它们从共享 subagent 模型进入兄弟后端,以及保留继承请求前缀的设计证据。 - [Subagent 子系统](../../../docs/subsystems/subagent.zh.md)——启动请求、结果、提供方约定与进程内深度和初始内容。 - [dsh-subagent-in-process-driver](../subagent-in-process-driver/README.zh.md)——本后端调用的共享运行驱动器。 - [dsh-subagent-spawn-in-process](../subagent-spawn-in-process/README.zh.md)——全新子级的兄弟后端。 - [dsh-tool-subagent](../tool-subagent/README.zh.md)——指向该提供方的面向模型委派工具。 - [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-subagent-fork-in-process)——每个受支持配置字段及其源声明。 -- [fork 保持 one-shot](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md)——随附组合为何把 fork 绑定为 one-shot。 +- [Fork child 保留 parent 请求前缀](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md)——可继续 fork 为何保留继承的请求前缀。 ----- @@ -143,7 +143,7 @@ fork 会把保留的已完成历史复制到子 agent 的请求中,子 agent 这些限制说明何时选择该后端是错误的;它们是当前包约束。 - **初始内容是一次性快照**——子 agent 只能看到 fork 时父级已完成的轮次,看不到父级此后记录的任何内容;不会实时共享上下文。 -- **fork 生命周期策略因组合而异**——base 组合包与 ACP/headless 示例使用一次性 fork,CLI 预设使用可继续 fork。两者都因父级与子级的消息定义逐字节相同而让继承前缀保持可复用;显式 persona、工具过滤、生成 SDK 或路由变化仍可破坏相等性。理由见[保持 fork 缓存的 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md)。 +- **前缀复用取决于请求输入是否匹配**——两种生命周期模式下,父级与子级的消息定义都逐字节相同;显式 persona、工具过滤、生成 SDK 或路由变化仍可破坏相等性。理由见[保持 fork 缓存的 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-fork-children-stay-one-shot.zh.md)。 - **随附 fork 工具不公开子级 LLM(大语言模型)路由选择**——它们继承父级提供方与模型,使复制的历史仍有资格复用 KV Cache。在某项改动能保留复用或公开有界重算成本前,路由选择保持禁用;[模型选择路由 Agent Note](../../../.agents/notes/implemented/feature/2026-08-18-model-selected-subagent-routes.zh.md)说明这项限制。 diff --git a/snapshots/sdk/text-turn/system-prompt.expected.md b/snapshots/sdk/text-turn/system-prompt.expected.md index b1c3c8348f..30d66481ec 100644 --- a/snapshots/sdk/text-turn/system-prompt.expected.md +++ b/snapshots/sdk/text-turn/system-prompt.expected.md @@ -24,4 +24,6 @@ Use goal tools for one long-running completion objective in the current session. Use the workflow tool ONLY when the user explicitly asks for a workflow or for large multi-agent orchestration: you write a JavaScript script (the tool description documents the exact format) that fans work out across many subagents with phases and structured results. For one or two delegations, prefer plain subagent calls. +Use subagent_fork in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set `run_in_background: false` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message. + Your working directory is {{cwd}}. diff --git a/snapshots/sdk/text-turn/tool-schemas.expected.json b/snapshots/sdk/text-turn/tool-schemas.expected.json index c5b2aedeba..c68f6a52b1 100644 --- a/snapshots/sdk/text-turn/tool-schemas.expected.json +++ b/snapshots/sdk/text-turn/tool-schemas.expected.json @@ -360,7 +360,7 @@ }, { "name": "subagent_fork", - "description": "Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn). Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive its result, not its intermediate steps. This call waits for the result by default. Set `run_in_background: true` to return a job id; collect with `job_output` and stop with `job_kill`.", + "description": "Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn). Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive its result, not its intermediate steps. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` steers the child's nearest step while it is running and starts a turn while it is idle. Set `run_in_background: false` only when your next action depends on receiving the result.", "parameters": { "type": "object", "properties": { @@ -374,7 +374,7 @@ }, "run_in_background": { "type": "boolean", - "description": "Whether to run as a background job and return its id. Defaults to false; collect with job_output or stop with job_kill." + "description": "Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it." } }, "required": [