Module agents.a2a.protocol
Classes
class A2AMessage (from_agent: str,
to_agent: str,
type: str,
content: Dict[str, Any],
id: str = <factory>,
timestamp: float = <factory>,
metadata: Dict[str, Any] | None = None)-
Expand source code
@dataclass class A2AMessage: """ Message format for agent-to-agent communication. Attributes: from_agent (str): ID of the agent sending the message. to_agent (str): ID of the agent receiving the message. type (str): Type/category of the message (e.g., "specialist_query", "model_response"). content (Dict[str, Any]): The actual message content and data. id (str): Unique identifier for the message. Auto-generated if not provided. timestamp (float): Unix timestamp when the message was created. metadata (Optional[Dict[str, Any]]): Additional message metadata. """ from_agent: str to_agent: str type: str content: Dict[str, Any] id: str = field(default_factory=lambda: str(uuid.uuid4())) timestamp: float = field(default_factory=time.time) metadata: Optional[Dict[str, Any]] = NoneMessage format for agent-to-agent communication.
Attributes
from_agent:str- ID of the agent sending the message.
to_agent:str- ID of the agent receiving the message.
type:str- Type/category of the message (e.g., "specialist_query", "model_response").
content:Dict[str, Any]- The actual message content and data.
id:str- Unique identifier for the message. Auto-generated if not provided.
timestamp:float- Unix timestamp when the message was created.
metadata:Optional[Dict[str, Any]]- Additional message metadata.
Instance variables
var content : Dict[str, Any]var from_agent : strvar id : strvar metadata : Dict[str, Any] | Nonevar timestamp : floatvar to_agent : strvar type : str
class A2AProtocol (agent: Agent)-
Expand source code
class A2AProtocol: """ Handles agent-to-agent communication and message routing. Uses correlation-based request-response matching to ensure responses are routed to the correct requesting agent, even with concurrent queries. """ def __init__(self, agent: 'Agent'): """ Initialize the A2A protocol for an agent. Args: agent ('Agent'): The agent instance that will use this protocol. """ self.agent = agent self.registry = AgentRegistry() self._message_handlers: Dict[str, List[Callable]] = {} self._pending_requests: OrderedDict[str, PendingRequest] = OrderedDict() self._global_event_handler = None self._pipeline_event_handler = None self._sweep_task: Optional[asyncio.Task] = None self._deferred_model_handlers: List[Callable] = [] async def register(self, card: AgentCard) -> None: """ Register the agent with the global registry and start background tasks. Args: card (AgentCard): The agent's capability card. """ self.registry.register_agent(card, self.agent) # Start timeout sweep for pending requests if self._sweep_task is None: self._sweep_task = asyncio.create_task(self._sweep_expired_requests()) async def unregister(self) -> None: """ Unregister the agent and clean up all resources. """ traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None if traces_flow_manager: try: traces_flow_manager.end_a2a_communication() except Exception as e: print(f"Failed to end A2A communication trace: {e}") # Cancel sweep task if self._sweep_task: self._sweep_task.cancel() self._sweep_task = None # Unregister all message handlers for message_type in list(self._message_handlers.keys()): for handler in list(self._message_handlers.get(message_type, [])): self.off_message(message_type, handler) await self.registry.unregister_agent(self.agent.id) self._pending_requests.clear() def on_message(self, message_type: str, handler: Callable[[A2AMessage], None]) -> None: """ Register a message handler for specific message types. Args: message_type (str): Type of message to handle (e.g., "specialist_query", "model_response"). handler (Callable[[A2AMessage], None]): Async function to handle the message. Raises: ValueError: If the handler is not callable or not an async function. """ if not callable(handler): raise ValueError("Handler must be a callable function") if not asyncio.iscoroutinefunction(handler): raise ValueError("Handler must be an async function") if message_type not in self._message_handlers: self._message_handlers[message_type] = [] if handler not in self._message_handlers[message_type]: self._message_handlers[message_type].append(handler) if message_type == "model_response": self._setup_model_response_listener(handler) def _setup_model_response_listener(self, handler: Callable) -> None: """ Set up event listeners for model responses, deferring if pipeline not ready. """ if (hasattr(self.agent, 'session') and self.agent.session and hasattr(self.agent.session, 'pipeline') and self.agent.session.pipeline): self._attach_response_listeners(handler) else: self._deferred_model_handlers.append(handler) logger.info(f"Deferring model_response listener for agent {self.agent.id} — pipeline not ready yet") def _attach_deferred_listeners(self) -> None: """ Attach any deferred model_response listeners. Called by AgentSession after the pipeline is started and ready. """ if self._deferred_model_handlers: for handler in self._deferred_model_handlers: self._attach_response_listeners(handler) self._deferred_model_handlers.clear() logger.info(f"Attached deferred model_response listeners for agent {self.agent.id}") def _attach_response_listeners(self, handler: Callable) -> None: """ Wire up event listeners for capturing LLM responses and routing them back to the requesting agent via correlation IDs. """ def on_model_response(data): response = data.get('text', '') if not response or not self._pending_requests: return # FIFO: match to the oldest pending request correlation_id, pending = next(iter(self._pending_requests.items())) del self._pending_requests[correlation_id] message = A2AMessage( from_agent=self.agent.id, to_agent=pending.from_agent, type="model_response", content={"response": response}, metadata={"correlation_id": correlation_id} ) _safe_create_task(handler(message)) pipeline = self.agent.session.pipeline # Per-pipeline listener for cascading mode (naturally scoped, no collision) self._pipeline_event_handler = on_model_response pipeline.on("content_generated", on_model_response) # Global listener for realtime mode text responses # Collision is handled by the _pending_requests guard above: # if no pending requests, the event is ignored if getattr(pipeline.config, 'is_realtime', False): self._global_event_handler = on_model_response global_event_emitter.on("text_response", on_model_response) def off_message(self, message_type: str, handler: Callable[[A2AMessage], None]) -> None: """ Unregister a message handler. Args: message_type (str): Type of message to unregister the handler from. handler (Callable[[A2AMessage], None]): The handler function to remove. """ if message_type in self._message_handlers: if handler in self._message_handlers[message_type]: self._message_handlers[message_type].remove(handler) if not self._message_handlers[message_type]: del self._message_handlers[message_type] if message_type == "model_response": if self._global_event_handler: global_event_emitter.off( "text_response", self._global_event_handler) self._global_event_handler = None if self._pipeline_event_handler and hasattr(self.agent, 'session') and self.agent.session and hasattr(self.agent.session, 'pipeline'): self.agent.session.pipeline.off( "content_generated", self._pipeline_event_handler) self._pipeline_event_handler = None async def send_message(self, to_agent: str, message_type: str, content: Dict[str, Any], metadata: Optional[Dict[str, Any]] = None) -> None: """ Send a message to another agent. Args: to_agent (str): ID of the target agent to send the message to. message_type (str): Type/category of the message. content (Dict[str, Any]): The message content and data. metadata (Optional[Dict[str, Any]]): Additional message metadata. """ target_agent = self.registry.get_agent_instance(to_agent) if not target_agent: logger.error(f"A2A send_message failed: target agent '{to_agent}' not found in registry. " f"Registered agents: {list(self.registry.agents.keys())}") return # Generate correlation ID for request-response matching correlation_id = str(uuid.uuid4()) if metadata is None: metadata = {} metadata["correlation_id"] = correlation_id message = A2AMessage( from_agent=self.agent.id, to_agent=to_agent, type=message_type, content=content, metadata=metadata ) traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None sender_span = None if traces_flow_manager: try: attributes = { "from_agent": message.from_agent, "to_agent": message.to_agent, "message_type": message.type, "direction": "outgoing", "correlation_id": correlation_id, "content_preview": str(content)[:100] + "..." if len(str(content)) > 100 else str(content) } sender_span = traces_flow_manager.create_a2a_trace( "Message Sent", attributes ) except Exception as e: print(f"Failed to create sender A2A trace: {e}") # Store pending request on the TARGET agent ONLY if it has a model_response handler. # This means the target will produce an LLM response that needs routing back. # Don't store for messages like "specialist_response" where no LLM response is expected. if hasattr(target_agent, 'a2a') and "model_response" in target_agent.a2a._message_handlers: target_agent.a2a._pending_requests[correlation_id] = PendingRequest( correlation_id=correlation_id, from_agent=self.agent.id, to_agent=to_agent, created_at=time.time(), ) if message_type == "specialist_query": sender_is_realtime = False if hasattr(self.agent, 'session') and hasattr(self.agent.session, 'pipeline'): sender_is_realtime = getattr(self.agent.session.pipeline.config, 'is_realtime', False) receiver_is_realtime = False if hasattr(target_agent, 'session') and hasattr(target_agent.session, 'pipeline'): receiver_is_realtime = getattr(target_agent.session.pipeline.config, 'is_realtime', False) metrics_collector.set_a2a_handoff() receiver_span = None if traces_flow_manager: try: attributes = { "from_agent": message.from_agent, "to_agent": message.to_agent, "message_type": message.type, "direction": "incoming", "correlation_id": correlation_id, "content_preview": str(content)[:100] + "..." if len(str(content)) > 100 else str(content) } receiver_span = traces_flow_manager.create_a2a_trace( "Message Received", attributes ) except Exception as e: print(f"Failed to create receiver A2A trace: {e}") # Handle message: invoke registered handlers or fallback to direct pipeline routing if hasattr(target_agent, 'a2a') and message_type in target_agent.a2a._message_handlers: handlers = target_agent.a2a._message_handlers[message_type] for handler_func in handlers: try: await handler_func(message) except Exception as e: logger.error( f"Error in message handler for {message_type} on agent {to_agent}: {e}", exc_info=True) elif message_type == "specialist_query" and hasattr(target_agent, 'session') and hasattr(target_agent.session, 'pipeline'): await target_agent.session.pipeline.send_text_message(content.get("query", "")) if traces_flow_manager: if receiver_span: traces_flow_manager.end_a2a_trace( receiver_span, f"Message from {message.from_agent} processed" ) if sender_span: traces_flow_manager.end_a2a_trace( sender_span, f"Message to {message.to_agent} delivered" ) async def _sweep_expired_requests(self) -> None: """Background task to clean up timed-out pending requests.""" while True: try: await asyncio.sleep(5) now = time.time() expired = [ cid for cid, req in self._pending_requests.items() if now - req.created_at > req.timeout ] for cid in expired: req = self._pending_requests.pop(cid) logger.warning( f"A2A request {cid} from {req.from_agent} to {req.to_agent} " f"timed out after {req.timeout}s" ) except asyncio.CancelledError: break except Exception as e: logger.error(f"Error in A2A sweep task: {e}", exc_info=True)Handles agent-to-agent communication and message routing.
Uses correlation-based request-response matching to ensure responses are routed to the correct requesting agent, even with concurrent queries.
Initialize the A2A protocol for an agent.
Args
agent ('Agent'): The agent instance that will use this protocol.
Methods
def off_message(self,
message_type: str,
handler: Callable[[A2AMessage], None]) ‑> None-
Expand source code
def off_message(self, message_type: str, handler: Callable[[A2AMessage], None]) -> None: """ Unregister a message handler. Args: message_type (str): Type of message to unregister the handler from. handler (Callable[[A2AMessage], None]): The handler function to remove. """ if message_type in self._message_handlers: if handler in self._message_handlers[message_type]: self._message_handlers[message_type].remove(handler) if not self._message_handlers[message_type]: del self._message_handlers[message_type] if message_type == "model_response": if self._global_event_handler: global_event_emitter.off( "text_response", self._global_event_handler) self._global_event_handler = None if self._pipeline_event_handler and hasattr(self.agent, 'session') and self.agent.session and hasattr(self.agent.session, 'pipeline'): self.agent.session.pipeline.off( "content_generated", self._pipeline_event_handler) self._pipeline_event_handler = NoneUnregister a message handler.
Args
message_type:str- Type of message to unregister the handler from.
handler:Callable[[A2AMessage], None]- The handler function to remove.
def on_message(self,
message_type: str,
handler: Callable[[A2AMessage], None]) ‑> None-
Expand source code
def on_message(self, message_type: str, handler: Callable[[A2AMessage], None]) -> None: """ Register a message handler for specific message types. Args: message_type (str): Type of message to handle (e.g., "specialist_query", "model_response"). handler (Callable[[A2AMessage], None]): Async function to handle the message. Raises: ValueError: If the handler is not callable or not an async function. """ if not callable(handler): raise ValueError("Handler must be a callable function") if not asyncio.iscoroutinefunction(handler): raise ValueError("Handler must be an async function") if message_type not in self._message_handlers: self._message_handlers[message_type] = [] if handler not in self._message_handlers[message_type]: self._message_handlers[message_type].append(handler) if message_type == "model_response": self._setup_model_response_listener(handler)Register a message handler for specific message types.
Args
message_type:str- Type of message to handle (e.g., "specialist_query", "model_response").
handler:Callable[[A2AMessage], None]- Async function to handle the message.
Raises
ValueError- If the handler is not callable or not an async function.
async def register(self,
card: AgentCard) ‑> None-
Expand source code
async def register(self, card: AgentCard) -> None: """ Register the agent with the global registry and start background tasks. Args: card (AgentCard): The agent's capability card. """ self.registry.register_agent(card, self.agent) # Start timeout sweep for pending requests if self._sweep_task is None: self._sweep_task = asyncio.create_task(self._sweep_expired_requests())Register the agent with the global registry and start background tasks.
Args
card:AgentCard- The agent's capability card.
async def send_message(self,
to_agent: str,
message_type: str,
content: Dict[str, Any],
metadata: Dict[str, Any] | None = None) ‑> None-
Expand source code
async def send_message(self, to_agent: str, message_type: str, content: Dict[str, Any], metadata: Optional[Dict[str, Any]] = None) -> None: """ Send a message to another agent. Args: to_agent (str): ID of the target agent to send the message to. message_type (str): Type/category of the message. content (Dict[str, Any]): The message content and data. metadata (Optional[Dict[str, Any]]): Additional message metadata. """ target_agent = self.registry.get_agent_instance(to_agent) if not target_agent: logger.error(f"A2A send_message failed: target agent '{to_agent}' not found in registry. " f"Registered agents: {list(self.registry.agents.keys())}") return # Generate correlation ID for request-response matching correlation_id = str(uuid.uuid4()) if metadata is None: metadata = {} metadata["correlation_id"] = correlation_id message = A2AMessage( from_agent=self.agent.id, to_agent=to_agent, type=message_type, content=content, metadata=metadata ) traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None sender_span = None if traces_flow_manager: try: attributes = { "from_agent": message.from_agent, "to_agent": message.to_agent, "message_type": message.type, "direction": "outgoing", "correlation_id": correlation_id, "content_preview": str(content)[:100] + "..." if len(str(content)) > 100 else str(content) } sender_span = traces_flow_manager.create_a2a_trace( "Message Sent", attributes ) except Exception as e: print(f"Failed to create sender A2A trace: {e}") # Store pending request on the TARGET agent ONLY if it has a model_response handler. # This means the target will produce an LLM response that needs routing back. # Don't store for messages like "specialist_response" where no LLM response is expected. if hasattr(target_agent, 'a2a') and "model_response" in target_agent.a2a._message_handlers: target_agent.a2a._pending_requests[correlation_id] = PendingRequest( correlation_id=correlation_id, from_agent=self.agent.id, to_agent=to_agent, created_at=time.time(), ) if message_type == "specialist_query": sender_is_realtime = False if hasattr(self.agent, 'session') and hasattr(self.agent.session, 'pipeline'): sender_is_realtime = getattr(self.agent.session.pipeline.config, 'is_realtime', False) receiver_is_realtime = False if hasattr(target_agent, 'session') and hasattr(target_agent.session, 'pipeline'): receiver_is_realtime = getattr(target_agent.session.pipeline.config, 'is_realtime', False) metrics_collector.set_a2a_handoff() receiver_span = None if traces_flow_manager: try: attributes = { "from_agent": message.from_agent, "to_agent": message.to_agent, "message_type": message.type, "direction": "incoming", "correlation_id": correlation_id, "content_preview": str(content)[:100] + "..." if len(str(content)) > 100 else str(content) } receiver_span = traces_flow_manager.create_a2a_trace( "Message Received", attributes ) except Exception as e: print(f"Failed to create receiver A2A trace: {e}") # Handle message: invoke registered handlers or fallback to direct pipeline routing if hasattr(target_agent, 'a2a') and message_type in target_agent.a2a._message_handlers: handlers = target_agent.a2a._message_handlers[message_type] for handler_func in handlers: try: await handler_func(message) except Exception as e: logger.error( f"Error in message handler for {message_type} on agent {to_agent}: {e}", exc_info=True) elif message_type == "specialist_query" and hasattr(target_agent, 'session') and hasattr(target_agent.session, 'pipeline'): await target_agent.session.pipeline.send_text_message(content.get("query", "")) if traces_flow_manager: if receiver_span: traces_flow_manager.end_a2a_trace( receiver_span, f"Message from {message.from_agent} processed" ) if sender_span: traces_flow_manager.end_a2a_trace( sender_span, f"Message to {message.to_agent} delivered" )Send a message to another agent.
Args
to_agent:str- ID of the target agent to send the message to.
message_type:str- Type/category of the message.
content:Dict[str, Any]- The message content and data.
metadata:Optional[Dict[str, Any]]- Additional message metadata.
async def unregister(self) ‑> None-
Expand source code
async def unregister(self) -> None: """ Unregister the agent and clean up all resources. """ traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None if traces_flow_manager: try: traces_flow_manager.end_a2a_communication() except Exception as e: print(f"Failed to end A2A communication trace: {e}") # Cancel sweep task if self._sweep_task: self._sweep_task.cancel() self._sweep_task = None # Unregister all message handlers for message_type in list(self._message_handlers.keys()): for handler in list(self._message_handlers.get(message_type, [])): self.off_message(message_type, handler) await self.registry.unregister_agent(self.agent.id) self._pending_requests.clear()Unregister the agent and clean up all resources.
class AgentRegistry (agents: Dict[str, AgentCard] = <factory>,
agent_instances: Dict[str, ForwardRef('Agent')] = <factory>)-
Expand source code
@dataclass class AgentRegistry: """ Singleton registry for managing agent registration and discovery. """ _instance = None agents: Dict[str, AgentCard] = field(default_factory=dict) agent_instances: Dict[str, 'Agent'] = field(default_factory=dict) def __new__(cls): if cls._instance is None: cls._instance = super(AgentRegistry, cls).__new__(cls) if not hasattr(cls._instance, 'agents'): cls._instance.agents = {} if not hasattr(cls._instance, 'agent_instances'): cls._instance.agent_instances = {} return cls._instance def register_agent(self, card: AgentCard, agent_instance: 'Agent' = None): """ Register an agent with its capabilities in the registry. Args: card (AgentCard): The agent's capability card containing metadata. agent_instance ('Agent', optional): The actual agent instance for direct communication. """ self.agents[card.id] = card if agent_instance: self.agent_instances[card.id] = agent_instance traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None if traces_flow_manager: total_agents = len(self.agents) attributes = { "agent_id": card.id, "agent_name": card.name, "agent_domain": card.domain, "agent_capabilities": ", ".join(card.capabilities), "agent_description": card.description, "registration_order": total_agents, "total_registered_agents": total_agents, "agent_role": "primary" if total_agents == 1 else "secondary", } if card.metadata: attributes.update(card.metadata) try: reg_span = traces_flow_manager.create_a2a_trace( "Agent Registration", attributes ) if reg_span: traces_flow_manager.end_a2a_trace( reg_span, f"Agent {card.name} registered successfully" ) except Exception as e: print(f"Failed to create A2A registration trace: {e}") async def unregister_agent(self, agent_id: str): """ Remove an agent from the registry. Args: agent_id (str): The ID of the agent to unregister. """ self.agents.pop(agent_id, None) self.agent_instances.pop(agent_id, None) def find_agents_by_domain(self, domain: str) -> List[str]: """ Find all agents that handle a specific domain. Args: domain (str): The domain to search for (e.g., "customer_service", "technical_support"). Returns: List[str]: List of agent IDs that handle the specified domain. """ return [ agent_id for agent_id, card in self.agents.items() if card.domain == domain ] def get_all_agents(self) -> Dict[str, AgentCard]: """ Get all registered agents in the system. Returns: Dict[str, AgentCard]: Dictionary mapping agent IDs to their capability cards. """ return self.agents def get_agent_instance(self, agent_id: str) -> Optional['Agent']: """ Get an agent instance by ID for direct communication. Args: agent_id (str): The ID of the agent to retrieve. Returns: Optional['Agent']: The agent instance if found, None otherwise. """ return self.agent_instances.get(agent_id) async def find_agents_by_capability(self, capability: str) -> List[str]: """ Find all agents that have a specific capability. Args: capability (str): The capability to search for (e.g., "text_generation", "image_analysis"). Returns: List[str]: List of agent IDs that have the specified capability. """ return [ agent_id for agent_id, card in self.agents.items() if capability in card.capabilities ]Singleton registry for managing agent registration and discovery.
Instance variables
var agent_instances : Dict[str, videosdk.agent.Agent]var agents : Dict[str, AgentCard]
Methods
async def find_agents_by_capability(self, capability: str) ‑> List[str]-
Expand source code
async def find_agents_by_capability(self, capability: str) -> List[str]: """ Find all agents that have a specific capability. Args: capability (str): The capability to search for (e.g., "text_generation", "image_analysis"). Returns: List[str]: List of agent IDs that have the specified capability. """ return [ agent_id for agent_id, card in self.agents.items() if capability in card.capabilities ]Find all agents that have a specific capability.
Args
capability:str- The capability to search for (e.g., "text_generation", "image_analysis").
Returns
List[str]- List of agent IDs that have the specified capability.
def find_agents_by_domain(self, domain: str) ‑> List[str]-
Expand source code
def find_agents_by_domain(self, domain: str) -> List[str]: """ Find all agents that handle a specific domain. Args: domain (str): The domain to search for (e.g., "customer_service", "technical_support"). Returns: List[str]: List of agent IDs that handle the specified domain. """ return [ agent_id for agent_id, card in self.agents.items() if card.domain == domain ]Find all agents that handle a specific domain.
Args
domain:str- The domain to search for (e.g., "customer_service", "technical_support").
Returns
List[str]- List of agent IDs that handle the specified domain.
def get_agent_instance(self, agent_id: str) ‑> videosdk.agent.Agent | None-
Expand source code
def get_agent_instance(self, agent_id: str) -> Optional['Agent']: """ Get an agent instance by ID for direct communication. Args: agent_id (str): The ID of the agent to retrieve. Returns: Optional['Agent']: The agent instance if found, None otherwise. """ return self.agent_instances.get(agent_id)Get an agent instance by ID for direct communication.
Args
agent_id:str- The ID of the agent to retrieve.
Returns
Optional['Agent']: The agent instance if found, None otherwise.
def get_all_agents(self) ‑> Dict[str, AgentCard]-
Expand source code
def get_all_agents(self) -> Dict[str, AgentCard]: """ Get all registered agents in the system. Returns: Dict[str, AgentCard]: Dictionary mapping agent IDs to their capability cards. """ return self.agentsGet all registered agents in the system.
Returns
Dict[str, AgentCard]- Dictionary mapping agent IDs to their capability cards.
def register_agent(self,
card: AgentCard,
agent_instance: Agent = None)-
Expand source code
def register_agent(self, card: AgentCard, agent_instance: 'Agent' = None): """ Register an agent with its capabilities in the registry. Args: card (AgentCard): The agent's capability card containing metadata. agent_instance ('Agent', optional): The actual agent instance for direct communication. """ self.agents[card.id] = card if agent_instance: self.agent_instances[card.id] = agent_instance traces_flow_manager = metrics_collector.traces_flow_manager if metrics_collector else None if traces_flow_manager: total_agents = len(self.agents) attributes = { "agent_id": card.id, "agent_name": card.name, "agent_domain": card.domain, "agent_capabilities": ", ".join(card.capabilities), "agent_description": card.description, "registration_order": total_agents, "total_registered_agents": total_agents, "agent_role": "primary" if total_agents == 1 else "secondary", } if card.metadata: attributes.update(card.metadata) try: reg_span = traces_flow_manager.create_a2a_trace( "Agent Registration", attributes ) if reg_span: traces_flow_manager.end_a2a_trace( reg_span, f"Agent {card.name} registered successfully" ) except Exception as e: print(f"Failed to create A2A registration trace: {e}")Register an agent with its capabilities in the registry.
Args
card:AgentCard- The agent's capability card containing metadata.
agent_instance ('Agent', optional): The actual agent instance for direct communication.
async def unregister_agent(self, agent_id: str)-
Expand source code
async def unregister_agent(self, agent_id: str): """ Remove an agent from the registry. Args: agent_id (str): The ID of the agent to unregister. """ self.agents.pop(agent_id, None) self.agent_instances.pop(agent_id, None)Remove an agent from the registry.
Args
agent_id:str- The ID of the agent to unregister.
class PendingRequest (correlation_id: str,
from_agent: str,
to_agent: str,
created_at: float,
timeout: float = 30.0)-
Expand source code
@dataclass class PendingRequest: """ Tracks an outgoing A2A request awaiting a response. Used for correlation-based response routing. """ correlation_id: str from_agent: str to_agent: str created_at: float timeout: float = 30.0Tracks an outgoing A2A request awaiting a response. Used for correlation-based response routing.
Instance variables
var correlation_id : strvar created_at : floatvar from_agent : strvar timeout : floatvar to_agent : str