diff --git a/Cargo.lock b/Cargo.lock index e38e0f3..14bfb8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,9 +26,9 @@ dependencies = [ [[package]] name = "agent-client-protocol-schema" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158b8b314ca8072d2600b734df23b62389eda58a951618754d51a60ca6d0b1cd" +checksum = "6903a00e8ac822f9bacac59a1932754d7387c72ebb7c9c7439ad021505591da4" dependencies = [ "anyhow", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 07b1a16..f8968db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ tokio = { version = "1.48", features = ["full"] } tokio-util = { version = "0.7", features = ["compat"] } # Protocol -agent-client-protocol-schema = { version = "=0.10.4" } +agent-client-protocol-schema = { version = "=0.10.5" } # Serialization serde = { version = "1.0", features = ["derive", "rc"] } diff --git a/examples/agent.rs b/examples/agent.rs index 5dae9bf..194d6be 100644 --- a/examples/agent.rs +++ b/examples/agent.rs @@ -142,6 +142,25 @@ impl acp::Agent for ExampleAgent { Ok(acp::SetSessionModelResponse::default()) } + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + args: acp::SetSessionConfigOptionRequest, + ) -> Result { + log::info!("Received set session config option request {args:?}"); + Ok(acp::SetSessionConfigOptionResponse::new(vec![ + acp::SessionConfigOption::select( + args.config_id, + "Example Option", + args.value, + vec![ + acp::SessionConfigSelectOption::new("option1", "Option 1"), + acp::SessionConfigSelectOption::new("option2", "Option 2"), + ]), + ), + ])) + } + async fn ext_method(&self, args: acp::ExtRequest) -> Result { log::info!( "Received extension method call: method={}, params={:?}", diff --git a/src/agent-client-protocol/src/agent.rs b/src/agent-client-protocol/src/agent.rs index 3c1c423..31fd6b2 100644 --- a/src/agent-client-protocol/src/agent.rs +++ b/src/agent-client-protocol/src/agent.rs @@ -12,6 +12,8 @@ use agent_client_protocol_schema::{ForkSessionRequest, ForkSessionResponse}; use agent_client_protocol_schema::{ListSessionsRequest, ListSessionsResponse}; #[cfg(feature = "unstable_session_resume")] use agent_client_protocol_schema::{ResumeSessionRequest, ResumeSessionResponse}; +#[cfg(feature = "unstable_session_config_options")] +use agent_client_protocol_schema::{SetSessionConfigOptionRequest, SetSessionConfigOptionResponse}; #[cfg(feature = "unstable_session_model")] use agent_client_protocol_schema::{SetSessionModelRequest, SetSessionModelResponse}; use serde_json::value::RawValue; @@ -132,6 +134,25 @@ pub trait Agent { Err(Error::method_not_found()) } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Sets the current value for a session configuration option. + /// + /// Configuration options allow agents to expose arbitrary selectors (like model choice, + /// reasoning level, etc.) that clients can display and modify. + /// + /// The response returns the full list of configuration options with their current values, + /// as changing one option may affect others. + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + _args: SetSessionConfigOptionRequest, + ) -> Result { + Err(Error::method_not_found()) + } + /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -225,6 +246,13 @@ impl Agent for Rc { ) -> Result { self.as_ref().set_session_model(args).await } + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + args: SetSessionConfigOptionRequest, + ) -> Result { + self.as_ref().set_session_config_option(args).await + } #[cfg(feature = "unstable_session_list")] async fn list_sessions(&self, args: ListSessionsRequest) -> Result { self.as_ref().list_sessions(args).await @@ -278,6 +306,13 @@ impl Agent for Arc { ) -> Result { self.as_ref().set_session_model(args).await } + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + args: SetSessionConfigOptionRequest, + ) -> Result { + self.as_ref().set_session_config_option(args).await + } #[cfg(feature = "unstable_session_list")] async fn list_sessions(&self, args: ListSessionsRequest) -> Result { self.as_ref().list_sessions(args).await diff --git a/src/agent-client-protocol/src/lib.rs b/src/agent-client-protocol/src/lib.rs index 93bb851..1952b77 100644 --- a/src/agent-client-protocol/src/lib.rs +++ b/src/agent-client-protocol/src/lib.rs @@ -185,6 +185,19 @@ impl Agent for ClientSideConnection { .await } + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + args: SetSessionConfigOptionRequest, + ) -> Result { + self.conn + .request( + AGENT_METHOD_NAMES.session_set_config_option, + Some(ClientRequest::SetSessionConfigOptionRequest(args)), + ) + .await + } + async fn ext_method(&self, args: ExtRequest) -> Result { self.conn .request( @@ -560,6 +573,12 @@ impl Side for AgentSide { m if m == AGENT_METHOD_NAMES.session_resume => serde_json::from_str(params.get()) .map(ClientRequest::ResumeSessionRequest) .map_err(Into::into), + #[cfg(feature = "unstable_session_config_options")] + m if m == AGENT_METHOD_NAMES.session_set_config_option => { + serde_json::from_str(params.get()) + .map(ClientRequest::SetSessionConfigOptionRequest) + .map_err(Into::into) + } m if m == AGENT_METHOD_NAMES.session_prompt => serde_json::from_str(params.get()) .map(ClientRequest::PromptRequest) .map_err(Into::into), @@ -644,6 +663,11 @@ impl MessageHandler for T { let response = self.resume_session(args).await?; Ok(AgentResponse::ResumeSessionResponse(response)) } + #[cfg(feature = "unstable_session_config_options")] + ClientRequest::SetSessionConfigOptionRequest(args) => { + let response = self.set_session_config_option(args).await?; + Ok(AgentResponse::SetSessionConfigOptionResponse(response)) + } ClientRequest::ExtMethodRequest(args) => { let response = self.ext_method(args).await?; Ok(AgentResponse::ExtMethodResponse(response)) diff --git a/src/agent-client-protocol/src/rpc_tests.rs b/src/agent-client-protocol/src/rpc_tests.rs index 968c6d0..1b097e5 100644 --- a/src/agent-client-protocol/src/rpc_tests.rs +++ b/src/agent-client-protocol/src/rpc_tests.rs @@ -252,6 +252,30 @@ impl Agent for TestAgent { Ok(agent_client_protocol_schema::ResumeSessionResponse::new()) } + #[cfg(feature = "unstable_session_config_options")] + async fn set_session_config_option( + &self, + args: agent_client_protocol_schema::SetSessionConfigOptionRequest, + ) -> Result { + Ok( + agent_client_protocol_schema::SetSessionConfigOptionResponse::new(vec![ + agent_client_protocol_schema::SessionConfigOption::select( + args.config_id, + "Test Option", + args.value, + vec![ + agent_client_protocol_schema::SessionConfigSelectOption::new( + "value1", "Value 1", + ), + agent_client_protocol_schema::SessionConfigSelectOption::new( + "value2", "Value 2", + ), + ], + ), + ]), + ) + } + async fn ext_method(&self, args: ExtRequest) -> Result { dbg!(); match dbg!(args.method.as_ref()) { @@ -872,3 +896,36 @@ async fn test_session_info_update() { }) .await; } + +#[cfg(feature = "unstable_session_config_options")] +#[tokio::test] +async fn test_set_session_config_option() { + 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); + + // Set a config option + let response = agent_conn + .set_session_config_option( + agent_client_protocol_schema::SetSessionConfigOptionRequest::new( + "test-session", + "mode", + "value2", + ), + ) + .await + .expect("set_session_config_option failed"); + + // Verify we got config options back + assert_eq!(response.config_options.len(), 1); + assert_eq!( + response.config_options[0].id, + agent_client_protocol_schema::SessionConfigId::new("mode") + ); + }) + .await; +}