Add back DeletePathTool
to agent2 (#36168)
This was probably removed accidentally as a result of a merge conflict. Release Notes: - N/A
This commit is contained in:
parent
8e4f30abcb
commit
b3d048d6dc
2 changed files with 57 additions and 80 deletions
|
@ -1,8 +1,8 @@
|
||||||
use crate::{AgentResponseEvent, Thread, templates::Templates};
|
use crate::{AgentResponseEvent, Thread, templates::Templates};
|
||||||
use crate::{
|
use crate::{
|
||||||
ContextServerRegistry, CopyPathTool, CreateDirectoryTool, DiagnosticsTool, EditFileTool,
|
ContextServerRegistry, CopyPathTool, CreateDirectoryTool, DeletePathTool, DiagnosticsTool,
|
||||||
FetchTool, FindPathTool, GrepTool, ListDirectoryTool, MovePathTool, NowTool, OpenTool,
|
EditFileTool, FetchTool, FindPathTool, GrepTool, ListDirectoryTool, MovePathTool, NowTool,
|
||||||
ReadFileTool, TerminalTool, ThinkingTool, ToolCallAuthorization, UserMessageContent,
|
OpenTool, ReadFileTool, TerminalTool, ThinkingTool, ToolCallAuthorization, UserMessageContent,
|
||||||
WebSearchTool,
|
WebSearchTool,
|
||||||
};
|
};
|
||||||
use acp_thread::AgentModelSelector;
|
use acp_thread::AgentModelSelector;
|
||||||
|
@ -583,22 +583,22 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
|
||||||
default_model,
|
default_model,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
thread.add_tool(CreateDirectoryTool::new(project.clone()));
|
|
||||||
thread.add_tool(CopyPathTool::new(project.clone()));
|
thread.add_tool(CopyPathTool::new(project.clone()));
|
||||||
|
thread.add_tool(CreateDirectoryTool::new(project.clone()));
|
||||||
|
thread.add_tool(DeletePathTool::new(project.clone(), action_log.clone()));
|
||||||
thread.add_tool(DiagnosticsTool::new(project.clone()));
|
thread.add_tool(DiagnosticsTool::new(project.clone()));
|
||||||
thread.add_tool(MovePathTool::new(project.clone()));
|
|
||||||
thread.add_tool(ListDirectoryTool::new(project.clone()));
|
|
||||||
thread.add_tool(OpenTool::new(project.clone()));
|
|
||||||
thread.add_tool(ThinkingTool);
|
|
||||||
thread.add_tool(FindPathTool::new(project.clone()));
|
|
||||||
thread.add_tool(FetchTool::new(project.read(cx).client().http_client()));
|
|
||||||
thread.add_tool(GrepTool::new(project.clone()));
|
|
||||||
thread.add_tool(ReadFileTool::new(project.clone(), action_log));
|
|
||||||
thread.add_tool(EditFileTool::new(cx.entity()));
|
thread.add_tool(EditFileTool::new(cx.entity()));
|
||||||
|
thread.add_tool(FetchTool::new(project.read(cx).client().http_client()));
|
||||||
|
thread.add_tool(FindPathTool::new(project.clone()));
|
||||||
|
thread.add_tool(GrepTool::new(project.clone()));
|
||||||
|
thread.add_tool(ListDirectoryTool::new(project.clone()));
|
||||||
|
thread.add_tool(MovePathTool::new(project.clone()));
|
||||||
thread.add_tool(NowTool);
|
thread.add_tool(NowTool);
|
||||||
|
thread.add_tool(OpenTool::new(project.clone()));
|
||||||
|
thread.add_tool(ReadFileTool::new(project.clone(), action_log));
|
||||||
thread.add_tool(TerminalTool::new(project.clone(), cx));
|
thread.add_tool(TerminalTool::new(project.clone(), cx));
|
||||||
// TODO: Needs to be conditional based on zed model or not
|
thread.add_tool(ThinkingTool);
|
||||||
thread.add_tool(WebSearchTool);
|
thread.add_tool(WebSearchTool); // TODO: Enable this only if it's a zed model.
|
||||||
thread
|
thread
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ pub struct Thread {
|
||||||
/// Survives across multiple requests as the model performs tool calls and
|
/// Survives across multiple requests as the model performs tool calls and
|
||||||
/// we run tools, report their results.
|
/// we run tools, report their results.
|
||||||
running_turn: Option<Task<()>>,
|
running_turn: Option<Task<()>>,
|
||||||
pending_agent_message: Option<AgentMessage>,
|
pending_message: Option<AgentMessage>,
|
||||||
tools: BTreeMap<SharedString, Arc<dyn AnyAgentTool>>,
|
tools: BTreeMap<SharedString, Arc<dyn AnyAgentTool>>,
|
||||||
context_server_registry: Entity<ContextServerRegistry>,
|
context_server_registry: Entity<ContextServerRegistry>,
|
||||||
profile_id: AgentProfileId,
|
profile_id: AgentProfileId,
|
||||||
|
@ -437,7 +437,7 @@ impl Thread {
|
||||||
messages: Vec::new(),
|
messages: Vec::new(),
|
||||||
completion_mode: CompletionMode::Normal,
|
completion_mode: CompletionMode::Normal,
|
||||||
running_turn: None,
|
running_turn: None,
|
||||||
pending_agent_message: None,
|
pending_message: None,
|
||||||
tools: BTreeMap::default(),
|
tools: BTreeMap::default(),
|
||||||
context_server_registry,
|
context_server_registry,
|
||||||
profile_id,
|
profile_id,
|
||||||
|
@ -463,7 +463,7 @@ impl Thread {
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub fn last_message(&self) -> Option<Message> {
|
pub fn last_message(&self) -> Option<Message> {
|
||||||
if let Some(message) = self.pending_agent_message.clone() {
|
if let Some(message) = self.pending_message.clone() {
|
||||||
Some(Message::Agent(message))
|
Some(Message::Agent(message))
|
||||||
} else {
|
} else {
|
||||||
self.messages.last().cloned()
|
self.messages.last().cloned()
|
||||||
|
@ -485,7 +485,7 @@ impl Thread {
|
||||||
pub fn cancel(&mut self) {
|
pub fn cancel(&mut self) {
|
||||||
// TODO: do we need to emit a stop::cancel for ACP?
|
// TODO: do we need to emit a stop::cancel for ACP?
|
||||||
self.running_turn.take();
|
self.running_turn.take();
|
||||||
self.flush_pending_agent_message();
|
self.flush_pending_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate(&mut self, message_id: UserMessageId) -> Result<()> {
|
pub fn truncate(&mut self, message_id: UserMessageId) -> Result<()> {
|
||||||
|
@ -521,74 +521,58 @@ impl Thread {
|
||||||
mpsc::unbounded::<Result<AgentResponseEvent, LanguageModelCompletionError>>();
|
mpsc::unbounded::<Result<AgentResponseEvent, LanguageModelCompletionError>>();
|
||||||
let event_stream = AgentResponseEventStream(events_tx);
|
let event_stream = AgentResponseEventStream(events_tx);
|
||||||
|
|
||||||
let user_message_ix = self.messages.len();
|
|
||||||
self.messages.push(Message::User(UserMessage {
|
self.messages.push(Message::User(UserMessage {
|
||||||
id: message_id,
|
id: message_id.clone(),
|
||||||
content,
|
content,
|
||||||
}));
|
}));
|
||||||
log::info!("Total messages in thread: {}", self.messages.len());
|
log::info!("Total messages in thread: {}", self.messages.len());
|
||||||
self.running_turn = Some(cx.spawn(async move |thread, cx| {
|
self.running_turn = Some(cx.spawn(async move |this, cx| {
|
||||||
log::info!("Starting agent turn execution");
|
log::info!("Starting agent turn execution");
|
||||||
let turn_result = async {
|
let turn_result = async {
|
||||||
// Perform one request, then keep looping if the model makes tool calls.
|
|
||||||
let mut completion_intent = CompletionIntent::UserPrompt;
|
let mut completion_intent = CompletionIntent::UserPrompt;
|
||||||
'outer: loop {
|
loop {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Building completion request with intent: {:?}",
|
"Building completion request with intent: {:?}",
|
||||||
completion_intent
|
completion_intent
|
||||||
);
|
);
|
||||||
let request = thread.update(cx, |thread, cx| {
|
let request = this.update(cx, |this, cx| {
|
||||||
thread.build_completion_request(completion_intent, cx)
|
this.build_completion_request(completion_intent, cx)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Stream events, appending to messages and collecting up tool uses.
|
|
||||||
log::info!("Calling model.stream_completion");
|
log::info!("Calling model.stream_completion");
|
||||||
let mut events = model.stream_completion(request, cx).await?;
|
let mut events = model.stream_completion(request, cx).await?;
|
||||||
log::debug!("Stream completion started successfully");
|
log::debug!("Stream completion started successfully");
|
||||||
|
|
||||||
let mut tool_uses = FuturesUnordered::new();
|
let mut tool_uses = FuturesUnordered::new();
|
||||||
while let Some(event) = events.next().await {
|
while let Some(event) = events.next().await {
|
||||||
match event {
|
match event? {
|
||||||
Ok(LanguageModelCompletionEvent::Stop(reason)) => {
|
LanguageModelCompletionEvent::Stop(reason) => {
|
||||||
event_stream.send_stop(reason);
|
event_stream.send_stop(reason);
|
||||||
if reason == StopReason::Refusal {
|
if reason == StopReason::Refusal {
|
||||||
thread.update(cx, |thread, _cx| {
|
this.update(cx, |this, _cx| this.truncate(message_id))??;
|
||||||
thread.pending_agent_message = None;
|
return Ok(());
|
||||||
thread.messages.truncate(user_message_ix);
|
|
||||||
})?;
|
|
||||||
break 'outer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(event) => {
|
event => {
|
||||||
log::trace!("Received completion event: {:?}", event);
|
log::trace!("Received completion event: {:?}", event);
|
||||||
thread
|
this.update(cx, |this, cx| {
|
||||||
.update(cx, |thread, cx| {
|
tool_uses.extend(this.handle_streamed_completion_event(
|
||||||
tool_uses.extend(thread.handle_streamed_completion_event(
|
event,
|
||||||
event,
|
&event_stream,
|
||||||
&event_stream,
|
cx,
|
||||||
cx,
|
));
|
||||||
));
|
})
|
||||||
})
|
.ok();
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
log::error!("Error in completion stream: {:?}", error);
|
|
||||||
event_stream.send_error(error);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no tool uses, the turn is done.
|
|
||||||
if tool_uses.is_empty() {
|
if tool_uses.is_empty() {
|
||||||
log::info!("No tool uses found, completing turn");
|
log::info!("No tool uses found, completing turn");
|
||||||
break;
|
return Ok(());
|
||||||
}
|
}
|
||||||
log::info!("Found {} tool uses to execute", tool_uses.len());
|
log::info!("Found {} tool uses to execute", tool_uses.len());
|
||||||
|
|
||||||
// As tool results trickle in, insert them in the last user
|
|
||||||
// message so that they can be sent on the next tick of the
|
|
||||||
// agentic loop.
|
|
||||||
while let Some(tool_result) = tool_uses.next().await {
|
while let Some(tool_result) = tool_uses.next().await {
|
||||||
log::info!("Tool finished {:?}", tool_result);
|
log::info!("Tool finished {:?}", tool_result);
|
||||||
|
|
||||||
|
@ -604,29 +588,21 @@ impl Thread {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
thread
|
this.update(cx, |this, _cx| {
|
||||||
.update(cx, |thread, _cx| {
|
this.pending_message()
|
||||||
thread
|
.tool_results
|
||||||
.pending_agent_message()
|
.insert(tool_result.tool_use_id.clone(), tool_result);
|
||||||
.tool_results
|
})
|
||||||
.insert(tool_result.tool_use_id.clone(), tool_result);
|
.ok();
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread.update(cx, |thread, _cx| thread.flush_pending_agent_message())?;
|
this.update(cx, |this, _| this.flush_pending_message())?;
|
||||||
|
|
||||||
completion_intent = CompletionIntent::ToolResults;
|
completion_intent = CompletionIntent::ToolResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
thread
|
this.update(cx, |this, _| this.flush_pending_message()).ok();
|
||||||
.update(cx, |thread, _cx| thread.flush_pending_agent_message())
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
if let Err(error) = turn_result {
|
if let Err(error) = turn_result {
|
||||||
log::error!("Turn execution failed: {:?}", error);
|
log::error!("Turn execution failed: {:?}", error);
|
||||||
event_stream.send_error(error);
|
event_stream.send_error(error);
|
||||||
|
@ -668,7 +644,8 @@ impl Thread {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
StartMessage { .. } => {
|
StartMessage { .. } => {
|
||||||
self.messages.push(Message::Agent(AgentMessage::default()));
|
self.flush_pending_message();
|
||||||
|
self.pending_message = Some(AgentMessage::default());
|
||||||
}
|
}
|
||||||
Text(new_text) => self.handle_text_event(new_text, event_stream, cx),
|
Text(new_text) => self.handle_text_event(new_text, event_stream, cx),
|
||||||
Thinking { text, signature } => {
|
Thinking { text, signature } => {
|
||||||
|
@ -706,7 +683,7 @@ impl Thread {
|
||||||
) {
|
) {
|
||||||
events_stream.send_text(&new_text);
|
events_stream.send_text(&new_text);
|
||||||
|
|
||||||
let last_message = self.pending_agent_message();
|
let last_message = self.pending_message();
|
||||||
if let Some(AgentMessageContent::Text(text)) = last_message.content.last_mut() {
|
if let Some(AgentMessageContent::Text(text)) = last_message.content.last_mut() {
|
||||||
text.push_str(&new_text);
|
text.push_str(&new_text);
|
||||||
} else {
|
} else {
|
||||||
|
@ -727,7 +704,7 @@ impl Thread {
|
||||||
) {
|
) {
|
||||||
event_stream.send_thinking(&new_text);
|
event_stream.send_thinking(&new_text);
|
||||||
|
|
||||||
let last_message = self.pending_agent_message();
|
let last_message = self.pending_message();
|
||||||
if let Some(AgentMessageContent::Thinking { text, signature }) =
|
if let Some(AgentMessageContent::Thinking { text, signature }) =
|
||||||
last_message.content.last_mut()
|
last_message.content.last_mut()
|
||||||
{
|
{
|
||||||
|
@ -744,7 +721,7 @@ impl Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_redacted_thinking_event(&mut self, data: String, cx: &mut Context<Self>) {
|
fn handle_redacted_thinking_event(&mut self, data: String, cx: &mut Context<Self>) {
|
||||||
let last_message = self.pending_agent_message();
|
let last_message = self.pending_message();
|
||||||
last_message
|
last_message
|
||||||
.content
|
.content
|
||||||
.push(AgentMessageContent::RedactedThinking(data));
|
.push(AgentMessageContent::RedactedThinking(data));
|
||||||
|
@ -768,7 +745,7 @@ impl Thread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the last message ends in the current tool use
|
// Ensure the last message ends in the current tool use
|
||||||
let last_message = self.pending_agent_message();
|
let last_message = self.pending_message();
|
||||||
let push_new_tool_use = last_message.content.last_mut().map_or(true, |content| {
|
let push_new_tool_use = last_message.content.last_mut().map_or(true, |content| {
|
||||||
if let AgentMessageContent::ToolUse(last_tool_use) = content {
|
if let AgentMessageContent::ToolUse(last_tool_use) = content {
|
||||||
if last_tool_use.id == tool_use.id {
|
if last_tool_use.id == tool_use.id {
|
||||||
|
@ -871,12 +848,12 @@ impl Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_agent_message(&mut self) -> &mut AgentMessage {
|
fn pending_message(&mut self) -> &mut AgentMessage {
|
||||||
self.pending_agent_message.get_or_insert_default()
|
self.pending_message.get_or_insert_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_pending_agent_message(&mut self) {
|
fn flush_pending_message(&mut self) {
|
||||||
let Some(mut message) = self.pending_agent_message.take() else {
|
let Some(mut message) = self.pending_message.take() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -997,7 +974,7 @@ impl Thread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = self.pending_agent_message.as_ref() {
|
if let Some(message) = self.pending_message.as_ref() {
|
||||||
messages.extend(message.to_request());
|
messages.extend(message.to_request());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,7 +990,7 @@ impl Thread {
|
||||||
markdown.push_str(&message.to_markdown());
|
markdown.push_str(&message.to_markdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = self.pending_agent_message.as_ref() {
|
if let Some(message) = self.pending_message.as_ref() {
|
||||||
markdown.push('\n');
|
markdown.push('\n');
|
||||||
markdown.push_str(&message.to_markdown());
|
markdown.push_str(&message.to_markdown());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue