Skip to main content

distri_a2a/
a2a_types.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5/// Represents the Agent-to-Agent (A2A) specification version.
6pub const A2A_VERSION: &str = "0.10.0";
7
8/// Describes an agent's capabilities, skills, and metadata, serving as a public profile.
9/// See: https://google.github.io/A2A/specification/#agentcard-object-structure
10#[derive(Serialize, Deserialize, Debug, JsonSchema)]
11#[serde(rename_all = "camelCase")]
12pub struct AgentCard {
13    /// The version of the A2A specification this agent adheres to.
14    pub version: String,
15    /// The agent's unique name.
16    pub name: String,
17    /// A short description of the agent's purpose.
18    pub description: String,
19    /// The URL where the agent can be reached.
20    pub url: String,
21    /// A URL to an icon for the agent.
22    #[serde(default)]
23    pub icon_url: Option<String>,
24    /// A URL to the agent's documentation.
25    #[serde(default)]
26    pub documentation_url: Option<String>,
27    /// Information about the agent's provider.
28    #[serde(default)]
29    pub provider: Option<AgentProvider>,
30    /// The preferred transport method for communicating with the agent.
31    #[serde(default)]
32    pub preferred_transport: Option<String>,
33    /// The agent's capabilities.
34    pub capabilities: AgentCapabilities,
35    /// The default input modes the agent accepts.
36    pub default_input_modes: Vec<String>,
37    /// The default output modes the agent produces.
38    pub default_output_modes: Vec<String>,
39    /// The skills the agent possesses.
40    pub skills: Vec<AgentSkill>,
41    /// The security schemes supported by the agent.
42    #[serde(default)]
43    pub security_schemes: HashMap<String, SecurityScheme>,
44    /// The security requirements for the agent.
45    #[serde(default)]
46    pub security: Vec<HashMap<String, Vec<String>>>,
47}
48
49/// Provides information about the organization or individual that created the agent.
50#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
51#[serde(rename_all = "camelCase")]
52pub struct AgentProvider {
53    /// The name of the organization.
54    pub organization: String,
55    /// A URL to the provider's website.
56    pub url: String,
57}
58
59/// Defines the agent's supported features and extensions.
60#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone, Default)]
61#[serde(rename_all = "camelCase")]
62pub struct AgentCapabilities {
63    /// Whether the agent supports streaming responses. Default is true.
64    #[serde(default = "default_true")]
65    pub streaming: bool,
66    /// Whether the agent can send push notifications. Default is false.
67    #[serde(default)]
68    pub push_notifications: bool,
69    /// Whether the agent can provide a history of state transitions.
70    #[serde(default = "default_true")]
71    pub state_transition_history: bool,
72    /// Any extensions the agent supports.
73    #[serde(default)]
74    pub extensions: Vec<AgentExtension>,
75}
76fn default_true() -> bool {
77    true
78}
79
80/// Describes a custom extension supported by the agent.
81#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct AgentExtension {
84    /// A URI that uniquely identifies the extension.
85    pub uri: String,
86    /// A description of the extension.
87    #[serde(default)]
88    pub description: Option<String>,
89    /// Whether the extension is required for the agent to function.
90    #[serde(default)]
91    pub required: bool,
92    /// Any parameters the extension requires.
93    #[serde(default)]
94    pub params: Option<serde_json::Value>,
95}
96
97/// Describes a specific skill or capability of the agent.
98#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
99#[serde(rename_all = "camelCase")]
100pub struct AgentSkill {
101    /// A unique identifier for the skill.
102    pub id: String,
103    /// The name of the skill.
104    pub name: String,
105    /// A description of what the skill does.
106    pub description: String,
107    /// Tags for categorizing the skill.
108    #[serde(default)]
109    pub tags: Vec<String>,
110    /// Examples of how to use the skill.
111    #[serde(default)]
112    pub examples: Vec<String>,
113    /// The input modes the skill accepts, overriding agent defaults.
114    #[serde(default)]
115    pub input_modes: Option<Vec<String>>,
116    /// The output modes the skill produces, overriding agent defaults.
117    #[serde(default)]
118    pub output_modes: Option<Vec<String>>,
119}
120
121/// Defines a security scheme for authenticating with the agent.
122#[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/// An API key-based security scheme.
132#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
133#[serde(rename_all = "camelCase")]
134pub struct APIKeySecurityScheme {
135    /// The name of the header, query, or cookie parameter to be used.
136    pub name: String,
137    /// The location of the API key.
138    #[serde(rename = "in")]
139    pub location: String,
140    /// A description of the security scheme.
141    #[serde(default)]
142    pub description: Option<String>,
143}
144
145/// An HTTP authentication-based security scheme.
146#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
147#[serde(rename_all = "camelCase")]
148pub struct HTTPAuthSecurityScheme {
149    /// The name of the HTTP Authorization scheme to be used.
150    pub scheme: String,
151    /// A hint to the client about the format of the bearer token.
152    #[serde(default)]
153    pub bearer_format: Option<String>,
154    /// A description of the security scheme.
155    #[serde(default)]
156    pub description: Option<String>,
157}
158
159/// An OAuth2-based security scheme.
160#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
161#[serde(rename_all = "camelCase")]
162pub struct OAuth2SecurityScheme {
163    /// The OAuth2 flows supported by this scheme.
164    pub flows: OAuthFlows,
165    /// A description of the security scheme.
166    #[serde(default)]
167    pub description: Option<String>,
168}
169
170/// An OpenID Connect-based security scheme.
171#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
172#[serde(rename_all = "camelCase")]
173pub struct OpenIdConnectSecurityScheme {
174    /// The OpenID Connect discovery URL.
175    pub open_id_connect_url: String,
176    /// A description of the security scheme.
177    #[serde(default)]
178    pub description: Option<String>,
179}
180
181/// Defines the OAuth2 flows.
182#[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/// The implicit OAuth2 flow.
196#[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/// The password-based OAuth2 flow.
206#[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/// The client credentials OAuth2 flow.
216#[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/// The authorization code OAuth2 flow.
226#[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// JSON-RPC Types
237
238/// A JSON-RPC request object.
239#[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/// A JSON-RPC response object.
249#[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/// A JSON-RPC error object.
260#[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// A2A Method Params
269
270/// Parameters for the `message/send` method.
271#[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/// Configuration for sending a message.
282#[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/// A message exchanged between a user and an agent.
318#[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        // Verify it deserializes back correctly (round-trip test)
374        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/// The role of the message sender.
385#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
386#[serde(rename_all = "camelCase")]
387pub enum Role {
388    User,
389    #[default]
390    Agent,
391}
392
393/// A part of a message.
394#[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/// A text part of a message.
406#[derive(Serialize, Deserialize, Debug, Clone)]
407pub struct TextPart {
408    pub text: String,
409}
410
411/// A file part of a message.
412#[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/// A file object, which can be represented by a URI or by its raw bytes.
430#[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/// A data part of a message, containing arbitrary JSON data.
450#[derive(Serialize, Deserialize, Debug, Clone)]
451pub struct DataPart {
452    pub data: serde_json::Value,
453}
454
455/// Configuration for push notifications.
456#[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/// Parameters for methods that operate on a task by its ID.
467#[derive(Serialize, Deserialize, Debug)]
468#[serde(rename_all = "camelCase")]
469pub struct TaskIdParams {
470    pub id: String,
471}
472
473/// Represents a task being executed by the agent.
474#[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/// The status of a task.
490#[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/// The state of a task.
501#[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/// An artifact produced by a task.
517#[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// A2A Streaming Response Types
529
530/// Task Status Update Event - sent during streaming
531#[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/// Task Artifact Update Event - sent during streaming
544#[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// Event Broadcasting Types
560
561/// Event for broadcasting task status changes
562#[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}