Skip to main content

aster_a2ui/
protocol.rs

1//! A2UI 协议消息类型
2//!
3//! 定义服务端到客户端和客户端到服务端的消息格式
4
5use serde::{Deserialize, Serialize};
6
7use crate::catalog::Component;
8
9/// A2UI 协议版本
10pub const PROTOCOL_VERSION: &str = "v0.10";
11
12// ============================================================================
13// 服务端到客户端消息
14// ============================================================================
15
16/// 服务端到客户端的消息信封
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
18pub struct ServerMessage {
19    /// 协议版本
20    pub version: String,
21    /// 消息内容(四选一)
22    #[serde(flatten)]
23    pub content: ServerMessageContent,
24}
25
26/// 服务端消息内容
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28#[serde(rename_all = "camelCase")]
29pub enum ServerMessageContent {
30    /// 创建 Surface
31    CreateSurface(CreateSurface),
32    /// 更新组件
33    UpdateComponents(UpdateComponents),
34    /// 更新数据模型
35    UpdateDataModel(UpdateDataModel),
36    /// 删除 Surface
37    DeleteSurface(DeleteSurface),
38}
39
40/// 创建 Surface 消息
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
42#[serde(rename_all = "camelCase")]
43pub struct CreateSurface {
44    /// Surface 唯一标识符
45    pub surface_id: String,
46    /// 组件目录 ID
47    pub catalog_id: String,
48    /// 主题配置
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub theme: Option<Theme>,
51    /// 是否发送数据模型
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub send_data_model: Option<bool>,
54}
55
56/// 主题配置
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
58#[serde(rename_all = "camelCase")]
59pub struct Theme {
60    /// 主色调
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub primary_color: Option<String>,
63    /// 图标 URL
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub icon_url: Option<String>,
66    /// Agent 显示名称
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub agent_display_name: Option<String>,
69}
70
71/// 更新组件消息
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
73#[serde(rename_all = "camelCase")]
74pub struct UpdateComponents {
75    /// Surface ID
76    pub surface_id: String,
77    /// 组件列表
78    pub components: Vec<Component>,
79}
80
81/// 更新数据模型消息
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
83#[serde(rename_all = "camelCase")]
84pub struct UpdateDataModel {
85    /// Surface ID
86    pub surface_id: String,
87    /// JSON Pointer 路径(默认为 "/")
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub path: Option<String>,
90    /// 新值
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub value: Option<serde_json::Value>,
93}
94
95/// 删除 Surface 消息
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
97#[serde(rename_all = "camelCase")]
98pub struct DeleteSurface {
99    /// Surface ID
100    pub surface_id: String,
101}
102
103// ============================================================================
104// 客户端到服务端消息
105// ============================================================================
106
107/// 客户端到服务端的消息信封
108#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
109pub struct ClientMessage {
110    /// 协议版本
111    pub version: String,
112    /// 消息内容
113    #[serde(flatten)]
114    pub content: ClientMessageContent,
115}
116
117/// 客户端消息内容
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
119#[serde(rename_all = "camelCase")]
120pub enum ClientMessageContent {
121    /// 动作事件
122    Action(ActionMessage),
123    /// 错误消息
124    Error(ErrorMessage),
125}
126
127/// 动作消息(用户交互触发)
128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
129#[serde(rename_all = "camelCase")]
130pub struct ActionMessage {
131    /// 事件名称
132    pub name: String,
133    /// Surface ID
134    pub surface_id: String,
135    /// 触发事件的组件 ID
136    pub source_component_id: String,
137    /// ISO 8601 时间戳
138    pub timestamp: String,
139    /// 事件上下文
140    pub context: serde_json::Map<String, serde_json::Value>,
141}
142
143/// 错误消息
144#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
145#[serde(rename_all = "camelCase")]
146pub struct ErrorMessage {
147    /// 错误代码
148    pub code: ErrorCode,
149    /// Surface ID
150    pub surface_id: String,
151    /// 错误消息
152    pub message: String,
153    /// JSON Pointer 路径(仅 VALIDATION_FAILED)
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub path: Option<String>,
156}
157
158/// 错误代码
159#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
160pub enum ErrorCode {
161    /// 验证失败
162    #[serde(rename = "VALIDATION_FAILED")]
163    ValidationFailed,
164    /// 其他错误
165    #[serde(other)]
166    Other,
167}
168
169/// 客户端能力声明(通过 Transport metadata 发送)
170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
171#[serde(rename_all = "camelCase")]
172pub struct ClientCapabilities {
173    /// 支持的组件目录 ID 列表
174    pub supported_catalog_ids: Vec<String>,
175    /// 内联目录定义(可选)
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub inline_catalogs: Option<Vec<Catalog>>,
178}
179
180/// 目录定义
181#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
182#[serde(rename_all = "camelCase")]
183pub struct Catalog {
184    /// 目录唯一标识符
185    pub catalog_id: String,
186    /// 组件定义
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub components: Option<serde_json::Map<String, serde_json::Value>>,
189    /// 函数定义
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub functions: Option<Vec<FunctionDefinition>>,
192    /// 主题定义
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub theme: Option<serde_json::Map<String, serde_json::Value>>,
195}
196
197/// 函数定义
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
199#[serde(rename_all = "camelCase")]
200pub struct FunctionDefinition {
201    /// 函数名称
202    pub name: String,
203    /// 函数描述
204    #[serde(skip_serializing_if = "Option::is_none")]
205    pub description: Option<String>,
206    /// 参数 JSON Schema
207    pub parameters: serde_json::Value,
208    /// 返回类型
209    pub return_type: String,
210}
211
212/// 客户端数据模型(通过 Transport metadata 发送)
213#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
214#[serde(rename_all = "camelCase")]
215pub struct ClientDataModel {
216    /// 协议版本
217    pub version: String,
218    /// Surface ID 到数据模型的映射
219    pub surfaces: std::collections::HashMap<String, serde_json::Value>,
220}
221
222// ============================================================================
223// 构建器模式
224// ============================================================================
225
226impl ServerMessage {
227    /// 创建新的服务端消息
228    pub fn new(content: ServerMessageContent) -> Self {
229        Self {
230            version: PROTOCOL_VERSION.to_string(),
231            content,
232        }
233    }
234
235    /// 创建 CreateSurface 消息
236    pub fn create_surface(surface_id: &str, catalog_id: &str) -> Self {
237        Self::new(ServerMessageContent::CreateSurface(CreateSurface {
238            surface_id: surface_id.to_string(),
239            catalog_id: catalog_id.to_string(),
240            theme: None,
241            send_data_model: None,
242        }))
243    }
244
245    /// 创建 UpdateComponents 消息
246    pub fn update_components(surface_id: &str, components: Vec<Component>) -> Self {
247        Self::new(ServerMessageContent::UpdateComponents(UpdateComponents {
248            surface_id: surface_id.to_string(),
249            components,
250        }))
251    }
252
253    /// 创建 UpdateDataModel 消息
254    pub fn update_data_model(surface_id: &str, value: serde_json::Value) -> Self {
255        Self::new(ServerMessageContent::UpdateDataModel(UpdateDataModel {
256            surface_id: surface_id.to_string(),
257            path: None,
258            value: Some(value),
259        }))
260    }
261
262    /// 创建 DeleteSurface 消息
263    pub fn delete_surface(surface_id: &str) -> Self {
264        Self::new(ServerMessageContent::DeleteSurface(DeleteSurface {
265            surface_id: surface_id.to_string(),
266        }))
267    }
268}
269
270impl ClientMessage {
271    /// 创建新的客户端消息
272    pub fn new(content: ClientMessageContent) -> Self {
273        Self {
274            version: PROTOCOL_VERSION.to_string(),
275            content,
276        }
277    }
278
279    /// 创建动作消息
280    pub fn action(
281        surface_id: &str,
282        name: &str,
283        source_component_id: &str,
284        context: serde_json::Map<String, serde_json::Value>,
285    ) -> Self {
286        Self::new(ClientMessageContent::Action(ActionMessage {
287            name: name.to_string(),
288            surface_id: surface_id.to_string(),
289            source_component_id: source_component_id.to_string(),
290            timestamp: chrono::Utc::now().to_rfc3339(),
291            context,
292        }))
293    }
294
295    /// 创建验证失败错误消息
296    pub fn validation_error(surface_id: &str, path: &str, message: &str) -> Self {
297        Self::new(ClientMessageContent::Error(ErrorMessage {
298            code: ErrorCode::ValidationFailed,
299            surface_id: surface_id.to_string(),
300            message: message.to_string(),
301            path: Some(path.to_string()),
302        }))
303    }
304
305    /// 创建通用错误消息
306    pub fn error(surface_id: &str, message: &str) -> Self {
307        Self::new(ClientMessageContent::Error(ErrorMessage {
308            code: ErrorCode::Other,
309            surface_id: surface_id.to_string(),
310            message: message.to_string(),
311            path: None,
312        }))
313    }
314}
315
316impl ClientCapabilities {
317    /// 创建新的客户端能力声明
318    pub fn new(supported_catalog_ids: Vec<String>) -> Self {
319        Self {
320            supported_catalog_ids,
321            inline_catalogs: None,
322        }
323    }
324
325    /// 添加内联目录
326    pub fn with_inline_catalog(mut self, catalog: Catalog) -> Self {
327        self.inline_catalogs
328            .get_or_insert_with(Vec::new)
329            .push(catalog);
330        self
331    }
332}
333
334impl ClientDataModel {
335    /// 创建新的客户端数据模型
336    pub fn new() -> Self {
337        Self {
338            version: PROTOCOL_VERSION.to_string(),
339            surfaces: std::collections::HashMap::new(),
340        }
341    }
342
343    /// 添加 Surface 数据模型
344    pub fn with_surface(mut self, surface_id: &str, data: serde_json::Value) -> Self {
345        self.surfaces.insert(surface_id.to_string(), data);
346        self
347    }
348}
349
350impl Default for ClientDataModel {
351    fn default() -> Self {
352        Self::new()
353    }
354}