fix(subagent): respect optional runtime context suppression

This commit is contained in:
ZiyaZhang committed 2026-10-12 03:04:08 -07:00
1 parent 2998eb0311
commit 77483f61d9
14 files changed
+69 -18

No files matched your search

@@ -18,8 +18,8 @@
en: a9fe46283ea28722
zh: 7b7d1be7c070b893
/agent-note-configure-subagent-persona-tool-visibility-and-depth/decision/depth-is-an-absolute-tree-cap:
en: 432aeeeec0721802
zh: fbdfea5be3bc83ed
en: 28816df0fde0ef56
zh: bf906e6c286645e0
/agent-note-configure-subagent-persona-tool-visibility-and-depth/decision/capability-gating-keeps-providers-honest:
en: 5334afafefdb0f59
zh: 7e96c9a08bbc3d1a
@@ -55,7 +55,7 @@ The effective parent depth is the greater of durable `SessionHeader.delegationDe
Every public entry validates the domain rather than relying on one model-facing configuration path. Negative values, fractions, negative zero, non-finite values, unsafe integers, malformed stored parent depth, and derived overflow all reject. A direct `SubagentStartRequest` may omit the cap to leave depth unbounded; `dsh-tool-subagent` instead reads the live Host depth setting (initially `1`), accepts a numeric override, and uses explicit `'provider-managed'` to omit the cap for an out-of-process provider whose deployment owns its recursion budget. The [base profile](../../../../packages/bundle/base/cordis.patch.yml) uses the Host setting. A numeric tool cap fails at provider mount when the provider lacks `depthLimit`.
A deployment can combine depth and filtering, but the numeric cap does not synthesize a filter. The delegation tool stays visible at the cap because authorization may depend on runtime state; every attempted start checks the calling agent's current durable and runtime depth, and a rejected start returns an errored tool result without publishing a child. A deployment may separately deny delegation tools in children when its visibility policy is static. Neither choice changes the provider's conversation-history behavior. At the cap, the tool contributes a required runtime-context notice telling the model to work directly. Reading the live cap and durable depth at request time keeps resumed and reconfigured agents informed without changing their system prompt or tool schemas; unchanged context is not repeatedly appended.
A deployment can combine depth and filtering, but the numeric cap does not synthesize a filter. The delegation tool stays visible at the cap because authorization may depend on runtime state; every attempted start checks the calling agent's current durable and runtime depth, and a rejected start returns an errored tool result without publishing a child. A deployment may separately deny delegation tools in children when its visibility policy is static. Neither choice changes the provider's conversation-history behavior. At the cap, the tool contributes an optional runtime-context notice telling the model to work directly. `includeRuntimeContext: false` suppresses this advisory notice; the runtime depth guard remains active. When enabled, the notice reads the live cap and durable depth at request time to keep resumed and reconfigured agents informed without changing their system prompt or tool schemas; unchanged context is not repeatedly appended.
### Capability gating keeps providers honest
@@ -57,7 +57,7 @@ subagent 启动有三个独立的组合控制:`persona`、`toolFilter` 和 `ma
每个公开入口都自行验证值域,而非依赖单一的面向模型配置路径。负值、小数、负零、非有限值、不安全整数、格式错误的存储父级深度以及推导溢出均被拒绝。直接的 `SubagentStartRequest` 可以省略上限,让此机制不约束深度;`dsh-tool-subagent` 则读取实时 Host 深度设置(初始值为 `1`)、接受数值覆盖,并使用显式的 `'provider-managed'` 来省略由进程外提供方部署拥有递归预算时的上限。[base profile](../../../../packages/bundle/base/cordis.patch.yml)采用 Host 设置。提供方缺少 `depthLimit` 时,数值工具上限会在提供方挂载阶段失败。
部署可以组合深度与过滤,但数值上限不会合成过滤器。委派工具在上限处仍然可见,因为授权可能依赖运行时状态;每次尝试启动都会检查调用方 agent 当前的持久与运行时深度,被拒绝的启动返回错误工具结果,且不发布子 agent。可见性策略固定的部署可以另外在子 agent 中 deny 委派工具。两种选择都不改变提供方的对话历史行为。达到上限时,工具贡献一条必需的运行时上下文提示,让模型直接完成工作。每次请求读取实时上限与持久深度,使恢复会话或调整配置后的 agent 获知当前限制,同时不改变其系统提示词或工具 schema;未变化的上下文不会重复追加。
部署可以组合深度与过滤,但数值上限不会合成过滤器。委派工具在上限处仍然可见,因为授权可能依赖运行时状态;每次尝试启动都会检查调用方 agent 当前的持久与运行时深度,被拒绝的启动返回错误工具结果,且不发布子 agent。可见性策略固定的部署可以另外在子 agent 中 deny 委派工具。两种选择都不改变提供方的对话历史行为。达到上限时,工具贡献一条可选的运行时上下文提示,让模型直接完成工作。`includeRuntimeContext: false` 会抑制这条建议性提示;运行时的深度拦截仍然生效。提示启用时,每次请求读取实时上限与持久深度,使恢复会话或调整配置后的 agent 获知当前限制,同时不改变其系统提示词或工具 schema;未变化的上下文不会重复追加。
### 能力门控保持提供方诚实
+2 -2
View File
@@ -48,8 +48,8 @@
en: 2b53c1d07ef68f24
zh: 33a3c17ab56adf57
/deepseek-ai-dsh-persona/model-experience/the-persona-section/what-the-model-sees:
en: 164029cbcb3f09e1
zh: 884aa8e9c7820caa
en: 5c276dd49a9c5053
zh: be5a329928edde7a
/deepseek-ai-dsh-persona/model-experience/the-persona-section/token-effect:
en: 346e80f3b7a8c7fd
zh: da0e19a955d56c51
+1 -1
View File
@@ -96,7 +96,7 @@ Read these pages when the package-level contract is not enough; they move from t
#### What the model sees
The `deployment:persona-prefix` section at order `0` carries this row's `prefix`; `deployment:persona-suffix` at order `10200` carries its `suffix`, after first-party guidance. Both replace their deployment defaults and resolve prompt variables. In complete mode, the model sees only the rendered prefix section as its system prompt. Runtime context remains enabled by default. With `includeRuntimeContext: false`, the model still receives required context, such as the current working directory and applicable delegation-depth limits; optional context is omitted.
The `deployment:persona-prefix` section at order `0` carries this row's `prefix`; `deployment:persona-suffix` at order `10200` carries its `suffix`, after first-party guidance. Both replace their deployment defaults and resolve prompt variables. In complete mode, the model sees only the rendered prefix section as its system prompt. Runtime context remains enabled by default. With `includeRuntimeContext: false`, the model still receives required context, such as the current working directory; optional context is omitted.
#### Token effect
+1 -1
View File
@@ -96,7 +96,7 @@ kind: "package-reference"
#### 模型看到什么
位于 order `0` 的 `deployment:persona-prefix` 段落携带本行的 `prefix`;位于 order `10200` 的 `deployment:persona-suffix` 在第一方指导之后携带其 `suffix`。两者分别替换对应的部署默认值,并解析提示词变量。在完整模式下,模型只会看到渲染后的前缀段落作为系统提示词。运行时上下文默认保持启用。设置 `includeRuntimeContext: false` 后,模型仍会收到必需上下文,例如当前工作目录和适用的委派深度限制;可选上下文则会省略。
位于 order `0` 的 `deployment:persona-prefix` 段落携带本行的 `prefix`;位于 order `10200` 的 `deployment:persona-suffix` 在第一方指导之后携带其 `suffix`。两者分别替换对应的部署默认值,并解析提示词变量。在完整模式下,模型只会看到渲染后的前缀段落作为系统提示词。运行时上下文默认保持启用。设置 `includeRuntimeContext: false` 后,模型仍会收到必需上下文,例如当前工作目录;可选上下文则会省略。
#### Token 影响
@@ -93,14 +93,14 @@
en: 1e58e87365d88e45
zh: 7648aa3b3865057f
/deepseek-ai-dsh-tool-subagent/model-experience/runtime-depth-context/what-the-model-sees:
en: 5d8cacfcc690735e
zh: ccb5657677f4f24b
en: fde048c427103086
zh: 6614730cc00f02e4
/deepseek-ai-dsh-tool-subagent/model-experience/runtime-depth-context/what-the-model-sees/depth-limit-notice:
en: 0ae8dbcee66d0cd6
zh: 5a69283739ae59e0
/deepseek-ai-dsh-tool-subagent/model-experience/runtime-depth-context/token-effect:
en: 85780200aeda7d71
zh: ded2dc8ff9b5a677
en: dae9cd59b9649b5a
zh: 8bb35289ebaeaf7b
/deepseek-ai-dsh-tool-subagent/model-experience/runtime-depth-context/kv-cache-effect:
en: 9e6e8bc993992908
zh: 4de1e9d85ab3bfca
+2 -2
View File
@@ -176,7 +176,7 @@ Prefix-stable while the visible tool names are unchanged; adding or removing a v
#### What the model sees
When the calling agent reaches or exceeds a visible tool's effective numeric depth cap, a required runtime-context snapshot tells it to do the work directly. The cap is resolved again at each request, including after settings changes or session resume. Hidden tools and `provider-managed` limits contribute no depth text. For a child at depth one with a cap of one:
When the calling agent reaches or exceeds a visible tool's effective numeric depth cap, an optional runtime-context snapshot tells it to do the work directly. The cap is resolved again at each request, including after settings changes or session resume. Hidden tools and `provider-managed` limits contribute no depth text. For a child at depth one with a cap of one:
##### Depth-limit notice
@@ -186,7 +186,7 @@ Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do no
#### Token effect
One short contribution per capped tool joins the user-role runtime-context snapshot. Unchanged snapshots are not appended again; agents below the cap receive no additional text. Optional-context suppression retains this operational limit notice.
One short contribution per capped tool joins the user-role runtime-context snapshot. Unchanged snapshots are not appended again; agents below the cap receive no additional text. `includeRuntimeContext: false` suppresses this notice without changing runtime depth enforcement.
#### KV Cache effect
+2 -2
View File
@@ -176,7 +176,7 @@ Start independent delegations with `subagent` or `subagent_fork` together in one
#### 模型看到什么
当调用方 agent 达到或超过某个可见工具实际生效的数值深度上限时,必需的运行时上下文快照会提示它直接完成工作。每次请求都会重新解析上限,包括 settings 变更或会话恢复之后。隐藏的工具和 `provider-managed` 上限不贡献深度文本。深度和上限都为一时,子 agent 看到:
当调用方 agent 达到或超过某个可见工具实际生效的数值深度上限时,可选的运行时上下文快照会提示它直接完成工作。每次请求都会重新解析上限,包括 settings 变更或会话恢复之后。隐藏的工具和 `provider-managed` 上限不贡献深度文本。深度和上限都为一时,子 agent 看到:
##### 深度上限提示
@@ -186,7 +186,7 @@ Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do no
#### Token 影响
每个达到上限的工具向用户角色的运行时上下文快照贡献一小段文本。未变化的快照不会重复追加;未达到上限的 agent 不收到额外文本。抑制可选上下文时,仍保留这条操作限制提示。
每个达到上限的工具向用户角色的运行时上下文快照贡献一小段文本。未变化的快照不会重复追加;未达到上限的 agent 不收到额外文本。`includeRuntimeContext: false` 会抑制这条提示,但不改变运行时对深度上限的强制执行。
#### KV Cache 影响
@@ -387,7 +387,6 @@ export function apply(ctx: Context, config: Config, session?: Session): void {
runtimeCtx.systemPrompt.context({
name: `tool:${toolName}:depth`,
order: runtimeCtx.systemPrompt.getContextOrder('SUBAGENT_DELEGATION'),
required: true,
text: (context) => {
if (context.agent === undefined || mounted === undefined
|| runtimeCtx.tools.get(toolName, context.scope) !== mounted.definition) return ''
@@ -38,8 +38,14 @@ describe('delegation depth context', () => {
+ ' Do not call `subagent` at this depth; carry out the work directly.',
] : [])
const restore = agent.ctx.systemPrompt.suppressRuntimeContext()
try {
expect(await depthContext(ctx, agent)).toEqual([])
expect(ctx.systemPrompt.refreshContext(assembly, assembleContextFor(agent))
.contexts.some(part => part.name.endsWith(':depth'))).toBe(false)
} finally {
restore()
}
expect(await depthContext(ctx, agent)).toHaveLength(remaining === 0 ? 1 : 0)
restore()
})
it('uses the runtime depth when it is deeper than the saved header', async () => {
@@ -0,0 +1,17 @@
# Suppress optional hints at the root depth cap while retaining the tool and
# the provider's runtime enforcement.
- id: system-prompt
name: '@deepseek-ai/dsh-system-prompt'
config:
includeRuntimeContext: false
personaPrefix: |
You are a coding assistant powered by the {{model}} model. Your bash tool runs under a file sandbox — a `[sandbox: file access denied …]` result is policy, not a command bug.
Verify your work by running the code or tests. Keep answers brief and factual.
- id: tool-subagent
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: spawn
toolName: subagent
maxDepth: 0
@@ -0,0 +1,22 @@
{"type":"session","version":4,"id":"{{session:1}}","createdAt":1783352044766,"cwd":"{{cwd}}","isSeeded":false,"delegationDepth":0}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"sandbox/mode","data":{"mode":"danger-full-access"}}
{"type":"approval/policy","data":{"policy":"never"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Attempt one subagent call beyond the configured cap, then report the rejection."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{message:2}}"}},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Attempt one subagent call beyond the configured cap, then report the rejection."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."}]},"role":"user","id":"{{message:3}}"},"surfaceOp":"append"}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
{"type":"session/title","data":{"title":"Attempt one subagent call beyond","messageSeqs":[8],"source":{"kind":"fallback"}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"call_depth_one_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:4}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":1789625678968,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1789625678968,"index":0,"dt":[],"id":"call_depth_one_rejected","name":"subagent","args":["{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"]},{"type":"chunk","time":1789625678968,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"call_depth_one_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}}},{"type":"chunk","time":1789625678968,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":1789625678968,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_depth_one_rejected","name":"subagent","arguments":"{\"description\":\"Exceed depth cap\",\"prompt\":\"This child must never start.\"}"}}
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_depth_one_rejected"},"toolCallId":"call_depth_one_rejected","content":[{"type":"text","text":"Error: subagent depth 1 exceeds maxDepth 0"}],"isError":true,"id":"{{message:5}}"}},"sourceEventSeqs":[14],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"step/start","data":{"turn":1,"step":2}}
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"DEPTH_REJECTED"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:6}}"},"usage":{"inputTokens":10,"outputTokens":2},"stream":[{"type":"chunk","time":1789625678991,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1789625678991,"index":0,"dt":[],"texts":["DEPTH_REJECTED"]},{"type":"chunk","time":1789625678991,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"DEPTH_REJECTED"}}},{"type":"chunk","time":1789625678991,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":2}}},{"type":"chunk","time":1789625678991,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":2}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -0,0 +1,7 @@
version: 1
scenario: subagent-depth-context-disabled
profile: headless
composition: default
recording: authored
header:
class: default