@@ -551,7 +551,10 @@ impl AuthMethod {
551551 pub fn description ( & self ) -> Option < & str > {
552552 match self {
553553 Self :: Agent ( a) => a. description . as_deref ( ) ,
554- Self :: Other ( a) => a. description . as_deref ( ) ,
554+ Self :: Other ( a) => a
555+ . fields
556+ . get ( "description" )
557+ . and_then ( serde_json:: Value :: as_str) ,
555558 Self :: Terminal ( t) => t. description . as_deref ( ) ,
556559 }
557560 }
@@ -565,7 +568,7 @@ impl AuthMethod {
565568 pub fn meta ( & self ) -> Option < & Meta > {
566569 match self {
567570 Self :: Agent ( a) => a. meta . as_ref ( ) ,
568- Self :: Other ( a) => a. meta . as_ref ( ) ,
571+ Self :: Other ( a) => a. fields . get ( "_meta" ) . and_then ( serde_json :: Value :: as_object ) ,
569572 Self :: Terminal ( t) => t. meta . as_ref ( ) ,
570573 }
571574 }
@@ -592,22 +595,8 @@ pub struct OtherAuthMethod {
592595 pub method_id : AuthMethodId ,
593596 /// Human-readable name of the authentication method.
594597 pub name : String ,
595- /// Optional description providing more details about this authentication method.
596- #[ serde_as( deserialize_as = "DefaultOnError" ) ]
597- #[ cfg_attr( feature = "schemars" , schemars( extend( "x-deserialize-default-on-error" = true ) ) ) ]
598- #[ serde( default ) ]
599- pub description : Option < String > ,
600- /// The _meta property is reserved by ACP to allow clients and agents to attach additional
601- /// metadata to their interactions. Omitted and `null` are equivalent and mean no metadata.
602- /// Implementations MUST NOT make assumptions about values at these keys.
603- ///
604- /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility)
605- #[ serde_as( deserialize_as = "DefaultOnError" ) ]
606- #[ cfg_attr( feature = "schemars" , schemars( extend( "x-deserialize-default-on-error" = true ) ) ) ]
607- #[ serde( default ) ]
608- #[ serde( rename = "_meta" ) ]
609- pub meta : Option < Meta > ,
610- /// Additional fields from the unknown authentication method payload.
598+ /// The remaining fields of the unknown authentication method payload, preserved verbatim,
599+ /// including `description` and `_meta`.
611600 #[ serde( flatten) ]
612601 pub fields : BTreeMap < String , serde_json:: Value > ,
613602}
@@ -624,35 +613,13 @@ impl OtherAuthMethod {
624613 fields. remove ( "type" ) ;
625614 fields. remove ( "methodId" ) ;
626615 fields. remove ( "name" ) ;
627- fields. remove ( "description" ) ;
628- fields. remove ( "_meta" ) ;
629616 Self {
630617 type_ : type_. into ( ) ,
631618 method_id : method_id. into ( ) ,
632619 name : name. into ( ) ,
633- description : None ,
634- meta : None ,
635620 fields,
636621 }
637622 }
638-
639- /// Optional description providing more details about this authentication method.
640- #[ must_use]
641- pub fn description ( mut self , description : impl IntoOption < String > ) -> Self {
642- self . description = description. into_option ( ) ;
643- self
644- }
645-
646- /// The _meta property is reserved by ACP to allow clients and agents to attach additional
647- /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
648- /// these keys.
649- ///
650- /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility)
651- #[ must_use]
652- pub fn meta ( mut self , meta : impl IntoOption < Meta > ) -> Self {
653- self . meta = meta. into_option ( ) ;
654- self
655- }
656623}
657624
658625impl < ' de > Deserialize < ' de > for OtherAuthMethod {
@@ -667,9 +634,6 @@ impl<'de> Deserialize<'de> for OtherAuthMethod {
667634 type_ : String ,
668635 method_id : AuthMethodId ,
669636 name : String ,
670- description : Option < String > ,
671- #[ serde( rename = "_meta" ) ]
672- meta : Option < Meta > ,
673637 #[ serde( flatten) ]
674638 fields : BTreeMap < String , serde_json:: Value > ,
675639 }
@@ -686,8 +650,6 @@ impl<'de> Deserialize<'de> for OtherAuthMethod {
686650 type_ : raw. type_ ,
687651 method_id : raw. method_id ,
688652 name : raw. name ,
689- description : raw. description ,
690- meta : raw. meta ,
691653 fields : raw. fields ,
692654 } )
693655 }
@@ -1477,17 +1439,8 @@ pub struct OtherReplayFrom {
14771439 /// future ACP variants.
14781440 #[ serde( rename = "type" ) ]
14791441 pub type_ : String ,
1480- /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1481- /// metadata to their interactions. Omitted and `null` are equivalent and mean no metadata.
1482- /// Implementations MUST NOT make assumptions about values at these keys.
1483- ///
1484- /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility)
1485- #[ serde_as( deserialize_as = "DefaultOnError" ) ]
1486- #[ cfg_attr( feature = "schemars" , schemars( extend( "x-deserialize-default-on-error" = true ) ) ) ]
1487- #[ serde( default ) ]
1488- #[ serde( rename = "_meta" ) ]
1489- pub meta : Option < Meta > ,
1490- /// Additional fields from the unknown replay cursor payload.
1442+ /// The remaining fields of the unknown replay cursor payload, preserved verbatim,
1443+ /// including `_meta`.
14911444 #[ serde( flatten) ]
14921445 pub fields : BTreeMap < String , serde_json:: Value > ,
14931446}
@@ -1497,24 +1450,11 @@ impl OtherReplayFrom {
14971450 #[ must_use]
14981451 pub fn new ( type_ : impl Into < String > , mut fields : BTreeMap < String , serde_json:: Value > ) -> Self {
14991452 fields. remove ( "type" ) ;
1500- fields. remove ( "_meta" ) ;
15011453 Self {
15021454 type_ : type_. into ( ) ,
1503- meta : None ,
15041455 fields,
15051456 }
15061457 }
1507-
1508- /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1509- /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1510- /// these keys.
1511- ///
1512- /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility)
1513- #[ must_use]
1514- pub fn meta ( mut self , meta : impl IntoOption < Meta > ) -> Self {
1515- self . meta = meta. into_option ( ) ;
1516- self
1517- }
15181458}
15191459
15201460impl < ' de > Deserialize < ' de > for OtherReplayFrom {
@@ -1536,15 +1476,7 @@ impl<'de> Deserialize<'de> for OtherReplayFrom {
15361476 ) ) ) ;
15371477 }
15381478
1539- let meta = fields
1540- . remove ( "_meta" )
1541- . and_then ( |value| serde_json:: from_value ( value) . ok ( ) ) ;
1542-
1543- Ok ( Self {
1544- type_,
1545- meta,
1546- fields,
1547- } )
1479+ Ok ( Self { type_, fields } )
15481480 }
15491481}
15501482
@@ -5913,6 +5845,31 @@ mod test_serialization {
59135845 json ! ( { "source" : "test" } ) . as_object ( ) . unwrap ( ) . clone ( )
59145846 }
59155847
5848+ #[ test]
5849+ fn other_fallbacks_preserve_optional_fields_verbatim ( ) {
5850+ let valid = json ! ( { "type" : "_custom" , "methodId" : "m" , "name" : "M" ,
5851+ "description" : "d" , "_meta" : { "k" : 1 } } ) ;
5852+ let method: AuthMethod = serde_json:: from_value ( valid. clone ( ) ) . unwrap ( ) ;
5853+ assert_eq ! ( method. description( ) , Some ( "d" ) ) ;
5854+ assert_eq ! (
5855+ method. meta( ) ,
5856+ Some ( & json!( { "k" : 1 } ) . as_object( ) . unwrap( ) . clone( ) )
5857+ ) ;
5858+ assert_eq ! ( serde_json:: to_value( & method) . unwrap( ) , valid) ;
5859+
5860+ // Malformed optional fields are kept as sent and read as absent.
5861+ let malformed = json ! ( { "type" : "_custom" , "methodId" : "m" , "name" : "M" ,
5862+ "description" : 42 , "_meta" : "bad" , "extra" : true } ) ;
5863+ let method: AuthMethod = serde_json:: from_value ( malformed. clone ( ) ) . unwrap ( ) ;
5864+ assert_eq ! ( method. description( ) , None ) ;
5865+ assert_eq ! ( method. meta( ) , None ) ;
5866+ assert_eq ! ( serde_json:: to_value( & method) . unwrap( ) , malformed) ;
5867+
5868+ let replay = json ! ( { "type" : "_custom" , "_meta" : "bad" , "cursor" : 3 } ) ;
5869+ let decoded: ReplayFrom = serde_json:: from_value ( replay. clone ( ) ) . unwrap ( ) ;
5870+ assert_eq ! ( serde_json:: to_value( & decoded) . unwrap( ) , replay) ;
5871+ }
5872+
59165873 fn serialized_meta_key_count ( value : & impl serde:: Serialize ) -> usize {
59175874 serde_json:: to_string ( value)
59185875 . unwrap ( )
0 commit comments