diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-21 20:47:14 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-21 20:47:14 +0300 |
| commit | 28360107c1bfab57fb0de99d74bfa48e74423ca8 (patch) | |
| tree | 30f9d953e48fb81b32f2a663500c6cff6f447f8f /src/server/headless/notifications.rs | |
| parent | 309749ad65f3aa596f077ec23a1bf3ee428b7a04 (diff) | |
fix: distinguish agent completion from startup and session changes (#4457)
refs #3338
refs #3990
refs #3916
Diffstat (limited to 'src/server/headless/notifications.rs')
| -rw-r--r-- | src/server/headless/notifications.rs | 80 |
1 files changed, 20 insertions, 60 deletions
diff --git a/src/server/headless/notifications.rs b/src/server/headless/notifications.rs index 722f95c5..a575cfe1 100644 --- a/src/server/headless/notifications.rs +++ b/src/server/headless/notifications.rs @@ -19,20 +19,6 @@ impl HeadlessServer { .unwrap_or(crate::detect::AgentState::Unknown) } - fn pane_effective_agent_label(&self, pane_id: crate::layout::PaneId) -> Option<String> { - self.app.state.workspaces.iter().find_map(|ws| { - ws.tabs.iter().find_map(|tab| { - let pane = tab.panes.get(&pane_id)?; - self.app - .state - .terminals - .get(&pane.attached_terminal_id) - .and_then(|terminal| terminal.effective_agent_label()) - .map(str::to_string) - }) - }) - } - fn forward_semantic_agent_notification( &mut self, update: &crate::app::actions::PaneStateUpdate, @@ -61,13 +47,9 @@ impl HeadlessServer { agent_label: Option<&str>, known_agent: Option<crate::detect::Agent>, ) -> bool { - let Some(kind) = crate::app::actions::notification_toast_for_state_change_with_agent_labels( - false, - previous_state, - state, - previous_agent_label, - agent_label, - ) else { + let Some(kind) = + crate::app::actions::notification_toast_for_state_change(false, previous_state, state) + else { return false; }; let Some(workspace) = self.app.state.workspaces.get(ws_idx) else { @@ -142,15 +124,11 @@ impl HeadlessServer { self.active_tab_suppresses_notifications(is_active_tab); if !update.suppress_completion && self.app.state.sound.allows(update.known_agent) { - if let Some(sound) = - crate::app::actions::notification_sound_for_state_change_with_agent_labels( - suppress_active_tab_notifications, - update.previous_state, - update.state, - update.previous_agent_label.as_deref(), - update.agent_label.as_deref(), - ) - { + if let Some(sound) = crate::app::actions::notification_sound_for_state_change( + suppress_active_tab_notifications, + update.previous_state, + update.state, + ) { self.send_notify_to_foreground_client( protocol::NotifyKind::Sound, sound_notify_message(sound), @@ -360,11 +338,8 @@ impl HeadlessServer { let pane_id_val = *pane_id; let agent_val = *agent; - // Find the previous effective state of this pane before the event - // is processed. Notifications must follow effective state changes, - // not raw fallback reports that may be masked by hook authority. + // Notifications follow effective changes, not fallback reports masked by hooks. let prev_state = self.pane_effective_state(pane_id_val); - let prev_agent_label = self.pane_effective_agent_label(pane_id_val); // Handle the state change (updates pane state, sets toast on AppState). // Headless mode disables local sound playback separately from the @@ -396,21 +371,16 @@ impl HeadlessServer { self.active_tab_suppresses_notifications(is_active_tab); let next_state = self.pane_effective_state(pane_id_val); - let next_agent_label = self.pane_effective_agent_label(pane_id_val); if !suppress_completion && self.app.state.toast_config.delay_seconds == 0 && self.app.state.sound.allows(agent_val) { - if let Some(sound) = - crate::app::actions::notification_sound_for_state_change_with_agent_labels( - suppress_active_tab_notifications, - prev_state, - next_state, - prev_agent_label.as_deref(), - next_agent_label.as_deref(), - ) - { + if let Some(sound) = crate::app::actions::notification_sound_for_state_change( + suppress_active_tab_notifications, + prev_state, + next_state, + ) { self.send_notify_to_foreground_client( protocol::NotifyKind::Sound, sound_notify_message(sound), @@ -437,7 +407,6 @@ impl HeadlessServer { suppress_active_tab_notifications, prev_state, next_state, - prev_agent_label.as_deref(), ) } } else { @@ -465,11 +434,8 @@ impl HeadlessServer { let pane_id_val = *pane_id; let agent_val = crate::detect::parse_agent_label(agent_label); - // Capture the previous effective state for this pane. Hook reports - // are already folded into pane.state; raw hook transitions must not - // produce a second notification path. + // Hook reports are already folded into the effective state. let prev_state = self.pane_effective_state(pane_id_val); - let prev_agent_label = self.pane_effective_agent_label(pane_id_val); self.sync_foreground_client_state(); let pane_updates = self.app.handle_internal_event_with_pane_updates(ev); @@ -499,21 +465,16 @@ impl HeadlessServer { self.active_tab_suppresses_notifications(is_active_tab); let next_state = self.pane_effective_state(pane_id_val); - let next_agent_label = self.pane_effective_agent_label(pane_id_val); if !suppress_completion && self.app.state.toast_config.delay_seconds == 0 && self.app.state.sound.allows(agent_val) { - if let Some(sound) = - crate::app::actions::notification_sound_for_state_change_with_agent_labels( - suppress_active_tab_notifications, - prev_state, - next_state, - prev_agent_label.as_deref(), - next_agent_label.as_deref(), - ) - { + if let Some(sound) = crate::app::actions::notification_sound_for_state_change( + suppress_active_tab_notifications, + prev_state, + next_state, + ) { self.send_notify_to_foreground_client( protocol::NotifyKind::Sound, sound_notify_message(sound), @@ -540,7 +501,6 @@ impl HeadlessServer { suppress_active_tab_notifications, prev_state, next_state, - prev_agent_label.as_deref(), ) } } else { |
