GAIA uses a sophisticated multi-agent architecture where specialized AI agents collaborate to handle different aspects of your tasks. Think of it as having a team of experts, each with deep knowledge of specific tools and domains.
# From: apps/api/app/agents/core/subagents/handoff_tools.pyasync def handoff( subagent_id: str, # Which subagent to use task: str, # What they should do config: RunnableConfig) -> str: """ Delegate a task to a specialized subagent. Example: handoff( subagent_id="gmail", task="Search for emails from [email protected] in last 7 days" ) The subagent: 1. Receives full context 2. Uses its specialized tools 3. Returns results to executor """
# Executor combines resultsresponse = """I found the email from your client and created a calendar event:📧 Email: "Proposal Discussion" from [email protected]📅 Event: Tuesday, Dec 17 at 2:00 PM (30 min)✅ Calendar invite sent to [email protected]"""
# From: apps/api/app/agents/core/graph_manager.pyclass GraphManager: """Singleton manager for agent graphs.""" _graphs: Dict[str, CompiledGraph] = {} @classmethod async def get_graph(cls, agent_name: str) -> CompiledGraph: """ Get or create agent graph. Graphs are compiled once and reused for efficiency. Each user execution uses same graph with different config. """
# Non-delegated tools (todos, reminders, search)# Executor agent has direct accesstools = [ create_todo, list_todos, create_reminder, web_search_tool, generate_document]# Agent can call these directly without handoff
# Delegated tools (gmail, calendar, notion)# Must go through specialized subagent# ❌ Wrong - executor can't access directlyawait GMAIL_SEND_MESSAGE(to="[email protected]", ...)# ✅ Correct - handoff to subagentawait handoff( subagent_id="gmail", task="Send email to [email protected]")
# From: apps/api/app/agents/tools/core/retrieval.py# Agents can discover tools at runtimetools = await retrieve_tools( query="send slack message", user_id=user_id, limit=5)# Returns:# - SLACK_SEND_MESSAGE# - SLACK_SEND_DIRECT_MESSAGE# - SLACK_UPDATE_MESSAGE# (only if user has Slack connected)
# Tool registry is cached@cacheasync def get_tool_registry() -> ToolRegistry: """Singleton registry - built once, used many times."""# User capabilities are cached@cache(ttl=300) # 5 minutesasync def get_user_integration_capabilities(user_id: str): """Avoid repeated DB queries for same user."""
// From: apps/api/app/agents/evals/datasets/gmail.json[ { "scenario": "Send email to team", "user_input": "Email the team about tomorrow's meeting", "expected_tools": ["GMAIL_SEND_MESSAGE"], "expected_behavior": "Sends to team distribution list", "constraints": ["Must include meeting time", "Professional tone"] }, // ... 50+ test scenarios per integration]
// From: apps/web/src/features/chat/// Every conversation has full execution trace:interface ConversationTrace { messages: Message[]; tool_calls: ToolCall[]; subagent_handoffs: Handoff[]; state_checkpoints: Checkpoint[]; memory_updates: MemoryUpdate[];}// Inspect exactly what happened at each step
# Agents have robust error handlingtry: result = await handoff("gmail", task)except ToolExecutionError as e: # Log error, inform user, suggest alternatives logger.error(f"Tool execution failed: {e}") return "I had trouble with Gmail. Would you like me to try another approach?"except RateLimitError as e: # Automatic retry with backoff await asyncio.sleep(e.retry_after) result = await handoff("gmail", task)