diff --git a/app/src/ai/conversation_details_panel.rs b/app/src/ai/conversation_details_panel.rs index b77c6ed9..c928af00 100644 --- a/app/src/ai/conversation_details_panel.rs +++ b/app/src/ai/conversation_details_panel.rs @@ -28,7 +28,6 @@ use warpui::{ }; use crate::ai::agent::api::ServerConversationToken; -#[cfg(target_family = "wasm")] use crate::ai::agent::conversation::AIConversation; use crate::ai::agent::conversation::{AIConversationId, ConversationStatus}; use crate::ai::agent_conversations_model::AgentRunDisplayStatus; @@ -42,7 +41,6 @@ use crate::ai::blocklist::BlocklistAIHistoryModel; use crate::ai::cloud_environments::{AmbientAgentEnvironment, CloudAmbientAgentEnvironment}; use crate::ai::harness_display; use crate::appearance::Appearance; -#[cfg(target_family = "wasm")] use crate::auth::UserUid; use crate::notebooks::NotebookId; use crate::send_telemetry_from_ctx; @@ -64,7 +62,6 @@ use crate::view_components::copyable_text_field::{ }; use crate::view_components::DismissibleToast; use crate::workspace::{ForkedConversationDestination, ToastStack, WorkspaceAction}; -#[cfg(target_family = "wasm")] use crate::workspaces::user_profiles::UserProfiles; const FIELD_SPACING: f32 = 16.0; @@ -161,7 +158,6 @@ impl CreatorInfo { } /// Create a CreatorInfo with just the first character as a fallback. - #[cfg(target_family = "wasm")] pub fn from_uid_fallback(uid: &str) -> Self { let first_char = uid.chars().next().unwrap_or('?').to_uppercase().to_string(); Self::new(first_char, None) @@ -224,7 +220,10 @@ impl ConversationDetailsData { .and_then(|metadata| metadata.initial_working_directory.clone()) }) } - #[cfg(target_family = "wasm")] + + /// Build details data from an in-memory `AIConversation`. Used both by the WASM + /// transcript/shared-session details panel and by the native pane-level details panel + /// when the active conversation is a local (non-cloud) Warp Agent run. pub fn from_conversation(conversation: &AIConversation, app: &AppContext) -> Self { let mut directory = None; let mut conversation_id = None; diff --git a/app/src/ai/conversation_details_panel_tests.rs b/app/src/ai/conversation_details_panel_tests.rs index aecfd76a..1e1c3ee4 100644 --- a/app/src/ai/conversation_details_panel_tests.rs +++ b/app/src/ai/conversation_details_panel_tests.rs @@ -5,14 +5,14 @@ use persistence::model::AgentConversationData; use warp_cli::agent::Harness; use warp_core::features::FeatureFlag; use warp_multi_agent_api as api; -use warpui::{App, EntityId}; +use warpui::{App, EntityId, SingletonEntity}; use crate::ai::agent::conversation::{AIConversation, AIConversationId}; use crate::ai::ambient_agents::task::{AgentConfigSnapshot, HarnessConfig, TaskCreatorInfo}; use crate::ai::ambient_agents::{AmbientAgentTask, AmbientAgentTaskState}; use crate::ai::blocklist::history_model::BlocklistAIHistoryModel; -use super::{ConversationDetailsData, PanelMode}; +use super::{ConversationDetailsData, CreditsInfo, PanelMode}; fn create_test_task(task_id: &str) -> AmbientAgentTask { let now = Utc::now(); @@ -224,6 +224,78 @@ fn test_from_task_resolves_harness() { }); } +#[test] +fn test_from_conversation_populates_local_conversation_fields() { + // Locks in that `ConversationDetailsData::from_conversation` works on native + // and surfaces the conversation-derived fields the conversation details panel + // renders for local Warp Agent runs (APP-3595). + App::test((), |mut app| async move { + let history_model = app.add_singleton_model(|_| BlocklistAIHistoryModel::new(vec![], &[])); + + let conversation_id = AIConversationId::new(); + let directory = "/tmp/local-conversation-directory"; + let conversation = create_restored_conversation( + conversation_id, + "root-task", + directory, + AgentConversationData { + server_conversation_token: None, + conversation_usage_metadata: None, + reverted_action_ids: None, + forked_from_server_conversation_token: None, + artifacts_json: None, + parent_agent_id: None, + agent_name: None, + parent_conversation_id: None, + run_id: None, + autoexecute_override: None, + last_event_sequence: None, + is_remote_child: false, + }, + ); + + history_model.update(&mut app, |model, ctx| { + model.restore_conversations(EntityId::new(), vec![conversation], ctx); + }); + + app.update(|ctx| { + let conversation = BlocklistAIHistoryModel::as_ref(ctx) + .conversation(&conversation_id) + .expect("conversation should be present"); + let data = ConversationDetailsData::from_conversation(conversation, ctx); + + // Mode should be Conversation with the working directory and no server-side + // conversation id (since this conversation was restored without a server token). + match &data.mode { + PanelMode::Conversation { + directory: panel_directory, + server_conversation_id, + ai_conversation_id, + status, + } => { + assert_eq!(panel_directory.as_deref(), Some(directory)); + assert!(server_conversation_id.is_none()); + // `from_conversation` does not have access to the in-memory + // AIConversationId; that field is populated only by the + // management view path (`from_conversation_metadata`). + assert!(ai_conversation_id.is_none()); + assert!(status.is_some()); + } + PanelMode::Task { .. } => { + panic!("expected Conversation mode for a local conversation") + } + } + + assert_eq!(data.title, "test query"); + assert_eq!(data.source_prompt.as_deref(), Some("test query")); + assert!(matches!( + data.credits, + Some(CreditsInfo::LocalConversation(_)) + )); + }); + }); +} + #[test] fn test_from_task_includes_linked_directory_when_server_token_matches() { App::test((), |mut app| async move { diff --git a/app/src/terminal/view.rs b/app/src/terminal/view.rs index b5ab8ebe..4d30c0b2 100644 --- a/app/src/terminal/view.rs +++ b/app/src/terminal/view.rs @@ -2748,18 +2748,21 @@ pub struct TerminalView { ambient_agent_view_model: Option>, pending_cloud_followup_task_id: Option, - /// Cloud mode conversation details panel (side panel showing task metadata). - cloud_mode_details_panel: + /// Conversation details panel (side panel showing conversation/task metadata). + /// Available for cloud Oz runs and for any active local AI conversation. + conversation_details_panel: ViewHandle, - /// Whether the cloud mode details panel is currently open. - is_cloud_mode_details_panel_open: bool, + /// Whether the conversation details panel is currently open. + is_conversation_details_panel_open: bool, /// Whether we've already auto-opened the panel when the agent started running. - /// This prevents re-opening the panel if the user manually closes it. - has_auto_opened_cloud_mode_details_panel: bool, - /// Mouse state handle for the cloud mode details panel toggle button in the pane header. + /// This prevents re-opening the panel if the user manually closes it. Only set + /// by the cloud-mode auto-open path; local conversations require the user to + /// click the pane-header toggle button to open the panel. + has_auto_opened_conversation_details_panel: bool, + /// Mouse state handle for the conversation details panel toggle button in the pane header. /// Only available on non-WASM platforms (WASM uses a per-window button instead). #[cfg(not(target_arch = "wasm32"))] - cloud_mode_details_panel_toggle_mouse_state: warpui::elements::MouseStateHandle, + conversation_details_panel_toggle_mouse_state: warpui::elements::MouseStateHandle, /// Mouse state handle for the ambient agent cancel button in the pane header. ambient_agent_cancel_mouse_state: warpui::elements::MouseStateHandle, @@ -3493,17 +3496,15 @@ impl TerminalView { ctx.subscribe_to_model(&ai_controller, |me, handle, event, ctx| { me.handle_ai_controller_event(handle, event, ctx); - // Refresh cloud mode details panel when agent output completes (may include new artifacts) + // Refresh the conversation details panel when agent output completes + // (may include new artifacts, run time, credits). This applies to both + // cloud-task-backed and local AI conversations as long as the panel is open. if matches!( event, BlocklistAIControllerEvent::FinishedReceivingOutput { .. } - ) && me.is_cloud_mode_details_panel_open - && me - .ambient_agent_view_model - .as_ref() - .is_some_and(|model| model.as_ref(ctx).is_ambient_agent()) + ) && me.is_conversation_details_panel_open { - me.fetch_and_update_cloud_mode_details_panel(ctx); + me.fetch_and_update_conversation_details_panel(ctx); } }); @@ -3528,13 +3529,13 @@ impl TerminalView { ); // Only refresh panel if it's currently open (avoids unnecessary work) if should_refresh_details_panel - && me.is_cloud_mode_details_panel_open + && me.is_conversation_details_panel_open && me .ambient_agent_view_model .as_ref() .is_some_and(|model| model.as_ref(ctx).is_ambient_agent()) { - me.fetch_and_update_cloud_mode_details_panel(ctx); + me.fetch_and_update_conversation_details_panel(ctx); ctx.notify(); } }, @@ -4029,19 +4030,19 @@ impl TerminalView { }) }); - // Cloud mode conversation details panel - let cloud_mode_details_panel = ctx.add_typed_action_view(|ctx| { + // Conversation details panel (cloud Oz runs and any active local AI conversation). + let conversation_details_panel = ctx.add_typed_action_view(|ctx| { crate::ai::conversation_details_panel::ConversationDetailsPanel::new( false, // don't show "Open" button since we're already viewing the conversation 320.0, // initial width ctx, ) }); - ctx.subscribe_to_view(&cloud_mode_details_panel, |me, _, event, ctx| { + ctx.subscribe_to_view(&conversation_details_panel, |me, _, event, ctx| { use crate::ai::conversation_details_panel::ConversationDetailsPanelEvent; match event { ConversationDetailsPanelEvent::Close => { - me.is_cloud_mode_details_panel_open = false; + me.is_conversation_details_panel_open = false; ctx.notify(); } ConversationDetailsPanelEvent::OpenPlanNotebook { notebook_uid } => { @@ -4183,12 +4184,12 @@ impl TerminalView { orchestration_pill_bar, is_using_conversation_for_pane_header_title: false, ambient_agent_view_model, + conversation_details_panel, + is_conversation_details_panel_open: false, + has_auto_opened_conversation_details_panel: false, pending_cloud_followup_task_id: None, - cloud_mode_details_panel, - is_cloud_mode_details_panel_open: false, - has_auto_opened_cloud_mode_details_panel: false, #[cfg(not(target_arch = "wasm32"))] - cloud_mode_details_panel_toggle_mouse_state: Default::default(), + conversation_details_panel_toggle_mouse_state: Default::default(), ambient_agent_cancel_mouse_state: Default::default(), active_init_project_model: None, is_pending_aws_login: false, @@ -5095,6 +5096,25 @@ impl TerminalView { { return; } + // If the conversation details panel is open and showing an active local + // AI conversation in this terminal view, refresh its data when status, + // artifacts, exchanges, or metadata change. Mirrors the WASM transcript + // panel refresh logic in `Workspace::handle_history_model_event` for + // APP-3595. + if self.is_conversation_details_panel_open + && matches!( + event, + BlocklistAIHistoryEvent::UpdatedConversationStatus { .. } + | BlocklistAIHistoryEvent::UpdatedConversationMetadata { .. } + | BlocklistAIHistoryEvent::UpdatedConversationArtifacts { .. } + | BlocklistAIHistoryEvent::UpdatedStreamingExchange { .. } + | BlocklistAIHistoryEvent::AppendedExchange { .. } + | BlocklistAIHistoryEvent::SetActiveConversation { .. } + | BlocklistAIHistoryEvent::RestoredConversations { .. } + ) + { + self.fetch_and_update_conversation_details_panel(ctx); + } match event { BlocklistAIHistoryEvent::AppendedExchange { exchange_id, @@ -6685,14 +6705,26 @@ impl TerminalView { self.ambient_agent_task_id_for_details_panel_from_model(&model, app) } - fn can_show_cloud_mode_details_ui_for_task_id(task_id: Option) -> bool { - FeatureFlag::CloudMode.is_enabled() && task_id.is_some() + /// Whether the conversation details side panel should be available in the + /// pane header / pane layout for this terminal view. + fn can_show_conversation_details_ui_from_model( + &self, + model: &TerminalModel, + app: &AppContext, + ) -> bool { + self.ambient_agent_task_id_for_details_panel_from_model(model, app) + .is_some() + || BlocklistAIHistoryModel::as_ref(app) + .active_conversation(self.view_id) + .is_some_and(|conversation| !conversation.is_empty()) } - fn can_show_cloud_mode_details_ui(&self, app: &AppContext) -> bool { - Self::can_show_cloud_mode_details_ui_for_task_id( - self.ambient_agent_task_id_for_details_panel(app), - ) + /// Convenience wrapper around + /// [`Self::can_show_conversation_details_ui_from_model`] that locks the + /// terminal model. Do not call from contexts that already hold the lock. + fn can_show_conversation_details_ui(&self, app: &AppContext) -> bool { + let model = self.model.lock(); + self.can_show_conversation_details_ui_from_model(&model, app) } fn maybe_insert_tombstone_for_non_running_shared_ambient_task( @@ -24624,7 +24656,7 @@ impl TypedActionView for TerminalView { | ExitAgentView | EnterCloudAgentView | StartNewAgentConversation - | ToggleCloudModeDetailsPanel + | ToggleConversationDetailsPanel | CancelAmbientAgentTask | OpenInlineHistoryMenu | OpenModelSelector @@ -25640,11 +25672,11 @@ impl TypedActionView for TerminalView { AwsCliNotInstalledBanner(action) => { self.handle_aws_cli_not_installed_banner_action(*action, ctx); } - ToggleCloudModeDetailsPanel => { - let will_open = !self.is_cloud_mode_details_panel_open; - self.is_cloud_mode_details_panel_open = will_open; + ToggleConversationDetailsPanel => { + let will_open = !self.is_conversation_details_panel_open; + self.is_conversation_details_panel_open = will_open; if will_open { - self.fetch_and_update_cloud_mode_details_panel(ctx); + self.fetch_and_update_conversation_details_panel(ctx); } ctx.notify(); } @@ -25700,8 +25732,6 @@ impl View for TerminalView { let appearance = Appearance::as_ref(app); let semantic_selection = SemanticSelection::as_ref(app); let model = self.model.lock(); - let ambient_agent_task_id_for_details_panel = - self.ambient_agent_task_id_for_details_panel_from_model(&model, app); let input_mode = if FeatureFlag::AgentView.is_enabled() && self.agent_view_controller.as_ref(app).is_fullscreen() { @@ -26182,18 +26212,19 @@ impl View for TerminalView { element }; - // Wrap with cloud mode details panel on the right if open - // On WASM, the panel is rendered in the wasm_view instead + // Wrap with conversation details panel on the right if open. + // On WASM, the panel is rendered in the wasm_view instead. + // + // Use the `_from_model` variant since `render` already holds + // `self.model.lock()` and the task-id lookup would otherwise re-lock. let should_show_panel = !cfg!(target_family = "wasm") - && self.is_cloud_mode_details_panel_open - && Self::can_show_cloud_mode_details_ui_for_task_id( - ambient_agent_task_id_for_details_panel, - ); + && self.is_conversation_details_panel_open + && self.can_show_conversation_details_ui_from_model(&model, app); if should_show_panel { // Wrap panel with agent view background for visual consistency let panel_with_background = - Container::new(ChildView::new(&self.cloud_mode_details_panel).finish()) + Container::new(ChildView::new(&self.conversation_details_panel).finish()) .with_background(agent_view_bg_fill(app)) .finish(); diff --git a/app/src/terminal/view/action.rs b/app/src/terminal/view/action.rs index 54a82e92..20286bb5 100644 --- a/app/src/terminal/view/action.rs +++ b/app/src/terminal/view/action.rs @@ -412,7 +412,7 @@ pub enum TerminalAction { EnterCloudAgentView, StartNewAgentConversation, /// Toggle the cloud mode conversation details panel - ToggleCloudModeDetailsPanel, + ToggleConversationDetailsPanel, /// Cancel the ambient agent task while it's loading CancelAmbientAgentTask, OpenInlineHistoryMenu, @@ -701,7 +701,7 @@ impl fmt::Debug for TerminalAction { ExitAgentView => write!(f, "ExitAgentView"), EnterCloudAgentView => write!(f, "EnterCloudAgentView"), StartNewAgentConversation => write!(f, "StartNewAgentConversation"), - ToggleCloudModeDetailsPanel => write!(f, "ToggleCloudModeDetailsPanel"), + ToggleConversationDetailsPanel => write!(f, "ToggleConversationDetailsPanel"), CancelAmbientAgentTask => write!(f, "CancelAmbientAgentTask"), OpenInlineHistoryMenu => write!(f, "OpenInlineHistoryMenu"), OpenModelSelector => write!(f, "OpenModelSelector"), diff --git a/app/src/terminal/view/ambient_agent/view_impl.rs b/app/src/terminal/view/ambient_agent/view_impl.rs index 3742b9ea..5f4690b1 100644 --- a/app/src/terminal/view/ambient_agent/view_impl.rs +++ b/app/src/terminal/view/ambient_agent/view_impl.rs @@ -244,7 +244,7 @@ impl TerminalView { self.pending_cloud_followup_task_id = None; } // Auto-open details panel for local cloud mode once the session is ready. - self.maybe_auto_open_cloud_mode_details_panel(ctx); + self.maybe_auto_open_conversation_details_panel(ctx); // Re-render to hide the loading screen now that the session is ready. ctx.emit(TerminalViewEvent::TerminalViewStateChanged); ctx.notify(); @@ -273,8 +273,8 @@ impl TerminalView { ctx, ); // Refresh the details panel to show failed status - if self.is_cloud_mode_details_panel_open { - self.fetch_and_update_cloud_mode_details_panel(ctx); + if self.is_conversation_details_panel_open { + self.fetch_and_update_conversation_details_panel(ctx); } // Re-render to show the error state in the footer. ctx.emit(TerminalViewEvent::TerminalViewStateChanged); @@ -326,8 +326,8 @@ impl TerminalView { ctx, ); // Refresh the details panel to show cancelled status - if self.is_cloud_mode_details_panel_open { - self.fetch_and_update_cloud_mode_details_panel(ctx); + if self.is_conversation_details_panel_open { + self.fetch_and_update_conversation_details_panel(ctx); } // Re-render to show the cancelled state in the footer. ctx.emit(TerminalViewEvent::TerminalViewStateChanged); @@ -874,52 +874,71 @@ impl TerminalView { } } - /// Fetches task data and updates the cloud mode details panel. - pub(in crate::terminal::view) fn fetch_and_update_cloud_mode_details_panel( + /// Fetches task data and updates the conversation details panel. + /// + /// Prefers cloud `AmbientAgentTask` data when this terminal view has an + /// associated task ID. Otherwise falls back to populating the panel from + /// the active local `AIConversation`, so the same panel can surface + /// conversation metadata for non-cloud Warp Agent runs (APP-3595). + pub(in crate::terminal::view) fn fetch_and_update_conversation_details_panel( &mut self, ctx: &mut ViewContext, ) { - let Some(task_id) = self.ambient_agent_task_id_for_details_panel(ctx) else { - log::warn!("fetch_and_update_cloud_mode_details_panel called without task_id"); - return; - }; + if let Some(task_id) = self.ambient_agent_task_id_for_details_panel(ctx) { + let task = crate::ai::agent_conversations_model::AgentConversationsModel::handle(ctx) + .update(ctx, |model, ctx| { + model.get_or_async_fetch_task_data(&task_id, ctx) + }); - let task = crate::ai::agent_conversations_model::AgentConversationsModel::handle(ctx) - .update(ctx, |model, ctx| { - model.get_or_async_fetch_task_data(&task_id, ctx) + let data = task + .as_ref() + .map(|task| ConversationDetailsData::from_task(task, None, None, ctx)) + .unwrap_or_else(|| ConversationDetailsData::from_task_id(task_id)); + self.conversation_details_panel.update(ctx, |panel, ctx| { + panel.set_conversation_details(data, ctx); }); + return; + } - let data = task - .as_ref() - .map(|task| ConversationDetailsData::from_task(task, None, None, ctx)) - .unwrap_or_else(|| ConversationDetailsData::from_task_id(task_id)); - self.cloud_mode_details_panel.update(ctx, |panel, ctx| { - panel.set_conversation_details(data, ctx); - }); + // No backing cloud task — populate from the active local conversation, if any. + let view_id = self.id(); + let history_model = BlocklistAIHistoryModel::handle(ctx); + let data = history_model + .as_ref(ctx) + .active_conversation(view_id) + .map(|conversation| ConversationDetailsData::from_conversation(conversation, ctx)); + + if let Some(data) = data { + self.conversation_details_panel.update(ctx, |panel, ctx| { + panel.set_conversation_details(data, ctx); + }); + } } - pub(in crate::terminal::view) fn refresh_cloud_mode_details_panel_if_open( + pub(in crate::terminal::view) fn refresh_conversation_details_panel_if_open( &mut self, ctx: &mut ViewContext, ) { - if self.is_cloud_mode_details_panel_open && self.can_show_cloud_mode_details_ui(ctx) { - self.fetch_and_update_cloud_mode_details_panel(ctx); + if self.is_conversation_details_panel_open && self.can_show_conversation_details_ui(ctx) { + self.fetch_and_update_conversation_details_panel(ctx); ctx.notify(); } } - /// Auto-opens the cloud mode details panel once. - /// This is used for local cloud mode sessions (after SessionReady) and shared ambient sessions (after join). - pub(in crate::terminal::view) fn maybe_auto_open_cloud_mode_details_panel( + /// Auto-opens the conversation details panel once for cloud mode runs. + /// This is used for local cloud mode sessions (after `SessionReady`) and + /// shared ambient sessions (after join). Local non-cloud conversations + /// require an explicit user click on the pane-header toggle button. + pub(in crate::terminal::view) fn maybe_auto_open_conversation_details_panel( &mut self, ctx: &mut ViewContext, ) { - if self.has_auto_opened_cloud_mode_details_panel { + if self.has_auto_opened_conversation_details_panel { return; } - self.is_cloud_mode_details_panel_open = true; - self.has_auto_opened_cloud_mode_details_panel = true; - self.fetch_and_update_cloud_mode_details_panel(ctx); + self.is_conversation_details_panel_open = true; + self.has_auto_opened_conversation_details_panel = true; + self.fetch_and_update_conversation_details_panel(ctx); ctx.notify(); } } diff --git a/app/src/terminal/view/pane_impl.rs b/app/src/terminal/view/pane_impl.rs index 48b24577..160d86ec 100644 --- a/app/src/terminal/view/pane_impl.rs +++ b/app/src/terminal/view/pane_impl.rs @@ -425,34 +425,35 @@ impl TerminalView { let mut icon_button_count: u32 = 0; - if FeatureFlag::CloudMode.is_enabled() { - let is_waiting_for_session = self + // Cloud-mode-only ambient agent cancel button is shown while we're waiting + // for the session to be ready. + let is_waiting_for_session = FeatureFlag::CloudMode.is_enabled() + && self .ambient_agent_view_model .as_ref() .is_some_and(|model| model.as_ref(app).is_waiting_for_session()); - let button_element = if is_waiting_for_session { - Some(self.render_ambient_agent_cancel_button(app)) - } else if self.can_show_cloud_mode_details_ui(app) { - #[cfg(not(target_arch = "wasm32"))] - { - Some(self.render_cloud_mode_details_toggle_button(app)) - } - #[cfg(target_arch = "wasm32")] - { - None - } - } else { + let button_element = if is_waiting_for_session { + Some(self.render_ambient_agent_cancel_button(app)) + } else if self.can_show_conversation_details_ui(app) { + #[cfg(not(target_arch = "wasm32"))] + { + Some(self.render_conversation_details_toggle_button(app)) + } + #[cfg(target_arch = "wasm32")] + { None - }; + } + } else { + None + }; - if let Some(button) = button_element { - icon_button_count += 1; - if let Some(existing) = left_of_overflow { - left_of_overflow = - Some(Flex::row().with_child(existing).with_child(button).finish()); - } else { - left_of_overflow = Some(button); - } + if let Some(button) = button_element { + icon_button_count += 1; + if let Some(existing) = left_of_overflow { + left_of_overflow = + Some(Flex::row().with_child(existing).with_child(button).finish()); + } else { + left_of_overflow = Some(button); } } @@ -772,13 +773,13 @@ impl TerminalView { .finish() } - /// Render the info button for toggling the cloud mode details panel. + /// Render the info button for toggling the conversation details panel. /// Only available on non-WASM platforms (WASM uses a per-window button instead). #[cfg(not(target_arch = "wasm32"))] - fn render_cloud_mode_details_toggle_button(&self, app: &AppContext) -> Box { + fn render_conversation_details_toggle_button(&self, app: &AppContext) -> Box { let appearance = Appearance::as_ref(app); let theme = appearance.theme(); - let is_open = self.is_cloud_mode_details_panel_open; + let is_open = self.is_conversation_details_panel_open; let ui_builder = appearance.ui_builder().clone(); // Use main text color when panel is open (hover-like appearance), sub color when closed @@ -792,7 +793,7 @@ impl TerminalView { appearance, icons::Icon::Info, is_open, // show active background when panel is open - self.cloud_mode_details_panel_toggle_mouse_state.clone(), + self.conversation_details_panel_toggle_mouse_state.clone(), icon_color, ); @@ -818,7 +819,7 @@ impl TerminalView { .build() .on_click(|ctx, _, _| { ctx.dispatch_typed_action::>( - PaneHeaderAction::CustomAction(TerminalAction::ToggleCloudModeDetailsPanel), + PaneHeaderAction::CustomAction(TerminalAction::ToggleConversationDetailsPanel), ); }) .finish() diff --git a/app/src/terminal/view/shared_session/view_impl.rs b/app/src/terminal/view/shared_session/view_impl.rs index 5d069e9f..20bbcd14 100644 --- a/app/src/terminal/view/shared_session/view_impl.rs +++ b/app/src/terminal/view/shared_session/view_impl.rs @@ -705,7 +705,7 @@ impl TerminalView { if FeatureFlag::CloudMode.is_enabled() && matches!(source_type, SessionSourceType::AmbientAgent { .. }) { - self.maybe_auto_open_cloud_mode_details_panel(ctx); + self.maybe_auto_open_conversation_details_panel(ctx); } send_telemetry_from_ctx!( @@ -810,7 +810,7 @@ impl TerminalView { model.mark_task_execution_ended(task_id, ctx); }); } - self.refresh_cloud_mode_details_panel_if_open(ctx); + self.refresh_conversation_details_panel_if_open(ctx); if !FeatureFlag::HandoffCloudCloud.is_enabled() || !FeatureFlag::CloudModeSetupV2.is_enabled() || self.conversation_ended_tombstone_view_id.is_some() diff --git a/app/src/terminal/view/shared_session/view_impl_test.rs b/app/src/terminal/view/shared_session/view_impl_test.rs index a5b84ca7..b5d334be 100644 --- a/app/src/terminal/view/shared_session/view_impl_test.rs +++ b/app/src/terminal/view/shared_session/view_impl_test.rs @@ -848,10 +848,10 @@ fn test_on_ambient_agent_execution_ended_refreshes_open_details_panel_to_termina model.enter_viewing_existing_session(task_id, ctx); }); - view.is_cloud_mode_details_panel_open = true; - view.fetch_and_update_cloud_mode_details_panel(ctx); + view.is_conversation_details_panel_open = true; + view.fetch_and_update_conversation_details_panel(ctx); assert_eq!( - view.cloud_mode_details_panel + view.conversation_details_panel .as_ref(ctx) .task_display_status_for_test(), Some(AgentRunDisplayStatus::TaskInProgress) @@ -859,7 +859,7 @@ fn test_on_ambient_agent_execution_ended_refreshes_open_details_panel_to_termina view.on_ambient_agent_execution_ended(ctx); assert_eq!( - view.cloud_mode_details_panel + view.conversation_details_panel .as_ref(ctx) .task_display_status_for_test(), Some(AgentRunDisplayStatus::ConversationSucceeded)