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