1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5#[serde(rename_all = "lowercase")]
6pub enum Role {
7 User,
8 Agent,
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct FileContent {
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub name: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none", rename = "mimeType")]
16 pub mime_type: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub bytes: Option<String>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub uri: Option<String>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(untagged)]
25pub enum Part {
26 Text {
27 text: String,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 metadata: Option<Map<String, Value>>,
30 },
31 File {
32 file: FileContent,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 metadata: Option<Map<String, Value>>,
35 },
36 Data {
37 data: Map<String, Value>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 metadata: Option<Map<String, Value>>,
40 },
41}
42
43impl Part {
44 pub fn text(text: String) -> Self {
45 Part::Text { text, metadata: None }
46 }
47
48 pub fn file(file: FileContent) -> Self {
49 Part::File { file, metadata: None }
50 }
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Message {
55 pub role: Role,
56 pub parts: Vec<Part>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub metadata: Option<Map<String, Value>>,
59 #[serde(rename = "messageId")]
60 pub message_id: String,
61 #[serde(skip_serializing_if = "Option::is_none", rename = "taskId")]
62 pub task_id: Option<String>,
63 #[serde(skip_serializing_if = "Option::is_none", rename = "contextId")]
64 pub context_id: Option<String>,
65}
66
67impl Message {
68 pub fn builder() -> MessageBuilder {
69 MessageBuilder::default()
70 }
71}
72
73#[derive(Default)]
74pub struct MessageBuilder {
75 role: Option<Role>,
76 parts: Vec<Part>,
77 metadata: Option<Map<String, Value>>,
78 message_id: Option<String>,
79 task_id: Option<String>,
80 context_id: Option<String>,
81}
82
83impl MessageBuilder {
84 pub fn role(mut self, role: Role) -> Self {
85 self.role = Some(role);
86 self
87 }
88
89 pub fn parts(mut self, parts: Vec<Part>) -> Self {
90 self.parts = parts;
91 self
92 }
93
94 pub fn metadata(mut self, metadata: Option<Map<String, Value>>) -> Self {
95 self.metadata = metadata;
96 self
97 }
98
99 pub fn message_id(mut self, id: String) -> Self {
100 self.message_id = Some(id);
101 self
102 }
103
104 pub fn build(self) -> Message {
105 Message {
106 role: self.role.unwrap_or(Role::User),
107 parts: self.parts,
108 metadata: self.metadata,
109 message_id: self.message_id.unwrap_or_default(),
110 task_id: self.task_id,
111 context_id: self.context_id,
112 }
113 }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct Artifact {
118 #[serde(rename = "artifactId")]
119 pub artifact_id: String,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub name: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub description: Option<String>,
124 pub parts: Vec<Part>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub metadata: Option<Map<String, Value>>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub extensions: Option<Vec<String>>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
132pub enum TaskState {
133 Submitted,
134 Working,
135 InputRequired,
136 Completed,
137 Failed,
138 Canceled,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct TaskStatus {
143 pub state: TaskState,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub message: Option<String>,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct TaskStatusUpdateEvent {
150 #[serde(rename = "taskId")]
151 pub task_id: String,
152 #[serde(skip_serializing_if = "Option::is_none", rename = "contextId")]
153 pub context_id: Option<String>,
154 pub status: TaskStatus,
155 #[serde(rename = "finalUpdate")]
156 pub final_update: bool,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct TaskArtifactUpdateEvent {
161 #[serde(rename = "taskId")]
162 pub task_id: String,
163 #[serde(skip_serializing_if = "Option::is_none", rename = "contextId")]
164 pub context_id: Option<String>,
165 pub artifact: Artifact,
166 pub append: bool,
167 #[serde(rename = "lastChunk")]
168 pub last_chunk: bool,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(untagged)]
173pub enum UpdateEvent {
174 TaskStatusUpdate(TaskStatusUpdateEvent),
175 TaskArtifactUpdate(TaskArtifactUpdateEvent),
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct AgentSkill {
180 pub id: String,
181 pub name: String,
182 pub description: String,
183 pub tags: Vec<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub examples: Option<Vec<String>>,
186}
187
188impl AgentSkill {
189 pub fn new(id: String, name: String, description: String, tags: Vec<String>) -> Self {
190 Self { id, name, description, tags, examples: None }
191 }
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct AgentCapabilities {
196 pub streaming: bool,
197 #[serde(rename = "pushNotifications")]
198 pub push_notifications: bool,
199 #[serde(rename = "stateTransitionHistory")]
200 pub state_transition_history: bool,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub extensions: Option<Vec<String>>,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct AgentCard {
207 pub name: String,
208 pub description: String,
209 pub url: String,
210 pub version: String,
211 #[serde(rename = "protocolVersion")]
212 pub protocol_version: String,
213 pub capabilities: AgentCapabilities,
214 pub skills: Vec<AgentSkill>,
215}
216
217impl AgentCard {
218 pub fn builder() -> AgentCardBuilder {
219 AgentCardBuilder::default()
220 }
221}
222
223#[derive(Default)]
224pub struct AgentCardBuilder {
225 name: Option<String>,
226 description: Option<String>,
227 url: Option<String>,
228 version: Option<String>,
229 capabilities: Option<AgentCapabilities>,
230 skills: Vec<AgentSkill>,
231}
232
233impl AgentCardBuilder {
234 pub fn name(mut self, name: String) -> Self {
235 self.name = Some(name);
236 self
237 }
238
239 pub fn description(mut self, description: String) -> Self {
240 self.description = Some(description);
241 self
242 }
243
244 pub fn url(mut self, url: String) -> Self {
245 self.url = Some(url);
246 self
247 }
248
249 pub fn version(mut self, version: String) -> Self {
250 self.version = Some(version);
251 self
252 }
253
254 pub fn capabilities(mut self, capabilities: AgentCapabilities) -> Self {
255 self.capabilities = Some(capabilities);
256 self
257 }
258
259 pub fn skills(mut self, skills: Vec<AgentSkill>) -> Self {
260 self.skills = skills;
261 self
262 }
263
264 pub fn build(self) -> AgentCard {
265 AgentCard {
266 name: self.name.unwrap_or_default(),
267 description: self.description.unwrap_or_default(),
268 url: self.url.unwrap_or_default(),
269 version: self.version.unwrap_or_else(|| "1.0.0".to_string()),
270 protocol_version: "0.3.0".to_string(),
271 capabilities: self.capabilities.unwrap_or(AgentCapabilities {
272 streaming: false,
273 push_notifications: false,
274 state_transition_history: false,
275 extensions: None,
276 }),
277 skills: self.skills,
278 }
279 }
280}