feat(engine): conversation-insertion primitives — keepInbox steer queue + steer events + deterministic cancel - #16
Conversation
|
Thanks @qiuYliangM for taking the time to contribute. This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered. Please read |
d2972b9 to
2f376e4
Compare
…ue + steer events + deterministic cancel
Two insertion semantics needed base support that was only best-effort:
- idle insertion (steer): messages could be silently dropped at turn
boundaries and hosts had no delivery confirmation
- forced insertion (interrupt): cancel never released a deterministic
"slot free" signal, and shell processes could survive the tool-future
drop race
Changes:
- steer queue becomes session-scoped (keepInbox): leftover steers are no
longer drained at new-turn start; collected-but-uninjected steers live on
the Engine and are re-injected by the next turn step boundary, surviving
cancel (aligned with deepseek-harness cancel(cause, { keepInbox: true }))
- steer_keep_inbox switch on EngineHandle (set before cancel): interrupt
(true) parks unconsumed steers for the next turn; stop (false) drops them
and emits Event::SteerDropped per message so hosts can remove the queued
chip and tell the user — nothing hangs invisible
- new events Event::SteerCommitted / Event::SteerDropped carry an FNV-1a
content hash so hosts can correlate delivery without full text; committed
is emitted at all three injection points (step boundary, post-stream,
post-tool)
- cancel now kills running shell process groups explicitly at both the
parallel and sequential tool select sites (drop(tool_tasks) does not
kill OS processes); shell.rs foreground poll switched from 100ms polling
to a select on the cancel token (broadcast wake, no longer loses to the
turn-loop drop)
Verification: cargo check + codewhale-tui --lib tests (9888 passed;
9 pre-existing Windows-environment failures reproduced on baseline).
评审修复(对应 pinvou-agent#308 宿主评审):
- 关联契约:SteerCommitted/SteerDropped 改携带入队时生成的 opaque
steer_id(SteerMessage { id, content }),替代 FNV-1a 内容哈希——
UTF-8 字节与 UTF-16 码元哈希对非 ASCII 内容必然不一致,事件关联全断。
- 撤回:EngineHandle::withdraw_steer 记入共享撤回集合,所有收集/注入点
过滤并恰好发一条 SteerDropped;撤回标记跨轮存活,SyncSession/Shutdown
清场时清除。宿主排队占位的取消由此在注入前真正生效。
- 停止语义:keep_inbox=false 在全部 Interrupted 出口统一 settle
(pending_steers + channel 残留逐条 SteerDropped),不再只清字段。
- 清场覆盖:Op::SyncSession 换会话前 drop_all_steers 发事件(修跨会话
注入),Op::Shutdown 同样处理;Drop for Engine 以 try_send 兜底。
- kill 收敛:cancel 只杀本轮前台(spawned_as_foreground 且无
owner_agent)shell 进程组,后台任务与子智能体 shell 不再被连带 kill。
测试:engine/tests.rs 新增 13 条(keepInbox park/drop、三处注入点、
SyncSession 清场、Drop 兜底、撤回五场景),shell/tests.rs 新增
kill_running_turn_foreground 范围回归。cargo test -p codewhale-tui --lib
--locked 无新增失败(基线 Windows 环境失败与负载 flake 除外)。
Signed-off-by: luzeyang (INT) <lu.zeyang@h3c.com>
Signed-off-by: hexin <372726039@qq.com>
a5ef9eb to
e109b9b
Compare
|
我已在 e109b9b 上完成一轮重构,烦请作者重点复核以下语义和边界:
测试做了精简:原方案测试净增约 852 行,现在约 407 行,保留 6 个关键生命周期契约及 Shell 范围测试。PR 总体由 +1432/-107 调整为 +1175/-142,净增 1325 降至 1033。 本地验证:
请重点确认两项产品语义是否符合预期:一是 Stop 丢弃未提交 steer、Interrupt 保留;二是取消父 turn 不终止后台任务和子 Agent Shell。 |
steer_lifecycle 测试精简中丢失的覆盖:宿主不经 Op::Shutdown 直接回收 引擎(evict/reclaim)时,Drop 必须为每条未消费 steer 尽力补发 SteerDropped(try_send),否则宿主排队占位悬挂。实现在 engine.rs:6354,本测试重新锁定该契约。 Signed-off-by: luzeyang (INT) <lu.zeyang@h3c.com>
|
已复核 两点产品语义确认符合预期:
另外几点复核结论: 我补回了一条被精简掉的 |
|
/lgtm |
Hosts that re-send a queued input through another path (interrupt-and-send) must know whether the engine copy can still be committed, otherwise the same message can be delivered twice: the withdrawal used to be fire-and-forget, and "no SteerCommitted received yet" cannot be distinguished from "already committed" on the async event path. SteerControlState::withdraw now reports from the authoritative unsettled ledger, and EngineHandle::withdraw_steer returns it: - Retired: the id was pending and is now marked withdrawn — guaranteed never to be injected, settles with exactly one SteerDropped; the host may safely re-send. - NotPending: the id already settled (committed or dropped) or was never seen — no-op with no event; the host must not re-send. The withdrawal-set invariants are unchanged: unknown ids do not grow the set (bounded), settled ids stay no-ops. Behavior test steer_lifecycle_withdrawal_is_bounded_and_prevents_commit now asserts all three outcomes. No-Issue: driven by pinvou-agent#308 review (interrupt-and-send resend race); upstream-neutral, same area as the conversation-insertion primitives in Pinvou#16. Signed-off-by: luzeyang (INT) <lu.zeyang@h3c.com>
Hosts that re-send a queued input through another path (interrupt-and-send) must know whether the engine copy can still be committed, otherwise the same message can be delivered twice: the withdrawal used to be fire-and-forget, and "no SteerCommitted received yet" cannot be distinguished from "already committed" on the async event path. SteerControlState::withdraw now reports from the authoritative unsettled ledger, and EngineHandle::withdraw_steer returns it: - Retired: the id was pending and is now marked withdrawn — guaranteed never to be injected, settles with exactly one SteerDropped; the host may safely re-send. - NotPending: the id already settled (committed or dropped) or was never seen — no-op with no event; the host must not re-send. The withdrawal-set invariants are unchanged: unknown ids do not grow the set (bounded), settled ids stay no-ops. Behavior test steer_lifecycle_withdrawal_is_bounded_and_prevents_commit now asserts all three outcomes. No-Issue: driven by pinvou-agent#308 review (interrupt-and-send resend race); upstream-neutral, same area as the conversation-insertion primitives in #16. Signed-off-by: luzeyang (INT) <lu.zeyang@h3c.com>
背景
两种插入语义需要底座支持(原为尽力而为):
改动
验证
cargo check --all-targets + codewhale-tui --lib 9888 测试通过(9 个 Windows 环境既有失败在基线复现)。
No-Issue: pinvou3 打断/插入语义的底座配套,由 pinvou-agent PR Hmbown#308 的同一需求驱动