refactor(agent-loop): start waking work directly
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 .agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.md
|
||||
2026-07-22-unified-send-and-coalesced-user-messages.md: c9e4a2195f01b72f1d0c16136c666f2e00e484d0
|
||||
2026-07-22-unified-send-and-coalesced-user-messages.zh.md: fc6d26b421ba30cab0937c6e3a7ef3a41c83d654
|
||||
2026-07-22-unified-send-and-coalesced-user-messages.md: f32d6ca65d5236e1fabdd177cdf54e36929c853f
|
||||
2026-07-22-unified-send-and-coalesced-user-messages.zh.md: 3e3176e74eadee958b43fe4d5cc288b7c60559ee
|
||||
|
||||
@@ -28,7 +28,7 @@ Separately, `context/message` and `user/message` had converged: the surface proj
|
||||
|
||||
**One accepted message keeps one representation.** Durable user-role input and additional model-facing context both use the identified, frozen `UserMessage` directly. The loop stores that value beside private routing state rather than copying its identity, content, or source into another public shape. Steering, injection, and tool-produced context each keep their identified messages in the next-step inbox. The [identified immutable message decision](2026-07-28-identified-immutable-message-values.md) supersedes this note's former `UserMessageData`/`AgentMessage` hierarchy and extends the representation to assistant and tool-result messages.
|
||||
|
||||
**Idle wakeup follows insertion.** A waking send reserves the driver and schedules pre-step processing for a microtask after the input enters its target inbox. Every send in one synchronous caller stack therefore enters before claiming starts, while reentrant cancellation or teardown cannot retire before the scheduled pre-step settles. Multiple idle `steer()` calls in that stack form one next-step batch.
|
||||
**Idle wakeup follows insertion.** A waking send inserts its input, then enters the running driver before returning. The first pre-step may claim that input immediately; later synchronous sends therefore join the running loop and wait for a later boundary. Cancellation belongs to the running turn signal from wakeup onward; no distinct pre-run phase intervenes.
|
||||
|
||||
**cancel gains keepInbox.** `cancel(cause, { keepInbox? })`; callers choose the cause explicitly, and `keepInbox: true` aborts the active turn while preserving queued and steering items (no discard event, and un-started work is not dropped).
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ agent 的对外驱动接口逐渐长出三个近乎平行的动词——`send`
|
||||
|
||||
**一条已接受消息只保留一种表示。** 持久的用户角色输入和附加的模型可见上下文都直接使用带标识且冻结的 `UserMessage`。循环把该值与私有路由状态存放在一起,不会将其标识、内容或来源复制到另一种公开形状中。steering、注入和工具产生的上下文都会在 next-step inbox 中保留各自带标识的消息。[带标识的不可变消息值决策](2026-07-28-identified-immutable-message-values.md)取代了本记录此前的 `UserMessageData`/`AgentMessage` 层级,并将这一表示扩展到 assistant 消息和工具结果消息。
|
||||
|
||||
**空闲唤醒在插入之后发生。** 会唤醒的发送会先保留驱动器,并在输入进入目标 inbox 后把 pre-step 处理调度到微任务。因此,同一同步调用栈中的每次发送都会在领取开始前进入 inbox,而可重入的取消或拆除在已调度的 pre-step 结算前无法完成退役。同一调用栈中多次空闲 `steer()` 会形成一个 next-step 批次。
|
||||
**空闲唤醒在插入之后发生。** 会唤醒的发送会先插入输入,再于返回前进入 running 驱动器。首次 pre-step 可能立即领取该输入;因此,后续同步发送会加入正在运行的循环,并等待更晚的边界。自唤醒开始,取消就归属于 running 轮次信号,中间不会插入独立的预运行 phase。
|
||||
|
||||
**cancel 新增 keepInbox。** `cancel(cause, { keepInbox? })`;调用方显式选择 cause,且 `keepInbox: true` 会中止活跃轮次,同时保留排队项和 steering 项(不发出 discard 事件,尚未启动的工作也不会被丢弃)。
|
||||
|
||||
|
||||
@@ -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-07-24-separate-context-injection-from-turn-execution.md
|
||||
2026-07-24-separate-context-injection-from-turn-execution.md: a1ae505a54f55d201559d62765abe423694aef6e
|
||||
2026-07-24-separate-context-injection-from-turn-execution.zh.md: 8a24442b9922a125e86b5478cc3d0d810d027505
|
||||
2026-07-24-separate-context-injection-from-turn-execution.md: bb28d96cf1494d94ad7a7d4a4714e536c7072d2f
|
||||
2026-07-24-separate-context-injection-from-turn-execution.zh.md: 73889a946295f88dcf5e5eff01949fe57e90ea64
|
||||
|
||||
@@ -26,7 +26,7 @@ Every additional context is an independent `UserMessage` whose `source` records
|
||||
|
||||
## Injection lifecycle
|
||||
|
||||
`inject()` always inserts context into the non-waking `next-step` inbox and commits that queue mutation as `agent/inbox/spliced`. A collecting or running driver claims it at the nearest later pre-step boundary. An idle driver leaves it pending until `followup()` or `steer()` supplies waking work; cancellation or disposal may discard it first without erasing the durable queue history.
|
||||
`inject()` always inserts context into the non-waking `next-step` inbox and commits that queue mutation as `agent/inbox/spliced`. A running driver claims it at the nearest later pre-step boundary. An idle driver leaves it pending until `followup()` or `steer()` supplies waking work; cancellation or disposal may discard it first without erasing the durable queue history.
|
||||
|
||||
The loop claims the current next-step batch before running `agent/pre-step`, so an injection that arrives after that claim may miss the request already being finalized. The next boundary claims it instead. An enter decision appends its returned messages inside the owning turn before the request consumes them. Context produced during an assistant tool-call batch therefore appears after that batch's complete ordered results.
|
||||
|
||||
@@ -62,7 +62,7 @@ This decision preserves the caller-owned framing decision from [unwrapped inject
|
||||
- `UserMessage` is the shared identified, frozen shape across prompt interception, tool execution, hook bridges, guards, and context producers.
|
||||
- Prompt-prefix placement, prompt envelopes, and `context/message` are absent from public types, durable events, projection, and UI replay.
|
||||
- Idle `inject()` immediately appends one durable inbox insertion but no model-visible `user/message`; a later waking delivery may start pre-step processing.
|
||||
- Collecting and active-turn injection is claimed at the nearest later pre-step boundary, after complete tool-result batches and before the request that consumes it.
|
||||
- Active-turn injection is claimed at the nearest later pre-step boundary, after complete tool-result batches and before the request that consumes it.
|
||||
- Rejected or failed pre-step drops its claimed batch; input inserted after the claim remains pending.
|
||||
- Unit, persistence/resume, invariant, and TUI coverage pin event order, claim ownership, and durable replay.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ agent API 曾用三种相互重叠的方式表示面向模型的补充输入:
|
||||
|
||||
## 注入生命周期
|
||||
|
||||
`inject()` 始终把上下文插入不会唤醒的 `next-step` inbox,并以 `agent/inbox/spliced` 提交该队列变更。collecting 或 running 驱动器会在最近的后续 pre-step 边界领取它。idle 驱动器会让它保持待处理,直至 `followup()` 或 `steer()` 提供可唤醒工作;在此之前,取消或 dispose(资源释放)可能将其丢弃,但不会抹除持久队列历史。
|
||||
`inject()` 始终把上下文插入不会唤醒的 `next-step` inbox,并以 `agent/inbox/spliced` 提交该队列变更。运行中的驱动器会在最近的后续 pre-step 边界领取它。idle 驱动器会让它保持待处理,直至 `followup()` 或 `steer()` 提供可唤醒工作;在此之前,取消或 dispose(资源释放)可能将其丢弃,但不会抹除持久队列历史。
|
||||
|
||||
循环会先领取当前 next-step 批次,再运行 `agent/pre-step`,因此领取后到达的注入可能赶不上正在最终确定的请求,而由下一次边界领取。enter decision 返回的消息会在所属轮次内、消费它们的请求之前追加。在助手工具调用批次期间产生的上下文因此只会出现在该批次全部有序结果之后。
|
||||
|
||||
@@ -62,7 +62,7 @@ enter 分支的 `PreStepDecision.messages` 是拟议步骤的完整批次。wate
|
||||
- `UserMessage` 是提示词拦截、工具执行、hook bridge、guard 和上下文生产方共享的带标识且冻结的形状。
|
||||
- 公共类型、持久事件、投影和 UI 回放中均不存在 prompt-prefix 放置方式、提示词封套与 `context/message`。
|
||||
- idle 状态下的 `inject()` 会立即追加一条持久 inbox 插入记录,但不会追加模型可见的 `user/message`;后续可唤醒投递可能开始 pre-step 处理。
|
||||
- collecting 和活跃轮次中的注入会在最近的后续 pre-step 边界领取,并位于完整工具结果批次之后、消费它的请求之前。
|
||||
- 活跃轮次中的注入会在最近的后续 pre-step 边界领取,并位于完整工具结果批次之后、消费它的请求之前。
|
||||
- pre-step reject 或失败会丢弃其已领取批次;领取后插入的 inbox 工作继续保持待处理。
|
||||
- 单元测试、持久化与 resume 测试、不变量测试和 TUI 覆盖会固定事件顺序、领取归属和持久回放。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user