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(Box<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, Deserialize, Debug, Clone)]
261pub struct JsonRpcError {
262 pub code: i32,
263 pub message: String,
264 #[serde(default, skip_serializing_if = "Option::is_none")]
265 pub data: Option<serde_json::Value>,
266}
267
268#[derive(Deserialize, Debug)]
275#[serde(bound(deserialize = "T: serde::Deserialize<'de>"))]
276pub struct JsonRpcResponseFor<T> {
277 #[serde(default)]
278 pub result: Option<T>,
279 #[serde(default)]
280 pub error: Option<JsonRpcError>,
281}
282
283impl JsonRpcResponse {
284 pub fn success(id: Option<serde_json::Value>, result: serde_json::Value) -> Self {
286 Self {
287 jsonrpc: "2.0".to_string(),
288 id,
289 result: Some(result),
290 error: None,
291 }
292 }
293
294 pub fn error(id: Option<serde_json::Value>, error: JsonRpcError) -> Self {
296 Self {
297 jsonrpc: "2.0".to_string(),
298 id,
299 result: None,
300 error: Some(error),
301 }
302 }
303}
304
305impl JsonRpcError {
306 pub fn new(code: i32, message: impl Into<String>) -> Self {
308 Self {
309 code,
310 message: message.into(),
311 data: None,
312 }
313 }
314
315 pub fn invalid_params(msg: impl Into<String>) -> Self {
317 Self::new(-32602, msg)
318 }
319
320 pub fn method_not_found(method: &str) -> Self {
322 Self::new(-32601, format!("Method not found: {method}"))
323 }
324
325 pub fn internal(msg: impl Into<String>) -> Self {
327 Self::new(-32603, msg)
328 }
329}
330
331#[derive(Serialize, Deserialize, Debug)]
335#[serde(rename_all = "camelCase")]
336pub struct MessageSendParams {
337 pub message: Message,
338 #[serde(default)]
339 pub configuration: Option<MessageSendConfiguration>,
340 #[serde(default)]
341 pub metadata: Option<serde_json::Value>,
342}
343
344#[derive(Serialize, Deserialize, Debug, Default)]
346#[serde(rename_all = "camelCase")]
347pub struct MessageSendConfiguration {
348 pub accepted_output_modes: Vec<String>,
349 #[serde(default)]
350 pub blocking: bool,
351 #[serde(default)]
352 pub history_length: Option<u32>,
353 #[serde(default)]
354 pub push_notification_config: Option<PushNotificationConfig>,
355}
356
357#[derive(Serialize, Deserialize, Debug, Clone)]
358#[serde(untagged)]
359pub enum MessageKind {
360 Message(Message),
361 TaskStatusUpdate(TaskStatusUpdateEvent),
362 Artifact(Artifact),
363}
364
365impl MessageKind {
366 pub fn set_update_props(&mut self, metadata: serde_json::Value, context_id: String) {
367 match self {
368 MessageKind::Message(ref mut m) => {
369 m.metadata = Some(metadata);
370 m.context_id = Some(context_id);
371 }
372 MessageKind::TaskStatusUpdate(ref mut m) => {
373 m.metadata = Some(metadata);
374 m.context_id = context_id;
375 }
376 MessageKind::Artifact(_) => {}
377 }
378 }
379}
380#[derive(Serialize, Deserialize, Debug, Clone)]
382#[serde(rename_all = "camelCase")]
383pub struct Message {
384 pub kind: EventKind,
385 pub message_id: String,
386 pub role: Role,
387 pub parts: Vec<Part>,
388 #[serde(default)]
389 pub context_id: Option<String>,
390 #[serde(default)]
391 pub task_id: Option<String>,
392 #[serde(default)]
393 pub reference_task_ids: Vec<String>,
394 #[serde(default)]
395 pub extensions: Vec<String>,
396 #[serde(default)]
397 pub metadata: Option<serde_json::Value>,
398}
399impl Default for Message {
400 fn default() -> Self {
401 Self {
402 message_id: Default::default(),
403 kind: EventKind::Message,
404 role: Role::Agent,
405 parts: vec![],
406 context_id: None,
407 task_id: None,
408 reference_task_ids: vec![],
409 extensions: vec![],
410 metadata: None,
411 }
412 }
413}
414#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
415pub enum EventKind {
416 #[default]
417 #[serde(rename = "message")]
418 Message,
419 #[serde(rename = "task")]
420 Task,
421 #[serde(rename = "status-update")]
422 TaskStatusUpdate,
423 #[serde(rename = "artifact-update")]
424 TaskArtifactUpdate,
425}
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430 #[test]
431 fn serialize_message_kind() {
432 let message_kind = MessageKind::Message(Message::default());
433 let serialized = serde_json::to_string(&message_kind).unwrap();
434
435 println!("{}", serialized);
436 let deserialized: MessageKind = serde_json::from_str(&serialized).unwrap();
438 match deserialized {
439 MessageKind::Message(msg) => {
440 assert_eq!(msg.kind, EventKind::Message);
441 assert_eq!(msg.role, Role::Agent);
442 }
443 _ => panic!("Expected MessageKind::Message"),
444 }
445 }
446}
447#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
449#[serde(rename_all = "camelCase")]
450pub enum Role {
451 User,
452 #[default]
453 Agent,
454}
455
456#[derive(Serialize, Deserialize, Debug, Clone)]
458#[serde(tag = "kind", rename_all = "camelCase")]
459pub enum Part {
460 #[serde(rename = "text")]
461 Text(TextPart),
462 #[serde(rename = "file")]
463 File(FilePart),
464 #[serde(rename = "data")]
465 Data(DataPart),
466}
467
468#[derive(Serialize, Deserialize, Debug, Clone)]
470pub struct TextPart {
471 pub text: String,
472}
473
474#[derive(Serialize, Deserialize, Debug, Clone)]
476#[serde(rename_all = "camelCase")]
477pub struct FilePart {
478 pub file: FileObject,
479 #[serde(default)]
480 pub metadata: Option<serde_json::Value>,
481}
482
483impl FilePart {
484 pub fn mime_type(&self) -> Option<&str> {
485 match &self.file {
486 FileObject::WithUri { mime_type, .. } => mime_type.as_deref(),
487 FileObject::WithBytes { mime_type, .. } => mime_type.as_deref(),
488 }
489 }
490}
491
492#[derive(Serialize, Deserialize, Debug, Clone)]
494#[serde(untagged, rename_all = "camelCase")]
495pub enum FileObject {
496 WithUri {
497 uri: String,
498 #[serde(default, rename = "mimeType")]
499 mime_type: Option<String>,
500 #[serde(default)]
501 name: Option<String>,
502 },
503 WithBytes {
504 bytes: String,
505 #[serde(default, rename = "mimeType")]
506 mime_type: Option<String>,
507 #[serde(default)]
508 name: Option<String>,
509 },
510}
511
512#[derive(Serialize, Deserialize, Debug, Clone)]
514pub struct DataPart {
515 pub data: serde_json::Value,
516}
517
518#[derive(Serialize, Deserialize, Debug, Default)]
520#[serde(rename_all = "camelCase")]
521pub struct PushNotificationConfig {
522 pub url: String,
523 #[serde(default)]
524 pub token: Option<String>,
525 #[serde(default)]
526 pub id: Option<String>,
527}
528
529#[derive(Serialize, Deserialize, Debug)]
531#[serde(rename_all = "camelCase")]
532pub struct TaskIdParams {
533 pub id: String,
534}
535
536#[derive(Serialize, Deserialize, Debug, Clone, Default)]
538#[serde(rename_all = "camelCase")]
539pub struct Task {
540 pub kind: EventKind,
541 pub id: String,
542 pub context_id: String,
543 pub status: TaskStatus,
544 #[serde(default)]
545 pub artifacts: Vec<Artifact>,
546 #[serde(default)]
547 pub history: Vec<Message>,
548 #[serde(default)]
549 pub metadata: Option<serde_json::Value>,
550}
551
552#[derive(Serialize, Deserialize, Debug, Clone, Default)]
554#[serde(rename_all = "camelCase")]
555pub struct TaskStatus {
556 pub state: TaskState,
557 #[serde(default)]
558 pub message: Option<Message>,
559 #[serde(default)]
560 pub timestamp: Option<String>,
561}
562
563#[derive(Serialize, Deserialize, Debug, Clone, Default)]
565#[serde(rename_all = "camelCase")]
566pub enum TaskState {
567 #[default]
568 Submitted,
569 Working,
570 InputRequired,
571 Completed,
572 Canceled,
573 Failed,
574 Rejected,
575 AuthRequired,
576 Unknown,
577}
578
579#[derive(Serialize, Deserialize, Debug, Clone)]
588#[serde(untagged)]
589pub enum SendMessageResult {
590 Task(Task),
591 Message(Message),
592}
593
594#[derive(Serialize, Deserialize, Debug, Clone)]
596#[serde(rename_all = "camelCase")]
597pub struct Artifact {
598 pub artifact_id: String,
599 pub parts: Vec<Part>,
600 #[serde(default)]
601 pub name: Option<String>,
602 #[serde(default)]
603 pub description: Option<String>,
604}
605
606#[derive(Serialize, Deserialize, Debug, Clone)]
610#[serde(rename_all = "camelCase")]
611pub struct TaskStatusUpdateEvent {
612 pub kind: EventKind,
613 pub task_id: String,
614 pub context_id: String,
615 pub status: TaskStatus,
616 pub r#final: bool,
617 #[serde(default)]
618 pub metadata: Option<serde_json::Value>,
619}
620
621#[derive(Serialize, Deserialize, Debug, Clone)]
623#[serde(rename_all = "camelCase")]
624pub struct TaskArtifactUpdateEvent {
625 pub kind: EventKind,
626 pub task_id: String,
627 pub context_id: String,
628 pub artifact: Artifact,
629 #[serde(default)]
630 pub append: Option<bool>,
631 #[serde(default)]
632 pub last_chunk: Option<bool>,
633 #[serde(default)]
634 pub metadata: Option<serde_json::Value>,
635}
636
637#[derive(Serialize, Deserialize, Debug, Clone)]
641#[serde(rename_all = "camelCase")]
642pub struct TaskStatusBroadcastEvent {
643 pub r#type: String,
644 pub task_id: String,
645 pub thread_id: String,
646 pub agent_id: String,
647 pub status: String,
648}