Skip to main content

agent_client_protocol_schema/
version.rs

1use derive_more::{Display, From};
2use schemars::JsonSchema;
3use serde::Serialize;
4
5/// Protocol version identifier.
6///
7/// This version is only bumped for breaking changes.
8/// Non-breaking changes should be introduced via capabilities.
9#[derive(
10    Debug, Clone, Copy, Serialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord, From, Display,
11)]
12pub struct ProtocolVersion(u16);
13
14impl ProtocolVersion {
15    /// Version `0` of the protocol.
16    ///
17    /// This was a pre-release version that shouldn't be used in production.
18    /// It is used as a fallback for any request whose version cannot be parsed
19    /// as a valid version, and should likely be treated as unsupported.
20    pub const V0: Self = Self(0);
21    /// Version `1` of the protocol.
22    ///
23    /// <https://agentclientprotocol.com/protocol/overview>
24    pub const V1: Self = Self(1);
25    /// Version `2` of the protocol.
26    ///
27    /// This is an unstable draft used for protocol iteration. It is only
28    /// available when the `unstable_protocol_v2` feature is enabled and is
29    /// **not** advertised by [`ProtocolVersion::LATEST`] yet — callers must
30    /// opt into V2 explicitly.
31    #[cfg(feature = "unstable_protocol_v2")]
32    pub const V2: Self = Self(2);
33    /// The latest stable supported version of the protocol.
34    ///
35    /// Currently this is version `1`. Enabling the `unstable_protocol_v2`
36    /// feature exposes `ProtocolVersion::V2` but does **not** change the
37    /// value of `LATEST` — v2 will only become the latest once it stabilizes.
38    pub const LATEST: Self = Self::V1;
39
40    #[cfg(test)]
41    #[must_use]
42    pub const fn new(version: u16) -> Self {
43        Self(version)
44    }
45}
46
47use serde::{Deserialize, Deserializer};
48
49impl<'de> Deserialize<'de> for ProtocolVersion {
50    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
51    where
52        D: Deserializer<'de>,
53    {
54        use serde::de::{self, Visitor};
55        use std::fmt;
56
57        struct ProtocolVersionVisitor;
58
59        impl Visitor<'_> for ProtocolVersionVisitor {
60            type Value = ProtocolVersion;
61
62            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
63                formatter.write_str("a protocol version number or string")
64            }
65
66            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
67            where
68                E: de::Error,
69            {
70                match u16::try_from(value) {
71                    Ok(value) => Ok(ProtocolVersion(value)),
72                    Err(_) => Err(E::custom(format!("protocol version {value} is too large"))),
73                }
74            }
75
76            fn visit_str<E>(self, _value: &str) -> Result<Self::Value, E>
77            where
78                E: de::Error,
79            {
80                // Old versions used strings, we consider all of those version 0
81                Ok(ProtocolVersion::V0)
82            }
83
84            fn visit_string<E>(self, _value: String) -> Result<Self::Value, E>
85            where
86                E: de::Error,
87            {
88                // Old versions used strings, we consider all of those version 0
89                Ok(ProtocolVersion::V0)
90            }
91        }
92
93        deserializer.deserialize_any(ProtocolVersionVisitor)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_deserialize_u64() {
103        let json = "1";
104        let version: ProtocolVersion = serde_json::from_str(json).unwrap();
105        assert_eq!(version, ProtocolVersion::new(1));
106    }
107
108    #[test]
109    fn test_deserialize_string() {
110        let json = "\"1.0.0\"";
111        let version: ProtocolVersion = serde_json::from_str(json).unwrap();
112        assert_eq!(version, ProtocolVersion::new(0));
113    }
114
115    #[test]
116    fn test_deserialize_large_number() {
117        let json = "100000";
118        let result: Result<ProtocolVersion, _> = serde_json::from_str(json);
119        assert!(result.is_err());
120    }
121
122    #[test]
123    fn test_deserialize_zero() {
124        let json = "0";
125        let version: ProtocolVersion = serde_json::from_str(json).unwrap();
126        assert_eq!(version, ProtocolVersion::new(0));
127    }
128
129    #[test]
130    fn test_deserialize_max_u16() {
131        let json = "65535";
132        let version: ProtocolVersion = serde_json::from_str(json).unwrap();
133        assert_eq!(version, ProtocolVersion::new(65535));
134    }
135}