Port terminal
tool to agent2 (#35918)
Release Notes: - N/A --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
This commit is contained in:
parent
422e0a2eb7
commit
086ea3c619
13 changed files with 882 additions and 112 deletions
|
@ -1,17 +1,13 @@
|
|||
use acp_thread::{
|
||||
AcpThread, AcpThreadEvent, AgentThreadEntry, AssistantMessage, AssistantMessageChunk,
|
||||
LoadError, MentionPath, ThreadStatus, ToolCall, ToolCallContent, ToolCallStatus,
|
||||
};
|
||||
use acp_thread::{AgentConnection, Plan};
|
||||
use action_log::ActionLog;
|
||||
use agent_client_protocol as acp;
|
||||
use agent_servers::AgentServer;
|
||||
use agent_settings::{AgentSettings, NotifyWhenAgentWaiting};
|
||||
use audio::{Audio, Sound};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
use std::process::ExitStatus;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use action_log::ActionLog;
|
||||
use agent_client_protocol as acp;
|
||||
use buffer_diff::BufferDiff;
|
||||
use collections::{HashMap, HashSet};
|
||||
use editor::{
|
||||
|
@ -32,6 +28,11 @@ use markdown::{HeadingLevelStyles, Markdown, MarkdownElement, MarkdownStyle};
|
|||
use parking_lot::Mutex;
|
||||
use project::{CompletionIntent, Project};
|
||||
use settings::{Settings as _, SettingsStore};
|
||||
use std::{
|
||||
cell::RefCell, collections::BTreeMap, path::Path, process::ExitStatus, rc::Rc, sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use terminal_view::TerminalView;
|
||||
use text::{Anchor, BufferSnapshot};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
|
@ -41,11 +42,6 @@ use util::ResultExt;
|
|||
use workspace::{CollaboratorId, Workspace};
|
||||
use zed_actions::agent::{Chat, NextHistoryMessage, PreviousHistoryMessage};
|
||||
|
||||
use ::acp_thread::{
|
||||
AcpThread, AcpThreadEvent, AgentThreadEntry, AssistantMessage, AssistantMessageChunk,
|
||||
LoadError, MentionPath, ThreadStatus, ToolCall, ToolCallContent, ToolCallStatus,
|
||||
};
|
||||
|
||||
use crate::acp::completion_provider::{ContextPickerCompletionProvider, MentionSet};
|
||||
use crate::acp::message_history::MessageHistory;
|
||||
use crate::agent_diff::AgentDiff;
|
||||
|
@ -63,6 +59,7 @@ pub struct AcpThreadView {
|
|||
project: Entity<Project>,
|
||||
thread_state: ThreadState,
|
||||
diff_editors: HashMap<EntityId, Entity<Editor>>,
|
||||
terminal_views: HashMap<EntityId, Entity<TerminalView>>,
|
||||
message_editor: Entity<Editor>,
|
||||
message_set_from_history: Option<BufferSnapshot>,
|
||||
_message_editor_subscription: Subscription,
|
||||
|
@ -193,6 +190,7 @@ impl AcpThreadView {
|
|||
notifications: Vec::new(),
|
||||
notification_subscriptions: HashMap::default(),
|
||||
diff_editors: Default::default(),
|
||||
terminal_views: Default::default(),
|
||||
list_state: list_state.clone(),
|
||||
scrollbar_state: ScrollbarState::new(list_state).parent_entity(&cx.entity()),
|
||||
last_error: None,
|
||||
|
@ -676,6 +674,16 @@ impl AcpThreadView {
|
|||
entry_ix: usize,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.sync_diff_multibuffers(entry_ix, window, cx);
|
||||
self.sync_terminals(entry_ix, window, cx);
|
||||
}
|
||||
|
||||
fn sync_diff_multibuffers(
|
||||
&mut self,
|
||||
entry_ix: usize,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(multibuffers) = self.entry_diff_multibuffers(entry_ix, cx) else {
|
||||
return;
|
||||
|
@ -739,6 +747,50 @@ impl AcpThreadView {
|
|||
)
|
||||
}
|
||||
|
||||
fn sync_terminals(&mut self, entry_ix: usize, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let Some(terminals) = self.entry_terminals(entry_ix, cx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let terminals = terminals.collect::<Vec<_>>();
|
||||
|
||||
for terminal in terminals {
|
||||
if self.terminal_views.contains_key(&terminal.entity_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let terminal_view = cx.new(|cx| {
|
||||
let mut view = TerminalView::new(
|
||||
terminal.read(cx).inner().clone(),
|
||||
self.workspace.clone(),
|
||||
None,
|
||||
self.project.downgrade(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
view.set_embedded_mode(None, cx);
|
||||
view
|
||||
});
|
||||
|
||||
let entity_id = terminal.entity_id();
|
||||
cx.observe_release(&terminal, move |this, _, _| {
|
||||
this.terminal_views.remove(&entity_id);
|
||||
})
|
||||
.detach();
|
||||
|
||||
self.terminal_views.insert(entity_id, terminal_view);
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_terminals(
|
||||
&self,
|
||||
entry_ix: usize,
|
||||
cx: &App,
|
||||
) -> Option<impl Iterator<Item = Entity<acp_thread::Terminal>>> {
|
||||
let entry = self.thread()?.read(cx).entries().get(entry_ix)?;
|
||||
Some(entry.terminals().map(|terminal| terminal.clone()))
|
||||
}
|
||||
|
||||
fn authenticate(
|
||||
&mut self,
|
||||
method: acp::AuthMethodId,
|
||||
|
@ -1106,7 +1158,7 @@ impl AcpThreadView {
|
|||
_ => tool_call
|
||||
.content
|
||||
.iter()
|
||||
.any(|content| matches!(content, ToolCallContent::Diff { .. })),
|
||||
.any(|content| matches!(content, ToolCallContent::Diff(_))),
|
||||
};
|
||||
|
||||
let is_collapsible = !tool_call.content.is_empty() && !needs_confirmation;
|
||||
|
@ -1303,7 +1355,7 @@ impl AcpThreadView {
|
|||
cx: &Context<Self>,
|
||||
) -> AnyElement {
|
||||
match content {
|
||||
ToolCallContent::ContentBlock { content } => {
|
||||
ToolCallContent::ContentBlock(content) => {
|
||||
if let Some(md) = content.markdown() {
|
||||
div()
|
||||
.p_2()
|
||||
|
@ -1318,9 +1370,8 @@ impl AcpThreadView {
|
|||
Empty.into_any_element()
|
||||
}
|
||||
}
|
||||
ToolCallContent::Diff { diff, .. } => {
|
||||
self.render_diff_editor(&diff.read(cx).multibuffer())
|
||||
}
|
||||
ToolCallContent::Diff(diff) => self.render_diff_editor(&diff.read(cx).multibuffer()),
|
||||
ToolCallContent::Terminal(terminal) => self.render_terminal(terminal),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1389,6 +1440,21 @@ impl AcpThreadView {
|
|||
.into_any()
|
||||
}
|
||||
|
||||
fn render_terminal(&self, terminal: &Entity<acp_thread::Terminal>) -> AnyElement {
|
||||
v_flex()
|
||||
.h_72()
|
||||
.child(
|
||||
if let Some(terminal_view) = self.terminal_views.get(&terminal.entity_id()) {
|
||||
// TODO: terminal has all the state we need to reproduce
|
||||
// what we had in the terminal card.
|
||||
terminal_view.clone().into_any_element()
|
||||
} else {
|
||||
Empty.into_any()
|
||||
},
|
||||
)
|
||||
.into_any()
|
||||
}
|
||||
|
||||
fn render_agent_logo(&self) -> AnyElement {
|
||||
Icon::new(self.agent.logo())
|
||||
.color(Color::Muted)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue