docs(subagent): clarify interrupt edge cases

This commit is contained in:
Hypatia May
2026-08-07 10:27:43 +08:00
committed by Tianyi Cui
parent 57e9e6977c
commit 336c84baf0
15 changed files with 43 additions and 30 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 .agents/notes/implemented/feature/2026-08-06-continuable-subagent-interrupt.md
2026-08-06-continuable-subagent-interrupt.md: 729f1eb8259aa28aa771ed71872ebce9cadd4ed8
2026-08-06-continuable-subagent-interrupt.zh.md: 15fe34d8b5e1d67623aabfe08710f341739e92e1
2026-08-06-continuable-subagent-interrupt.md: 7bbc6ecf6736e9e34924113be984a3bf7436b9b9
2026-08-06-continuable-subagent-interrupt.zh.md: 22a71bf4cd3d9b949ae8cf458a3c83b65739d396

View File

@@ -10,7 +10,7 @@ A running continuable subagent could not be stopped without destroying it. The c
## Decision
`ctx.subagents.interrupt(targetSessionId, authority)` stops only the live target's current turn. The manager primitive authorizes synchronously, calls the existing `Agent.cancel(cause, { keepInbox: true })`, and returns `void` — fire-and-return: the cancel signal is guaranteed issued, target quiescence is not awaited. Nothing else changes: no Activation disposal, no handle release, no descendant cascade, no inbox clearing, and no `AgentLoop` or `CancelOptions` change. Because `keepInbox` parks the pending queue at idle, an interrupt never auto-starts the next queued follow-up; only a later explicit waking send resumes the preserved FIFO order.
`ctx.subagents.interrupt(targetSessionId, authority)` stops only the live target's current turn. The manager primitive authorizes synchronously, calls the existing `Agent.cancel(cause, { keepInbox: true })`, and returns `void` — fire-and-return: the cancel signal is guaranteed issued, target quiescence is not awaited. Nothing else changes: no Activation disposal, no handle release, no descendant cascade, no inbox clearing, and no `AgentLoop` or `CancelOptions` change. Because `keepInbox` parks the unclaimed pending queue at idle, an interrupt never auto-starts the next queued follow-up; work already claimed into the interrupted turn belongs to that turn and is not requeued. Once the interrupted driver is idle, an explicit waking send resumes the preserved FIFO order.
Authority is a closed two-variant union, deliberately wider than delivery authority because stopping a turn is idempotent and delivers no content:
@@ -35,7 +35,11 @@ The Host RPC `subagent.interrupt` takes the continuable `SubagentAddress` and re
## Consequences
A human or ancestor can now stop a runaway continuable turn without losing the child, its queued work, or its running descendants; the cost is a deliberately weak postcondition (`accepted` means "signal issued", so a target may remain visibly `running` until it observes the signal) that clients must render honestly. The parked-queue rule means an interrupted child sits idle with retained work until someone sends a waking message — an intentional human-in-the-loop pause, not a scheduler defect. The Web Stop action and the model-facing `interrupt_agent` tool build on this primitive in the stacked follow-up PRs for issue #1535.
A human or ancestor can stop a runaway continuable turn without losing the child, its unclaimed queued work, or its running descendants; the cost is a deliberately weak postcondition (`accepted` means "signal issued", so a target may remain visibly `running` until it observes the signal) that clients must render honestly. The parked-queue rule means an interrupted child sits idle with retained work until a waking message arrives after the driver is idle — an intentional human-in-the-loop pause, not a scheduler defect. A waking send accepted during abort convergence currently remains queued without latching wake; Issue #1838 tracks the shared agent-loop correction.
The address-only RPC exposes one bit of live residency: an absent target is accepted while a live target under a mismatched parent returns `subagent-unauthorized`. The single-user local Host trust model accepts that observability; a future multi-principal Host must revisit both authority and response indistinguishability.
The Web Stop action and the model-facing `interrupt_agent` tool build on this primitive in the stacked follow-up PRs for issue #1535.
## Testing

View File

@@ -10,7 +10,7 @@ Status: implemented
## Decision
`ctx.subagents.interrupt(targetSessionId, authority)` 只停止在线目标的当前轮次。管理器原语同步完成鉴权,调用现有的 `Agent.cancel(cause, { keepInbox: true })`,然后返回 `void`——fire-and-return保证取消信号已发出但不等待目标静止。其余一切不变不 dispose Activation、不释放 handle、不级联后代、不清空 inbox也不改动 `AgentLoop``CancelOptions`。由于 `keepInbox` 让待处理队列停在 idle中断绝不会自动启动下一个排队的 follow-up只有之后一次显式唤醒发送按保留的 FIFO 顺序恢复。
`ctx.subagents.interrupt(targetSessionId, authority)` 只停止在线目标的当前轮次。管理器原语同步完成鉴权,调用现有的 `Agent.cancel(cause, { keepInbox: true })`,然后返回 `void`——fire-and-return保证取消信号已发出但不等待目标静止。其余一切不变不 dispose Activation、不释放 handle、不级联后代、不清空 inbox也不改动 `AgentLoop``CancelOptions`。由于 `keepInbox`尚未领取的待处理队列停在 idle中断绝不会自动启动下一个排队的 follow-up已被领取进入中断轮次的工作属于该轮次,不会重新入队。被中断的 driver 进入 idle 后,一次显式唤醒发送按保留的 FIFO 顺序恢复。
授权是一个封闭的双变体 union刻意比投递权限更宽因为停止一个轮次是幂等的且不投递任何内容
@@ -35,7 +35,11 @@ Host RPC `subagent.interrupt` 接收 continuable 的 `SubagentAddress` 并返回
## Consequences
人类或 ancestor 现在可以停止一个失控的 continuable 轮次,而不丢失 child、其排队工作或正在运行的后代代价是一个刻意保持弱的后置条件`accepted` 表示"信号已发出",目标在观察到信号前可能仍显示 `running`),客户端必须如实呈现。暂停队列规则意味着被中断的 child 会带着保留的工作停在 idle直到有人发送唤醒消息——这是有意的 human-in-the-loop 暂停,不是调度器缺陷。Web 的 Stop 操作和面向模型的 `interrupt_agent` 工具在 issue #1535 的后续 stacked PR 中基于此原语构建
人类或 ancestor 可以停止一个失控的 continuable 轮次,而不丢失 child、其尚未领取的排队工作或正在运行的后代;代价是一个刻意保持弱的后置条件(`accepted` 表示信号已发出,目标在观察到信号前可能仍显示 `running`),客户端必须如实呈现。暂停队列规则意味着被中断的 child 会带着保留的工作停在 idle直到 driver 进入 idle 后收到唤醒消息——这是有意的 human-in-the-loop 暂停,不是调度器缺陷。在 abort 收敛期间被接受的唤醒发送目前会保持排队而不锁存 wakeIssue #1838 跟踪共享的 agent-loop 修正
仅凭地址的 RPC 会暴露一位在线驻留信息:不存在的目标会被接受,而 parent 不匹配的在线目标会返回 `subagent-unauthorized`。单用户本地 Host 的信任模型接受这种可观察性;未来的多主体 Host 必须重新审视权限和响应不可区分性。
Web 的 Stop 操作和面向模型的 `interrupt_agent` 工具在 issue #1535 的后续 stacked PR 中基于此原语构建。
## Testing