From cea8e61fd941ac62a9e29ab89e27dded17a3f46b Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Wed, 23 Jul 2025 13:11:54 +0200 Subject: [PATCH] Push request and insert further --- crates/acp_thread/src/acp_thread.rs | 173 ++++++++-------------------- 1 file changed, 51 insertions(+), 122 deletions(-) diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs index 8c67e1dee5..7bec08a948 100644 --- a/crates/acp_thread/src/acp_thread.rs +++ b/crates/acp_thread/src/acp_thread.rs @@ -180,6 +180,31 @@ pub struct ToolCall { } impl ToolCall { + fn from_acp( + tool_call: acp::ToolCall, + status: ToolCallStatus, + language_registry: Arc, + cx: &mut App, + ) -> Self { + Self { + id: tool_call.id, + label: cx.new(|cx| { + Markdown::new( + tool_call.label.into(), + Some(language_registry.clone()), + None, + cx, + ) + }), + kind: tool_call.kind, + // todo! Do we assume there is either a coalesced content OR diff? + content: ToolCallContent::from_acp_contents(tool_call.content, language_registry, cx) + .into_iter() + .next(), + locations: tool_call.locations, + status, + } + } fn to_markdown(&self, cx: &App) -> String { let mut markdown = format!( "**Tool Call: {}**\nStatus: {}\n\n", @@ -780,98 +805,46 @@ impl AcpThread { cx: &mut Context, ) -> Result<()> { let language_registry = self.project.read(cx).languages().clone(); - - let new_tool_call = ToolCall { - id: tool_call.id, - label: cx.new(|cx| { - Markdown::new( - tool_call.label.into(), - Some(language_registry.clone()), - None, - cx, - ) - }), - kind: tool_call.kind, - // todo! Do we assume there is either a coalesced content OR diff? - content: ToolCallContent::from_acp_contents(tool_call.content, language_registry, cx) - .into_iter() - .next(), - locations: tool_call.locations, - status: ToolCallStatus::Allowed { - status: tool_call.status, - }, + let status = ToolCallStatus::Allowed { + status: tool_call.status, }; + let call = ToolCall::from_acp(tool_call, status, language_registry, cx); - if let Some((ix, current_call)) = self.tool_call_mut(tool_call.id) { - match &mut current_call.status { - ToolCallStatus::Allowed { status } => { - *status = tool_call.status; - } + let location = call.locations.last().cloned(); + + if let Some((ix, current_call)) = self.tool_call_mut(&call.id) { + match ¤t_call.status { ToolCallStatus::WaitingForConfirmation { .. } => { anyhow::bail!("Tool call hasn't been authorized yet") } ToolCallStatus::Rejected => { anyhow::bail!("Tool call was rejected and therefore can't be updated") } - ToolCallStatus::Canceled => { - current_call.status = ToolCallStatus::Allowed { status: new_status }; - } + ToolCallStatus::Allowed { .. } | ToolCallStatus::Canceled => {} } - *current_call = new_tool_call; - - let location = current_call.locations.last().cloned(); - if let Some(location) = location { - self.set_project_location(location, cx) - } + *current_call = call; cx.emit(AcpThreadEvent::EntryUpdated(ix)); } else { - let language_registry = self.project.read(cx).languages().clone(); - let call = ToolCall { - id: tool_call.id, - label: cx.new(|cx| { - Markdown::new( - tool_call.label.into(), - Some(language_registry.clone()), - None, - cx, - ) - }), - kind: tool_call.kind, - // todo! Do we assume there is either a coalesced content OR diff? - content: ToolCallContent::from_acp_contents( - tool_call.content, - language_registry, - cx, - ) - .into_iter() - .next(), - locations: tool_call.locations, - status: ToolCallStatus::Allowed { - status: tool_call.status, - }, - }; - - let location = call.locations.last().cloned(); - if let Some(location) = location { - self.set_project_location(location, cx) - } - self.push_entry(AgentThreadEntry::ToolCall(call), cx); } + if let Some(location) = location { + self.set_project_location(location, cx) + } + Ok(()) } - fn tool_call_mut(&mut self, id: acp::ToolCallId) -> Option<(usize, &mut ToolCall)> { + fn tool_call_mut(&mut self, id: &acp::ToolCallId) -> Option<(usize, &mut ToolCall)> { self.entries .iter_mut() .enumerate() .rev() .find_map(|(index, tool_call)| { if let AgentThreadEntry::ToolCall(tool_call) = tool_call - && tool_call.id == id + && &tool_call.id == id { Some((index, tool_call)) } else { @@ -885,7 +858,7 @@ impl AcpThread { tool_call: acp::ToolCall, possible_grants: Vec, cx: &mut Context, - ) -> ToolCallRequest { + ) -> oneshot::Receiver { let (tx, rx) = oneshot::channel(); let status = ToolCallStatus::WaitingForConfirmation { @@ -893,61 +866,18 @@ impl AcpThread { respond_tx: tx, }; - let id = self.insert_tool_call(tool_call, status, cx); - ToolCallRequest { id, outcome: rx } - } - - pub fn request_tool_call_confirmation( - &mut self, - tool_call_id: ToolCallId, - confirmation: acp_old::ToolCallConfirmation, - cx: &mut Context, - ) -> Result { - let project = self.project.read(cx).languages().clone(); - let Some((idx, call)) = self.tool_call_mut(tool_call_id) else { - anyhow::bail!("Tool call not found"); - }; - - let (tx, rx) = oneshot::channel(); - - call.status = ToolCallStatus::WaitingForConfirmation { - confirmation: ToolCallConfirmation::from_acp(confirmation, project, cx), - respond_tx: tx, - }; - - cx.emit(AcpThreadEvent::EntryUpdated(idx)); - - Ok(ToolCallRequest { - id: tool_call_id, - outcome: rx, - }) + self.insert_tool_call(tool_call, status, cx); + rx } fn insert_tool_call( &mut self, - tool_call: acp_old::PushToolCallParams, + tool_call: acp::ToolCall, status: ToolCallStatus, cx: &mut Context, - ) -> acp_old::ToolCallId { + ) { let language_registry = self.project.read(cx).languages().clone(); - let id = acp_old::ToolCallId(self.entries.len() as u64); - let call = ToolCall { - id, - label: cx.new(|cx| { - Markdown::new( - tool_call.label.into(), - Some(language_registry.clone()), - None, - cx, - ) - }), - icon: acp_icon_to_ui_icon(tool_call.icon), - content: tool_call - .content - .map(|content| ToolCallContent::from_acp(content, language_registry, cx)), - locations: tool_call.locations, - status, - }; + let call = ToolCall::from_acp(tool_call, status, language_registry, cx); let location = call.locations.last().cloned(); if let Some(location) = location { @@ -955,8 +885,6 @@ impl AcpThread { } self.push_entry(AgentThreadEntry::ToolCall(call), cx); - - id } pub fn authorize_tool_call( @@ -965,7 +893,7 @@ impl AcpThread { grant: acp::Grant, cx: &mut Context, ) { - let Some((ix, call)) = self.tool_call_mut(id) else { + let Some((ix, call)) = self.tool_call_mut(&id) else { return; }; @@ -1135,7 +1063,7 @@ impl AcpThread { call.status, ToolCallStatus::WaitingForConfirmation { .. } | ToolCallStatus::Allowed { - status: acp_old::ToolCallStatus::Running + status: acp::ToolCallStatus::InProgress } ); @@ -1147,6 +1075,7 @@ impl AcpThread { respond_tx, .. } = curr_status { + // todo! do we need a way to cancel rather than reject? respond_tx .send(acp_old::ToolCallConfirmationOutcome::Cancel) .ok(); @@ -1698,7 +1627,7 @@ mod tests { thread.entries[1], AgentThreadEntry::ToolCall(ToolCall { status: ToolCallStatus::Allowed { - status: acp_old::ToolCallStatus::Running, + status: acp::ToolCallStatus::InProgress, .. }, .. @@ -1742,7 +1671,7 @@ mod tests { thread.entries[1], AgentThreadEntry::ToolCall(ToolCall { status: ToolCallStatus::Allowed { - status: acp_old::ToolCallStatus::Finished, + status: acp::ToolCallStatus::Completed, .. }, ..