How to Handle Tool Calls with aisuite: A Complete Guide to Tool Registration and Execution
aisuite provides a unified framework to register Python functions as LLM tools, export OpenAI-compatible specifications, and execute tool calls with automatic validation, policy enforcement, and tracing via the Tools class in aisuite/utils/tools.py.
The aisuite library by Andrew Ng offers a robust abstraction for integrating external utilities with large language models. To handle tool calls effectively, you work with the Tools class which manages the complete lifecycle from registration to execution. The framework automatically handles argument validation, schema conversion, and safety policies while providing detailed tracing for debugging.
Stage 1: Registering Tools with Tools._add_tool
The foundation of the tool system lies in aisuite/utils/tools.py, where the Tools class provides the _add_tool method (lines 83-100) to register Python callables. When you register a function, the framework inspects __mcp_input_schema__ for MCP compatibility or infers types via __infer_from_signature, then builds a tool spec compatible with OpenAI's function-calling format.
During registration, the system performs three critical operations:
- Schema Detection – If the function has a
__mcp_input_schema__attribute, the framework preserves the original JSON-Schema via_convert_mcp_schema_to_tool_spec. - Pydantic Model Creation – The system generates a Pydantic model for argument validation using either
_create_pydantic_model_from_mcp_schemaor signature inference. - Metadata Storage – Any
__aisuite_tool_metadata__attached to the function is preserved for later tracing.
from aisuite.utils.tools import Tools
from aisuite.toolkits.shell import run_shell
tools = Tools()
tools._add_tool(run_shell) # Registers the shell tool automatically
MCP Schema Support
For tools implementing the Model Context Protocol (MCP), aisuite preserves complex JSON-Schemas verbatim to avoid losing information on nested objects or arrays. The framework still generates a temporary Pydantic model via _create_pydantic_model_from_mcp_schema (implemented in aisuite/mcp/schema_converter.py) to reuse the existing validation pipeline while maintaining the original schema specification.
Stage 2: Exporting OpenAI-Compatible Tool Specifications
Once registered, you must export the tool specifications to send to the LLM. The tools() method (line 111 in aisuite/utils/tools.py) returns a list of function definitions formatted for OpenAI's API via the __convert_to_openai_format helper (lines 315-320).
Each specification contains:
- name – The Python function name
- description – Extracted from the docstring
- parameters – A JSON-Schema derived from the Pydantic model, including types, required fields, and defaults
openai_spec = tools.tools() # Default format is "openai"
# Returns: [{"type": "function", "function": {"name": "run_shell", ...}}]
Stage 3: Executing Tool Calls with execute_tool
When the LLM returns a tool call, you invoke execute_tool (line 332 in aisuite/utils/tools.py) to handle the complete execution flow. This method validates arguments, enforces policies, and manages the response formatting.
The execution flow follows these steps:
- Argument Parsing – Converts JSON strings to dictionaries (lines 71-73)
- Validation – Instantiates the Pydantic model with
param_model(**arguments), raisingValidationErrorfor mismatched payloads (lines 78-84) - Policy Enforcement – If a
ToolPolicyis provided,_evaluate_tool_policydetermines whether to allow the call (lines 91-124) - Function Invocation – Calls the underlying Python function with validated arguments
- Result Handling – Returns both the raw results and formatted tool messages for the LLM (lines 174-182)
# Simulated LLM response
mock_response = {
"tool_calls": [
{
"id": "call_1",
"function": {
"name": "run_shell",
"arguments": '{"command":"echo hello"}'
}
}
]
}
results, messages = tools.execute_tool(mock_response["tool_calls"])
# results: [{'stdout': 'hello\n', 'stderr': '', 'code': 0}]
# messages: [{'role': 'tool', 'name': 'run_shell', ...}]
Implementing Safety Policies
The framework supports optional ToolPolicy objects that intercept calls before execution. Define a policy function that receives a ToolPolicyContext and returns a ToolPolicyDecision to allow or deny operations. The framework evaluates this policy in _evaluate_tool_policy (lines 91-124) before invoking the underlying function.
from aisuite.agents import ToolPolicyContext, ToolPolicyDecision
def block_dangerous_commands(context: ToolPolicyContext) -> ToolPolicyDecision:
command = context.arguments.get("command", "")
if "rm " in command:
return ToolPolicyDecision(allowed=False, reason="Dangerous command blocked")
return ToolPolicyDecision(allowed=True)
results, msgs = tools.execute_tool(
mock_response["tool_calls"],
tool_policy=block_dangerous_commands
)
Stage 4: Tracing and Artifact Management
Every tool execution emits trace events through _emit_tool_trace_event (lines 53-78), marking when tools start, complete, or fail. If an active run context contains an artifact_store (managed via aisuite/agents/context.py), both input arguments and return values pass through _artifactized_trace_value (lines 80-88 and 133-140), creating persistent records for debugging and reproducibility.
This integration enables automatic tracking of tool interactions without manual logging, supporting complex workflows in aisuite/toolkits/git.py and aisuite/toolkits/files.py alongside custom utilities.
Summary
- Register tools using
Tools._add_toolinaisuite/utils/tools.pyto automatically generate validation schemas and preserve__aisuite_tool_metadata__. - Export specifications via
Tools.tools()to generate OpenAI-compatible JSON schemas derived from Pydantic models for LLM prompts. - Execute safely with
Tools.execute_tool, which handles JSON parsing, Pydantic validation, optionalToolPolicyenforcement via_evaluate_tool_policy, and result formatting. - Trace automatically through built-in event emission and artifact storage when using the active run context from
aisuite/agents/context.py.
Frequently Asked Questions
How does aisuite validate tool arguments?
The framework uses Pydantic models generated during tool registration. When execute_tool processes a call, it validates arguments against param_model(**arguments) (lines 78-84 in aisuite/utils/tools.py), raising a ValidationError if the payload doesn't match the expected schema derived from the function signature or MCP schema.
Can I use existing MCP tools with aisuite?
Yes. The Tools class detects __mcp_input_schema__ attributes on functions and preserves the full JSON-Schema via _convert_mcp_schema_to_tool_spec. It creates temporary Pydantic models using _create_pydantic_model_from_mcp_schema (defined in aisuite/mcp/schema_converter.py) to maintain compatibility with the validation pipeline while retaining complex nested structures.
What safety mechanisms are available for tool execution?
The ToolPolicy system allows you to intercept calls before execution. Define a policy function that accepts ToolPolicyContext and returns ToolPolicyDecision to allow or deny specific operations. The framework evaluates this policy in _evaluate_tool_policy (lines 91-124) before invoking the underlying function, enabling you to block dangerous commands or restrict access to sensitive tools like those in aisuite/toolkits/shell.py.
Where does aisuite store tool execution history?
When an artifact_store is present in the active run context, the framework automatically artifactizes both inputs and outputs through _artifactized_trace_value. These artifacts attach to trace events emitted by _emit_tool_trace_event (lines 53-78), providing persistent records in aisuite/agents/context.py for debugging, audit trails, and visualization in the UI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →