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_schema or 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:

  1. Argument Parsing – Converts JSON strings to dictionaries (lines 71-73)
  2. Validation – Instantiates the Pydantic model with param_model(**arguments), raising ValidationError for mismatched payloads (lines 78-84)
  3. Policy Enforcement – If a ToolPolicy is provided, _evaluate_tool_policy determines whether to allow the call (lines 91-124)
  4. Function Invocation – Calls the underlying Python function with validated arguments
  5. 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_tool in aisuite/utils/tools.py to 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, optional ToolPolicy enforcement 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →