Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions knowledge/repos/jiuwenswarm/components/agent-runtime/_index.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
---
title: "Agent 运行时与会话"
created: 2026-09-30
updated: 2026-09-30
updated: 2026-10-01
type: index
tags: [jiuwenswarm]
sources: []
---

# Agent 运行时与会话

- [共享 Agent Runtime(jiuwenswarm/runtime)](jiuwenswarm-runtime.md)
- [Runtime Session 协调器(jiuwenswarm/runtime/session/)](jiuwenswarm-runtime-session.md)
## 什么时候查这里

请求规范化、会话 provision,以及 generation、lane 排队、交互输入、取消与关闭协调。

## 不放什么

持久会话元数据由服务端 session 模块拥有;cron 产生定时工作、通道处理传输,分别查对应 component。

## 目录内容

- [共享 Agent Runtime(jiuwenswarm/runtime)](jiuwenswarm-runtime.md) — 传输层无关的 Runtime:请求规范化、会话 create/switch/fork/delete、Plan 模式、模型/权限/MCP 目录
- [Runtime Session 协调器(jiuwenswarm/runtime/session/)](jiuwenswarm-runtime-session.md) — 会话执行协调:准入与 generation、lane 排队、unary/流式执行、control 投递与心跳链、取消与关闭

## 代码快速入口(Direct)
<!-- kb-init:quick-map -->

触发词:runtime、AgentRuntime、session create/switch/fork、session.delete、plan mode、model catalog、permission snapshot、MCP reference、push handler、process CLI、agent definition、运行时。PR 描述或改动命中下表一行时,先读该行的规则,再读页面其余部分。
触发词:runtime、AgentRuntime、session create/switch/fork、session.delete、plan mode、model catalog、permission snapshot、MCP reference、push handler、process CLI、agent definition、运行时、session lane、execution registry、work scheduler、deliver_control、cancel_execution、close_session、QUIESCING、control input、心跳链。PR 描述或改动命中下表一行时,先读该行的规则,再读页面其余部分。

| PR 描述在做什么 | 精确规则 | 第一批 live 源码 |
|---|---|---|
| runtime、AgentRuntime、session create/switch/fork、session.delete、plan mode、model… | 入口 | `jiuwenswarm/runtime/agent_definition.py`、`jiuwenswarm/runtime/context.py`、`jiuwenswarm/runtime/events.py` |
| session 执行协调、lane 排队、deliver_control、cancel_execution、close_session | Runtime Session 协调器(见目录内容) | `jiuwenswarm/runtime/session/coordinator.py`、`jiuwenswarm/runtime/session/execution_registry.py`、`jiuwenswarm/runtime/session/work_scheduler.py` |

## 验证入口

`tests/unit_tests/runtime/test_runtime_session_coordinator.py` 覆盖进程内排序、控制输入、取消与关闭;Runtime 上层契约见共享 Runtime 页。

## 专题入口

- [Runtime 交互输入、执行取代与取消](jiuwenswarm-runtime-control.md) — 协调等待交互的执行、补充输入、工作取代和子执行取消;会话注册、lane 调度与关闭由 Runtime Session 主页面说明。

- [Runtime unary 与流式执行](jiuwenswarm-runtime-execution.md) — 提交去重、超时与取消、终态 owner 和流消费者提前退出。
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "Runtime 交互输入、执行取代与取消"
created: 2026-10-01
updated: 2026-10-01
type: architecture
tags: [jiuwenswarm]
sources:
- openJiuwen-ai/jiuwenswarm@f0a69728c96b5961d993449f1a901cbd2f4dac5b:jiuwenswarm/runtime/session/coordinator.py
---

# Runtime 交互输入、执行取代与取消

## 职责和边界

协调等待交互的执行、补充输入、工作取代和子执行取消;会话注册、lane 调度与关闭由 Runtime Session 主页面说明。

### control 投递与心跳链

