adk_ui/
protocol_capabilities.rs1use serde::Serialize;
2
3pub const UI_DEFAULT_PROTOCOL: &str = "adk_ui";
5
6pub const TOOL_ENVELOPE_VERSION: &str = "1.0";
8
9pub const SUPPORTED_UI_PROTOCOLS: &[&str] = &["adk_ui", "a2ui", "ag_ui", "mcp_apps"];
11
12#[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#[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
70pub 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}