Display ACP plans (#34816)

Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
This commit is contained in:
Agus Zubiaga 2025-07-21 11:11:37 -03:00 committed by GitHub
parent 35b4a918c9
commit 405244d422
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 379 additions and 34 deletions

View file

@ -153,6 +153,7 @@ impl AgentServer for ClaudeCode {
let handler_task = cx.foreground_executor().spawn({
let end_turn_tx = end_turn_tx.clone();
let tool_id_map = tool_id_map.clone();
let delegate = delegate.clone();
async move {
while let Some(message) = incoming_message_rx.next().await {
ClaudeAgentConnection::handle_message(
@ -167,6 +168,7 @@ impl AgentServer for ClaudeCode {
});
let mut connection = ClaudeAgentConnection {
delegate,
outgoing_tx,
end_turn_tx,
_handler_task: handler_task,
@ -186,6 +188,7 @@ impl AgentConnection for ClaudeAgentConnection {
&self,
params: AnyAgentRequest,
) -> LocalBoxFuture<'static, Result<acp::AnyAgentResult>> {
let delegate = self.delegate.clone();
let end_turn_tx = self.end_turn_tx.clone();
let outgoing_tx = self.outgoing_tx.clone();
async move {
@ -201,6 +204,8 @@ impl AgentConnection for ClaudeAgentConnection {
Err(anyhow!("Authentication not supported"))
}
AnyAgentRequest::SendUserMessageParams(message) => {
delegate.clear_completed_plan_entries().await?;
let (tx, rx) = oneshot::channel();
end_turn_tx.borrow_mut().replace(tx);
let mut content = String::new();
@ -241,6 +246,7 @@ impl AgentConnection for ClaudeAgentConnection {
}
struct ClaudeAgentConnection {
delegate: AcpClientDelegate,
outgoing_tx: UnboundedSender<SdkMessage>,
end_turn_tx: Rc<RefCell<Option<oneshot::Sender<Result<()>>>>>,
_mcp_server: Option<ClaudeMcpServer>,
@ -267,8 +273,17 @@ impl ClaudeAgentConnection {
.log_err();
}
ContentChunk::ToolUse { id, name, input } => {
if let Some(resp) = delegate
.push_tool_call(ClaudeTool::infer(&name, input).as_acp())
let claude_tool = ClaudeTool::infer(&name, input);
if let ClaudeTool::TodoWrite(Some(params)) = claude_tool {
delegate
.update_plan(acp::UpdatePlanParams {
entries: params.todos.into_iter().map(Into::into).collect(),
})
.await
.log_err();
} else if let Some(resp) = delegate
.push_tool_call(claude_tool.as_acp())
.await
.log_err()
{

View file

@ -614,6 +614,16 @@ pub enum TodoPriority {
Low,
}
impl Into<acp::PlanEntryPriority> for TodoPriority {
fn into(self) -> acp::PlanEntryPriority {
match self {
TodoPriority::High => acp::PlanEntryPriority::High,
TodoPriority::Medium => acp::PlanEntryPriority::Medium,
TodoPriority::Low => acp::PlanEntryPriority::Low,
}
}
}
#[derive(Deserialize, Serialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum TodoStatus {
@ -622,6 +632,16 @@ pub enum TodoStatus {
Completed,
}
impl Into<acp::PlanEntryStatus> for TodoStatus {
fn into(self) -> acp::PlanEntryStatus {
match self {
TodoStatus::Pending => acp::PlanEntryStatus::Pending,
TodoStatus::InProgress => acp::PlanEntryStatus::InProgress,
TodoStatus::Completed => acp::PlanEntryStatus::Completed,
}
}
}
#[derive(Deserialize, Serialize, JsonSchema, Debug)]
pub struct Todo {
/// Unique identifier
@ -634,6 +654,16 @@ pub struct Todo {
pub status: TodoStatus,
}
impl Into<acp::PlanEntry> for Todo {
fn into(self) -> acp::PlanEntry {
acp::PlanEntry {
content: self.content,
priority: self.priority.into(),
status: self.status.into(),
}
}
}
#[derive(Deserialize, JsonSchema, Debug)]
pub struct TodoWriteToolParams {
pub todos: Vec<Todo>,