diff --git a/agent-client-protocol-schema/src/v1/agent.rs b/agent-client-protocol-schema/src/v1/agent.rs index f24fd3dc2..b2aa742e8 100644 --- a/agent-client-protocol-schema/src/v1/agent.rs +++ b/agent-client-protocol-schema/src/v1/agent.rs @@ -3341,8 +3341,8 @@ pub enum LlmProtocol { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct ProviderCurrentConfig { - /// Protocol currently used by this provider. - pub api_type: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Base URL currently used by this provider. pub base_url: String, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3361,9 +3361,9 @@ pub struct ProviderCurrentConfig { impl ProviderCurrentConfig { /// Builds [`ProviderCurrentConfig`] with the required fields set; optional fields start unset or empty. #[must_use] - pub fn new(api_type: LlmProtocol, base_url: impl Into) -> Self { + pub fn new(presentable_name: impl Into, base_url: impl Into) -> Self { Self { - api_type, + presentable_name: presentable_name.into(), base_url: base_url.into(), meta: None, } @@ -3381,28 +3381,6 @@ impl ProviderCurrentConfig { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// -/// Unique identifier for a configurable LLM provider. -#[cfg(feature = "unstable_llm_providers")] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)] -#[serde(transparent)] -#[from(Arc, String, &'static str)] -#[non_exhaustive] -pub struct ProviderId(pub Arc); - -#[cfg(feature = "unstable_llm_providers")] -impl ProviderId { - /// Wraps a protocol string as a typed [`ProviderId`]. - #[must_use] - pub fn new(id: impl Into>) -> Self { - Self(id.into()) - } -} - /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -3416,15 +3394,10 @@ impl ProviderId { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct ProviderInfo { - /// Provider identifier, for example "main" or "openai". - pub provider_id: ProviderId, - /// Supported protocol types for this provider. - #[serde_as(deserialize_as = "DefaultOnError>")] - #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))] - pub supported: Vec, - /// Whether this provider is mandatory and cannot be disabled via `providers/disable`. - /// If true, clients must not call `providers/disable` for this provider ID. - pub required: bool, + /// LLM protocol. + pub api_type: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Current effective non-secret routing config. /// Null or omitted means provider is disabled. #[serde(default)] @@ -3446,15 +3419,13 @@ impl ProviderInfo { /// Builds [`ProviderInfo`] with the required fields set; optional fields start unset or empty. #[must_use] pub fn new( - provider_id: impl Into, - supported: Vec, - required: bool, + api_type: LlmProtocol, + presentable_name: impl Into, current: impl IntoOption, ) -> Self { Self { - provider_id: provider_id.into(), - supported, - required, + api_type, + presentable_name: presentable_name.into(), current: current.into_option(), meta: None, } @@ -3476,16 +3447,16 @@ impl ProviderInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/list`. +/// Request parameters for `providers/list_api`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_API_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct ListProvidersRequest { +pub struct ListApiProvidersRequest { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3499,8 +3470,8 @@ pub struct ListProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl ListProvidersRequest { - /// Builds [`ListProvidersRequest`] with the required request fields set; optional fields start unset or empty. +impl ListApiProvidersRequest { + /// Builds [`ListApiProvidersRequest`] with the required request fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -3522,16 +3493,16 @@ impl ListProvidersRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/list`. +/// Response to `providers/list_api`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_API_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct ListProvidersResponse { +pub struct ListApiProvidersResponse { /// Configurable providers with current routing info suitable for UI display. pub providers: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3547,8 +3518,8 @@ pub struct ListProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl ListProvidersResponse { - /// Builds [`ListProvidersResponse`] with the required response fields set; optional fields start unset or empty. +impl ListApiProvidersResponse { + /// Builds [`ListApiProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new(providers: Vec) -> Self { Self { @@ -3573,26 +3544,24 @@ impl ListProvidersResponse { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/set`. -/// -/// Replaces the full configuration for one provider ID. +/// Configuration update for a single provider, keyed by API protocol. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProviderRequest { - /// Provider ID to configure. - pub provider_id: ProviderId, - /// Protocol type for this provider. - pub api_type: LlmProtocol, +pub struct ProviderConfigUpdate { + /// LLM protocol to configure. + pub api_protocol: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Base URL for requests sent through this provider. pub base_url: String, /// Full headers map for this provider. /// May include authorization, routing, or other integration-specific headers. + /// Omitting this field is equivalent to an empty map (no headers). #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub headers: HashMap, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3608,17 +3577,17 @@ pub struct SetProviderRequest { } #[cfg(feature = "unstable_llm_providers")] -impl SetProviderRequest { - /// Builds [`SetProviderRequest`] with the required request fields set; optional fields start unset or empty. +impl ProviderConfigUpdate { + /// Builds [`ProviderConfigUpdate`] with the required fields set; optional fields start unset or empty. #[must_use] pub fn new( - provider_id: impl Into, - api_type: LlmProtocol, + api_protocol: LlmProtocol, + presentable_name: impl Into, base_url: impl Into, ) -> Self { Self { - provider_id: provider_id.into(), - api_type, + api_protocol, + presentable_name: presentable_name.into(), base_url: base_url.into(), headers: HashMap::new(), meta: None, @@ -3627,6 +3596,7 @@ impl SetProviderRequest { /// Full headers map for this provider. /// May include authorization, routing, or other integration-specific headers. + /// Omitting this field is equivalent to an empty map (no headers). #[must_use] pub fn headers(mut self, headers: HashMap) -> Self { self.headers = headers; @@ -3649,16 +3619,69 @@ impl SetProviderRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/set`. +/// Request parameters for `providers/configure`. +/// +/// Overrides (updates) the configuration for a set of providers keyed by API protocol. +#[cfg(feature = "unstable_llm_providers")] +#[serde_as] +#[skip_serializing_none] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_CONFIGURE_METHOD_NAME)))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct ConfigureProvidersRequest { + /// Configuration updates to apply, one per API protocol. + pub provider_configurations: Vec, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde_as(deserialize_as = "DefaultOnError")] + #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))] + #[serde(default)] + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_llm_providers")] +impl ConfigureProvidersRequest { + /// Builds [`ConfigureProvidersRequest`] with the required request fields set; optional fields start unset or empty. + #[must_use] + pub fn new(provider_configurations: Vec) -> Self { + Self { + provider_configurations, + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `providers/configure`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_CONFIGURE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProviderResponse { +pub struct ConfigureProvidersResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3672,8 +3695,8 @@ pub struct SetProviderResponse { } #[cfg(feature = "unstable_llm_providers")] -impl SetProviderResponse { - /// Builds [`SetProviderResponse`] with the required response fields set; optional fields start unset or empty. +impl ConfigureProvidersResponse { + /// Builds [`ConfigureProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -3695,18 +3718,20 @@ impl SetProviderResponse { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/disable`. +/// Request parameters for `providers/restore`. +/// +/// Restores the listed API protocols to the agent's default provider configuration. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_RESTORE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProviderRequest { - /// Provider ID to disable. - pub provider_id: ProviderId, +pub struct RestoreProvidersRequest { + /// List of API protocols to restore to default providers. + pub api_protocols: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3720,12 +3745,12 @@ pub struct DisableProviderRequest { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProviderRequest { - /// Builds [`DisableProviderRequest`] with the required request fields set; optional fields start unset or empty. +impl RestoreProvidersRequest { + /// Builds [`RestoreProvidersRequest`] with the required request fields set; optional fields start unset or empty. #[must_use] - pub fn new(provider_id: impl Into) -> Self { + pub fn new(api_protocols: Vec) -> Self { Self { - provider_id: provider_id.into(), + api_protocols, meta: None, } } @@ -3746,16 +3771,16 @@ impl DisableProviderRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/disable`. +/// Response to `providers/restore`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_RESTORE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProviderResponse { +pub struct RestoreProvidersResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3769,8 +3794,8 @@ pub struct DisableProviderResponse { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProviderResponse { - /// Builds [`DisableProviderResponse`] with the required response fields set; optional fields start unset or empty. +impl RestoreProvidersResponse { + /// Builds [`RestoreProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -4625,15 +4650,15 @@ pub struct AgentMethodNames { pub initialize: &'static str, /// Method for authenticating with the agent. pub authenticate: &'static str, - /// Method for listing configurable providers. + /// Method for listing supported provider APIs. #[cfg(feature = "unstable_llm_providers")] - pub providers_list: &'static str, - /// Method for setting provider configuration. + pub providers_list_api: &'static str, + /// Method for configuring providers. #[cfg(feature = "unstable_llm_providers")] - pub providers_set: &'static str, - /// Method for disabling a provider. + pub providers_configure: &'static str, + /// Method for restoring providers to their defaults. #[cfg(feature = "unstable_llm_providers")] - pub providers_disable: &'static str, + pub providers_restore: &'static str, /// Method for creating a new session. pub session_new: &'static str, /// Method for loading an existing session. @@ -4699,11 +4724,11 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { initialize: INITIALIZE_METHOD_NAME, authenticate: AUTHENTICATE_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_list: PROVIDERS_LIST_METHOD_NAME, + providers_list_api: PROVIDERS_LIST_API_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_set: PROVIDERS_SET_METHOD_NAME, + providers_configure: PROVIDERS_CONFIGURE_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_disable: PROVIDERS_DISABLE_METHOD_NAME, + providers_restore: PROVIDERS_RESTORE_METHOD_NAME, session_new: SESSION_NEW_METHOD_NAME, session_load: SESSION_LOAD_METHOD_NAME, session_set_mode: SESSION_SET_MODE_METHOD_NAME, @@ -4745,15 +4770,15 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize"; /// Method name for the authenticate request. pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate"; -/// Method name for listing configurable providers. +/// Method name for listing supported provider APIs. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list"; -/// Method name for setting provider configuration. +pub(crate) const PROVIDERS_LIST_API_METHOD_NAME: &str = "providers/list_api"; +/// Method name for configuring providers. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set"; -/// Method name for disabling a provider. +pub(crate) const PROVIDERS_CONFIGURE_METHOD_NAME: &str = "providers/configure"; +/// Method name for restoring providers to their defaults. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable"; +pub(crate) const PROVIDERS_RESTORE_METHOD_NAME: &str = "providers/restore"; /// Method name for creating a new session. pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new"; /// Method name for loading an existing session. @@ -4819,23 +4844,23 @@ pub enum ClientRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Lists providers that can be configured by the client. + /// Lists the provider APIs supported by the agent. #[cfg(feature = "unstable_llm_providers")] - ListProvidersRequest(ListProvidersRequest), + ListApiProvidersRequest(ListApiProvidersRequest), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Replaces the configuration for a provider. + /// Configures a set of providers keyed by API protocol. #[cfg(feature = "unstable_llm_providers")] - SetProviderRequest(SetProviderRequest), + ConfigureProvidersRequest(ConfigureProvidersRequest), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Disables a provider. + /// Restores a set of providers to the agent's default configuration. #[cfg(feature = "unstable_llm_providers")] - DisableProviderRequest(DisableProviderRequest), + RestoreProvidersRequest(RestoreProvidersRequest), /// Logs out of the current authenticated state. /// /// After a successful logout, all new sessions will require authentication. @@ -4978,11 +5003,11 @@ impl ClientRequest { Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize, Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate, #[cfg(feature = "unstable_llm_providers")] - Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list, + Self::ListApiProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list_api, #[cfg(feature = "unstable_llm_providers")] - Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set, + Self::ConfigureProvidersRequest(_) => AGENT_METHOD_NAMES.providers_configure, #[cfg(feature = "unstable_llm_providers")] - Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable, + Self::RestoreProvidersRequest(_) => AGENT_METHOD_NAMES.providers_restore, Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout, Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new, Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load, @@ -5025,15 +5050,15 @@ pub enum AgentResponse { InitializeResponse(InitializeResponse), /// Successful result returned for a `authenticate` request. AuthenticateResponse(#[serde(default)] AuthenticateResponse), - /// Successful result returned for a `providers/list` request. + /// Successful result returned for a `providers/list_api` request. #[cfg(feature = "unstable_llm_providers")] - ListProvidersResponse(ListProvidersResponse), - /// Successful result returned for a `providers/set` request. + ListApiProvidersResponse(ListApiProvidersResponse), + /// Successful result returned for a `providers/configure` request. #[cfg(feature = "unstable_llm_providers")] - SetProviderResponse(#[serde(default)] SetProviderResponse), - /// Successful result returned for a `providers/disable` request. + ConfigureProvidersResponse(#[serde(default)] ConfigureProvidersResponse), + /// Successful result returned for a `providers/restore` request. #[cfg(feature = "unstable_llm_providers")] - DisableProviderResponse(#[serde(default)] DisableProviderResponse), + RestoreProvidersResponse(#[serde(default)] RestoreProvidersResponse), /// Successful result returned for a `logout` request. LogoutResponse(#[serde(default)] LogoutResponse), /// Successful result returned for a `session/new` request. @@ -6101,20 +6126,19 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] fn test_provider_current_config_serialization() { - let config = - ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com"); + let config = ProviderCurrentConfig::new("Anthropic", "https://api.anthropic.com"); let json = serde_json::to_value(&config).unwrap(); assert_eq!( json, json!({ - "apiType": "anthropic", + "presentableName": "Anthropic", "baseUrl": "https://api.anthropic.com" }) ); let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.api_type, LlmProtocol::Anthropic); + assert_eq!(deserialized.presentable_name, "Anthropic"); assert_eq!(deserialized.base_url, "https://api.anthropic.com"); } @@ -6122,12 +6146,11 @@ mod test_serialization { #[test] fn test_provider_info_with_current_config() { let info = ProviderInfo::new( - "main", - vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi], - true, + LlmProtocol::Anthropic, + "Anthropic", Some(ProviderCurrentConfig::new( - LlmProtocol::Anthropic, - "https://api.anthropic.com", + "Local Anthropic proxy", + "http://localhost/anthropic", )), ); @@ -6135,50 +6158,46 @@ mod test_serialization { assert_eq!( json, json!({ - "providerId": "main", - "supported": ["anthropic", "openai"], - "required": true, + "apiType": "anthropic", + "presentableName": "Anthropic", "current": { - "apiType": "anthropic", - "baseUrl": "https://api.anthropic.com" + "presentableName": "Local Anthropic proxy", + "baseUrl": "http://localhost/anthropic" } }) ); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "main"); - assert_eq!(deserialized.supported.len(), 2); - assert!(deserialized.required); + assert_eq!(deserialized.api_type, LlmProtocol::Anthropic); + assert_eq!(deserialized.presentable_name, "Anthropic"); assert!(deserialized.current.is_some()); assert_eq!( - deserialized.current.as_ref().unwrap().api_type, - LlmProtocol::Anthropic + deserialized.current.as_ref().unwrap().presentable_name, + "Local Anthropic proxy" + ); + assert_eq!( + deserialized.current.as_ref().unwrap().base_url, + "http://localhost/anthropic" ); } #[cfg(feature = "unstable_llm_providers")] #[test] fn test_provider_info_disabled() { - let info = ProviderInfo::new( - "secondary", - vec![LlmProtocol::OpenAi], - false, - None::, - ); + let info = ProviderInfo::new(LlmProtocol::OpenAi, "OpenAI", None::); let json = serde_json::to_value(&info).unwrap(); assert_eq!( json, json!({ - "providerId": "secondary", - "supported": ["openai"], - "required": false + "apiType": "openai", + "presentableName": "OpenAI" }) ); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "secondary"); - assert!(!deserialized.required); + assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); + assert_eq!(deserialized.presentable_name, "OpenAI"); assert!(deserialized.current.is_none()); } @@ -6187,9 +6206,8 @@ mod test_serialization { fn test_provider_info_missing_current_defaults_to_none() { // current is optional; omitting it should decode as None let json = json!({ - "providerId": "main", - "supported": ["anthropic"], - "required": true + "apiType": "anthropic", + "presentableName": "Anthropic" }); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); assert!(deserialized.current.is_none()); @@ -6202,9 +6220,8 @@ mod test_serialization { // both must deserialize into None so the disabled state is preserved // regardless of which form the peer chose to send. let json = json!({ - "providerId": "main", - "supported": ["anthropic"], - "required": true, + "apiType": "anthropic", + "presentableName": "Anthropic", "current": null }); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); @@ -6213,82 +6230,93 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_list_providers_response_serialization() { - let response = ListProvidersResponse::new(vec![ProviderInfo::new( - "main", - vec![LlmProtocol::Anthropic], - true, + fn test_list_api_providers_response_serialization() { + let response = ListApiProvidersResponse::new(vec![ProviderInfo::new( + LlmProtocol::Anthropic, + "Anthropic", Some(ProviderCurrentConfig::new( - LlmProtocol::Anthropic, + "Anthropic", "https://api.anthropic.com", )), )]); let json = serde_json::to_value(&response).unwrap(); assert_eq!(json["providers"].as_array().unwrap().len(), 1); - assert_eq!(json["providers"][0]["providerId"], "main"); + assert_eq!(json["providers"][0]["apiType"], "anthropic"); - let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap(); + let deserialized: ListApiProvidersResponse = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.providers.len(), 1); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_provider_request_serialization() { + fn test_configure_providers_request_serialization() { use std::collections::HashMap; let mut headers = HashMap::new(); headers.insert("Authorization".to_string(), "Bearer sk-test".to_string()); - let request = - SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") - .headers(headers); + let request = ConfigureProvidersRequest::new(vec![ + ProviderConfigUpdate::new( + LlmProtocol::OpenAi, + "Corporate OpenAI gateway", + "https://api.openai.com/v1", + ) + .headers(headers), + ]); let json = serde_json::to_value(&request).unwrap(); assert_eq!( json, json!({ - "providerId": "main", - "apiType": "openai", - "baseUrl": "https://api.openai.com/v1", - "headers": { - "Authorization": "Bearer sk-test" - } + "providerConfigurations": [{ + "apiProtocol": "openai", + "presentableName": "Corporate OpenAI gateway", + "baseUrl": "https://api.openai.com/v1", + "headers": { + "Authorization": "Bearer sk-test" + } + }] }) ); - let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "main"); - assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); - assert_eq!(deserialized.base_url, "https://api.openai.com/v1"); - assert_eq!(deserialized.headers.len(), 1); + let deserialized: ConfigureProvidersRequest = serde_json::from_value(json).unwrap(); + assert_eq!(deserialized.provider_configurations.len(), 1); + let update = &deserialized.provider_configurations[0]; + assert_eq!(update.api_protocol, LlmProtocol::OpenAi); + assert_eq!(update.presentable_name, "Corporate OpenAI gateway"); + assert_eq!(update.base_url, "https://api.openai.com/v1"); + assert_eq!(update.headers.len(), 1); assert_eq!( - deserialized.headers.get("Authorization").unwrap(), + update.headers.get("Authorization").unwrap(), "Bearer sk-test" ); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_provider_request_omits_empty_headers() { - let request = - SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); + fn test_provider_config_update_omits_empty_headers() { + let update = ProviderConfigUpdate::new( + LlmProtocol::Anthropic, + "Anthropic", + "https://api.anthropic.com", + ); - let json = serde_json::to_value(&request).unwrap(); + let json = serde_json::to_value(&update).unwrap(); // headers should be omitted when empty assert!(!json.as_object().unwrap().contains_key("headers")); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_disable_provider_request_serialization() { - let request = DisableProviderRequest::new("secondary"); + fn test_restore_providers_request_serialization() { + let request = RestoreProvidersRequest::new(vec![LlmProtocol::OpenAi]); let json = serde_json::to_value(&request).unwrap(); - assert_eq!(json, json!({ "providerId": "secondary" })); + assert_eq!(json, json!({ "apiProtocols": ["openai"] })); - let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "secondary"); + let deserialized: RestoreProvidersRequest = serde_json::from_value(json).unwrap(); + assert_eq!(deserialized.api_protocols, vec![LlmProtocol::OpenAi]); } #[cfg(feature = "unstable_llm_providers")] diff --git a/agent-client-protocol-schema/src/v2/agent.rs b/agent-client-protocol-schema/src/v2/agent.rs index 0689e98f1..328874761 100644 --- a/agent-client-protocol-schema/src/v2/agent.rs +++ b/agent-client-protocol-schema/src/v2/agent.rs @@ -3476,8 +3476,8 @@ pub enum LlmProtocol { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct ProviderCurrentConfig { - /// Protocol currently used by this provider. - pub api_type: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Base URL currently used by this provider. #[cfg_attr(feature = "schemars", schemars(url))] pub base_url: String, @@ -3497,9 +3497,9 @@ pub struct ProviderCurrentConfig { impl ProviderCurrentConfig { /// Builds [`ProviderCurrentConfig`] with the required fields set; optional fields start unset or empty. #[must_use] - pub fn new(api_type: LlmProtocol, base_url: impl Into) -> Self { + pub fn new(presentable_name: impl Into, base_url: impl Into) -> Self { Self { - api_type, + presentable_name: presentable_name.into(), base_url: base_url.into(), meta: None, } @@ -3517,28 +3517,6 @@ impl ProviderCurrentConfig { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// -/// Unique identifier for a configurable LLM provider. -#[cfg(feature = "unstable_llm_providers")] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)] -#[serde(transparent)] -#[from(forward)] -#[non_exhaustive] -pub struct ProviderId(pub Arc); - -#[cfg(feature = "unstable_llm_providers")] -impl ProviderId { - /// Wraps a protocol string as a typed [`ProviderId`]. - #[must_use] - pub fn new(id: impl Into) -> Self { - id.into() - } -} - /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -3552,15 +3530,10 @@ impl ProviderId { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct ProviderInfo { - /// Provider identifier, for example "main" or "openai". - pub provider_id: ProviderId, - /// Supported protocol types for this provider. - #[serde_as(deserialize_as = "DefaultOnError>")] - #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))] - pub supported: Vec, - /// Whether this provider is mandatory and cannot be disabled via `providers/disable`. - /// If true, clients must not call `providers/disable` for this provider ID. - pub required: bool, + /// LLM protocol. + pub api_type: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Current effective non-secret routing config. /// Null or omitted means provider is disabled. #[serde(default)] @@ -3582,15 +3555,13 @@ impl ProviderInfo { /// Builds [`ProviderInfo`] with the required fields set; optional fields start unset or empty. #[must_use] pub fn new( - provider_id: impl Into, - supported: Vec, - required: bool, + api_type: LlmProtocol, + presentable_name: impl Into, current: impl IntoOption, ) -> Self { Self { - provider_id: provider_id.into(), - supported, - required, + api_type, + presentable_name: presentable_name.into(), current: current.into_option(), meta: None, } @@ -3612,16 +3583,16 @@ impl ProviderInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/list`. +/// Request parameters for `providers/list_api`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_API_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct ListProvidersRequest { +pub struct ListApiProvidersRequest { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3635,8 +3606,8 @@ pub struct ListProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl ListProvidersRequest { - /// Builds [`ListProvidersRequest`] with the required request fields set; optional fields start unset or empty. +impl ListApiProvidersRequest { + /// Builds [`ListApiProvidersRequest`] with the required request fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -3658,16 +3629,16 @@ impl ListProvidersRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/list`. +/// Response to `providers/list_api`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_API_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct ListProvidersResponse { +pub struct ListApiProvidersResponse { /// Configurable providers with current routing info suitable for UI display. pub providers: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3683,8 +3654,8 @@ pub struct ListProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl ListProvidersResponse { - /// Builds [`ListProvidersResponse`] with the required response fields set; optional fields start unset or empty. +impl ListApiProvidersResponse { + /// Builds [`ListApiProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new(providers: Vec) -> Self { Self { @@ -3709,27 +3680,25 @@ impl ListProvidersResponse { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/set`. -/// -/// Replaces the full configuration for one provider ID. +/// Configuration update for a single provider, keyed by API protocol. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProviderRequest { - /// Provider ID to configure. - pub provider_id: ProviderId, - /// Protocol type for this provider. - pub api_type: LlmProtocol, +pub struct ProviderConfigUpdate { + /// LLM protocol to configure. + pub api_protocol: LlmProtocol, + /// Name of the provider to be shown in UI. + pub presentable_name: String, /// Base URL for requests sent through this provider. #[cfg_attr(feature = "schemars", schemars(url))] pub base_url: String, /// Full headers map for this provider. /// May include authorization, routing, or other integration-specific headers. + /// Omitting this field is equivalent to an empty map (no headers). #[serde(default, skip_serializing_if = "HashMap::is_empty")] pub headers: HashMap, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3745,17 +3714,17 @@ pub struct SetProviderRequest { } #[cfg(feature = "unstable_llm_providers")] -impl SetProviderRequest { - /// Builds [`SetProviderRequest`] with the required request fields set; optional fields start unset or empty. +impl ProviderConfigUpdate { + /// Builds [`ProviderConfigUpdate`] with the required fields set; optional fields start unset or empty. #[must_use] pub fn new( - provider_id: impl Into, - api_type: LlmProtocol, + api_protocol: LlmProtocol, + presentable_name: impl Into, base_url: impl Into, ) -> Self { Self { - provider_id: provider_id.into(), - api_type, + api_protocol, + presentable_name: presentable_name.into(), base_url: base_url.into(), headers: HashMap::new(), meta: None, @@ -3786,16 +3755,69 @@ impl SetProviderRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/set`. +/// Request parameters for `providers/configure`. +/// +/// Overrides (updates) the configuration for a set of providers keyed by API protocol. +#[cfg(feature = "unstable_llm_providers")] +#[serde_as] +#[skip_serializing_none] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_CONFIGURE_METHOD_NAME)))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct ConfigureProvidersRequest { + /// Configuration updates to apply, one per API protocol. + pub provider_configurations: Vec, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde_as(deserialize_as = "DefaultOnError")] + #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))] + #[serde(default)] + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_llm_providers")] +impl ConfigureProvidersRequest { + /// Builds [`ConfigureProvidersRequest`] with the required request fields set; optional fields start unset or empty. + #[must_use] + pub fn new(provider_configurations: Vec) -> Self { + Self { + provider_configurations, + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `providers/configure`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_CONFIGURE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProviderResponse { +pub struct ConfigureProvidersResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3809,8 +3831,8 @@ pub struct SetProviderResponse { } #[cfg(feature = "unstable_llm_providers")] -impl SetProviderResponse { - /// Builds [`SetProviderResponse`] with the required response fields set; optional fields start unset or empty. +impl ConfigureProvidersResponse { + /// Builds [`ConfigureProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -3832,18 +3854,20 @@ impl SetProviderResponse { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Request parameters for `providers/disable`. +/// Request parameters for `providers/restore`. +/// +/// Restores the listed API protocols to the agent's default provider configuration. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_RESTORE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProviderRequest { - /// Provider ID to disable. - pub provider_id: ProviderId, +pub struct RestoreProvidersRequest { + /// List of API protocols to restore to default providers. + pub api_protocols: Vec, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3857,12 +3881,12 @@ pub struct DisableProviderRequest { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProviderRequest { - /// Builds [`DisableProviderRequest`] with the required request fields set; optional fields start unset or empty. +impl RestoreProvidersRequest { + /// Builds [`RestoreProvidersRequest`] with the required request fields set; optional fields start unset or empty. #[must_use] - pub fn new(provider_id: impl Into) -> Self { + pub fn new(api_protocols: Vec) -> Self { Self { - provider_id: provider_id.into(), + api_protocols, meta: None, } } @@ -3883,16 +3907,16 @@ impl DisableProviderRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// -/// Response to `providers/disable`. +/// Response to `providers/restore`. #[cfg(feature = "unstable_llm_providers")] #[serde_as] #[skip_serializing_none] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))] +#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_RESTORE_METHOD_NAME)))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProviderResponse { +pub struct RestoreProvidersResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3906,8 +3930,8 @@ pub struct DisableProviderResponse { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProviderResponse { - /// Builds [`DisableProviderResponse`] with the required response fields set; optional fields start unset or empty. +impl RestoreProvidersResponse { + /// Builds [`RestoreProvidersResponse`] with the required response fields set; optional fields start unset or empty. #[must_use] pub fn new() -> Self { Self::default() @@ -4939,15 +4963,15 @@ pub struct AgentMethodNames { pub initialize: &'static str, /// Method for authenticating with the agent. pub auth_login: &'static str, - /// Method for listing configurable providers. + /// Method for listing supported provider APIs. #[cfg(feature = "unstable_llm_providers")] - pub providers_list: &'static str, - /// Method for setting provider configuration. + pub providers_list_api: &'static str, + /// Method for configuring providers. #[cfg(feature = "unstable_llm_providers")] - pub providers_set: &'static str, - /// Method for disabling a provider. + pub providers_configure: &'static str, + /// Method for restoring providers to their defaults. #[cfg(feature = "unstable_llm_providers")] - pub providers_disable: &'static str, + pub providers_restore: &'static str, /// Method for creating a new session. pub session_new: &'static str, /// Method for setting a configuration option for a session. @@ -5009,11 +5033,11 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { initialize: INITIALIZE_METHOD_NAME, auth_login: AUTH_LOGIN_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_list: PROVIDERS_LIST_METHOD_NAME, + providers_list_api: PROVIDERS_LIST_API_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_set: PROVIDERS_SET_METHOD_NAME, + providers_configure: PROVIDERS_CONFIGURE_METHOD_NAME, #[cfg(feature = "unstable_llm_providers")] - providers_disable: PROVIDERS_DISABLE_METHOD_NAME, + providers_restore: PROVIDERS_RESTORE_METHOD_NAME, session_new: SESSION_NEW_METHOD_NAME, session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME, session_prompt: SESSION_PROMPT_METHOD_NAME, @@ -5053,15 +5077,15 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize"; /// Method name for the `auth/login` request. pub(crate) const AUTH_LOGIN_METHOD_NAME: &str = "auth/login"; -/// Method name for listing configurable providers. +/// Method name for listing supported provider APIs. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list"; -/// Method name for setting provider configuration. +pub(crate) const PROVIDERS_LIST_API_METHOD_NAME: &str = "providers/list_api"; +/// Method name for configuring providers. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set"; -/// Method name for disabling a provider. +pub(crate) const PROVIDERS_CONFIGURE_METHOD_NAME: &str = "providers/configure"; +/// Method name for restoring providers to their defaults. #[cfg(feature = "unstable_llm_providers")] -pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable"; +pub(crate) const PROVIDERS_RESTORE_METHOD_NAME: &str = "providers/restore"; /// Method name for creating a new session. pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new"; /// Method name for setting a configuration option for a session. @@ -5126,23 +5150,23 @@ pub enum ClientRequest { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Lists providers that can be configured by the client. + /// Lists the provider APIs supported by the agent. #[cfg(feature = "unstable_llm_providers")] - ListProvidersRequest(Box), + ListApiProvidersRequest(Box), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Replaces the configuration for a provider. + /// Configures a set of providers keyed by API protocol. #[cfg(feature = "unstable_llm_providers")] - SetProviderRequest(Box), + ConfigureProvidersRequest(Box), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Disables a provider. + /// Restores a set of providers to the agent's default configuration. #[cfg(feature = "unstable_llm_providers")] - DisableProviderRequest(Box), + RestoreProvidersRequest(Box), /// Logs out of the current authenticated state. /// /// Agents MUST support this method when their `initialize` response advertised @@ -5260,11 +5284,11 @@ impl ClientRequest { Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize, Self::LoginAuthRequest(_) => AGENT_METHOD_NAMES.auth_login, #[cfg(feature = "unstable_llm_providers")] - Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list, + Self::ListApiProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list_api, #[cfg(feature = "unstable_llm_providers")] - Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set, + Self::ConfigureProvidersRequest(_) => AGENT_METHOD_NAMES.providers_configure, #[cfg(feature = "unstable_llm_providers")] - Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable, + Self::RestoreProvidersRequest(_) => AGENT_METHOD_NAMES.providers_restore, Self::LogoutAuthRequest(_) => AGENT_METHOD_NAMES.auth_logout, Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new, Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list, @@ -5304,15 +5328,15 @@ pub enum AgentResponse { InitializeResponse(Box), /// Successful result returned for an `auth/login` request. LoginAuthResponse(#[serde(default)] Box), - /// Successful result returned for a `providers/list` request. + /// Successful result returned for a `providers/list_api` request. #[cfg(feature = "unstable_llm_providers")] - ListProvidersResponse(Box), - /// Successful result returned for a `providers/set` request. + ListApiProvidersResponse(Box), + /// Successful result returned for a `providers/configure` request. #[cfg(feature = "unstable_llm_providers")] - SetProviderResponse(#[serde(default)] Box), - /// Successful result returned for a `providers/disable` request. + ConfigureProvidersResponse(#[serde(default)] Box), + /// Successful result returned for a `providers/restore` request. #[cfg(feature = "unstable_llm_providers")] - DisableProviderResponse(#[serde(default)] Box), + RestoreProvidersResponse(#[serde(default)] Box), /// Successful result returned for an `auth/logout` request. LogoutAuthResponse(#[serde(default)] Box), /// Successful result returned for a `session/new` request. @@ -6649,20 +6673,19 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] fn test_provider_current_config_serialization() { - let config = - ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com"); + let config = ProviderCurrentConfig::new("Anthropic", "https://api.anthropic.com"); let json = serde_json::to_value(&config).unwrap(); assert_eq!( json, json!({ - "apiType": "anthropic", + "presentableName": "Anthropic", "baseUrl": "https://api.anthropic.com" }) ); let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.api_type, LlmProtocol::Anthropic); + assert_eq!(deserialized.presentable_name, "Anthropic"); assert_eq!(deserialized.base_url, "https://api.anthropic.com"); } @@ -6670,12 +6693,11 @@ mod test_serialization { #[test] fn test_provider_info_with_current_config() { let info = ProviderInfo::new( - "main", - vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi], - true, + LlmProtocol::Anthropic, + "Anthropic", Some(ProviderCurrentConfig::new( - LlmProtocol::Anthropic, - "https://api.anthropic.com", + "Local Anthropic proxy", + "http://localhost/anthropic", )), ); @@ -6683,50 +6705,42 @@ mod test_serialization { assert_eq!( json, json!({ - "providerId": "main", - "supported": ["anthropic", "openai"], - "required": true, + "apiType": "anthropic", + "presentableName": "Anthropic", "current": { - "apiType": "anthropic", - "baseUrl": "https://api.anthropic.com" + "presentableName": "Local Anthropic proxy", + "baseUrl": "http://localhost/anthropic" } }) ); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "main"); - assert_eq!(deserialized.supported.len(), 2); - assert!(deserialized.required); + assert_eq!(deserialized.api_type, LlmProtocol::Anthropic); + assert_eq!(deserialized.presentable_name, "Anthropic"); assert!(deserialized.current.is_some()); assert_eq!( - deserialized.current.as_ref().unwrap().api_type, - LlmProtocol::Anthropic + deserialized.current.as_ref().unwrap().presentable_name, + "Local Anthropic proxy" ); } #[cfg(feature = "unstable_llm_providers")] #[test] fn test_provider_info_disabled() { - let info = ProviderInfo::new( - "secondary", - vec![LlmProtocol::OpenAi], - false, - None::, - ); + let info = ProviderInfo::new(LlmProtocol::OpenAi, "OpenAI", None::); let json = serde_json::to_value(&info).unwrap(); assert_eq!( json, json!({ - "providerId": "secondary", - "supported": ["openai"], - "required": false + "apiType": "openai", + "presentableName": "OpenAI" }) ); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "secondary"); - assert!(!deserialized.required); + assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); + assert_eq!(deserialized.presentable_name, "OpenAI"); assert!(deserialized.current.is_none()); } @@ -6735,9 +6749,8 @@ mod test_serialization { fn test_provider_info_missing_current_defaults_to_none() { // current is optional; omitting it should decode as None let json = json!({ - "providerId": "main", - "supported": ["anthropic"], - "required": true + "apiType": "anthropic", + "presentableName": "Anthropic" }); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); assert!(deserialized.current.is_none()); @@ -6750,9 +6763,8 @@ mod test_serialization { // both must deserialize into None so the disabled state is preserved // regardless of which form the peer chose to send. let json = json!({ - "providerId": "main", - "supported": ["anthropic"], - "required": true, + "apiType": "anthropic", + "presentableName": "Anthropic", "current": null }); let deserialized: ProviderInfo = serde_json::from_value(json).unwrap(); @@ -6761,82 +6773,93 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_list_providers_response_serialization() { - let response = ListProvidersResponse::new(vec![ProviderInfo::new( - "main", - vec![LlmProtocol::Anthropic], - true, + fn test_list_api_providers_response_serialization() { + let response = ListApiProvidersResponse::new(vec![ProviderInfo::new( + LlmProtocol::Anthropic, + "Anthropic", Some(ProviderCurrentConfig::new( - LlmProtocol::Anthropic, + "Anthropic", "https://api.anthropic.com", )), )]); let json = serde_json::to_value(&response).unwrap(); assert_eq!(json["providers"].as_array().unwrap().len(), 1); - assert_eq!(json["providers"][0]["providerId"], "main"); + assert_eq!(json["providers"][0]["apiType"], "anthropic"); - let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap(); + let deserialized: ListApiProvidersResponse = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.providers.len(), 1); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_provider_request_serialization() { + fn test_configure_providers_request_serialization() { use std::collections::HashMap; let mut headers = HashMap::new(); headers.insert("Authorization".to_string(), "Bearer sk-test".to_string()); - let request = - SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") - .headers(headers); + let request = ConfigureProvidersRequest::new(vec![ + ProviderConfigUpdate::new( + LlmProtocol::OpenAi, + "Corporate OpenAI gateway", + "https://api.openai.com/v1", + ) + .headers(headers), + ]); let json = serde_json::to_value(&request).unwrap(); assert_eq!( json, json!({ - "providerId": "main", - "apiType": "openai", - "baseUrl": "https://api.openai.com/v1", - "headers": { - "Authorization": "Bearer sk-test" - } + "providerConfigurations": [{ + "apiProtocol": "openai", + "presentableName": "Corporate OpenAI gateway", + "baseUrl": "https://api.openai.com/v1", + "headers": { + "Authorization": "Bearer sk-test" + } + }] }) ); - let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "main"); - assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); - assert_eq!(deserialized.base_url, "https://api.openai.com/v1"); - assert_eq!(deserialized.headers.len(), 1); + let deserialized: ConfigureProvidersRequest = serde_json::from_value(json).unwrap(); + assert_eq!(deserialized.provider_configurations.len(), 1); + let update = &deserialized.provider_configurations[0]; + assert_eq!(update.api_protocol, LlmProtocol::OpenAi); + assert_eq!(update.presentable_name, "Corporate OpenAI gateway"); + assert_eq!(update.base_url, "https://api.openai.com/v1"); + assert_eq!(update.headers.len(), 1); assert_eq!( - deserialized.headers.get("Authorization").unwrap(), + update.headers.get("Authorization").unwrap(), "Bearer sk-test" ); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_provider_request_omits_empty_headers() { - let request = - SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); + fn test_provider_config_update_omits_empty_headers() { + let update = ProviderConfigUpdate::new( + LlmProtocol::Anthropic, + "Anthropic", + "https://api.anthropic.com", + ); - let json = serde_json::to_value(&request).unwrap(); + let json = serde_json::to_value(&update).unwrap(); // headers should be omitted when empty assert!(!json.as_object().unwrap().contains_key("headers")); } #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_disable_provider_request_serialization() { - let request = DisableProviderRequest::new("secondary"); + fn test_restore_providers_request_serialization() { + let request = RestoreProvidersRequest::new(vec![LlmProtocol::OpenAi]); let json = serde_json::to_value(&request).unwrap(); - assert_eq!(json, json!({ "providerId": "secondary" })); + assert_eq!(json, json!({ "apiProtocols": ["openai"] })); - let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap(); - assert_eq!(deserialized.provider_id.to_string(), "secondary"); + let deserialized: RestoreProvidersRequest = serde_json::from_value(json).unwrap(); + assert_eq!(deserialized.api_protocols, vec![LlmProtocol::OpenAi]); } #[cfg(feature = "unstable_llm_providers")] diff --git a/docs/protocol/v1/draft/schema.mdx b/docs/protocol/v1/draft/schema.mdx index 009b0f6e5..2b7fe6fbe 100644 --- a/docs/protocol/v1/draft/schema.mdx +++ b/docs/protocol/v1/draft/schema.mdx @@ -706,22 +706,24 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d The list of suggestions. - -### providers/disable + +### providers/configure **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Disables a provider. +Configures a set of providers keyed by API protocol. -#### DisableProviderRequest +#### ConfigureProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/disable`. +Request parameters for `providers/configure`. + +Overrides (updates) the configuration for a set of providers keyed by API protocol. **Type:** Object @@ -735,17 +737,17 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/draft/extensibility) -ProviderId} required> - Provider ID to disable. +ProviderConfigUpdate[]} required> + Configuration updates to apply, one per API protocol. -#### DisableProviderResponse +#### ConfigureProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/disable`. +Response to `providers/configure`. **Type:** Object @@ -760,22 +762,22 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d - -### providers/list + +### providers/list_api **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Lists providers that can be configured by the client. +Lists the provider APIs supported by the agent. -#### ListProvidersRequest +#### ListApiProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/list`. +Request parameters for `providers/list_api`. **Type:** Object @@ -790,13 +792,13 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d -#### ListProvidersResponse +#### ListApiProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/list`. +Response to `providers/list_api`. **Type:** Object @@ -814,24 +816,24 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d Configurable providers with current routing info suitable for UI display. - -### providers/set + +### providers/restore **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Replaces the configuration for a provider. +Restores a set of providers to the agent's default configuration. -#### SetProviderRequest +#### RestoreProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/set`. +Request parameters for `providers/restore`. -Replaces the full configuration for one provider ID. +Restores the listed API protocols to the agent's default provider configuration. **Type:** Object @@ -845,27 +847,17 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/draft/extensibility) -LlmProtocol} required> - Protocol type for this provider. - - - Base URL for requests sent through this provider. - - - Full headers map for this provider. -May include authorization, routing, or other integration-specific headers. - -ProviderId} required> - Provider ID to configure. +LlmProtocol[]} required> + List of API protocols to restore to default providers. -#### SetProviderResponse +#### RestoreProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/set`. +Response to `providers/restore`. **Type:** Object @@ -6718,13 +6710,13 @@ Non-breaking changes should be introduced via capabilities. | Minimum | `0` | | Maximum | `65535` | -## ProviderCurrentConfig +## ProviderConfigUpdate **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Current effective non-secret routing configuration for a provider. +Configuration update for a single provider, keyed by API protocol. **Type:** Object @@ -6738,22 +6730,47 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/draft/extensibility) -LlmProtocol} required> - Protocol currently used by this provider. +LlmProtocol} required> + LLM protocol to configure. - Base URL currently used by this provider. + Base URL for requests sent through this provider. + + + Full headers map for this provider. +May include authorization, routing, or other integration-specific headers. +Omitting this field is equivalent to an empty map (no headers). + + + Name of the provider to be shown in UI. -## ProviderId +## ProviderCurrentConfig **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Unique identifier for a configurable LLM provider. +Current effective non-secret routing configuration for a provider. -**Type:** `string` +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/draft/extensibility) + + + + Base URL currently used by this provider. + + + Name of the provider to be shown in UI. + ## ProviderInfo @@ -6774,20 +6791,16 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/draft/extensibility) + +LlmProtocol} required> + LLM protocol. ProviderCurrentConfig | null} > Current effective non-secret routing config. Null or omitted means provider is disabled. -ProviderId} required> - Provider identifier, for example "main" or "openai". - - - Whether this provider is mandatory and cannot be disabled via `providers/disable`. -If true, clients must not call `providers/disable` for this provider ID. - -LlmProtocol[]} required> - Supported protocol types for this provider. + + Name of the provider to be shown in UI. ## ProvidersCapabilities diff --git a/docs/protocol/v2/draft/schema.mdx b/docs/protocol/v2/draft/schema.mdx index 99593f076..7298b25ec 100644 --- a/docs/protocol/v2/draft/schema.mdx +++ b/docs/protocol/v2/draft/schema.mdx @@ -743,22 +743,24 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d The list of suggestions. - -### providers/disable + +### providers/configure **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Disables a provider. +Configures a set of providers keyed by API protocol. -#### DisableProviderRequest +#### ConfigureProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/disable`. +Request parameters for `providers/configure`. + +Overrides (updates) the configuration for a set of providers keyed by API protocol. **Type:** Object @@ -772,17 +774,17 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) -ProviderId} required> - Provider ID to disable. +ProviderConfigUpdate[]} required> + Configuration updates to apply, one per API protocol. -#### DisableProviderResponse +#### ConfigureProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/disable`. +Response to `providers/configure`. **Type:** Object @@ -797,22 +799,22 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d - -### providers/list + +### providers/list_api **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Lists providers that can be configured by the client. +Lists the provider APIs supported by the agent. -#### ListProvidersRequest +#### ListApiProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/list`. +Request parameters for `providers/list_api`. **Type:** Object @@ -827,13 +829,13 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d -#### ListProvidersResponse +#### ListApiProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/list`. +Response to `providers/list_api`. **Type:** Object @@ -851,24 +853,24 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Configurable providers with current routing info suitable for UI display. - -### providers/set + +### providers/restore **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Replaces the configuration for a provider. +Restores a set of providers to the agent's default configuration. -#### SetProviderRequest +#### RestoreProvidersRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for `providers/set`. +Request parameters for `providers/restore`. -Replaces the full configuration for one provider ID. +Restores the listed API protocols to the agent's default provider configuration. **Type:** Object @@ -882,30 +884,17 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) -LlmProtocol} required> - Protocol type for this provider. - - - Base URL for requests sent through this provider. - - - Format: `uri` - - - - Full headers map for this provider. -May include authorization, routing, or other integration-specific headers. - -ProviderId} required> - Provider ID to configure. +LlmProtocol[]} required> + List of API protocols to restore to default providers. -#### SetProviderResponse +#### RestoreProvidersResponse **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to `providers/set`. +Response to `providers/restore`. **Type:** Object @@ -6905,13 +6894,13 @@ Non-breaking changes should be introduced via capabilities. | Minimum | `0` | | Maximum | `65535` | -## ProviderCurrentConfig +## ProviderConfigUpdate **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Current effective non-secret routing configuration for a provider. +Configuration update for a single provider, keyed by API protocol. **Type:** Object @@ -6925,25 +6914,53 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) -LlmProtocol} required> - Protocol currently used by this provider. +LlmProtocol} required> + LLM protocol to configure. - Base URL currently used by this provider. + Base URL for requests sent through this provider. - Format: `uri` + + Full headers map for this provider. +May include authorization, routing, or other integration-specific headers. +Omitting this field is equivalent to an empty map (no headers). + + + Name of the provider to be shown in UI. + -## ProviderId +## ProviderCurrentConfig **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Unique identifier for a configurable LLM provider. +Current effective non-secret routing configuration for a provider. -**Type:** `string` +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) + + + + Base URL currently used by this provider. + + - Format: `uri` + + + + Name of the provider to be shown in UI. + ## ProviderInfo @@ -6964,20 +6981,16 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) + +LlmProtocol} required> + LLM protocol. ProviderCurrentConfig | null} > Current effective non-secret routing config. Null or omitted means provider is disabled. -ProviderId} required> - Provider identifier, for example "main" or "openai". - - - Whether this provider is mandatory and cannot be disabled via `providers/disable`. -If true, clients must not call `providers/disable` for this provider ID. - -LlmProtocol[]} required> - Supported protocol types for this provider. + + Name of the provider to be shown in UI. ## ProvidersCapabilities diff --git a/docs/rfds/custom-llm-endpoint.mdx b/docs/rfds/custom-llm-endpoint.mdx index b40ed5f4e..b59897219 100644 --- a/docs/rfds/custom-llm-endpoint.mdx +++ b/docs/rfds/custom-llm-endpoint.mdx @@ -2,17 +2,17 @@ title: "Configurable LLM Providers" --- -- Author(s): [@anna239](https://github.com/anna239), [@xtmq](https://github.com/xtmq) +- Author(s): [@anna239](https://github.com/anna239), [@xtmq](https://github.com/xtmq), [@vadim-briliantov](https://github.com/Ololoshechkin) ## Elevator pitch > What are you proposing to change? -Add the ability for clients to discover and configure agent LLM providers (identified by `id`) via dedicated provider methods: +Add the ability for clients to discover and configure agent LLM providers (identified by API type) via dedicated provider methods: -- `providers/list` -- `providers/set` -- `providers/disable` +- `providers/list_api` +- `providers/configure` +- `providers/restore` This allows clients to route LLM requests through their own infrastructure (proxies, gateways, or self-hosted models) without agents needing to know about this configuration in advance. @@ -24,8 +24,8 @@ ACP does not currently define a standard method for configuring LLM providers. In practice, provider configuration is usually done via environment variables or agent-specific config files. That creates several problems: -- No standard way for clients to discover what providers an agent exposes -- No standard way to update one specific provider by id +- No standard way for clients to discover what provider APIs an agent supports/exposes +- No standard way to configure custom LLM provider connections for all (or some) of the supported LLM provider APIs - No standard way to disable a specific provider at runtime while preserving provider discoverability - Secret-bearing values in headers are difficult to handle safely when configuration must be round-tripped @@ -63,23 +63,41 @@ sequenceDiagram Client->>Agent: initialize Agent-->>Client: initialize response (agentCapabilities.providers = {}) - Client->>Agent: providers/list - Agent-->>Client: providers/list response + Client->>Agent: providers/list_api + Agent-->>Client: providers/list_api response - Client->>Agent: providers/set (id = "main") - Agent-->>Client: providers/set response + Client->>Agent: providers/configure + Agent-->>Client: providers/configure response - Client->>Agent: providers/disable (optional) - Agent-->>Client: providers/disable response + Client->>Agent: providers/restore (optional) + Agent-->>Client: providers/restore response Client->>Agent: session/new + + loop Prompt turns + Client->>Agent: session/prompt (user message) + Agent-->>Client: session/prompt response (stopReason) + + opt Client changes providers + opt Configure new LLM provider mapping + Client->>Agent: providers/configure (optional) + Agent-->>Client: providers/configure response + end + opt Restore to defaults + Client->>Agent: providers/restore (optional) + Agent-->>Client: providers/restore response + end + end + end ``` 1. Client initializes and checks `agentCapabilities.providers`. -2. Client calls `providers/list` to discover available providers, their current routing targets (or disabled state), supported protocol types, and whether they are required. -3. Client calls `providers/set` to apply new (required) configuration for a specific provider ID. -4. Client may call `providers/disable` when a non-required provider should be disabled. +2. Client calls `providers/list_api` to discover supported provider APIs (protocol types), and whether they are required. +3. Client calls `providers/configure` to apply new (required) configuration for a set of specific providers. +4. Client may call `providers/restore` when some set of LLM providers must be restored to defaults. 5. Client creates or loads sessions. +6. A client can then send `providers/configure` or `providers/restore` anytime +7. Then, after starting a new turn in any of the active sessions (there might be multiple sessions in parallel), agent starts using updated providers list. ### Capability advertisement @@ -116,27 +134,19 @@ type LlmProtocol = "anthropic" | "openai" | "azure" | "vertex" | "bedrock" | string; interface ProviderCurrentConfig { - /** Protocol currently used by this provider. */ - apiType: LlmProtocol; + /** Name of the provider to be shown in UI. */ + presentableName: string; /** Base URL currently used by this provider. */ baseUrl: string; } -type ProviderId = string; - interface ProviderInfo { - /** Provider identifier, for example "main" or "openai". */ - providerId: ProviderId; - - /** Supported protocol types for this provider. */ - supported: LlmProtocol[]; + /** LLM protocol. */ + apiType: LlmProtocol; - /** - * Whether this provider is mandatory and cannot be disabled via providers/disable. - * If true, clients must not call providers/disable for this provider ID. - */ - required: boolean; + /** Name of the provider to be shown in UI. */ + presentableName: string; /** * Current effective non-secret routing config. @@ -149,15 +159,15 @@ interface ProviderInfo { } ``` -### `providers/list` +### `providers/list_api` ```typescript -interface ProvidersListRequest { +interface ProviderAPIListRequest { /** Extension metadata */ _meta?: Record; } -interface ProvidersListResponse { +interface ProviderAPIListResponse { /** Configurable providers with current routing info suitable for UI display. */ providers: ProviderInfo[]; @@ -168,15 +178,15 @@ interface ProvidersListResponse { ### `providers/set` -`providers/set` updates the full configuration for one provider ID. +`providers/set` overrides (updates) the configuration for a set of providers. ```typescript -interface SetProviderRequest { - /** Provider ID to configure. */ - providerId: ProviderId; +interface ProviderConfigUpdateReq { + /** LLM protocol to configure. */ + apiProtocol: LlmProtocol; - /** Protocol type for this provider. */ - apiType: LlmProtocol; + /** Name of the provider to be shown in UI. */ + presentableName: string; /** Base URL for requests sent through this provider. */ baseUrl: string; @@ -192,18 +202,25 @@ interface SetProviderRequest { _meta?: Record; } -interface SetProviderResponse { +interface SetProvidersRequest { + providerConfigurations: ProviderConfigUpdateReq[]; + + /** Extension metadata */ + _meta?: Record; +} + +interface SetProvidersResponse { /** Extension metadata */ _meta?: Record; } ``` -### `providers/disable` +### `providers/restore` ```typescript -interface DisableProviderRequest { - /** Provider ID to disable. */ - providerId: ProviderId; +interface RestoreProvidersRequest { + /** List of API protocols to restore to default providers */ + apiProtocols: LlmProtocol[]; /** Extension metadata */ _meta?: Record; @@ -237,18 +254,18 @@ interface DisableProviderResponse { } ``` -**providers/list Request:** +**providers/list_api Request:** ```json { "jsonrpc": "2.0", "id": 1, - "method": "providers/list", + "method": "providers/list_api", "params": {} } ``` -**providers/list Response:** +**providers/list_api Response:** ```json { @@ -257,18 +274,16 @@ interface DisableProviderResponse { "result": { "providers": [ { - "providerId": "main", - "supported": ["bedrock", "vertex", "azure", "anthropic"], - "required": true, + "apiType": "anthropic", + "presentableName": "Anthropic", "current": { - "apiType": "anthropic", + "presentableName": "Local Anthropic proxy", "baseUrl": "http://localhost/anthropic" } }, { - "providerId": "openai", - "supported": ["openai"], - "required": false, + "apiType": "openai", + "presentableName": "OpenAI", "current": null } ] @@ -276,25 +291,34 @@ interface DisableProviderResponse { } ``` -**providers/set Request:** +**providers/configure Request:** ```json { "jsonrpc": "2.0", "id": 2, - "method": "providers/set", + "method": "providers/configure", "params": { - "providerId": "main", - "apiType": "anthropic", - "baseUrl": "https://llm-gateway.corp.example.com/anthropic/v1", - "headers": { - "X-Request-Source": "my-ide" - } + "providerConfigurations": [ + { + "apiProtocol": "anthropic", + "presentableName": "Corporate Anthropic gateway", + "baseUrl": "https://llm-gateway.corp.example.com/anthropic/v1", + "headers": { + "X-Request-Source": "my-ide" + } + }, + { + "apiProtocol": "openai", + "presentableName": "Corporate OpenAI gateway", + "baseUrl": "https://llm-gateway.corp.example.com/openai/v1" + } + ] } } ``` -**providers/set Response:** +**providers/configure Response:** ```json { @@ -304,20 +328,20 @@ interface DisableProviderResponse { } ``` -**providers/disable Request:** +**providers/restore Request:** ```json { "jsonrpc": "2.0", "id": 3, - "method": "providers/disable", + "method": "providers/restore", "params": { - "providerId": "openai" + "apiProtocols": ["openai"] } } ``` -**providers/disable Response:** +**providers/restore Response:** ```json { @@ -330,49 +354,42 @@ interface DisableProviderResponse { ### Behavior 1. **Capability discovery**: agents that support provider methods MUST advertise `agentCapabilities.providers: {}` in `initialize`. Clients SHOULD only call `providers/*` when this capability is present. -2. **Timing and session impact**: provider methods MUST be called after `initialize`. Clients SHOULD configure providers before creating or loading sessions. Agents MAY choose not to apply changes to already running sessions, but SHOULD apply them to sessions created or loaded after the change. -3. **List semantics**: `providers/list` returns configurable providers, their supported protocol types, current effective routing, and `required` flag. Providers SHOULD remain discoverable in list after `providers/disable`. -4. **Client behavior for required providers**: clients SHOULD NOT call `providers/disable` for providers where `required: true`. -5. **Disabled state encoding**: in `providers/list`, `current` omitted or `current: null` means the provider is disabled and MUST NOT be used by the agent for LLM calls. -6. **Set semantics and validation**: `providers/set` replaces the full configuration for the target `id` (`apiType`, `baseUrl`, `headers`); an omitted `headers` field is treated as an empty map. If `id` is unknown, `apiType` is unsupported for that provider, or params are malformed, agents SHOULD return `invalid_params`. -7. **Disable semantics**: `providers/disable` disables the target provider at runtime. A disabled provider MUST appear in `providers/list` with `current` omitted or `current: null`. If target provider has `required: true`, agents MUST return `invalid_params`. Disabling an unknown `id` SHOULD be treated as success (idempotent behavior). -8. **Scope and persistence**: provider configuration is process-scoped and SHOULD NOT be persisted to disk. +2. **Timing and session impact**: provider methods MUST be called after `initialize`. Clients SHOULD configure providers before creating or loading sessions. Agents MAY choose not to apply changes to prompt turns that are already running, but MUST apply them starting from the next prompt turn in any active session and to sessions created or loaded after the change. +3. **List semantics**: `providers/list_api` returns the supported provider APIs (protocol types), their presentable names, and the current effective non-secret routing config (`current`). Providers SHOULD remain discoverable in the list after `providers/restore`, and while disabled. +4. **Disabled state encoding**: in `providers/list_api`, `current` omitted or `current: null` means the provider is disabled and MUST NOT be used by the agent for LLM calls. +5. **Configure semantics and validation**: `providers/configure` replaces the full configuration (`presentableName`, `baseUrl`, `headers`) for every `apiProtocol` listed in `providerConfigurations`; an omitted `headers` field is treated as an empty map. Providers whose protocols are not listed keep their current configuration. If any `apiProtocol` is unsupported by the agent or params are malformed, agents SHOULD return `invalid_params` and SHOULD NOT apply the update partially. +6. **Restore semantics**: `providers/restore` restores every listed `apiProtocol` to the agent's default configuration. If the agent has no default for a protocol, the provider becomes disabled (`current` omitted or `current: null` in `providers/list_api`). Restoring a protocol that is already at its default, or that is unknown to the agent, SHOULD be treated as success (idempotent behavior). +7. **Scope and persistence**: provider configuration is process-scoped and SHOULD NOT be persisted to disk. ## Frequently asked questions > What questions have arisen over the course of authoring this document? -### What does `null` mean in `providers/list`? +### What does `null` mean in `providers/list_api`? `current` omitted or `current: null` means the provider is disabled. -When disabled, the agent MUST NOT route LLM calls through that provider until the client enables it again with `providers/set`. - -### Why is there a `required` flag? - -Some providers are mandatory for agent operation and must not be disabled. - -`required` lets clients hide or disable the provider-disable action in UI and avoid calling `providers/disable` for those ids. +When disabled, the agent MUST NOT route LLM calls through that provider until the client configures it again with `providers/configure`, or `providers/restore` brings back a default configuration for it. ### Why not a single `providers/update` method for full list replacement? A full-list update means the client must send complete configuration (including `headers`) for all providers every time. -If the client wants to change only one provider, it may not know headers for the others. In that case it cannot safely build a correct full-list payload. +If the client wants to change only some providers, it may not know headers for the others. In that case it cannot safely build a correct full-list payload. -Also, `providers/list` does not return headers, so the client cannot simply "take what the agent returned" and send it back with one edit. +Also, `providers/list_api` does not return headers, so the client cannot simply "take what the agent returned" and send it back with one edit. -Per-provider methods (`set` and `disable`) avoid this problem and keep updates explicit. +`providers/configure` accepts a subset of protocols and leaves the rest untouched, and `providers/restore` makes going back to defaults explicit. Together they avoid this problem and keep updates explicit. -### Why doesn't `providers/list` return headers? +### Why doesn't `providers/list_api` return headers? -Header values may contain secrets and should not be echoed by the agent. `providers/list` is intentionally limited to non-secret routing information (`current.apiType`, `current.baseUrl`). +Header values may contain secrets and should not be echoed by the agent. `providers/list_api` is intentionally limited to non-secret routing information (`current.presentableName`, `current.baseUrl`). -### Why are `providers/list` and `providers/set` payloads different? +### Why are `providers/list_api` and `providers/configure` payloads different? -`providers/set` accepts `headers`, including secrets, and is write-oriented. +`providers/configure` accepts `headers`, including secrets, and is write-oriented. -`providers/list` is read-oriented and returns only non-secret routing summary (`current`) for UI and capability discovery. +`providers/list_api` is read-oriented and returns only non-secret routing summary (`current`) for UI and capability discovery. ### Why is this separate from `initialize` params? @@ -384,14 +401,15 @@ Clients need capability discovery first, then provider discovery, then configura We did not choose it as the primary approach in this proposal because provider routing here needs dedicated semantics that are difficult to express with today's session config model: -- Multiple providers identified by `id`, each with its own lifecycle -- Structured payloads (`apiType`, `baseUrl`, full `headers` map) rather than simple scalar values -- Explicit discoverable (`providers/list`) and disable (`providers/disable`) semantics +- Multiple providers identified by API protocol, each with its own lifecycle +- Structured payloads (`apiProtocol`, `presentableName`, `baseUrl`, full `headers` map) rather than simple scalar values +- Explicit discovery (`providers/list_api`) and restore-to-defaults (`providers/restore`) semantics Today, `session-config` values are effectively string-oriented and do not define a standard multi-value/structured model for this use case. ## Revision history +- 2026-08-18: Reworked the API to be keyed by API protocol instead of provider `id`: `providers/list` renamed to `providers/list_api`, `providers/set` replaced by batch `providers/configure`, `providers/disable` replaced by `providers/restore` (restore protocols to agent defaults); dropped the `required` flag; added `presentableName` to `providerConfigurations` entries - 2026-04-19: Made `ProviderInfo.current` optional in `providers/list`; disabled state may be encoded as omitted `current` or `current: null` - 2026-03-22: Finalized provider disable semantics - `providers/remove` renamed to `providers/disable`, required providers are non-disableable, and disabled state is represented as `current: null` - 2026-03-21: Initial draft of provider configuration API (`providers/list`, `providers/set`, `providers/remove`) diff --git a/schema-generator/src/main.rs b/schema-generator/src/main.rs index 63690a6a2..2a347bf1a 100644 --- a/schema-generator/src/main.rs +++ b/schema-generator/src/main.rs @@ -1789,9 +1789,9 @@ starting with '$/' it is free to ignore the notification." "initialize" => self.agent.get("InitializeRequest").unwrap(), "authenticate" => self.agent.get("AuthenticateRequest").unwrap(), "auth/login" => self.agent.get("LoginAuthRequest").unwrap(), - "providers/list" => self.agent.get("ListProvidersRequest").unwrap(), - "providers/set" => self.agent.get("SetProviderRequest").unwrap(), - "providers/disable" => self.agent.get("DisableProviderRequest").unwrap(), + "providers/list_api" => self.agent.get("ListApiProvidersRequest").unwrap(), + "providers/configure" => self.agent.get("ConfigureProvidersRequest").unwrap(), + "providers/restore" => self.agent.get("RestoreProvidersRequest").unwrap(), "session/new" => self.agent.get("NewSessionRequest").unwrap(), "session/load" => self.agent.get("LoadSessionRequest").unwrap(), "session/list" => self.agent.get("ListSessionsRequest").unwrap(), diff --git a/schema/v1/meta.unstable.json b/schema/v1/meta.unstable.json index d8937f384..d200ba10c 100644 --- a/schema/v1/meta.unstable.json +++ b/schema/v1/meta.unstable.json @@ -3,9 +3,9 @@ "agentMethods": { "initialize": "initialize", "authenticate": "authenticate", - "providers_list": "providers/list", - "providers_set": "providers/set", - "providers_disable": "providers/disable", + "providers_list_api": "providers/list_api", + "providers_configure": "providers/configure", + "providers_restore": "providers/restore", "session_new": "session/new", "session_load": "session/load", "session_set_mode": "session/set_mode", diff --git a/schema/v1/schema.unstable.json b/schema/v1/schema.unstable.json index 55f376432..746dcdb51 100644 --- a/schema/v1/schema.unstable.json +++ b/schema/v1/schema.unstable.json @@ -2320,29 +2320,29 @@ ] }, { - "title": "ListProvidersResponse", - "description": "Successful result returned for a `providers/list` request.", + "title": "ListApiProvidersResponse", + "description": "Successful result returned for a `providers/list_api` request.", "allOf": [ { - "$ref": "#/$defs/ListProvidersResponse" + "$ref": "#/$defs/ListApiProvidersResponse" } ] }, { - "title": "SetProviderResponse", - "description": "Successful result returned for a `providers/set` request.", + "title": "ConfigureProvidersResponse", + "description": "Successful result returned for a `providers/configure` request.", "allOf": [ { - "$ref": "#/$defs/SetProviderResponse" + "$ref": "#/$defs/ConfigureProvidersResponse" } ] }, { - "title": "DisableProviderResponse", - "description": "Successful result returned for a `providers/disable` request.", + "title": "RestoreProvidersResponse", + "description": "Successful result returned for a `providers/restore` request.", "allOf": [ { - "$ref": "#/$defs/DisableProviderResponse" + "$ref": "#/$defs/RestoreProvidersResponse" } ] }, @@ -3528,8 +3528,8 @@ "x-side": "agent", "x-method": "authenticate" }, - "ListProvidersResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/list`.", + "ListApiProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/list_api`.", "type": "object", "properties": { "providers": { @@ -3548,32 +3548,23 @@ }, "required": ["providers"], "x-side": "agent", - "x-method": "providers/list" + "x-method": "providers/list_api" }, "ProviderInfo": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInformation about a configurable LLM provider.", "type": "object", "properties": { - "providerId": { - "description": "Provider identifier, for example \"main\" or \"openai\".", + "apiType": { + "description": "LLM protocol.", "allOf": [ { - "$ref": "#/$defs/ProviderId" + "$ref": "#/$defs/LlmProtocol" } ] }, - "supported": { - "description": "Supported protocol types for this provider.", - "type": "array", - "items": { - "$ref": "#/$defs/LlmProtocol" - }, - "x-deserialize-default-on-error": true, - "x-deserialize-skip-invalid-items": true - }, - "required": { - "description": "Whether this provider is mandatory and cannot be disabled via `providers/disable`.\nIf true, clients must not call `providers/disable` for this provider ID.", - "type": "boolean" + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" }, "current": { "description": "Current effective non-secret routing config.\nNull or omitted means provider is disabled.", @@ -3593,11 +3584,7 @@ "additionalProperties": true } }, - "required": ["providerId", "supported", "required"] - }, - "ProviderId": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nUnique identifier for a configurable LLM provider.", - "type": "string" + "required": ["apiType", "presentableName"] }, "LlmProtocol": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWell-known API protocol identifiers for LLM providers.\n\nAgents and clients MUST handle unknown protocol identifiers gracefully.\n\nProtocol names beginning with `_` are free for custom use, like other ACP extension methods.\nProtocol names that do not begin with `_` are reserved for the ACP spec.", @@ -3638,13 +3625,9 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCurrent effective non-secret routing configuration for a provider.", "type": "object", "properties": { - "apiType": { - "description": "Protocol currently used by this provider.", - "allOf": [ - { - "$ref": "#/$defs/LlmProtocol" - } - ] + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" }, "baseUrl": { "description": "Base URL currently used by this provider.", @@ -3657,10 +3640,10 @@ "additionalProperties": true } }, - "required": ["apiType", "baseUrl"] + "required": ["presentableName", "baseUrl"] }, - "SetProviderResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/set`.", + "ConfigureProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/configure`.", "type": "object", "properties": { "_meta": { @@ -3671,10 +3654,10 @@ } }, "x-side": "agent", - "x-method": "providers/set" + "x-method": "providers/configure" }, - "DisableProviderResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/disable`.", + "RestoreProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/restore`.", "type": "object", "properties": { "_meta": { @@ -3685,7 +3668,7 @@ } }, "x-side": "agent", - "x-method": "providers/disable" + "x-method": "providers/restore" }, "LogoutResponse": { "description": "Response to the `logout` method.", @@ -5888,29 +5871,29 @@ ] }, { - "title": "ListProvidersRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLists providers that can be configured by the client.", + "title": "ListApiProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLists the provider APIs supported by the agent.", "allOf": [ { - "$ref": "#/$defs/ListProvidersRequest" + "$ref": "#/$defs/ListApiProvidersRequest" } ] }, { - "title": "SetProviderRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReplaces the configuration for a provider.", + "title": "ConfigureProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nConfigures a set of providers keyed by API protocol.", "allOf": [ { - "$ref": "#/$defs/SetProviderRequest" + "$ref": "#/$defs/ConfigureProvidersRequest" } ] }, { - "title": "DisableProviderRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDisables a provider.", + "title": "RestoreProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRestores a set of providers to the agent's default configuration.", "allOf": [ { - "$ref": "#/$defs/DisableProviderRequest" + "$ref": "#/$defs/RestoreProvidersRequest" } ] }, @@ -6504,8 +6487,8 @@ "x-side": "agent", "x-method": "authenticate" }, - "ListProvidersRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/list`.", + "ListApiProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/list_api`.", "type": "object", "properties": { "_meta": { @@ -6516,34 +6499,52 @@ } }, "x-side": "agent", - "x-method": "providers/list" + "x-method": "providers/list_api" }, - "SetProviderRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/set`.\n\nReplaces the full configuration for one provider ID.", + "ConfigureProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/configure`.\n\nOverrides (updates) the configuration for a set of providers keyed by API protocol.", "type": "object", "properties": { - "providerId": { - "description": "Provider ID to configure.", - "allOf": [ - { - "$ref": "#/$defs/ProviderId" - } - ] + "providerConfigurations": { + "description": "Configuration updates to apply, one per API protocol.", + "type": "array", + "items": { + "$ref": "#/$defs/ProviderConfigUpdate" + } }, - "apiType": { - "description": "Protocol type for this provider.", + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["providerConfigurations"], + "x-side": "agent", + "x-method": "providers/configure" + }, + "ProviderConfigUpdate": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nConfiguration update for a single provider, keyed by API protocol.", + "type": "object", + "properties": { + "apiProtocol": { + "description": "LLM protocol to configure.", "allOf": [ { "$ref": "#/$defs/LlmProtocol" } ] }, + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" + }, "baseUrl": { "description": "Base URL for requests sent through this provider.", "type": "string" }, "headers": { - "description": "Full headers map for this provider.\nMay include authorization, routing, or other integration-specific headers.", + "description": "Full headers map for this provider.\nMay include authorization, routing, or other integration-specific headers.\nOmitting this field is equivalent to an empty map (no headers).", "type": "object", "additionalProperties": { "type": "string" @@ -6556,21 +6557,18 @@ "additionalProperties": true } }, - "required": ["providerId", "apiType", "baseUrl"], - "x-side": "agent", - "x-method": "providers/set" + "required": ["apiProtocol", "presentableName", "baseUrl"] }, - "DisableProviderRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/disable`.", + "RestoreProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/restore`.\n\nRestores the listed API protocols to the agent's default provider configuration.", "type": "object", "properties": { - "providerId": { - "description": "Provider ID to disable.", - "allOf": [ - { - "$ref": "#/$defs/ProviderId" - } - ] + "apiProtocols": { + "description": "List of API protocols to restore to default providers.", + "type": "array", + "items": { + "$ref": "#/$defs/LlmProtocol" + } }, "_meta": { "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", @@ -6579,9 +6577,9 @@ "additionalProperties": true } }, - "required": ["providerId"], + "required": ["apiProtocols"], "x-side": "agent", - "x-method": "providers/disable" + "x-method": "providers/restore" }, "LogoutRequest": { "description": "Request parameters for the logout method.\n\nTerminates the current authenticated session.", diff --git a/schema/v2/meta.unstable.json b/schema/v2/meta.unstable.json index 47d7973cb..827eea3c9 100644 --- a/schema/v2/meta.unstable.json +++ b/schema/v2/meta.unstable.json @@ -3,9 +3,9 @@ "agentMethods": { "initialize": "initialize", "auth_login": "auth/login", - "providers_list": "providers/list", - "providers_set": "providers/set", - "providers_disable": "providers/disable", + "providers_list_api": "providers/list_api", + "providers_configure": "providers/configure", + "providers_restore": "providers/restore", "session_new": "session/new", "session_set_config_option": "session/set_config_option", "session_prompt": "session/prompt", diff --git a/schema/v2/schema.unstable.json b/schema/v2/schema.unstable.json index 5480a33eb..550ee12b7 100644 --- a/schema/v2/schema.unstable.json +++ b/schema/v2/schema.unstable.json @@ -171,29 +171,29 @@ ] }, { - "title": "ListProvidersResponse", - "description": "Successful result returned for a `providers/list` request.", + "title": "ListApiProvidersResponse", + "description": "Successful result returned for a `providers/list_api` request.", "allOf": [ { - "$ref": "#/$defs/ListProvidersResponse" + "$ref": "#/$defs/ListApiProvidersResponse" } ] }, { - "title": "SetProviderResponse", - "description": "Successful result returned for a `providers/set` request.", + "title": "ConfigureProvidersResponse", + "description": "Successful result returned for a `providers/configure` request.", "allOf": [ { - "$ref": "#/$defs/SetProviderResponse" + "$ref": "#/$defs/ConfigureProvidersResponse" } ] }, { - "title": "DisableProviderResponse", - "description": "Successful result returned for a `providers/disable` request.", + "title": "RestoreProvidersResponse", + "description": "Successful result returned for a `providers/restore` request.", "allOf": [ { - "$ref": "#/$defs/DisableProviderResponse" + "$ref": "#/$defs/RestoreProvidersResponse" } ] }, @@ -3137,29 +3137,29 @@ ] }, { - "title": "ListProvidersResponse", - "description": "Successful result returned for a `providers/list` request.", + "title": "ListApiProvidersResponse", + "description": "Successful result returned for a `providers/list_api` request.", "allOf": [ { - "$ref": "#/$defs/ListProvidersResponse" + "$ref": "#/$defs/ListApiProvidersResponse" } ] }, { - "title": "SetProviderResponse", - "description": "Successful result returned for a `providers/set` request.", + "title": "ConfigureProvidersResponse", + "description": "Successful result returned for a `providers/configure` request.", "allOf": [ { - "$ref": "#/$defs/SetProviderResponse" + "$ref": "#/$defs/ConfigureProvidersResponse" } ] }, { - "title": "DisableProviderResponse", - "description": "Successful result returned for a `providers/disable` request.", + "title": "RestoreProvidersResponse", + "description": "Successful result returned for a `providers/restore` request.", "allOf": [ { - "$ref": "#/$defs/DisableProviderResponse" + "$ref": "#/$defs/RestoreProvidersResponse" } ] }, @@ -4403,8 +4403,8 @@ "x-side": "agent", "x-method": "auth/login" }, - "ListProvidersResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/list`.", + "ListApiProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/list_api`.", "type": "object", "properties": { "providers": { @@ -4423,32 +4423,23 @@ }, "required": ["providers"], "x-side": "agent", - "x-method": "providers/list" + "x-method": "providers/list_api" }, "ProviderInfo": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nInformation about a configurable LLM provider.", "type": "object", "properties": { - "providerId": { - "description": "Provider identifier, for example \"main\" or \"openai\".", + "apiType": { + "description": "LLM protocol.", "allOf": [ { - "$ref": "#/$defs/ProviderId" + "$ref": "#/$defs/LlmProtocol" } ] }, - "supported": { - "description": "Supported protocol types for this provider.", - "type": "array", - "items": { - "$ref": "#/$defs/LlmProtocol" - }, - "x-deserialize-default-on-error": true, - "x-deserialize-skip-invalid-items": true - }, - "required": { - "description": "Whether this provider is mandatory and cannot be disabled via `providers/disable`.\nIf true, clients must not call `providers/disable` for this provider ID.", - "type": "boolean" + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" }, "current": { "description": "Current effective non-secret routing config.\nNull or omitted means provider is disabled.", @@ -4468,11 +4459,7 @@ "additionalProperties": true } }, - "required": ["providerId", "supported", "required"] - }, - "ProviderId": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nUnique identifier for a configurable LLM provider.", - "type": "string" + "required": ["apiType", "presentableName"] }, "LlmProtocol": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWell-known API protocol identifiers for LLM providers.\n\nAgents and clients MUST handle unknown protocol identifiers gracefully.\n\nProtocol names beginning with `_` are free for custom use, like other ACP extension methods.\nProtocol names that do not begin with `_` are reserved for the ACP spec.", @@ -4513,13 +4500,9 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCurrent effective non-secret routing configuration for a provider.", "type": "object", "properties": { - "apiType": { - "description": "Protocol currently used by this provider.", - "allOf": [ - { - "$ref": "#/$defs/LlmProtocol" - } - ] + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" }, "baseUrl": { "description": "Base URL currently used by this provider.", @@ -4533,10 +4516,10 @@ "additionalProperties": true } }, - "required": ["apiType", "baseUrl"] + "required": ["presentableName", "baseUrl"] }, - "SetProviderResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/set`.", + "ConfigureProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/configure`.", "type": "object", "properties": { "_meta": { @@ -4547,10 +4530,10 @@ } }, "x-side": "agent", - "x-method": "providers/set" + "x-method": "providers/configure" }, - "DisableProviderResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/disable`.", + "RestoreProvidersResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/restore`.", "type": "object", "properties": { "_meta": { @@ -4561,7 +4544,7 @@ } }, "x-side": "agent", - "x-method": "providers/disable" + "x-method": "providers/restore" }, "LogoutAuthResponse": { "description": "Response to the `auth/logout` method.", @@ -7356,29 +7339,29 @@ ] }, { - "title": "ListProvidersRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLists providers that can be configured by the client.", + "title": "ListApiProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLists the provider APIs supported by the agent.", "allOf": [ { - "$ref": "#/$defs/ListProvidersRequest" + "$ref": "#/$defs/ListApiProvidersRequest" } ] }, { - "title": "SetProviderRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReplaces the configuration for a provider.", + "title": "ConfigureProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nConfigures a set of providers keyed by API protocol.", "allOf": [ { - "$ref": "#/$defs/SetProviderRequest" + "$ref": "#/$defs/ConfigureProvidersRequest" } ] }, { - "title": "DisableProviderRequest", - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDisables a provider.", + "title": "RestoreProvidersRequest", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRestores a set of providers to the agent's default configuration.", "allOf": [ { - "$ref": "#/$defs/DisableProviderRequest" + "$ref": "#/$defs/RestoreProvidersRequest" } ] }, @@ -7820,8 +7803,8 @@ "x-side": "agent", "x-method": "auth/login" }, - "ListProvidersRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/list`.", + "ListApiProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/list_api`.", "type": "object", "properties": { "_meta": { @@ -7832,35 +7815,53 @@ } }, "x-side": "agent", - "x-method": "providers/list" + "x-method": "providers/list_api" }, - "SetProviderRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/set`.\n\nReplaces the full configuration for one provider ID.", + "ConfigureProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/configure`.\n\nOverrides (updates) the configuration for a set of providers keyed by API protocol.", "type": "object", "properties": { - "providerId": { - "description": "Provider ID to configure.", - "allOf": [ - { - "$ref": "#/$defs/ProviderId" - } - ] + "providerConfigurations": { + "description": "Configuration updates to apply, one per API protocol.", + "type": "array", + "items": { + "$ref": "#/$defs/ProviderConfigUpdate" + } }, - "apiType": { - "description": "Protocol type for this provider.", + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["providerConfigurations"], + "x-side": "agent", + "x-method": "providers/configure" + }, + "ProviderConfigUpdate": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nConfiguration update for a single provider, keyed by API protocol.", + "type": "object", + "properties": { + "apiProtocol": { + "description": "LLM protocol to configure.", "allOf": [ { "$ref": "#/$defs/LlmProtocol" } ] }, + "presentableName": { + "description": "Name of the provider to be shown in UI.", + "type": "string" + }, "baseUrl": { "description": "Base URL for requests sent through this provider.", "type": "string", "format": "uri" }, "headers": { - "description": "Full headers map for this provider.\nMay include authorization, routing, or other integration-specific headers.", + "description": "Full headers map for this provider.\nMay include authorization, routing, or other integration-specific headers.\nOmitting this field is equivalent to an empty map (no headers).", "type": "object", "additionalProperties": { "type": "string" @@ -7873,21 +7874,18 @@ "additionalProperties": true } }, - "required": ["providerId", "apiType", "baseUrl"], - "x-side": "agent", - "x-method": "providers/set" + "required": ["apiProtocol", "presentableName", "baseUrl"] }, - "DisableProviderRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/disable`.", + "RestoreProvidersRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/restore`.\n\nRestores the listed API protocols to the agent's default provider configuration.", "type": "object", "properties": { - "providerId": { - "description": "Provider ID to disable.", - "allOf": [ - { - "$ref": "#/$defs/ProviderId" - } - ] + "apiProtocols": { + "description": "List of API protocols to restore to default providers.", + "type": "array", + "items": { + "$ref": "#/$defs/LlmProtocol" + } }, "_meta": { "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility)", @@ -7896,9 +7894,9 @@ "additionalProperties": true } }, - "required": ["providerId"], + "required": ["apiProtocols"], "x-side": "agent", - "x-method": "providers/disable" + "x-method": "providers/restore" }, "LogoutAuthRequest": { "description": "Request parameters for the `auth/logout` method.\n\nTerminates the current authenticated session.\n\nAgents MUST support this method when their `initialize` response advertised\nat least one valid authentication method. Clients MUST NOT call this method\nwhen `authMethods` was omitted or empty.",