Source Code:
cpp/ in the GAIA repository.See also: Overview for architecture, execution flow, and getting started.
Error Handling & Recovery
The framework handles failures at every layer — LLM connection, JSON parsing, and tool execution — so your agent doesn’t crash on transient errors.LLM Connection Failures
If the LLM server is unreachable or returns an error, the agent retries once automatically, then exits gracefully:result field — there is no exception to catch. HTTP timeouts: 30s connection, 120s read.
Malformed JSON Recovery
Local LLMs often return imperfect JSON. The parser applies six extraction strategies in sequence:- Direct JSON parse
- Extract from markdown code blocks (
```json ... ```) - Bracket-matching — find first complete
{...}in mixed text - Fix common syntax errors (trailing commas, single quotes, missing brackets)
- Regex extraction of individual fields (
"thought","tool","answer") - Treat entire response as a plain-text conversational answer
Tool Execution Errors
When a tool callback throws an exception or returns{"status": "error", ...}, the agent enters error recovery mode:
- The error is captured (exceptions are caught, not propagated)
- The error context is sent back to the LLM: “Tool execution failed. Please try an alternative approach.”
- The LLM reasons about the error and may try a different tool or strategy
- If the LLM cannot recover within
maxSteps, the agent returns the last error as the result
MCP Auto-Reconnect
If an MCP server disconnects mid-session (process crash, timeout), the agent reconnects automatically:Loop Detection
The agent detects infinite tool call loops — when the LLM calls the same tool with the same arguments 4+ times in a row. When detected, the agent stops and returns:Thread Safety
Blocking Semantics
processQuery() is fully blocking. It runs the complete agent loop (LLM calls, tool executions, history management) on the calling thread and returns only when a final answer is produced or the step limit is reached.
This means:
- Do not call
processQuery()from a UI thread — it will freeze the UI for the duration of the agent run - Use a background thread or async wrapper for GUI integration
Concurrent Agent Instances
DifferentAgent instances are fully independent and can run in parallel on separate threads. Each agent owns its own conversation history, tool registry, MCP connections, and output handler.
Single-Agent Rules
Do NOT callprocessQuery() concurrently on the same agent instance. There are no internal locks — concurrent calls will corrupt conversation history and produce undefined behavior.
connectMcpServer() or disconnectMcpServer() while processQuery() is running.
Security Model
Tool Registration Is Explicit
Only tools registered viaregisterTool() or discovered from a connected MCP server are available. There is no reflection, auto-discovery, or dynamic code execution. The LLM can only call tools that your code has explicitly registered.
Tool Callback Responsibility
The framework does not validate tool arguments before passing them to your callback. Each tool is responsible for:- Validating its input parameters (types, ranges, formats)
- Sanitizing paths and shell arguments
- Rejecting unexpected or dangerous inputs
MCP Server Trust
MCP servers are trusted implicitly — all tools they expose are registered without review. Only connect to MCP servers you control. In production, audit the tool list returned by each server before deployment.Prompt Injection
The LLM decides which tool to call based on user input and conversation history. A malicious user could craft input that causes the LLM to misuse a tool. Mitigations:- Validate in the tool callback — don’t trust the LLM’s argument choices blindly
- Use restrictive tool descriptions — describe exactly what the tool does and what arguments it accepts
- Limit tool scope — register only the tools needed for your use case
- Consider confirmation flows — for destructive operations, require user confirmation before executing
Conversation History
Conversation history persists betweenprocessQuery() calls on the same agent. Previous queries and tool results are visible to subsequent LLM calls. For multi-user scenarios, create a new Agent instance per user session to prevent data leakage.
Production Deployment
Binary Sizes
Measured with MSVC 2022 Release build (x64):| Artifact | Size | Notes |
|---|---|---|
gaia_core.lib (static) | ~18 MB | Includes statically linked nlohmann_json and cpp-httplib |
| Example executable | ~400-440 KB | Linked against static library |
| Shared library (DLL) | Smaller | Build with -DBUILD_SHARED_LIBS=ON — ships only framework code |
DLL / Shared Library
The framework supports both static and shared library builds. DLL export macros (GAIA_API) are already applied to all public classes:
GAIA_API macro automatically switches from __declspec(dllexport) to __declspec(dllimport).
Install Targets
The CMake install target produces a complete SDK package:find_package(gaia_core) to link against the installed SDK.
Runtime Configuration
The LLM endpoint can be configured at runtime via environment variable — no recompilation needed:AgentConfig fields are set at construction time. For dynamic configuration, read from a config file or registry in your makeConfig() function.
HTTPS Support
HTTPS is supported via OpenSSL (enabled by default withGAIA_ENABLE_SSL=ON). For local-only deployments where the LLM runs on localhost, you can disable SSL to remove the OpenSSL dependency:
API Quick Reference
Agent
ToolRegistry
OutputHandler
Subclass to integrate agent output with your own UI. All methods are virtual:MCPClient
Next Steps
Overview
Architecture, execution flow, and getting started
Custom Agent
Custom prompts, typed tools, MCP servers, and output capture
Integration Guide
Consume gaia_core in your own CMake project
Quickstart
Prerequisites, build steps, and running your first demo