diff --git a/crates/acp-client/src/driver.rs b/crates/acp-client/src/driver.rs index 5683d068..092961de 100644 --- a/crates/acp-client/src/driver.rs +++ b/crates/acp-client/src/driver.rs @@ -17,8 +17,8 @@ use agent_client_protocol::{ Agent, ClientSideConnection, ContentBlock as AcpContentBlock, ImageContent, Implementation, InitializeRequest, LoadSessionRequest, McpServer, NewSessionRequest, PermissionOptionId, PromptRequest, ProtocolVersion, RequestPermissionOutcome, RequestPermissionRequest, - RequestPermissionResponse, SelectedPermissionOutcome, SessionNotification, SessionUpdate, - TextContent, + RequestPermissionResponse, SelectedPermissionOutcome, SessionConfigOption, SessionInfoUpdate, + SessionModelState, SessionNotification, SessionUpdate, TextContent, }; use async_trait::async_trait; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; @@ -58,6 +58,22 @@ pub trait MessageWriter: Send + Sync { /// Record the result/output of a tool call. async fn record_tool_result(&self, content: &str); + + /// Called when session info is updated (title, timestamps, etc.). + /// + /// Delivered via `SessionUpdate::SessionInfoUpdate` notifications during a + /// session, or extracted from setup responses. + async fn on_session_info_update(&self, _info: &SessionInfoUpdate) {} + + /// Called when model state is received from session setup responses. + /// + /// `SessionModelState` is only delivered in `NewSessionResponse` and + /// `LoadSessionResponse`. Mid-session model changes are surfaced through + /// `on_config_option_update` via `ConfigOptionUpdate` with category `Model`. + async fn on_model_state_update(&self, _state: &SessionModelState) {} + + /// Called when session configuration options change. + async fn on_config_option_update(&self, _options: &[SessionConfigOption]) {} } /// Storage interface for persisting agent session data. @@ -834,6 +850,21 @@ impl agent_client_protocol::Client for AcpNotificationHandler { &self, notification: SessionNotification, ) -> agent_client_protocol::Result<()> { + // Session metadata events are forwarded regardless of phase. + match ¬ification.update { + SessionUpdate::SessionInfoUpdate(info) => { + self.writer.on_session_info_update(info).await; + return Ok(()); + } + SessionUpdate::ConfigOptionUpdate(update) => { + self.writer + .on_config_option_update(&update.config_options) + .await; + return Ok(()); + } + _ => {} + } + // Determine the action to take under the lock, then drop the lock // before calling into the writer to avoid holding it across await points. enum LiveAction { @@ -1032,6 +1063,7 @@ async fn run_acp_protocol( connection, working_dir, store, + &handler.writer, our_session_id, acp_session_id, mcp_servers, @@ -1092,6 +1124,7 @@ async fn setup_acp_session( connection: &ClientSideConnection, working_dir: &Path, store: &Arc, + writer: &Arc, our_session_id: &str, acp_session_id: Option<&str>, mcp_servers: &[McpServer], @@ -1136,7 +1169,7 @@ async fn setup_acp_session( "Resuming ACP session {existing_id} via load_session for session {our_session_id}" ); - connection + let load_response = connection .load_session( LoadSessionRequest::new(existing_id.to_string(), working_dir.to_path_buf()) .mcp_servers(mcp_servers.to_vec()), @@ -1144,6 +1177,13 @@ async fn setup_acp_session( .await .map_err(|e| format!("Failed to load ACP session: {e:?}"))?; + if let Some(ref models) = load_response.models { + writer.on_model_state_update(models).await; + } + if let Some(ref options) = load_response.config_options { + writer.on_config_option_update(options).await; + } + Ok(existing_id.to_string()) } None => { @@ -1158,6 +1198,14 @@ async fn setup_acp_session( store .set_agent_session_id(our_session_id, &new_id) .map_err(|e| format!("Failed to save agent session ID: {e}"))?; + + if let Some(ref models) = session_response.models { + writer.on_model_state_update(models).await; + } + if let Some(ref options) = session_response.config_options { + writer.on_config_option_update(options).await; + } + Ok(new_id) } } diff --git a/crates/acp-client/src/lib.rs b/crates/acp-client/src/lib.rs index 467a2431..be16747a 100644 --- a/crates/acp-client/src/lib.rs +++ b/crates/acp-client/src/lib.rs @@ -22,7 +22,10 @@ mod simple; mod types; // Re-export the main API -pub use agent_client_protocol::{McpServer, McpServerHttp, McpServerSse}; +pub use agent_client_protocol::{ + ConfigOptionUpdate, McpServer, McpServerHttp, McpServerSse, ModelInfo, SessionConfigOption, + SessionConfigOptionCategory, SessionInfoUpdate, SessionModelState, +}; pub use driver::{ strip_code_fences, AcpDriver, AgentDriver, BasicMessageWriter, MessageWriter, Store, };