From 80a5f8c58927b10143dca9c257a58ad43af897e0 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Tue, 31 Mar 2026 22:18:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dacp=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=A9=BA=E7=94=A8=E9=87=8F=E4=BF=A1=E6=81=AF=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E4=B8=AD=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/acp/connection.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/acp/connection.rs b/src-tauri/src/acp/connection.rs index b217a0e..146b1ea 100644 --- a/src-tauri/src/acp/connection.rs +++ b/src-tauri/src/acp/connection.rs @@ -21,7 +21,8 @@ use sacp::schema::{ }; use sacp::util::MatchDispatch; use sacp::{ - on_receive_request, Agent, Client, ConnectionTo, Responder, SessionMessage, UntypedMessage, + on_receive_request, Agent, Client, ConnectionTo, Dispatch, Responder, SessionMessage, + UntypedMessage, }; use sacp_tokio::AcpAgent; use tokio::sync::mpsc; @@ -752,6 +753,7 @@ async fn run_connection( if let SessionMessage::SessionMessage(dispatch) = msg { let cid = conn_id.clone(); let h = emitter_clone.clone(); + let dispatch = fix_usage_update_nulls(dispatch); let _ = MatchDispatch::new(dispatch) .if_notification(async |notif: SessionNotification| { if matches!( @@ -1552,6 +1554,7 @@ async fn run_conversation_loop<'a>( let cid = conn_id.to_string(); let h = emitter.clone(); let cwd_opt = Some(cwd); + let dispatch = fix_usage_update_nulls(dispatch); let _ = MatchDispatch::new(dispatch) .if_notification( async |notif: SessionNotification| { @@ -1637,6 +1640,7 @@ async fn run_conversation_loop<'a>( let runtime = terminal_runtime.clone(); let session_id = sid.clone(); let cwd_opt = Some(cwd); + let dispatch = fix_usage_update_nulls(dispatch); if let Err(e) = MatchDispatch::new(dispatch) .if_notification( async |notif: SessionNotification| { @@ -2123,6 +2127,27 @@ fn map_plan_entries(plan: &Plan) -> Vec { .collect() } +/// Fix null fields in `usage_update` notifications that would otherwise fail deserialization. +/// +/// Some ACP agents send `"used": null` in usage_update notifications, but the +/// upstream schema expects `u64`. This function patches the raw JSON params +/// so that `null` numeric fields default to `0`. +fn fix_usage_update_nulls(mut dispatch: Dispatch) -> Dispatch { + if let Dispatch::Notification(ref mut msg) = dispatch { + if let Some(update) = msg.params.get_mut("update") { + if update.get("sessionUpdate").and_then(|v| v.as_str()) == Some("usage_update") { + if update.get("used").map(|v| v.is_null()).unwrap_or(false) { + update["used"] = serde_json::Value::from(0u64); + } + if update.get("size").map(|v| v.is_null()).unwrap_or(false) { + update["size"] = serde_json::Value::from(0u64); + } + } + } + } + dispatch +} + /// Convert a SessionUpdate into AcpEvent(s) and emit to frontend. fn emit_conversation_update( connection_id: &str,