adk_server/a2a/
agent_card.rs1use crate::a2a::{AgentCapabilities, AgentCard, AgentSkill};
2use adk_core::Agent;
3
4pub fn build_agent_skills(agent: &dyn Agent) -> Vec<AgentSkill> {
5 let mut skills = build_primary_skills(agent);
6 skills.extend(build_sub_agent_skills(agent));
7 skills
8}
9
10fn build_primary_skills(agent: &dyn Agent) -> Vec<AgentSkill> {
11 vec![AgentSkill::new(
12 agent.name().to_string(),
13 agent.name().to_string(),
14 agent.description().to_string(),
15 vec!["agent".to_string()],
16 )]
17}
18
19fn build_sub_agent_skills(agent: &dyn Agent) -> Vec<AgentSkill> {
20 let sub_agents = agent.sub_agents();
21 if sub_agents.is_empty() {
22 return vec![];
23 }
24
25 let mut skills = vec![];
26
27 let descriptions: Vec<String> = sub_agents
29 .iter()
30 .map(|sub| {
31 if sub.description().is_empty() {
32 "No description".to_string()
33 } else {
34 sub.description().to_string()
35 }
36 })
37 .collect();
38
39 skills.push(AgentSkill::new(
40 format!("{}-sub-agents", agent.name()),
41 "sub-agents".to_string(),
42 format!("Orchestrates: {}", descriptions.join("; ")),
43 vec!["orchestration".to_string()],
44 ));
45
46 for sub in sub_agents {
48 let sub_skills = build_primary_skills(sub.as_ref());
49 for skill in sub_skills {
50 skills.push(AgentSkill::new(
51 format!("{}_{}", sub.name(), skill.id),
52 format!("{}: {}", sub.name(), skill.name),
53 skill.description,
54 {
55 let mut tags = vec![format!("sub_agent:{}", sub.name())];
56 tags.extend(skill.tags);
57 tags
58 },
59 ));
60 }
61 }
62
63 skills
64}
65
66pub fn build_agent_card(agent: &dyn Agent, base_url: &str) -> AgentCard {
67 AgentCard::builder()
68 .name(agent.name().to_string())
69 .description(agent.description().to_string())
70 .url(base_url.to_string())
71 .version("1.0.0".to_string())
72 .capabilities(AgentCapabilities {
73 streaming: true,
74 push_notifications: false,
75 state_transition_history: true,
76 extensions: None,
77 })
78 .skills(build_agent_skills(agent))
79 .build()
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use adk_core::{Agent, EventStream};
86 use async_trait::async_trait;
87 use std::sync::Arc;
88
89 struct TestAgent {
90 name: String,
91 description: String,
92 }
93
94 #[async_trait]
95 impl Agent for TestAgent {
96 fn name(&self) -> &str {
97 &self.name
98 }
99
100 fn description(&self) -> &str {
101 &self.description
102 }
103
104 async fn run(
105 &self,
106 _ctx: Arc<dyn adk_core::InvocationContext>,
107 ) -> adk_core::Result<EventStream> {
108 unimplemented!()
109 }
110
111 fn sub_agents(&self) -> &[Arc<dyn Agent>] {
112 &[]
113 }
114 }
115
116 #[test]
117 fn test_build_agent_skills() {
118 let agent =
119 TestAgent { name: "test_agent".to_string(), description: "A test agent".to_string() };
120
121 let skills = build_agent_skills(&agent);
122 assert_eq!(skills.len(), 1);
123 assert_eq!(skills[0].id, "test_agent");
124 assert_eq!(skills[0].name, "test_agent");
125 }
126
127 #[test]
128 fn test_build_agent_card() {
129 let agent =
130 TestAgent { name: "test_agent".to_string(), description: "A test agent".to_string() };
131
132 let card = build_agent_card(&agent, "https://example.com");
133 assert_eq!(card.name, "test_agent");
134 assert_eq!(card.url, "https://example.com");
135 assert!(card.capabilities.streaming);
136 }
137}