Skip to main content

adk_ui/
protocol_capabilities.rs

1use serde::Serialize;
2
3/// Default runtime protocol profile for server integrations.
4pub const UI_DEFAULT_PROTOCOL: &str = "adk_ui";
5
6/// Tool envelope version used by protocol-aware legacy tool responses.
7pub const TOOL_ENVELOPE_VERSION: &str = "1.0";
8
9/// Supported runtime protocol profile values.
10pub const SUPPORTED_UI_PROTOCOLS: &[&str] = &["adk_ui", "a2ui", "ag_ui", "mcp_apps"];
11
12/// Planned deprecation metadata for runtime/profile consumers.
13#[derive(Debug, Clone, Serialize)]
14#[serde(rename_all = "camelCase")]
15pub struct UiProtocolDeprecationSpec {
16    pub stage: &'static str,
17    pub announced_on: &'static str,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub sunset_target_on: Option<&'static str>,
20    pub replacement_protocols: &'static [&'static str],
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub note: Option<&'static str>,
23}
24
25/// Static capability contract for each supported UI protocol.
26#[derive(Debug, Clone, Serialize)]
27pub struct UiProtocolCapabilitySpec {
28    pub protocol: &'static str,
29    pub versions: &'static [&'static str],
30    pub features: &'static [&'static str],
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub deprecation: Option<&'static UiProtocolDeprecationSpec>,
33}
34
35pub const ADK_UI_LEGACY_DEPRECATION: UiProtocolDeprecationSpec = UiProtocolDeprecationSpec {
36    stage: "planned",
37    announced_on: "2026-02-07",
38    sunset_target_on: Some("2026-12-31"),
39    replacement_protocols: &["a2ui", "ag_ui", "mcp_apps"],
40    note: Some("Legacy adk_ui profile remains supported during migration."),
41};
42
43pub const UI_PROTOCOL_CAPABILITIES: &[UiProtocolCapabilitySpec] = &[
44    UiProtocolCapabilitySpec {
45        protocol: "adk_ui",
46        versions: &["1.0"],
47        features: &["legacy_components", "theme", "events"],
48        deprecation: Some(&ADK_UI_LEGACY_DEPRECATION),
49    },
50    UiProtocolCapabilitySpec {
51        protocol: "a2ui",
52        versions: &["0.9"],
53        features: &["jsonl", "createSurface", "updateComponents", "updateDataModel"],
54        deprecation: None,
55    },
56    UiProtocolCapabilitySpec {
57        protocol: "ag_ui",
58        versions: &["0.1"],
59        features: &["run_lifecycle", "custom_events", "event_stream"],
60        deprecation: None,
61    },
62    UiProtocolCapabilitySpec {
63        protocol: "mcp_apps",
64        versions: &["sep-1865"],
65        features: &["ui_resource_uri", "tool_meta", "html_resource"],
66        deprecation: None,
67    },
68];
69
70/// Normalize runtime UI profile aliases to canonical values.
71pub fn normalize_runtime_ui_protocol(raw: &str) -> Option<&'static str> {
72    match raw.trim().to_ascii_lowercase().as_str() {
73        "adk_ui" => Some("adk_ui"),
74        "a2ui" => Some("a2ui"),
75        "ag_ui" | "ag-ui" => Some("ag_ui"),
76        "mcp_apps" | "mcp-apps" => Some("mcp_apps"),
77        _ => None,
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn normalize_runtime_protocol_accepts_aliases() {
87        assert_eq!(normalize_runtime_ui_protocol("adk_ui"), Some("adk_ui"));
88        assert_eq!(normalize_runtime_ui_protocol("A2UI"), Some("a2ui"));
89        assert_eq!(normalize_runtime_ui_protocol("ag-ui"), Some("ag_ui"));
90        assert_eq!(normalize_runtime_ui_protocol("mcp-apps"), Some("mcp_apps"));
91        assert_eq!(normalize_runtime_ui_protocol("unknown"), None);
92    }
93
94    #[test]
95    fn capability_specs_cover_supported_protocols() {
96        let protocols: Vec<&str> =
97            UI_PROTOCOL_CAPABILITIES.iter().map(|spec| spec.protocol).collect();
98        assert_eq!(protocols, SUPPORTED_UI_PROTOCOLS);
99    }
100
101    #[test]
102    fn capability_specs_include_versions() {
103        for spec in UI_PROTOCOL_CAPABILITIES {
104            assert!(!spec.versions.is_empty(), "missing versions for {}", spec.protocol);
105            assert!(!spec.features.is_empty(), "missing features for {}", spec.protocol);
106        }
107    }
108
109    #[test]
110    fn legacy_profile_has_deprecation_metadata() {
111        let legacy = UI_PROTOCOL_CAPABILITIES
112            .iter()
113            .find(|spec| spec.protocol == "adk_ui")
114            .expect("adk_ui capability");
115        let deprecation = legacy.deprecation.expect("adk_ui deprecation metadata");
116        assert_eq!(deprecation.announced_on, "2026-02-07");
117        assert_eq!(deprecation.sunset_target_on, Some("2026-12-31"));
118    }
119}