1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5pub const A2A_VERSION: &str = "0.10.0";
7
8#[derive(Serialize, Deserialize, Debug, JsonSchema)]
11#[serde(rename_all = "camelCase")]
12pub struct AgentCard {
13 pub version: String,
15 pub name: String,
17 pub description: String,
19 pub url: String,
21 #[serde(default)]
23 pub icon_url: Option<String>,
24 #[serde(default)]
26 pub documentation_url: Option<String>,
27 #[serde(default)]
29 pub provider: Option<AgentProvider>,
30 #[serde(default)]
32 pub preferred_transport: Option<String>,
33 pub capabilities: AgentCapabilities,
35 pub default_input_modes: Vec<String>,
37 pub default_output_modes: Vec<String>,
39 pub skills: Vec<AgentSkill>,
41 #[serde(default)]
43 pub security_schemes: HashMap<String, SecurityScheme>,
44 #[serde(default)]
46 pub security: Vec<HashMap<String, Vec<String>>>,
47}
48
49#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
51#[serde(rename_all = "camelCase")]
52pub struct AgentProvider {
53 pub organization: String,
55 pub url: String,
57}
58
59#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)]
61#[serde(rename_all = "camelCase")]
62pub struct AgentCapabilities {
63 #[serde(default = "default_true")]
65 pub streaming: bool,
66 #[serde(default)]
68 pub push_notifications: bool,
69 #[serde(default = "default_true")]
71 pub state_transition_history: bool,
72 #[serde(default)]
74 pub extensions: Vec<AgentExtension>,
75}
76fn default_true() -> bool {
77 true
78}
79
80#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct AgentExtension {
84 pub uri: String,
86 #[serde(default)]
88 pub description: Option<String>,
89 #[serde(default)]
91 pub required: bool,
92 #[serde(default)]
94 pub params: Option<serde_json::Value>,
95}
96
97#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
99#[serde(rename_all = "camelCase")]
100pub struct AgentSkill {
101 pub id: String,
103 pub name: String,
105 pub description: String,
107 #[serde(default)]
109 pub tags: Vec<String>,
110 #[serde(default)]
112 pub examples: Vec<String>,
113 #[serde(default)]
115 pub input_modes: Option<Vec<String>>,
116 #[serde(default)]
118 pub output_modes: Option<Vec<String>>,
119}
120
121#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
123#[serde(tag = "type", rename_all = "camelCase")]
124pub enum SecurityScheme {
125 ApiKey(APIKeySecurityScheme),
126 Http(HTTPAuthSecurityScheme),
127 Oauth2(OAuth2SecurityScheme),
128 OpenIdConnect(OpenIdConnectSecurityScheme),
129}
130
131#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
133#[serde(rename_all = "camelCase")]
134pub struct APIKeySecurityScheme {
135 pub name: String,
137 #[serde(rename = "in")]
139 pub location: String,
140 #[serde(default)]
142 pub description: Option<String>,
143}
144
145#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
147#[serde(rename_all = "camelCase")]
148pub struct HTTPAuthSecurityScheme {
149 pub scheme: String,
151 #[serde(default)]
153 pub bearer_format: Option<String>,
154 #[serde(default)]
156 pub description: Option<String>,
157}
158
159#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
161#[serde(rename_all = "camelCase")]
162pub struct OAuth2SecurityScheme {
163 pub flows: OAuthFlows,
165 #[serde(default)]
167 pub description: Option<String>,
168}
169
170#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
172#[serde(rename_all = "camelCase")]
173pub struct OpenIdConnectSecurityScheme {
174 pub open_id_connect_url: String,
176 #[serde(default)]
178 pub description: Option<String>,
179}
180
181#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)]
183#[serde(rename_all = "camelCase")]
184pub struct OAuthFlows {
185 #[serde(default)]
186 pub implicit: Option<ImplicitOAuthFlow>,
187 #[serde(default)]
188 pub password: Option<PasswordOAuthFlow>,
189 #[serde(default)]
190 pub client_credentials: Option<ClientCredentialsOAuthFlow>,
191 #[serde(default)]
192 pub authorization_code: Option<AuthorizationCodeOAuthFlow>,
193}
194
195#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
197#[serde(rename_all = "camelCase")]
198pub struct ImplicitOAuthFlow {
199 pub authorization_url: String,
200 #[serde(default)]
201 pub refresh_url: Option<String>,
202 pub scopes: HashMap<String, String>,
203}
204
205#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
207#[serde(rename_all = "camelCase")]
208pub struct PasswordOAuthFlow {
209 pub token_url: String,
210 #[serde(default)]
211 pub refresh_url: Option<String>,
212 pub scopes: HashMap<String, String>,
213}
214
215#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
217#[serde(rename_all = "camelCase")]
218pub struct ClientCredentialsOAuthFlow {
219 pub token_url: String,
220 #[serde(default)]
221 pub refresh_url: Option<String>,
222 pub scopes: HashMap<String, String>,
223}
224
225#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
227#[serde(rename_all = "camelCase")]
228pub struct AuthorizationCodeOAuthFlow {
229 pub authorization_url: String,
230 pub token_url: String,
231 #[serde(default)]
232 pub refresh_url: Option<String>,
233 pub scopes: HashMap<String, String>,
234}
235
236#[derive(Serialize, Deserialize, Debug)]
240pub struct JsonRpcRequest {
241 pub jsonrpc: String,
242 pub method: String,
243 pub params: serde_json::Value,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub id: Option<serde_json::Value>,
246}
247
248#[derive(Serialize, Debug)]
250pub struct JsonRpcResponse {
251 pub jsonrpc: String,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub result: Option<serde_json::Value>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub error: Option<JsonRpcError>,
256 pub id: Option<serde_json::Value>,
257}
258
259#[derive(Serialize, Debug)]
261pub struct JsonRpcError {
262 pub code: i32,
263 pub message: String,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub data: Option<serde_json::Value>,
266}
267
268#[derive(Serialize, Deserialize, Debug)]
272#[serde(rename_all = "camelCase")]
273pub struct MessageSendParams {
274 pub message: Message,
275 #[serde(default)]
276 pub configuration: Option<MessageSendConfiguration>,
277 #[serde(default)]
278 pub metadata: Option<serde_json::Value>,
279}
280
281#[derive(Serialize, Deserialize, Debug, Default)]
283#[serde(rename_all = "camelCase")]
284pub struct MessageSendConfiguration {
285 pub accepted_output_modes: Vec<String>,
286 #[serde(default)]
287 pub blocking: bool,
288 #[serde(default)]
289 pub history_length: Option<u32>,
290 #[serde(default)]
291 pub push_notification_config: Option<PushNotificationConfig>,
292}
293
294#[derive(Serialize, Deserialize, Debug, Clone)]
295#[serde(untagged)]
296pub enum MessageKind {
297 Message(Message),
298 TaskStatusUpdate(TaskStatusUpdateEvent),
299 Artifact(Artifact),
300}
301
302impl MessageKind {
303 pub fn set_update_props(&mut self, metadata: serde_json::Value, context_id: String) {
304 match self {
305 MessageKind::Message(ref mut m) => {
306 m.metadata = Some(metadata);
307 m.context_id = Some(context_id);
308 }
309 MessageKind::TaskStatusUpdate(ref mut m) => {
310 m.metadata = Some(metadata);
311 m.context_id = context_id;
312 }
313 MessageKind::Artifact(_) => {}
314 }
315 }
316}
317#[derive(Serialize, Deserialize, Debug, Clone)]
319#[serde(rename_all = "camelCase")]
320pub struct Message {
321 pub kind: EventKind,
322 pub message_id: String,
323 pub role: Role,
324 pub parts: Vec<Part>,
325 #[serde(default)]
326 pub context_id: Option<String>,
327 #[serde(default)]
328 pub task_id: Option<String>,
329 #[serde(default)]
330 pub reference_task_ids: Vec<String>,
331 #[serde(default)]
332 pub extensions: Vec<String>,
333 #[serde(default)]
334 pub metadata: Option<serde_json::Value>,
335}
336impl Default for Message {
337 fn default() -> Self {
338 Self {
339 message_id: Default::default(),
340 kind: EventKind::Message,
341 role: Role::Agent,
342 parts: vec![],
343 context_id: None,
344 task_id: None,
345 reference_task_ids: vec![],
346 extensions: vec![],
347 metadata: None,
348 }
349 }
350}
351#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
352pub enum EventKind {
353 #[default]
354 #[serde(rename = "message")]
355 Message,
356 #[serde(rename = "task")]
357 Task,
358 #[serde(rename = "status-update")]
359 TaskStatusUpdate,
360 #[serde(rename = "artifact-update")]
361 TaskArtifactUpdate,
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 #[test]
368 fn serialize_message_kind() {
369 let message_kind = MessageKind::Message(Message::default());
370 let serialized = serde_json::to_string(&message_kind).unwrap();
371
372 println!("{}", serialized);
373 let deserialized: MessageKind = serde_json::from_str(&serialized).unwrap();
375 match deserialized {
376 MessageKind::Message(msg) => {
377 assert_eq!(msg.kind, EventKind::Message);
378 assert_eq!(msg.role, Role::Agent);
379 }
380 _ => panic!("Expected MessageKind::Message"),
381 }
382 }
383}
384#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
386#[serde(rename_all = "camelCase")]
387pub enum Role {
388 User,
389 #[default]
390 Agent,
391}
392
393#[derive(Serialize, Deserialize, Debug, Clone)]
395#[serde(tag = "kind", rename_all = "camelCase")]
396pub enum Part {
397 #[serde(rename = "text")]
398 Text(TextPart),
399 #[serde(rename = "file")]
400 File(FilePart),
401 #[serde(rename = "data")]
402 Data(DataPart),
403}
404
405#[derive(Serialize, Deserialize, Debug, Clone)]
407pub struct TextPart {
408 pub text: String,
409}
410
411#[derive(Serialize, Deserialize, Debug, Clone)]
413#[serde(rename_all = "camelCase")]
414pub struct FilePart {
415 pub file: FileObject,
416 #[serde(default)]
417 pub metadata: Option<serde_json::Value>,
418}
419
420impl FilePart {
421 pub fn mime_type(&self) -> Option<&str> {
422 match &self.file {
423 FileObject::WithUri { mime_type, .. } => mime_type.as_deref(),
424 FileObject::WithBytes { mime_type, .. } => mime_type.as_deref(),
425 }
426 }
427}
428
429#[derive(Serialize, Deserialize, Debug, Clone)]
431#[serde(untagged, rename_all = "camelCase")]
432pub enum FileObject {
433 WithUri {
434 uri: String,
435 #[serde(default, rename = "mimeType")]
436 mime_type: Option<String>,
437 #[serde(default)]
438 name: Option<String>,
439 },
440 WithBytes {
441 bytes: String,
442 #[serde(default, rename = "mimeType")]
443 mime_type: Option<String>,
444 #[serde(default)]
445 name: Option<String>,
446 },
447}
448
449#[derive(Serialize, Deserialize, Debug, Clone)]
451pub struct DataPart {
452 pub data: serde_json::Value,
453}
454
455#[derive(Serialize, Deserialize, Debug, Default)]
457#[serde(rename_all = "camelCase")]
458pub struct PushNotificationConfig {
459 pub url: String,
460 #[serde(default)]
461 pub token: Option<String>,
462 #[serde(default)]
463 pub id: Option<String>,
464}
465
466#[derive(Serialize, Deserialize, Debug)]
468#[serde(rename_all = "camelCase")]
469pub struct TaskIdParams {
470 pub id: String,
471}
472
473#[derive(Serialize, Deserialize, Debug, Clone, Default)]
475#[serde(rename_all = "camelCase")]
476pub struct Task {
477 pub kind: EventKind,
478 pub id: String,
479 pub context_id: String,
480 pub status: TaskStatus,
481 #[serde(default)]
482 pub artifacts: Vec<Artifact>,
483 #[serde(default)]
484 pub history: Vec<Message>,
485 #[serde(default)]
486 pub metadata: Option<serde_json::Value>,
487}
488
489#[derive(Serialize, Deserialize, Debug, Clone, Default)]
491#[serde(rename_all = "camelCase")]
492pub struct TaskStatus {
493 pub state: TaskState,
494 #[serde(default)]
495 pub message: Option<Message>,
496 #[serde(default)]
497 pub timestamp: Option<String>,
498}
499
500#[derive(Serialize, Deserialize, Debug, Clone, Default)]
502#[serde(rename_all = "camelCase")]
503pub enum TaskState {
504 #[default]
505 Submitted,
506 Working,
507 InputRequired,
508 Completed,
509 Canceled,
510 Failed,
511 Rejected,
512 AuthRequired,
513 Unknown,
514}
515
516#[derive(Serialize, Deserialize, Debug, Clone)]
518#[serde(rename_all = "camelCase")]
519pub struct Artifact {
520 pub artifact_id: String,
521 pub parts: Vec<Part>,
522 #[serde(default)]
523 pub name: Option<String>,
524 #[serde(default)]
525 pub description: Option<String>,
526}
527
528#[derive(Serialize, Deserialize, Debug, Clone)]
532#[serde(rename_all = "camelCase")]
533pub struct TaskStatusUpdateEvent {
534 pub kind: EventKind,
535 pub task_id: String,
536 pub context_id: String,
537 pub status: TaskStatus,
538 pub r#final: bool,
539 #[serde(default)]
540 pub metadata: Option<serde_json::Value>,
541}
542
543#[derive(Serialize, Deserialize, Debug, Clone)]
545#[serde(rename_all = "camelCase")]
546pub struct TaskArtifactUpdateEvent {
547 pub kind: EventKind,
548 pub task_id: String,
549 pub context_id: String,
550 pub artifact: Artifact,
551 #[serde(default)]
552 pub append: Option<bool>,
553 #[serde(default)]
554 pub last_chunk: Option<bool>,
555 #[serde(default)]
556 pub metadata: Option<serde_json::Value>,
557}
558
559#[derive(Serialize, Deserialize, Debug, Clone)]
563#[serde(rename_all = "camelCase")]
564pub struct TaskStatusBroadcastEvent {
565 pub r#type: String,
566 pub task_id: String,
567 pub thread_id: String,
568 pub agent_id: String,
569 pub status: String,
570}