Refactor ToolCallStatus enum to flat variants (#36356)

Replace nested Allowed variant with distinct statuses for clearer status
handling.

Release Notes:

- N/A
This commit is contained in:
Ben Brandt 2025-08-17 15:05:23 +02:00 committed by GitHub
parent da8a692ec0
commit 5895fac377
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 72 additions and 70 deletions

View file

@ -223,7 +223,7 @@ impl ToolCall {
} }
if let Some(status) = status { if let Some(status) = status {
self.status = ToolCallStatus::Allowed { status }; self.status = status.into();
} }
if let Some(title) = title { if let Some(title) = title {
@ -344,30 +344,48 @@ impl ToolCall {
#[derive(Debug)] #[derive(Debug)]
pub enum ToolCallStatus { pub enum ToolCallStatus {
/// The tool call hasn't started running yet, but we start showing it to
/// the user.
Pending,
/// The tool call is waiting for confirmation from the user.
WaitingForConfirmation { WaitingForConfirmation {
options: Vec<acp::PermissionOption>, options: Vec<acp::PermissionOption>,
respond_tx: oneshot::Sender<acp::PermissionOptionId>, respond_tx: oneshot::Sender<acp::PermissionOptionId>,
}, },
Allowed { /// The tool call is currently running.
status: acp::ToolCallStatus, InProgress,
}, /// The tool call completed successfully.
Completed,
/// The tool call failed.
Failed,
/// The user rejected the tool call.
Rejected, Rejected,
/// The user cancelled generation so the tool call was cancelled.
Canceled, Canceled,
} }
impl From<acp::ToolCallStatus> for ToolCallStatus {
fn from(status: acp::ToolCallStatus) -> Self {
match status {
acp::ToolCallStatus::Pending => Self::Pending,
acp::ToolCallStatus::InProgress => Self::InProgress,
acp::ToolCallStatus::Completed => Self::Completed,
acp::ToolCallStatus::Failed => Self::Failed,
}
}
}
impl Display for ToolCallStatus { impl Display for ToolCallStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!( write!(
f, f,
"{}", "{}",
match self { match self {
ToolCallStatus::Pending => "Pending",
ToolCallStatus::WaitingForConfirmation { .. } => "Waiting for confirmation", ToolCallStatus::WaitingForConfirmation { .. } => "Waiting for confirmation",
ToolCallStatus::Allowed { status } => match status { ToolCallStatus::InProgress => "In Progress",
acp::ToolCallStatus::Pending => "Pending", ToolCallStatus::Completed => "Completed",
acp::ToolCallStatus::InProgress => "In Progress", ToolCallStatus::Failed => "Failed",
acp::ToolCallStatus::Completed => "Completed",
acp::ToolCallStatus::Failed => "Failed",
},
ToolCallStatus::Rejected => "Rejected", ToolCallStatus::Rejected => "Rejected",
ToolCallStatus::Canceled => "Canceled", ToolCallStatus::Canceled => "Canceled",
} }
@ -759,11 +777,7 @@ impl AcpThread {
AgentThreadEntry::UserMessage(_) => return false, AgentThreadEntry::UserMessage(_) => return false,
AgentThreadEntry::ToolCall( AgentThreadEntry::ToolCall(
call @ ToolCall { call @ ToolCall {
status: status: ToolCallStatus::InProgress | ToolCallStatus::Pending,
ToolCallStatus::Allowed {
status:
acp::ToolCallStatus::InProgress | acp::ToolCallStatus::Pending,
},
.. ..
}, },
) if call.diffs().next().is_some() => { ) if call.diffs().next().is_some() => {
@ -945,9 +959,7 @@ impl AcpThread {
tool_call: acp::ToolCall, tool_call: acp::ToolCall,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Result<(), acp::Error> { ) -> Result<(), acp::Error> {
let status = ToolCallStatus::Allowed { let status = tool_call.status.into();
status: tool_call.status,
};
self.upsert_tool_call_inner(tool_call.into(), status, cx) self.upsert_tool_call_inner(tool_call.into(), status, cx)
} }
@ -1074,9 +1086,7 @@ impl AcpThread {
ToolCallStatus::Rejected ToolCallStatus::Rejected
} }
acp::PermissionOptionKind::AllowOnce | acp::PermissionOptionKind::AllowAlways => { acp::PermissionOptionKind::AllowOnce | acp::PermissionOptionKind::AllowAlways => {
ToolCallStatus::Allowed { ToolCallStatus::InProgress
status: acp::ToolCallStatus::InProgress,
}
} }
}; };
@ -1097,7 +1107,10 @@ impl AcpThread {
match &entry { match &entry {
AgentThreadEntry::ToolCall(call) => match call.status { AgentThreadEntry::ToolCall(call) => match call.status {
ToolCallStatus::WaitingForConfirmation { .. } => return true, ToolCallStatus::WaitingForConfirmation { .. } => return true,
ToolCallStatus::Allowed { .. } ToolCallStatus::Pending
| ToolCallStatus::InProgress
| ToolCallStatus::Completed
| ToolCallStatus::Failed
| ToolCallStatus::Rejected | ToolCallStatus::Rejected
| ToolCallStatus::Canceled => continue, | ToolCallStatus::Canceled => continue,
}, },
@ -1290,10 +1303,9 @@ impl AcpThread {
if let AgentThreadEntry::ToolCall(call) = entry { if let AgentThreadEntry::ToolCall(call) = entry {
let cancel = matches!( let cancel = matches!(
call.status, call.status,
ToolCallStatus::WaitingForConfirmation { .. } ToolCallStatus::Pending
| ToolCallStatus::Allowed { | ToolCallStatus::WaitingForConfirmation { .. }
status: acp::ToolCallStatus::InProgress | ToolCallStatus::InProgress
}
); );
if cancel { if cancel {
@ -1939,10 +1951,7 @@ mod tests {
assert!(matches!( assert!(matches!(
thread.entries[1], thread.entries[1],
AgentThreadEntry::ToolCall(ToolCall { AgentThreadEntry::ToolCall(ToolCall {
status: ToolCallStatus::Allowed { status: ToolCallStatus::InProgress,
status: acp::ToolCallStatus::InProgress,
..
},
.. ..
}) })
)); ));
@ -1981,10 +1990,7 @@ mod tests {
assert!(matches!( assert!(matches!(
thread.entries[1], thread.entries[1],
AgentThreadEntry::ToolCall(ToolCall { AgentThreadEntry::ToolCall(ToolCall {
status: ToolCallStatus::Allowed { status: ToolCallStatus::Completed,
status: acp::ToolCallStatus::Completed,
..
},
.. ..
}) })
)); ));

View file

@ -134,7 +134,9 @@ pub async fn test_tool_call(server: impl AgentServer + 'static, cx: &mut TestApp
matches!( matches!(
entry, entry,
AgentThreadEntry::ToolCall(ToolCall { AgentThreadEntry::ToolCall(ToolCall {
status: ToolCallStatus::Allowed { .. }, status: ToolCallStatus::Pending
| ToolCallStatus::InProgress
| ToolCallStatus::Completed,
.. ..
}) })
) )
@ -212,7 +214,9 @@ pub async fn test_tool_call_with_permission(
assert!(thread.entries().iter().any(|entry| matches!( assert!(thread.entries().iter().any(|entry| matches!(
entry, entry,
AgentThreadEntry::ToolCall(ToolCall { AgentThreadEntry::ToolCall(ToolCall {
status: ToolCallStatus::Allowed { .. }, status: ToolCallStatus::Pending
| ToolCallStatus::InProgress
| ToolCallStatus::Completed,
.. ..
}) })
))); )));
@ -223,7 +227,9 @@ pub async fn test_tool_call_with_permission(
thread.read_with(cx, |thread, cx| { thread.read_with(cx, |thread, cx| {
let AgentThreadEntry::ToolCall(ToolCall { let AgentThreadEntry::ToolCall(ToolCall {
content, content,
status: ToolCallStatus::Allowed { .. }, status: ToolCallStatus::Pending
| ToolCallStatus::InProgress
| ToolCallStatus::Completed,
.. ..
}) = thread }) = thread
.entries() .entries()

View file

@ -1053,14 +1053,10 @@ impl AcpThreadView {
let card_header_id = SharedString::from("inner-tool-call-header"); let card_header_id = SharedString::from("inner-tool-call-header");
let status_icon = match &tool_call.status { let status_icon = match &tool_call.status {
ToolCallStatus::Allowed { ToolCallStatus::Pending
status: acp::ToolCallStatus::Pending, | ToolCallStatus::WaitingForConfirmation { .. }
} | ToolCallStatus::Completed => None,
| ToolCallStatus::WaitingForConfirmation { .. } => None, ToolCallStatus::InProgress => Some(
ToolCallStatus::Allowed {
status: acp::ToolCallStatus::InProgress,
..
} => Some(
Icon::new(IconName::ArrowCircle) Icon::new(IconName::ArrowCircle)
.color(Color::Accent) .color(Color::Accent)
.size(IconSize::Small) .size(IconSize::Small)
@ -1071,16 +1067,7 @@ impl AcpThreadView {
) )
.into_any(), .into_any(),
), ),
ToolCallStatus::Allowed { ToolCallStatus::Rejected | ToolCallStatus::Canceled | ToolCallStatus::Failed => Some(
status: acp::ToolCallStatus::Completed,
..
} => None,
ToolCallStatus::Rejected
| ToolCallStatus::Canceled
| ToolCallStatus::Allowed {
status: acp::ToolCallStatus::Failed,
..
} => Some(
Icon::new(IconName::Close) Icon::new(IconName::Close)
.color(Color::Error) .color(Color::Error)
.size(IconSize::Small) .size(IconSize::Small)
@ -1146,15 +1133,23 @@ impl AcpThreadView {
tool_call.content.is_empty(), tool_call.content.is_empty(),
cx, cx,
)), )),
ToolCallStatus::Allowed { .. } | ToolCallStatus::Canceled => v_flex() ToolCallStatus::Pending
.w_full() | ToolCallStatus::InProgress
.children(tool_call.content.iter().map(|content| { | ToolCallStatus::Completed
div() | ToolCallStatus::Failed
.child( | ToolCallStatus::Canceled => {
self.render_tool_call_content(entry_ix, content, tool_call, window, cx), v_flex()
) .w_full()
.into_any_element() .children(tool_call.content.iter().map(|content| {
})), div()
.child(
self.render_tool_call_content(
entry_ix, content, tool_call, window, cx,
),
)
.into_any_element()
}))
}
ToolCallStatus::Rejected => v_flex().size_0(), ToolCallStatus::Rejected => v_flex().size_0(),
}; };
@ -1467,12 +1462,7 @@ impl AcpThreadView {
let tool_failed = matches!( let tool_failed = matches!(
&tool_call.status, &tool_call.status,
ToolCallStatus::Rejected ToolCallStatus::Rejected | ToolCallStatus::Canceled | ToolCallStatus::Failed
| ToolCallStatus::Canceled
| ToolCallStatus::Allowed {
status: acp::ToolCallStatus::Failed,
..
}
); );
let output = terminal_data.output(); let output = terminal_data.output();