From 3d3269a0e60279e4df3a22522b731bc8015cc691 Mon Sep 17 00:00:00 2001 From: steve02081504 Date: Sun, 1 Mar 2026 20:36:37 +0800 Subject: [PATCH] add `agent_message_clear` impls https://github.com/agentclientprotocol/agent-client-protocol/pull/465 --- examples/client.rs | 7 ++- src/agent-client-protocol/CHANGELOG.md | 6 ++ src/agent-client-protocol/src/rpc_tests.rs | 68 ++++++++++++++++++++++ src/sacp-test/src/test_client.rs | 16 +++-- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/examples/client.rs b/examples/client.rs index 0b357ce..27e9a5a 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -90,7 +90,12 @@ impl acp::Client for ExampleClient { }; println!("| Agent: {text}"); } - _ => {} // Handle future variants gracefully + acp::SessionUpdate::AgentMessageClear => { + // Clear accumulated streamed content for the current agent message. + // Subsequent agent_message_chunk will append from empty. + println!("| Agent: (message cleared)"); + } + _ => {} // Handle other variants gracefully } Ok(()) } diff --git a/src/agent-client-protocol/CHANGELOG.md b/src/agent-client-protocol/CHANGELOG.md index 167b771..d41d6c4 100644 --- a/src/agent-client-protocol/CHANGELOG.md +++ b/src/agent-client-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased] + +### Added + +- Support for `agent_message_clear` session update (RFD [agent_message_clear](https://github.com/agentclientprotocol/agent-client-protocol/blob/main/docs/rfds/agent_message_clear.md)): clients can clear accumulated streamed content for the current agent message; example client and tests updated. + ## [0.9.4](https://github.com/agentclientprotocol/rust-sdk/compare/v0.9.3...v0.9.4) - 2026-02-04 ### Added diff --git a/src/agent-client-protocol/src/rpc_tests.rs b/src/agent-client-protocol/src/rpc_tests.rs index 093e00a..6a47742 100644 --- a/src/agent-client-protocol/src/rpc_tests.rs +++ b/src/agent-client-protocol/src/rpc_tests.rs @@ -627,6 +627,9 @@ async fn test_full_conversation_flow() { found_final_message = true; } } + SessionUpdate::AgentMessageClear => { + // Client would clear accumulated message; test just verifies we receive it. + } SessionUpdate::ToolCall(_) => { found_tool_call = true; } @@ -647,6 +650,71 @@ async fn test_full_conversation_flow() { .await; } +#[tokio::test] +async fn test_agent_message_clear_sequence() { + let local_set = tokio::task::LocalSet::new(); + local_set + .run_until(async { + let client = TestClient::new(); + let agent = TestAgent::new(); + let (agent_conn, client_conn) = create_connection_pair(&client, &agent); + + let session_id = SessionId::new("clear-test-session"); + agent_conn + .prompt(PromptRequest::new( + session_id.clone(), + vec!["Say hello then replace with goodbye".into()], + )) + .await + .expect("prompt failed"); + + // Agent sends draft, then clear, then final (RFD agent_message_clear usage pattern) + client_conn + .session_notification(SessionNotification::new( + session_id.clone(), + SessionUpdate::AgentMessageChunk(ContentChunk::new("Drafting...".into())), + )) + .await + .expect("session_notification failed"); + client_conn + .session_notification(SessionNotification::new( + session_id.clone(), + SessionUpdate::AgentMessageClear, + )) + .await + .expect("session_notification failed"); + client_conn + .session_notification(SessionNotification::new( + session_id.clone(), + SessionUpdate::AgentMessageChunk(ContentChunk::new("Here is the final result.".into())), + )) + .await + .expect("session_notification failed"); + + for _ in 0..10 { + tokio::task::yield_now().await; + } + + let updates = client.session_notifications.lock().unwrap(); + let mut clear_seen = false; + let mut final_chunk_seen = false; + for n in updates.iter() { + match &n.update { + SessionUpdate::AgentMessageClear => clear_seen = true, + SessionUpdate::AgentMessageChunk(ContentChunk { content: ContentBlock::Text(t), .. }) => { + if t.text.contains("final result") { + final_chunk_seen = true; + } + } + _ => {} + } + } + assert!(clear_seen, "Client should receive agent_message_clear"); + assert!(final_chunk_seen, "Client should receive final chunk after clear"); + }) + .await; +} + #[tokio::test] async fn test_extension_methods_and_notifications() { let local_set = tokio::task::LocalSet::new(); diff --git a/src/sacp-test/src/test_client.rs b/src/sacp-test/src/test_client.rs index 6315fa1..007403e 100644 --- a/src/sacp-test/src/test_client.rs +++ b/src/sacp-test/src/test_client.rs @@ -42,11 +42,17 @@ where JrHandlerChain::new() .name("test-client") .on_receive_notification(async |notif: SessionNotification, _cx| { - // Collect text from AgentMessageChunk updates - if let SessionUpdate::AgentMessageChunk(chunk) = ¬if.update - && let ContentBlock::Text(text_content) = &chunk.content - { - collected_text.push_str(&text_content.text); + // Collect text from AgentMessageChunk updates; clear on AgentMessageClear + match ¬if.update { + SessionUpdate::AgentMessageChunk(chunk) => { + if let ContentBlock::Text(text_content) = &chunk.content { + collected_text.push_str(&text_content.text); + } + } + SessionUpdate::AgentMessageClear => { + collected_text.clear(); + } + _ => {} } Ok(()) })