- `deliver_control` 的父执行 = 当前 generation 里活跃、`waiting_control_id == request_id` 且状态 RUNNING/WAITING_FOR_CONTROL 的最新者(按 started_at/created_at 取 max);找不到抛 "session has no active execution"([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L881-L901))。
- claim 是四元组 (session_id, generation, parent_execution_id, request_id),重复投递抛 "control input is already being delivered"。claim 先加、子执行创建仍可能失败:失败时 finally 释放 claim,父执行保持可重试——泄漏的 claim 或被恢复却无人接手的父都会把问题永久卡死(源码注释;测试 `test_failed_control_setup_releases_claim_and_parent`)([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L293-L316))。
- 投递完成时若父已终态/记录被替换/会话 QUIESCING 或 CLOSED:子记 CANCELLED 并抛 `SessionExecutionEndedError`("control input arrived after its execution ended: ...")([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L338-L352);测试 `test_control_result_after_parent_ended_raises_typed_error`)。
- control 子执行失败/被取消:子记 CANCELLED/FAILED;父若原本在等且未终态,重新 mark_awaiting_control + mark_waiting,答案可以重试;取消 control 子执行不会取消父工作([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L320-L336);测试 `test_control_input_cancellation_does_not_cancel_parent_work`)。
- 链式追问:control 操作自己的 `suspension_key` 又给出 control_id 时,若有 HEARTBEAT 祖先(`_heartbeat_root` 沿 parent 链、限同 session+generation 查找),则把心跳根重新挂起(waiting)、control 子记 SUCCEEDED;无心跳根时挂起 control 子自身。普通父等到答案后 SUCCEEDED;若父已发布更新的 waiting_control_id 则不覆盖([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L354-L377)、[L934-L953](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L934-L953);测试 `test_control_input_resumes_work_after_output_stream_ends`)。
- `deliver_control_stream` 是流式版:观察在操作结束前就可见(包括第二个问题),claim 用 per-record 的 `stream_control_claims`(按 request_id),重复抛 "interaction answer is already in progress";父只认已存在的匹配交互,绝不认一次新对话轮。消费者拥有该 generator,退出时必须 close([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L404-L495))。
- `record_interaction` 供被拥有的回调执行中登记交互:仅当会话 ACTIVE 且找到 RUNNING 的匹配 request_id 才写 waiting_control_id 并刷新 gate,返回 bool([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L265-L282))。`has_control_target` / `control_target_work_kind` 供宿主预判 control 能否送达及其根工作类型。

### 补充输入(stream_session_input)

- 语义:输入不恢复、不完成、也不替换等待中的交互。会话里任一活跃执行在等答案 → `SessionInputRejectedError`("session is waiting for an interaction answer; supplemental input was not sent");父执行正在取消 → 同样拒绝;`expected_execution_id` 与当前父不符 → `SessionInputTargetError`([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L497-L546);两个异常定义在 `jiuwenswarm/runtime/session_input.py`)。
- 有父(RUNNING 且非 SESSION_INPUT/GOAL_CONTROL/GOAL_ATTACH)时以 SESSION_INPUT 挂到父执行并传 `operation(record.channel_id)`;无父时作为新 CHAT_STREAM 走 `idle_operation` 兜底。

### 新工作取代等待中的执行

- 新 CHAT_UNARY/CHAT_STREAM 会把同 generation 中 WAITING_FOR_CONTROL 的 CHAT_UNARY/CHAT_STREAM/HEARTBEAT 记 `cancellation_requested=True` 并置 CANCELLED;新 GOAL_STREAM 同理取代 WAITING_FOR_CONTROL 的 GOAL_STREAM/GOAL_ATTACH([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L811-L836);测试 `test_new_work_supersedes_waiting_control`)。

### 取消(cancel_execution)

- 选择器:request_id / execution_id / 整个 session(均 active_only),先经 `_with_descendants` BFS 扩展子执行,范围限同 (session_id, generation)([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L648-L679)、[L955-L979](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L955-L979);测试 `test_cancel_by_request_execution_and_session`)。
- 两条取消路径:scheduled 类走 `SessionWorkScheduler.cancel_handles`;SESSION_MESSAGE(虽属 scheduled)和非 scheduled 类按 `_requires_direct_cancel` 直接 cancel 其 asyncio 任务([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L852-L856))。等待默认 `cancel_timeout=5.0` 秒,调用可用 `wait_timeout` 覆盖。
- 结果 `CancelExecutionResult(matched, cancelled, timed_out)`:超时未退出的执行保持原状态(如 RUNNING)且 `cancellation_requested=True`,仍被登记表跟踪;未超时的非终态一律强制记 CANCELLED([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L680-L692);测试 `test_cancel_timeout_keeps_resistant_execution_tracked`)。

## 怎样验证

