docs(subagent): record the public interrupt in the continuation contract docs
The continuable-subagent core-data page and the continuation lifecycle Agent Note claimed no public subagent cancellation existed; interrupt() is now that one public stop. Both pages and their Chinese counterparts state the shipped contract and link the owning interrupt note. Refs #1535
This commit is contained in:
@@ -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 docs/core-data-structures/subagent.md
|
||||
subagent.md: 4d7552eb5749284d90e31e62d8ac02e3d7a21b1d
|
||||
subagent.zh.md: ebcb1ce445c164352109d6613028c7a36c10d6d4
|
||||
subagent.md: fba934233fb7e890d6a68bd4cc7d37f90ab913ed
|
||||
subagent.zh.md: 70651397f82e2cf4c0fe18aa26ff8247484ca0aa
|
||||
|
||||
@@ -139,7 +139,20 @@ The Agent inbox is the only queue. Every continuation message becomes one `Agent
|
||||
|
||||
Follow-up authority comes from an exact live Agent tool context. The authenticated Agent must be the durable child's direct parent recorded in `SessionHeader.parentSession`. `MessageSource` and `senderSessionId` are durable provenance after admission and grant no authority; the optional model-facing tool uses `CoordinatorMessageSource`.
|
||||
|
||||
For both operations the caller signal owns lookup, materialization, and admission only until inbox acceptance. Afterwards the manager owns the Activation independently: later caller cancellation neither cancels the accepted turn nor disposes the child, and the seam exposes no public subagent cancellation or steering operation.
|
||||
For both operations the caller signal owns lookup, materialization, and admission only until inbox acceptance. Afterwards the manager owns the Activation independently: later caller cancellation neither cancels the accepted turn nor disposes the child, and the seam exposes no steering operation.
|
||||
|
||||
`SubagentService.interrupt(targetSessionId, authority)` is the one public stop: it authorizes synchronously, issues `Agent.cancel(cause, { keepInbox: true })` on the live target, and returns without awaiting quiescence. The Activation, its pending inbox work, and published descendants are untouched; only a later waking send resumes the parked FIFO queue. An absent target — unknown, one-shot, or already settled — and a manager-less composition are accepted no-ops; a wrong parent address or a stale, self-targeting, or non-ancestor caller rejects with `UNAUTHORIZED`.
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
* Authority under which one interrupt request is admitted. `user` carries the
|
||||
* durable direct-parent address a human client presented; `ancestor` carries
|
||||
* the exact live Agent object whose recorded lineage must contain the caller.
|
||||
*/
|
||||
type SubagentInterruptAuthority =
|
||||
| { readonly kind: 'user'; readonly parentSessionId: SessionId }
|
||||
| { readonly kind: 'ancestor'; readonly agent: Agent }
|
||||
```
|
||||
|
||||
Every Activation owns its `AgentHandle` and an `ownedChildren: Set<SessionId>`; because one Session has at most one live Activation, the child Session id identifies the live child without another runtime-incarnation reference. Starting a child or submitting parent-originated work registers the child in a continuation-managed parent's set before the child can run, and that parent cannot settle while the set is non-empty. A top-level or other non-continuation Agent has no Activation and stays outside the waiting graph. Child release happens only after the child Agent is quiescent, every child of that child is disposed, the best-effort final session flush settles, and the child's `AgentHandle` completes disposal.
|
||||
|
||||
|
||||
@@ -139,7 +139,20 @@ Agent 收件箱是唯一的队列。每条继续执行消息都会成为一个 `
|
||||
|
||||
后续操作的权限来自确切的在线 Agent 工具上下文。已认证的 Agent 必须是持久化子 agent 在 `SessionHeader.parentSession` 中记录的直接父级。`MessageSource` 与 `senderSessionId` 在准入之后是持久的来源凭据,不授予任何权限;可选的面向模型工具使用 `CoordinatorMessageSource`。
|
||||
|
||||
对于这两种操作,调用方 signal 仅在收件箱接受之前掌管查找、物化与准入。此后管理器独立掌管该 Activation:之后的调用方取消既不会取消已接受的轮次,也不会 dispose 子 agent,并且该 seam 不对外暴露任何 subagent 取消或 steering(中途引导)操作。
|
||||
对于这两种操作,调用方 signal 仅在收件箱接受之前掌管查找、物化与准入。此后管理器独立掌管该 Activation:之后的调用方取消既不会取消已接受的轮次,也不会 dispose 子 agent,并且该 seam 不对外暴露任何 steering(中途引导)操作。
|
||||
|
||||
`SubagentService.interrupt(targetSessionId, authority)` 是唯一的公开停止操作:它同步完成鉴权,对在线目标发出 `Agent.cancel(cause, { keepInbox: true })`,然后不等待静止即返回。Activation、其待处理的 inbox 工作与已发布的后代均不受影响;只有之后的一次唤醒发送才会恢复被暂停的 FIFO 队列。不存在的目标——未知、一次性或已结算——以及未绑定管理器的组合是被接受的 no-op;错误的 parent 地址,或过期、指向自身、非 ancestor 的调用方会以 `UNAUTHORIZED` 拒绝。
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
* Authority under which one interrupt request is admitted. `user` carries the
|
||||
* durable direct-parent address a human client presented; `ancestor` carries
|
||||
* the exact live Agent object whose recorded lineage must contain the caller.
|
||||
*/
|
||||
type SubagentInterruptAuthority =
|
||||
| { readonly kind: 'user'; readonly parentSessionId: SessionId }
|
||||
| { readonly kind: 'ancestor'; readonly agent: Agent }
|
||||
```
|
||||
|
||||
每个 Activation 都拥有自己的 `AgentHandle` 和一个 `ownedChildren: Set<SessionId>`;由于一份会话至多有一个存活 Activation,子会话 id 无需另一个运行时化身引用即可标识存活的子 agent。启动子 agent 或提交源自 parent 的工作,会在子 agent 能够运行之前将其注册到受继续执行管理的父级集合中;只要该集合非空,该父级就无法 settle。顶层或其他非继续执行的 Agent 没有 Activation,处于 waiting 图之外。只有当子 Agent 已停稳、该子 agent 的每个子级都已 dispose、best-effort 的最终会话 flush 结算完毕,且子 agent 的 `AgentHandle` 完成 dispose 之后,才会释放子 agent。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user