Agent Services API
This section details the core components responsible for the AI Agent's lifecycle, orchestration, and execution.
Location: backend/app/services/agent/
Agent Orchestrator
File: agent_orchestrator.py
The Agent Orchestrator is the brain of the application. It uses LangGraph to define a cyclic state graph that manages the conversation flow between the User, the LLM, and the Tools.
create_graph_agent
def create_graph_agent(
llm: BaseChatModel,
tools: List[StructuredTool],
prompt: ChatPromptTemplate,
model_provider: str = "gemini"
) -> StateGraphConstructs the uncompiled state machine for the agent.
Logic Flow:
- Agent Node: Calls the LLM with the current conversation state and bound tools.
- Route Tools: Uses
route_toolsto check the LLM's output.- If no tools are called -> Ends turn.
- If tools are called -> Checks permissions.
- If approval required -> Routes to
human_review. - If auto-approved -> Routes to
tools.
- If approval required -> Routes to
- Human Review Node: Pauses execution (via LangGraph interrupt) if user permission is needed. Waiting for distinct "Approved" or "Denied" signals.
- Tools Node: Executes approved tools and feeds output back to the Agent Node.
GraphAgentExecutor
A compatibility wrapper that makes the LangGraph executable look like a standard LangChain AgentExecutor. This allows the rest of the FastAPI application (streaming endpoints, etc.) to interact with the new graph system without refactoring.
Agent Factory
File: agent_factory.py
Responsible for assembling a unique agent instance for every request, tailored to the specific user's context (connected tools, permissions, etc.).
create_final_agent_pipeline
async def create_final_agent_pipeline(
user_mcp_servers: Dict[str, Any],
user_id: str = None,
model_provider: str = "gemini",
model_name: str = "gemini-2.5-flash"
) -> GraphAgentExecutorKey Responsibilities:
- LLM Selection: Calls
llm_factoryto get the correct model (e.g., Gemini, OpenAI). - Tool Construction: Iterates through
user_mcp_serversto build executable tools usingtools.py. - Registry Init: Registers these tools into a local
ToolRegistryso the agent can "search" for them if needed. - Graph Compilation: Compiles the
StateGraphwith aMemorySavercheckpointer for conversation state persistence.
Dynamic Tools
File: tools.py
This module handles the complex logic of converting remote MCP tool definitions (JSON schemas) into executable Python functions (LangChain StructuredTool objects).
build_tools_from_servers
async def build_tools_from_servers(
user_mcp_servers: Dict,
user_id: str = None,
blocking: bool = True
) -> List[StructuredTool]Process:
- Connect: Initializes an
MCPConnectorfor each server. - Discover: Fetches the list of tools (using cache if available).
- Permission Filter: Removes any tools internally disabled by
ToolPermissionrecords. - Wrap: Converts each tool into a
StructuredToolusingcreate_tool_func.
create_tool_func
Wraps the raw MCP connector.run_tool call with Safety & Robustness layers:
- Retry Logic: Uses
tenacityexponential backoff for transient network errors. - Permission Check: Before execution, checks
PendingApprovaltables. If the tool is "sensitive" and not approved, it blocks execution until the user approves via the UI.
LLM Factory
File: llm_factory.py
get_llm
@lru_cache(maxsize=16)
def get_llm(
model_provider: str,
model_name: str
) -> BaseChatModelWhy it matters: LLM Clients (like ChatGoogleGenerativeAI or ChatOpenAI) can be expensive to instantiate repeatedly. This factory uses Python's @lru_cache to keep a singleton instance for each model configuration, significantly reducing latency per request.