源码链接固定在 f0a69728c96b5961d993449f1a901cbd2f4dac5b。聚焦单测选择器和验证范围见[原模块页面](jiuwenswarm-runtime-session.md#怎样验证);单元契约不能替代真实服务、模型端点或跨平台集成验证。

## 相关文档

- [原模块架构与入口](jiuwenswarm-runtime-session.md)
- [相邻模块](../cron-scheduling/jiuwenswarm-runtime-cron.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: "Runtime unary 与流式执行"
created: 2026-10-01
updated: 2026-10-01
type: architecture
tags: [jiuwenswarm]
sources:
- openJiuwen-ai/jiuwenswarm@f0a69728c96b5961d993449f1a901cbd2f4dac5b:jiuwenswarm/runtime/session/coordinator.py
---

# Runtime unary 与流式执行

## 职责和边界

说明已准入会话工作如何提交 unary 操作、处理 deadline、保留终态 owner 并解耦流生产者与消费者;会话注册、lane 调度与关闭见[协调器主页面](jiuwenswarm-runtime-session.md)。

### unary 执行

- `run_unary` 在调用方任务里 await 完成并返回值;`submit_unary` 排后台任务、立刻返回 QUEUED 快照。`submit_unary` 在对应记录仍留在 registry 时,按 (session_id, request_id, generation) 去重:重复提交返回同一 execution 快照;终态记录被 TTL/容量淘汰后,同一 request_id 可创建新执行,work_kind 不一致抛 `ValueError("request_id already belongs to ...")`([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L127-L159))。
- `submit_unary` 的 SESSION_MESSAGE 先 `await record.control_ready.wait()`:会话里有执行在等交互答案时,排队消息不会被调度([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L151-L154);测试 `test_session_message_waits_for_heartbeat_interaction`)。
- 超时与取消的区分:`timeout_scope`(`asyncio.Timeout`)expired 时,CancelledError 记 FAILED(error=timeout_error,默认 "execution deadline exceeded")而非 CANCELLED;操作吞掉取消返回"迟到成功"也照样记 FAILED 并向调用方抛 `TimeoutError`([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L177-L201);测试 `test_swallowed_deadline_cancellation_is_still_failed`)。
- `wait_for_terminal=True` 置 `retain_owner_task`;非 scheduled 工作(例如 HEARTBEAT)拿到值后等 `terminal_event`,终态 CANCELLED 抛 CancelledError、FAILED 抛 RuntimeError;owner task 退出前该终态执行不被登记表淘汰([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L226-L232);测试 `test_retained_terminal_owner_is_not_evicted_before_task_exit`)。
- 调用方任务被取消时:scheduled 的先经 scheduler 取消,未到终态则记 CANCELLED,随后级联取消子执行(`_cancel_descendants`)再刷新会话状态;其他异常同样取消子执行([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L234-L256);测试 `test_cancelling_unary_caller_also_stops_owned_operation`)。子执行取消被再次打断时,会不可中断地等它们退出([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L1044-L1057);测试 `test_interrupted_descendant_cancel_keeps_child_tracked`)。

### 流式执行(run_stream)

- 生产者/消费者经有界 `asyncio.Queue`(默认 64)解耦;生产者对每个条目跑 `suspension_key`,产出 control_id 就 mark_awaiting_control 并刷新 gate;终止标记(done/error)即使缓冲满也必须投递,否则消费者在最后一个数据项之后会永远等待(源码注释明说)([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L565-L614))。
- 消费者提前退出(aclose/异常)且生产任务未完成时,协调器对该 handle 调 `cancel_execution`,在取消等待期限内等待生产者;抵抗取消并超时的任务仍由 registry 跟踪([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L625-L646);测试 `test_stream_early_close_cancels_producer_and_waits_for_exit`、`test_external_stream_cancel_unblocks_consumer`)。
- lane 使用规则:`scheduled` 且不是 SESSION_MESSAGE 才进 lane——流式 mailbox 消息已持有宿主准入,排进聊天 lane 会死锁在等待该准入的用户轮次后面(源码注释);GOAL_STREAM 非 scheduled 不占 lane,聊天占用 lane 时仍可运行([coordinator.py](https://github.com/openJiuwen-ai/jiuwenswarm/blob/f0a69728c96b5961d993449f1a901cbd2f4dac5b/jiuwenswarm/runtime/session/coordinator.py#L616-L624);测试 `test_admitted_session_message_stream_bypasses_user_waiting_in_lane`、`test_goal_stream_runs_while_chat_lane_is_busy`)。

## 怎样验证

焦点用例与验证范围见[协调器验证入口](jiuwenswarm-runtime-session.md#怎样验证)。这里只记录固定源码 f0a69728c96b5961d993449f1a901cbd2f4dac5b 的进程内契约,不代替真实生产生命周期验证。

## 相关文档

- [Runtime Session 的准入、状态与关闭](jiuwenswarm-runtime-session.md)
- [Runtime 交互输入、执行取代与取消](jiuwenswarm-runtime-control.md)
Loading
Loading