Skip to content

Feat/delegation continue sessions#382

Open
7iook wants to merge 3 commits into
xintaofei:mainfrom
7iook:feat/delegation-continue-sessions
Open

Feat/delegation continue sessions#382
7iook wants to merge 3 commits into
xintaofei:mainfrom
7iook:feat/delegation-continue-sessions

Conversation

@7iook

@7iook 7iook commented Jul 26, 2026

Copy link
Copy Markdown

delegate_to_agent 派出的子代理不再是一次性的:

  • 主 AI 续聊:新增 continue_with_session(task_id, message, continuation_id) / close_session 两个 MCP 工具。子任务完成后子代理保留(kept-alive 池,全局 + 每父会话双层上限,FIFO 驱逐),主 AI 可在同一 task_id
    下多轮追问,不再重派、不再重复探索。
  • 用户端入口:委托状态卡的子代理会话弹窗底部新增续聊输入框——用户可以直接给子代理发消息,该轮结果主 AI 通过 get_delegation_status 同样可见(同一 task 的新 turn)。
  • 进程回收后可恢复:子代理连接被驱逐/重启丢失后,续聊自动走 session/load resume;恢复不了会在发送前返回稳定错误码(resume_unavailable 等 6 个),而不是静默开新会话丢上下文。
  • 侧边栏收纳:委托子会话默认从侧边栏隐藏(设置里可开),显示时带 Sub 徽标。

#375 的关系

实现了与 #375 相同的 wire 契约(工具名/参数/错误码可对齐),动手前对 #375 做过逐行审阅,发现三个问题,本 PR 均已在结构上规避:

  1. 闲置回收静默丢上下文:kept-alive 子代理被 idle-sweep 断开时没有任何状态迁移/事件,后续 continue 直接失败且无法解释原因。本实现将「连接释放」与「会话终结」分离(released 是资源状态,resume 凭证 external_id
    永不被覆盖),回收后续聊走 resume 路径。
  2. 超额驱逐泄漏进程:cap 驱逐只删缓存记录、不 disconnect 子代理连接。本实现驱逐在 settle 锁内决策、锁外统一 disconnect,并有回归测试钉住。
  3. continue 与 cancel 的注册窗口竞态:continue 派发提交后、注册完成前到达的 cancel 会悬挂。本实现所有会话状态迁移收敛到单一 settle 入口(choke point),close/cancel/continue 并发均有红-绿测试覆盖。

其它设计点:continuation_id 强制幂等(重试同一次提交返回首次结果,不双发);事件按 turn_version 单调排序,乱序/丢失时前端以 get_delegation_status 为权威源重查;续聊可用性由后端五档判定(running / continuable_live /
continuable_resume / released / not_continuable),前端不自行推导。

兼容性

  • 委托功能总开关默认仍为关闭;开启后 v1 的一次性委托行为不变,续聊是纯增量能力。
  • delegation_completed 仍只对首轮 tool_call 发一次;续聊轮终态由新增的 delegation_session_update(session 级寻址)宣告,旧前端忽略该事件不受影响。

测试

  • Rust:delegation 模块 349 个测试全绿(含 close/continue 竞态、驱逐、resume 失败路径的红-绿用例);cargo clippy -D warnings 干净
  • 前端:tsc 零错;vitest 相关 26 个文件 304 个测试全绿(多轮时间线切分、续聊输入框五档门控、Sub 徽标判定等)

7 added 3 commits July 27, 2026 02:47
Replace the v1 one-shot delegation lifecycle (child torn down at first
terminal state, broker.rs "v1 one-shot" comment) with continuable
sessions shared between the parent LLM and the user.

Backend:
- Session/Turn/Operation three-layer split inside the broker; the
  completed cache now only caches result text (evicting it can no
  longer change domain behavior)
- continue_with_session / close_session MCP tools (wire-compatible
  with upstream PR xintaofei#375; close is release semantics, session_released
  with session_closed accepted as a historical alias)
- Keep-alive with kept_alive_cap (global + per-parent FIFO) on top of
  idle-sweep reclamation; resume via external_id with triple binding
  checks (agent_type/folder/uniqueness) and pre-side-effect
  resume_unavailable instead of silent session/new downgrade
- Startup rebuild protocol (rebuilding retryable state, per-row
  failure isolation, ledger not reused across restarts)
- Continuation registered cancellable before the follow-up prompt is
  sent (closes the register-window cancel race), close-vs-continue
  serialization hardened at the settle_session choke point
- update_external_id resume-safe/skip-delegate guards at all four
  call sites so a degraded session/new can never overwrite the resume
  credential of a delegate row
- session-scoped delegation_session_update event (task_id, turn_id,
  turn_version, origin); no duplicate completion against an
  already-terminal parent_tool_use_id

User entry point (not present in upstream PR xintaofei#375):
- continue/close/availability HTTP + Tauri commands keyed by
  conversation id, continuation_id idempotency ledger across all
  three entries (MCP arm included, listener never mints ids)
- Sub-agent dialog composer gated by five-state continuation
  availability; errors surfaced with stable codes
- Sidebar discoverability: Sub badge, sub-session filter toggle
  (default off), delegate rows excluded from the root list by DB
  markers only (immune to worktree indentation)
- Multi-turn timeline: prefix cut anchored to the in-flight user turn
  so earlier completed turns stay visible while a new turn streams

Verification: rust --lib 1805 passed / clippy -D warnings clean /
frontend vitest 2835 passed / tsc clean. Independent read-only review
(heterogeneous model) returned 0 critical; both important findings
(close-vs-continue compound-failure leak, unguarded external_id call
sites) fixed with red-green tests in this change.

Spec: docs/specs/delegation-continue-session/{requirements,design,tasks}.md
(3-round codex cross-review converged; introspection archived)
…igin settles

① 根因: 续聊轮(turn_version>1)按 2.8a 抑制第二次 delegation_completed,
   替代事件 delegation_session_update 存在两个消费缺口——
   a) delegation-context(状态卡)只消费 started/completed,卡片在续聊轮
      的 started 重播后翻回"运行中"却永远收不到落停信号;
   b) User-origin 续聊的 parent_connection_id 是合成 id,emitter 解析不到
      即静默丢弃 → 用户从 Dialog 发起的续聊完成时前端零推送,只能重开
      Dialog 才能看到结果。
② 修复: emitter 增加 child_connection_id 回落(父连接解析不到时改走子连接
   事件流,桌面 firehose / web attach 流均可达);delegation-context 消费
   session_update 将卡片落停(ok + 调度 detach,与 completed 路径对称);
   Dialog 收到本子会话的 session_update 时 refetchDetail(preserveLive)。
③ 影响面: event_emitter trait 及 Noop/Mock/prod 三实现、broker 调用点与
   注释、delegation-context、sub-agent-session-dialog;新增 Rust 回落
   fan-out 测试;Rust delegation 349 passed、clippy 零告警、tsc 零错、
   vitest 57 passed。
…lt-in Task tool

① 根因: 用户说"派个 sub"时,主 AI 默认选自家内置 Task/Agent 工具——
   其进程内 subagent 对用户不可见不可交互(源码核实 v2.1.88:寻址表与
   实体均为进程内存,无外部驱动面),用户诉求的"可切入交互/待命"落空。
② 修复: delegate_to_agent 描述开头新增与内置 Task 工具的抉择规则——
   用户要求可交互/可待命/可回查的子代理派发时用本工具;@ 提及仍是
   确定性硬路由(已有)。
③ 影响面: 仅 tool_schema.json 文案;companion 59 测试通过,JSON 校验 OK。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant