diff --git a/agent-client-protocol-schema/src/v1/elicitation.rs b/agent-client-protocol-schema/src/v1/elicitation.rs index e64d8b087..c169940d7 100644 --- a/agent-client-protocol-schema/src/v1/elicitation.rs +++ b/agent-client-protocol-schema/src/v1/elicitation.rs @@ -64,7 +64,7 @@ pub enum ElicitationSchemaType { Object, } -/// A titled enum option with a const value and human-readable title. +/// A titled enum option with a const value, human-readable title, and optional description. #[serde_as] #[skip_serializing_none] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -75,6 +75,11 @@ pub struct EnumOption { pub value: String, /// Human-readable title for this option. pub title: String, + /// Human-readable description. + #[serde_as(deserialize_as = "DefaultOnError")] + #[schemars(extend("x-deserialize-default-on-error" = true))] + #[serde(default)] + pub description: Option, /// 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. @@ -94,10 +99,18 @@ impl EnumOption { Self { value: value.into(), title: title.into(), + description: None, meta: None, } } + /// Human-readable description. + #[must_use] + pub fn description(mut self, description: impl IntoOption) -> Self { + self.description = description.into_option(); + self + } + /// 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. @@ -2615,7 +2628,7 @@ mod tests { let schema = ElicitationSchema::new().property( "country", StringPropertySchema::new().one_of(vec![ - EnumOption::new("us", "United States"), + EnumOption::new("us", "United States").description("Use US English spelling."), EnumOption::new("uk", "United Kingdom"), ]), true, @@ -2627,12 +2640,20 @@ mod tests { assert_eq!(one_of.len(), 2); assert_eq!(one_of[0]["const"], "us"); assert_eq!(one_of[0]["title"], "United States"); + assert_eq!(one_of[0]["description"], "Use US English spelling."); + assert!(one_of[1].get("description").is_none()); let roundtripped: ElicitationSchema = serde_json::from_value(json).unwrap(); if let ElicitationPropertySchema::String(s) = roundtripped.properties.get("country").unwrap() { - assert_eq!(s.one_of.as_ref().unwrap().len(), 2); + let one_of = s.one_of.as_ref().unwrap(); + assert_eq!(one_of.len(), 2); + assert_eq!( + one_of[0].description.as_deref(), + Some("Use US English spelling.") + ); + assert!(one_of[1].description.is_none()); } else { panic!("expected String variant"); } diff --git a/agent-client-protocol-schema/src/v2/conversion.rs b/agent-client-protocol-schema/src/v2/conversion.rs index bdef9c7ff..43a899d59 100644 --- a/agent-client-protocol-schema/src/v2/conversion.rs +++ b/agent-client-protocol-schema/src/v2/conversion.rs @@ -7616,10 +7616,16 @@ impl IntoV1 for super::EnumOption { type Output = crate::v1::EnumOption; fn into_v1(self) -> Result { - let Self { value, title, meta } = self; + let Self { + value, + title, + description, + meta, + } = self; Ok(crate::v1::EnumOption { value: value.into_v1()?, title: title.into_v1()?, + description: description.into_v1()?, meta: meta.into_v1()?, }) } @@ -7630,10 +7636,16 @@ impl IntoV2 for crate::v1::EnumOption { type Output = super::EnumOption; fn into_v2(self) -> Result { - let Self { value, title, meta } = self; + let Self { + value, + title, + description, + meta, + } = self; Ok(super::EnumOption { value: value.into_v2()?, title: title.into_v2()?, + description: description.into_v2()?, meta: meta.into_v2()?, }) } diff --git a/agent-client-protocol-schema/src/v2/elicitation.rs b/agent-client-protocol-schema/src/v2/elicitation.rs index 71941e761..1feb8541f 100644 --- a/agent-client-protocol-schema/src/v2/elicitation.rs +++ b/agent-client-protocol-schema/src/v2/elicitation.rs @@ -69,7 +69,7 @@ pub enum ElicitationSchemaType { Object, } -/// A titled enum option with a const value and human-readable title. +/// A titled enum option with a const value, human-readable title, and optional description. #[serde_as] #[skip_serializing_none] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -80,6 +80,11 @@ pub struct EnumOption { pub value: String, /// Human-readable title for this option. pub title: String, + /// Human-readable description. + #[serde_as(deserialize_as = "DefaultOnError")] + #[schemars(extend("x-deserialize-default-on-error" = true))] + #[serde(default)] + pub description: Option, /// 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. @@ -99,10 +104,18 @@ impl EnumOption { Self { value: value.into(), title: title.into(), + description: None, meta: None, } } + /// Human-readable description. + #[must_use] + pub fn description(mut self, description: impl IntoOption) -> Self { + self.description = description.into_option(); + self + } + /// 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. @@ -2560,7 +2573,7 @@ mod tests { let schema = ElicitationSchema::new().property( "country", StringPropertySchema::new().one_of(vec![ - EnumOption::new("us", "United States"), + EnumOption::new("us", "United States").description("Use US English spelling."), EnumOption::new("uk", "United Kingdom"), ]), true, @@ -2572,12 +2585,20 @@ mod tests { assert_eq!(one_of.len(), 2); assert_eq!(one_of[0]["const"], "us"); assert_eq!(one_of[0]["title"], "United States"); + assert_eq!(one_of[0]["description"], "Use US English spelling."); + assert!(one_of[1].get("description").is_none()); let roundtripped: ElicitationSchema = serde_json::from_value(json).unwrap(); if let ElicitationPropertySchema::String(s) = roundtripped.properties.get("country").unwrap() { - assert_eq!(s.one_of.as_ref().unwrap().len(), 2); + let one_of = s.one_of.as_ref().unwrap(); + assert_eq!(one_of.len(), 2); + assert_eq!( + one_of[0].description.as_deref(), + Some("Use US English spelling.") + ); + assert!(one_of[1].description.is_none()); } else { panic!("expected String variant"); } diff --git a/docs/protocol/v1/draft/schema.mdx b/docs/protocol/v1/draft/schema.mdx index 94c4ace97..3d174486a 100644 --- a/docs/protocol/v1/draft/schema.mdx +++ b/docs/protocol/v1/draft/schema.mdx @@ -4423,7 +4423,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d ## EnumOption -A titled enum option with a const value and human-readable title. +A titled enum option with a const value, human-readable title, and optional description. **Type:** Object @@ -4440,6 +4440,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/d The constant value for this option. + + Human-readable description. + Human-readable title for this option. diff --git a/docs/protocol/v2/draft/schema.mdx b/docs/protocol/v2/draft/schema.mdx index 0b36faea7..f4e53095d 100644 --- a/docs/protocol/v2/draft/schema.mdx +++ b/docs/protocol/v2/draft/schema.mdx @@ -4178,7 +4178,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d ## EnumOption -A titled enum option with a const value and human-readable title. +A titled enum option with a const value, human-readable title, and optional description. **Type:** Object @@ -4195,6 +4195,9 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d The constant value for this option. + + Human-readable description. + Human-readable title for this option. diff --git a/docs/rfds/elicitation.mdx b/docs/rfds/elicitation.mdx index 8733f2ec3..b96734722 100644 --- a/docs/rfds/elicitation.mdx +++ b/docs/rfds/elicitation.mdx @@ -99,12 +99,18 @@ Agents send elicitation requests when they need information from the user. This "oneOf": [ { "const": "conservative", - "title": "Conservative - Minimal changes" + "title": "Conservative - Minimal changes", + "description": "Make minimal changes and avoid broad cleanup." + }, + { + "const": "balanced", + "title": "Balanced (Recommended)", + "description": "Fix the issue and clean nearby code when it lowers risk." }, - { "const": "balanced", "title": "Balanced (Recommended)" }, { "const": "aggressive", - "title": "Aggressive - Maximum optimization" + "title": "Aggressive - Maximum optimization", + "description": "Refactor more broadly to optimize the affected area." } ], "default": "balanced" @@ -270,9 +276,21 @@ Single-select enum (with titles): "title": "Color Selection", "description": "Choose your favorite color", "oneOf": [ - { "const": "#FF0000", "title": "Red" }, - { "const": "#00FF00", "title": "Green" }, - { "const": "#0000FF", "title": "Blue" } + { + "const": "#FF0000", + "title": "Red", + "description": "High emphasis and warning-oriented." + }, + { + "const": "#00FF00", + "title": "Green", + "description": "Positive status and success-oriented." + }, + { + "const": "#0000FF", + "title": "Blue", + "description": "Neutral and informational." + } ], "default": "#FF0000" } @@ -306,9 +324,21 @@ Multi-select enum (with titles): "maxItems": 2, "items": { "anyOf": [ - { "const": "#FF0000", "title": "Red" }, - { "const": "#00FF00", "title": "Green" }, - { "const": "#0000FF", "title": "Blue" } + { + "const": "#FF0000", + "title": "Red", + "description": "High emphasis and warning-oriented." + }, + { + "const": "#00FF00", + "title": "Green", + "description": "Positive status and success-oriented." + }, + { + "const": "#0000FF", + "title": "Blue", + "description": "Neutral and informational." + } ] }, "default": ["#FF0000", "#00FF00"] @@ -373,9 +403,21 @@ The agent sends an `elicitation/create` request when it needs information from t "type": "string", "title": "Refactoring Strategy", "oneOf": [ - { "const": "conservative", "title": "Conservative" }, - { "const": "balanced", "title": "Balanced (Recommended)" }, - { "const": "aggressive", "title": "Aggressive" } + { + "const": "conservative", + "title": "Conservative", + "description": "Make minimal changes and avoid broad cleanup." + }, + { + "const": "balanced", + "title": "Balanced (Recommended)", + "description": "Fix the issue and clean nearby code when it lowers risk." + }, + { + "const": "aggressive", + "title": "Aggressive", + "description": "Refactor more broadly to optimize the affected area." + } ], "default": "balanced" } diff --git a/schema/v1/schema.unstable.json b/schema/v1/schema.unstable.json index 3f15cb948..d0d3b6964 100644 --- a/schema/v1/schema.unstable.json +++ b/schema/v1/schema.unstable.json @@ -1770,7 +1770,7 @@ ] }, "EnumOption": { - "description": "A titled enum option with a const value and human-readable title.", + "description": "A titled enum option with a const value, human-readable title, and optional description.", "type": "object", "properties": { "const": { @@ -1781,6 +1781,11 @@ "description": "Human-readable title for this option.", "type": "string" }, + "description": { + "description": "Human-readable description.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, "_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"], diff --git a/schema/v2/schema.unstable.json b/schema/v2/schema.unstable.json index 8a31ef090..dca3447b7 100644 --- a/schema/v2/schema.unstable.json +++ b/schema/v2/schema.unstable.json @@ -2396,7 +2396,7 @@ ] }, "EnumOption": { - "description": "A titled enum option with a const value and human-readable title.", + "description": "A titled enum option with a const value, human-readable title, and optional description.", "type": "object", "properties": { "const": { @@ -2407,6 +2407,11 @@ "description": "Human-readable title for this option.", "type": "string" }, + "description": { + "description": "Human-readable description.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, "_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"],