Skip to main content

brainwires_a2a/
agent_card.rs

1//! Agent card types: AgentCard, AgentCapabilities, AgentSkill, security schemes, OAuth flows.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Self-describing manifest for an agent.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct AgentCard {
9    /// Human-readable agent name.
10    pub name: String,
11    /// Human-readable description.
12    pub description: String,
13    /// Agent version string.
14    pub version: String,
15    /// Ordered list of supported interfaces (first is preferred).
16    #[serde(rename = "supportedInterfaces")]
17    pub supported_interfaces: Vec<AgentInterface>,
18    /// Agent capabilities.
19    pub capabilities: AgentCapabilities,
20    /// Agent skills.
21    pub skills: Vec<AgentSkill>,
22    /// Default input media types.
23    #[serde(rename = "defaultInputModes")]
24    pub default_input_modes: Vec<String>,
25    /// Default output media types.
26    #[serde(rename = "defaultOutputModes")]
27    pub default_output_modes: Vec<String>,
28    /// Service provider information.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub provider: Option<AgentProvider>,
31    /// Security scheme definitions.
32    #[serde(rename = "securitySchemes", skip_serializing_if = "Option::is_none")]
33    pub security_schemes: Option<HashMap<String, SecurityScheme>>,
34    /// Security requirements.
35    #[serde(
36        rename = "securityRequirements",
37        skip_serializing_if = "Option::is_none"
38    )]
39    pub security_requirements: Option<Vec<SecurityRequirement>>,
40    /// URL to additional documentation.
41    #[serde(rename = "documentationUrl", skip_serializing_if = "Option::is_none")]
42    pub documentation_url: Option<String>,
43    /// Icon URL.
44    #[serde(rename = "iconUrl", skip_serializing_if = "Option::is_none")]
45    pub icon_url: Option<String>,
46    /// JWS signatures for the agent card.
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub signatures: Option<Vec<AgentCardSignature>>,
49}
50
51/// Declares a protocol binding interface for the agent.
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct AgentInterface {
54    /// URL where this interface is available.
55    pub url: String,
56    /// Protocol binding: `JSONRPC`, `GRPC`, `HTTP+JSON`.
57    #[serde(rename = "protocolBinding")]
58    pub protocol_binding: String,
59    /// Optional tenant identifier.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub tenant: Option<String>,
62    /// A2A protocol version.
63    #[serde(rename = "protocolVersion")]
64    pub protocol_version: String,
65}
66
67/// Agent capabilities.
68#[derive(Debug, Clone, Default, Serialize, Deserialize)]
69pub struct AgentCapabilities {
70    /// Supports streaming responses.
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub streaming: Option<bool>,
73    /// Supports push notifications.
74    #[serde(rename = "pushNotifications", skip_serializing_if = "Option::is_none")]
75    pub push_notifications: Option<bool>,
76    /// Supports extended agent card.
77    #[serde(rename = "extendedAgentCard", skip_serializing_if = "Option::is_none")]
78    pub extended_agent_card: Option<bool>,
79    /// Protocol extensions supported.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub extensions: Option<Vec<AgentExtension>>,
82}
83
84/// A protocol extension declaration.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct AgentExtension {
87    /// Unique URI identifying the extension.
88    pub uri: String,
89    /// Human-readable description.
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub description: Option<String>,
92    /// Whether the client must comply.
93    #[serde(default)]
94    pub required: bool,
95    /// Extension-specific parameters.
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub params: Option<HashMap<String, serde_json::Value>>,
98}
99
100/// An agent's specific capability or function.
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct AgentSkill {
103    /// Unique skill identifier.
104    pub id: String,
105    /// Human-readable skill name.
106    pub name: String,
107    /// Detailed description.
108    pub description: String,
109    /// Keywords describing capabilities.
110    pub tags: Vec<String>,
111    /// Example prompts/scenarios.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub examples: Option<Vec<String>>,
114    /// Override input modes for this skill.
115    #[serde(rename = "inputModes", skip_serializing_if = "Option::is_none")]
116    pub input_modes: Option<Vec<String>>,
117    /// Override output modes for this skill.
118    #[serde(rename = "outputModes", skip_serializing_if = "Option::is_none")]
119    pub output_modes: Option<Vec<String>>,
120    /// Security requirements for this skill.
121    #[serde(
122        rename = "securityRequirements",
123        skip_serializing_if = "Option::is_none"
124    )]
125    pub security_requirements: Option<Vec<SecurityRequirement>>,
126}
127
128/// Agent service provider.
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct AgentProvider {
131    /// Provider website or documentation URL.
132    pub url: String,
133    /// Organization name.
134    pub organization: String,
135}
136
137/// JWS signature for an AgentCard (RFC 7515).
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct AgentCardSignature {
140    /// Base64url-encoded protected JWS header.
141    pub protected: String,
142    /// Base64url-encoded computed signature.
143    pub signature: String,
144    /// Unprotected header values.
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub header: Option<HashMap<String, serde_json::Value>>,
147}
148
149/// Security requirements map: scheme name -> required scopes.
150#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151pub struct SecurityRequirement {
152    /// Map of security scheme names to their required scopes.
153    pub schemes: HashMap<String, Vec<String>>,
154}
155
156/// Security scheme (wrapper-based oneOf).
157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
158pub struct SecurityScheme {
159    /// API key authentication.
160    #[serde(skip_serializing_if = "Option::is_none", rename = "apiKeySecurityScheme")]
161    pub api_key: Option<ApiKeySecurityScheme>,
162    /// HTTP authentication (Bearer, Basic, etc).
163    #[serde(skip_serializing_if = "Option::is_none", rename = "httpAuthSecurityScheme")]
164    pub http_auth: Option<HttpAuthSecurityScheme>,
165    /// OAuth 2.0 authentication.
166    #[serde(skip_serializing_if = "Option::is_none", rename = "oauth2SecurityScheme")]
167    pub oauth2: Option<OAuth2SecurityScheme>,
168    /// OpenID Connect authentication.
169    #[serde(skip_serializing_if = "Option::is_none", rename = "openIdConnectSecurityScheme")]
170    pub open_id_connect: Option<OpenIdConnectSecurityScheme>,
171    /// Mutual TLS authentication.
172    #[serde(skip_serializing_if = "Option::is_none", rename = "mtlsSecurityScheme")]
173    pub mtls: Option<MutualTlsSecurityScheme>,
174}
175
176/// API key security scheme details.
177#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
178pub struct ApiKeySecurityScheme {
179    /// Parameter name.
180    pub name: String,
181    /// Location: `query`, `header`, or `cookie`.
182    #[serde(rename = "in")]
183    pub location: String,
184    /// Description.
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub description: Option<String>,
187}
188
189/// HTTP authentication security scheme details.
190#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
191pub struct HttpAuthSecurityScheme {
192    /// Auth scheme name (e.g. `Bearer`).
193    pub scheme: String,
194    /// Format hint (e.g. `JWT`).
195    #[serde(rename = "bearerFormat", skip_serializing_if = "Option::is_none")]
196    pub bearer_format: Option<String>,
197    /// Description.
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub description: Option<String>,
200}
201
202/// OAuth 2.0 security scheme details.
203#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
204pub struct OAuth2SecurityScheme {
205    /// OAuth2 flow configuration.
206    pub flows: OAuthFlows,
207    /// Description.
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub description: Option<String>,
210    /// OAuth2 metadata URL (RFC 8414).
211    #[serde(rename = "oauth2MetadataUrl", skip_serializing_if = "Option::is_none")]
212    pub oauth2_metadata_url: Option<String>,
213}
214
215/// OpenID Connect security scheme details.
216#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
217pub struct OpenIdConnectSecurityScheme {
218    /// OIDC discovery URL.
219    #[serde(rename = "openIdConnectUrl")]
220    pub open_id_connect_url: String,
221    /// Description.
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub description: Option<String>,
224}
225
226/// Mutual TLS security scheme details.
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
228pub struct MutualTlsSecurityScheme {
229    /// Description.
230    #[serde(skip_serializing_if = "Option::is_none")]
231    pub description: Option<String>,
232}
233
234/// OAuth 2.0 flow configuration (wrapper-based oneOf).
235#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
236pub struct OAuthFlows {
237    /// Authorization Code flow.
238    #[serde(skip_serializing_if = "Option::is_none", rename = "authorizationCode")]
239    pub authorization_code: Option<AuthorizationCodeOAuthFlow>,
240    /// Client Credentials flow.
241    #[serde(skip_serializing_if = "Option::is_none", rename = "clientCredentials")]
242    pub client_credentials: Option<ClientCredentialsOAuthFlow>,
243    /// Implicit flow (deprecated).
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub implicit: Option<ImplicitOAuthFlow>,
246    /// Password flow (deprecated).
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub password: Option<PasswordOAuthFlow>,
249    /// Device Code flow (RFC 8628).
250    #[serde(skip_serializing_if = "Option::is_none", rename = "deviceCode")]
251    pub device_code: Option<DeviceCodeOAuthFlow>,
252}
253
254/// Authorization Code OAuth flow.
255#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
256pub struct AuthorizationCodeOAuthFlow {
257    /// Authorization URL.
258    #[serde(rename = "authorizationUrl")]
259    pub authorization_url: String,
260    /// Token URL.
261    #[serde(rename = "tokenUrl")]
262    pub token_url: String,
263    /// Refresh URL.
264    #[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
265    pub refresh_url: Option<String>,
266    /// Available scopes.
267    pub scopes: HashMap<String, String>,
268    /// Whether PKCE is required.
269    #[serde(rename = "pkceRequired", skip_serializing_if = "Option::is_none")]
270    pub pkce_required: Option<bool>,
271}
272
273/// Client Credentials OAuth flow.
274#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
275pub struct ClientCredentialsOAuthFlow {
276    /// Token URL.
277    #[serde(rename = "tokenUrl")]
278    pub token_url: String,
279    /// Refresh URL.
280    #[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
281    pub refresh_url: Option<String>,
282    /// Available scopes.
283    pub scopes: HashMap<String, String>,
284}
285
286/// Implicit OAuth flow (deprecated).
287#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
288pub struct ImplicitOAuthFlow {
289    /// Authorization URL.
290    #[serde(rename = "authorizationUrl", skip_serializing_if = "Option::is_none")]
291    pub authorization_url: Option<String>,
292    /// Refresh URL.
293    #[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
294    pub refresh_url: Option<String>,
295    /// Available scopes.
296    #[serde(default)]
297    pub scopes: HashMap<String, String>,
298}
299
300/// Password OAuth flow (deprecated).
301#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
302pub struct PasswordOAuthFlow {
303    /// Token URL.
304    #[serde(rename = "tokenUrl", skip_serializing_if = "Option::is_none")]
305    pub token_url: Option<String>,
306    /// Refresh URL.
307    #[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
308    pub refresh_url: Option<String>,
309    /// Available scopes.
310    #[serde(default)]
311    pub scopes: HashMap<String, String>,
312}
313
314/// Device Code OAuth flow (RFC 8628).
315#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
316pub struct DeviceCodeOAuthFlow {
317    /// Device authorization URL.
318    #[serde(rename = "deviceAuthorizationUrl")]
319    pub device_authorization_url: String,
320    /// Token URL.
321    #[serde(rename = "tokenUrl")]
322    pub token_url: String,
323    /// Refresh URL.
324    #[serde(rename = "refreshUrl", skip_serializing_if = "Option::is_none")]
325    pub refresh_url: Option<String>,
326    /// Available scopes.
327    pub scopes: HashMap<String, String>,
328}