Perform the full session close sequence. Idempotent: subsequent calls are no-ops and are guaranteed not to panic. Sequence (see [`AgentSession::close`](super::AgentSession::close) for the public-facing contract): 1. Flip the `closed` flag so further `send`/`stream` fast-fail; 2. Fire the session-level cancellation token so every derived run and subagent task token fires; 3. Mark the active run as
(&self)
| 65 | /// 5. Cancel pending HITL tool confirmations so blocked tool callers |
| 66 | /// receive a rejection instead of hanging. |
| 67 | pub(crate) async fn close(&self) { |
| 68 | if self.closed.swap(true, Ordering::AcqRel) { |
| 69 | return; |
| 70 | } |
| 71 | |
| 72 | // 1. Fire the session-level token so children cascade. |
| 73 | self.session_cancel.cancel(); |
| 74 | |
| 75 | // 2. Mark the active run cancelled and fire AHP hook bookkeeping. |
| 76 | // The per-run token has already fired via step 1; this loop |
| 77 | // just updates the run store and emits the hook event. |
| 78 | let had_active_token = self.cancel_token.lock().await.is_some(); |
| 79 | if had_active_token { |
| 80 | if let Some(run_id) = self.current_run_id.lock().await.clone() { |
| 81 | let _ = self.run_store.mark_cancelled(&run_id).await; |
| 82 | if let Some(hook) = &self.hook_executor { |
| 83 | hook.record_run_cancelled(&run_id, &self.session_id, Some("cancelled by host")) |
| 84 | .await; |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // 3. Mark every still-running subagent task cancelled. |
| 90 | let pending: Vec<String> = self |
| 91 | .subagent_tasks |
| 92 | .list_for_parent(&self.session_id) |
| 93 | .await |
| 94 | .into_iter() |
| 95 | .filter(|task| task.status == SubagentStatus::Running) |
| 96 | .map(|task| task.task_id) |
| 97 | .collect(); |
| 98 | for task_id in pending { |
| 99 | let _ = self.subagent_tasks.cancel(&task_id).await; |
| 100 | } |
| 101 | |
| 102 | // 4. Cancel pending HITL confirmations. |
| 103 | if let Some(manager) = &self.confirmation_manager { |
| 104 | let _ = manager.cancel_all().await; |
| 105 | } |
| 106 | |
| 107 | tracing::info!(session_id = %self.session_id, "AgentSession closed"); |
| 108 | } |
| 109 | } |