From 2c375e2e0a310266002abc483945f71f776be7a0 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:50:52 -0300 Subject: [PATCH] agent_ui: Ensure message editor placeholder text is accurate (#42375) This PR creates a dedicated function for the agent panel message editor's placeholder text so that we can wait for the agent initialization to capture whether they support slash commands or not. On the one (nice) hand, this allow us to stop matching agents by name and make this a bit more generic. On the other (bad) hand, the "/ for commands" bit should take a little second to show up because we can only know whether an agent supports it after it is initialized. This is particularly relevant now that we have agents coming from extensions and for them, we would obviously not be able to match by name. Release Notes: - agent: Fixed agent panel message editor's placeholder text by making it more accurate as to whether agents support slash commands, particularly those coming from extensions. --- crates/agent_ui/src/acp/message_editor.rs | 11 ++++++++ crates/agent_ui/src/acp/thread_view.rs | 34 ++++++++++++++--------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/crates/agent_ui/src/acp/message_editor.rs b/crates/agent_ui/src/acp/message_editor.rs index 7789564d3b8b0c03ebb207e634d718a359befafe..4f919a6c0425e48575d09380339730d7ddb26172 100644 --- a/crates/agent_ui/src/acp/message_editor.rs +++ b/crates/agent_ui/src/acp/message_editor.rs @@ -1195,6 +1195,17 @@ impl MessageEditor { self.editor.read(cx).text(cx) } + pub fn set_placeholder_text( + &mut self, + placeholder: &str, + window: &mut Window, + cx: &mut Context, + ) { + self.editor.update(cx, |editor, cx| { + editor.set_placeholder_text(placeholder, window, cx); + }); + } + #[cfg(test)] pub fn set_text(&mut self, text: &str, window: &mut Window, cx: &mut Context) { self.editor.update(cx, |editor, cx| { diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 306976473d772f55cfdf1ee9caa65eab4f1d5552..17daf5a18e97829d5e4d64d30d266b5d5d271e7b 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -337,19 +337,7 @@ impl AcpThreadView { let prompt_capabilities = Rc::new(RefCell::new(acp::PromptCapabilities::default())); let available_commands = Rc::new(RefCell::new(vec![])); - let placeholder = if agent.name() == "Zed Agent" { - format!("Message the {} — @ to include context", agent.name()) - } else if agent.name() == "Claude Code" - || agent.name() == "Codex" - || !available_commands.borrow().is_empty() - { - format!( - "Message {} — @ to include context, / for commands", - agent.name() - ) - } else { - format!("Message {} — @ to include context", agent.name()) - }; + let placeholder = placeholder_text(agent.name().as_ref(), false); let message_editor = cx.new(|cx| { let mut editor = MessageEditor::new( @@ -1456,7 +1444,14 @@ impl AcpThreadView { }); } + let has_commands = !available_commands.is_empty(); self.available_commands.replace(available_commands); + + let new_placeholder = placeholder_text(self.agent.name().as_ref(), has_commands); + + self.message_editor.update(cx, |editor, cx| { + editor.set_placeholder_text(&new_placeholder, window, cx); + }); } AcpThreadEvent::ModeUpdated(_mode) => { // The connection keeps track of the mode @@ -5708,6 +5703,19 @@ fn loading_contents_spinner(size: IconSize) -> AnyElement { .into_any_element() } +fn placeholder_text(agent_name: &str, has_commands: bool) -> String { + if agent_name == "Zed Agent" { + format!("Message the {} — @ to include context", agent_name) + } else if has_commands { + format!( + "Message {} — @ to include context, / for commands", + agent_name + ) + } else { + format!("Message {} — @ to include context", agent_name) + } +} + impl Focusable for AcpThreadView { fn focus_handle(&self, cx: &App) -> FocusHandle { match self.thread_state {