use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ClientCapabilities {
#[serde(flatten)]
pub extra: Value,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct AgentCapabilities {
#[serde(default)]
pub streaming: Option<bool>,
#[serde(default)]
pub tools: Option<Vec<String>>,
#[serde(flatten)]
pub extra: Value,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_empty_client_capabilities_serializes_to_empty_object() {
let caps = ClientCapabilities::default();
let serialized = serde_json::to_value(&caps).expect("serialize ClientCapabilities");
assert!(
serialized.is_object(),
"ClientCapabilities must serialize to a JSON object, got: {serialized}"
);
}
#[test]
fn test_client_capabilities_roundtrip_with_extra() {
let raw = json!({ "experimentalFeatureX": true, "version": 2 });
let caps: ClientCapabilities =
serde_json::from_value(raw.clone()).expect("deserialize ClientCapabilities");
let back = serde_json::to_value(&caps).expect("re-serialize ClientCapabilities");
assert_eq!(back, raw, "extra fields must survive a roundtrip");
}
#[test]
fn test_agent_capabilities_defaults() {
let caps = AgentCapabilities::default();
assert!(caps.streaming.is_none());
assert!(caps.tools.is_none());
}
#[test]
fn test_agent_capabilities_roundtrip() {
let raw = json!({
"streaming": true,
"tools": ["read_file", "run_shell"],
"futureField": "ignored-gracefully"
});
let caps: AgentCapabilities =
serde_json::from_value(raw.clone()).expect("deserialize AgentCapabilities");
assert_eq!(caps.streaming, Some(true));
let expected: &[String] = &[
"read_file".to_string(),
"run_shell".to_string(),
];
assert_eq!(caps.tools.as_deref(), Some(expected));
let back = serde_json::to_value(&caps).expect("re-serialize AgentCapabilities");
assert_eq!(back, raw, "all fields including extra must survive a roundtrip");
}
}