brainwires_agent_network/identity/
agent_identity.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use uuid::Uuid;
4
5pub type ProtocolId = String;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct AgentIdentity {
15 pub id: Uuid,
17 pub name: String,
19 pub agent_card: AgentCard,
21}
22
23impl AgentIdentity {
24 pub fn new(name: impl Into<String>) -> Self {
26 Self {
27 id: Uuid::new_v4(),
28 name: name.into(),
29 agent_card: AgentCard::default(),
30 }
31 }
32
33 pub fn with_id(id: Uuid, name: impl Into<String>) -> Self {
35 Self {
36 id,
37 name: name.into(),
38 agent_card: AgentCard::default(),
39 }
40 }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, Default)]
48pub struct AgentCard {
49 pub capabilities: Vec<String>,
52 pub supported_protocols: Vec<ProtocolId>,
55 pub metadata: HashMap<String, serde_json::Value>,
57 pub endpoint: Option<String>,
60 pub max_concurrent_tasks: Option<usize>,
62 pub compute_capacity: Option<f64>,
64}
65
66impl AgentCard {
67 pub fn supports_protocol(&self, protocol: &str) -> bool {
69 self.supported_protocols
70 .iter()
71 .any(|p| p.eq_ignore_ascii_case(protocol))
72 }
73
74 pub fn has_capability(&self, capability: &str) -> bool {
76 self.capabilities
77 .iter()
78 .any(|c| c.eq_ignore_ascii_case(capability))
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn new_identity_has_unique_id() {
88 let a = AgentIdentity::new("agent-a");
89 let b = AgentIdentity::new("agent-b");
90 assert_ne!(a.id, b.id);
91 assert_eq!(a.name, "agent-a");
92 }
93
94 #[test]
95 fn with_id_preserves_uuid() {
96 let id = Uuid::nil();
97 let identity = AgentIdentity::with_id(id, "test");
98 assert_eq!(identity.id, Uuid::nil());
99 }
100
101 #[test]
102 fn agent_card_protocol_check() {
103 let card = AgentCard {
104 supported_protocols: vec!["mcp".into(), "a2a".into()],
105 ..Default::default()
106 };
107 assert!(card.supports_protocol("MCP"));
108 assert!(card.supports_protocol("a2a"));
109 assert!(!card.supports_protocol("ipc"));
110 }
111
112 #[test]
113 fn agent_card_capability_check() {
114 let card = AgentCard {
115 capabilities: vec!["code-review".into(), "file-editing".into()],
116 ..Default::default()
117 };
118 assert!(card.has_capability("Code-Review"));
119 assert!(!card.has_capability("deploy"));
120 }
121
122 #[test]
123 fn identity_serde_roundtrip() {
124 let mut identity = AgentIdentity::new("test-agent");
125 identity.agent_card.capabilities = vec!["search".into()];
126 identity.agent_card.endpoint = Some("tcp://localhost:9090".into());
127
128 let json = serde_json::to_string(&identity).unwrap();
129 let deserialized: AgentIdentity = serde_json::from_str(&json).unwrap();
130
131 assert_eq!(deserialized.id, identity.id);
132 assert_eq!(deserialized.name, "test-agent");
133 assert_eq!(deserialized.agent_card.capabilities, vec!["search"]);
134 assert_eq!(
135 deserialized.agent_card.endpoint.as_deref(),
136 Some("tcp://localhost:9090")
137 );
138 }
139
140 #[test]
141 fn default_agent_card_is_empty() {
142 let card = AgentCard::default();
143 assert!(card.capabilities.is_empty());
144 assert!(card.supported_protocols.is_empty());
145 assert!(card.metadata.is_empty());
146 assert!(card.endpoint.is_none());
147 assert!(card.max_concurrent_tasks.is_none());
148 assert!(card.compute_capacity.is_none());
149 }
150}