How to Get Tool Invocation Requests from an aisuite Response

aisuite exposes tool invocation requests through the tool_calls attribute on response.choices[0].message, which contains a list of ToolCall objects with name and arguments fields that you can extract manually or let the client resolve automatically via the max_turns parameter.

When building agentic workflows with andrewyng/aisuite, you need to intercept tool invocation requests that the model generates before they execute. The library surfaces these requests from the underlying provider's response in a unified format, letting you handle them manually or delegate execution to the built-in multi-turn handler.

Where Tool Calls Live in the Response Object

The aisuite client extracts raw tool-call information exactly as the underlying provider supplies it. When a model emits a function call, the provider places a list of ToolCall objects on the message located at response.choices[0].message.

In aisuite/client.py (lines 309–317), the completion flow handles the response by exposing the tool_calls attribute on the assistant message. This attribute is not added by aisuite itself but is surfaced directly from the provider's response structure, ensuring compatibility with OpenAI, Anthropic, Google, and other supported backends.

Extracting Tool Invocation Requests Manually

To inspect tool calls without automatic execution, omit the max_turns parameter when calling client.chat.completions.create(). After the call returns, access the tool invocation requests using getattr() with a safe fallback:

from aisuite.client import Client
from aisuite.utils.tools import Tools

client = Client(provider_configs={"openai": {"api_key": "YOUR_KEY"}})

def get_weather(location: str) -> str:
    return f"The weather in {location} is sunny."

tools = Tools([get_weather])

response = client.chat.completions.create(
    model="openai:gpt-4o-mini",
    messages=[{"role": "user", "content": "What's the weather in Paris?"}],
    tools=tools,
    max_turns=None,  # Disable automatic execution

)

tool_calls = getattr(response.choices[0].message, "tool_calls", None)

if tool_calls:
    for call in tool_calls:
        print(f"Tool name: {call.name}")
        print(f"Arguments: {call.arguments}")  # JSON string

        print(f"Call ID: {getattr(call, 'id', None)}")

Each ToolCall object contains:

  • name: The function name to invoke
  • arguments: A JSON string containing the parameters
  • id: An optional identifier for tracking the call

Automatic Multi-Turn Handling

If you enable max_turns (for example, max_turns=5), the client enters a loop that automatically executes tools and returns the final response after resolution. In this mode, response.choices[0].message.tool_calls will be empty because all invocations have been processed.

However, you can still inspect the intermediate tool calls. According to the implementation in aisuite/client.py (lines 319–327), the client stores intermediate responses in response.intermediate_responses and the final message list in response.choices[0].intermediate_messages:

response = client.chat.completions.create(
    model="openai:gpt-4o-mini",
    messages=[{"role": "user", "content": "What's the weather in Paris?"}],
    tools=tools,
    max_turns=3,  # Allow up to 3 tool turns

)

# Final answer after automatic execution

print(response.choices[0].message.content)

# Inspect the tool calls that were automatically handled

for intermediate in response.intermediate_responses:
    calls = getattr(intermediate.choices[0].message, "tool_calls", [])
    for call in calls:
        print(f"Executed: {call.name} with {call.arguments}")

Complete Working Example

This example demonstrates both manual extraction and the Tools helper registration:

from aisuite.client import Client
from aisuite.utils.tools import Tools

# Initialize client

client = Client(provider_configs={"openai": {"api_key": "YOUR_KEY"}})

# Define tool schema

def calculate_sum(a: int, b: int) -> int:
    """Add two numbers together."""
    return a + b

tools = Tools([calculate_sum])

# Manual mode - inspect tool invocation requests

response = client.chat.completions.create(
    model="openai:gpt-4o-mini",
    messages=[{"role": "user", "content": "Calculate 5 plus 3"}],
    tools=tools,
)

message = response.choices[0].message
tool_calls = getattr(message, "tool_calls", None)

if tool_calls:
    for tc in tool_calls:
        print(f"Requested: {tc.name}")
        print(f"Params: {tc.arguments}")

The Tools helper (located in aisuite/utils/tools.py) automatically converts Python callables into OpenAI-compatible function schemas, which the client injects into the request when you pass the tools parameter.

Summary

  • aisuite surfaces tool calls through response.choices[0].message.tool_calls as a list of ToolCall objects.
  • Manual extraction requires using getattr(message, "tool_calls", None) to safely access the attribute, which contains name, arguments, and optional id fields.
  • Automatic execution via max_turns resolves tool calls internally, leaving the final response with empty tool_calls but preserving history in intermediate_responses.
  • Provider agnostic: The extraction pattern works across all supported providers (OpenAI, Anthropic, Google, Ollama) because aisuite normalizes the response structure in aisuite/client.py.

Frequently Asked Questions

How do I check if a response contains tool calls before accessing them?

Use getattr(response.choices[0].message, "tool_calls", None) rather than direct attribute access. This pattern safely returns None if the model did not generate any tool invocation requests, preventing AttributeError exceptions when the attribute is missing.

What is the difference between using max_turns and manual tool handling?

When you set max_turns to a positive integer (like max_turns=5), the client automatically executes tool calls and feeds results back to the model until reaching the limit or completion. When max_turns is None, the client returns immediately after the first model response, allowing you to inspect tool_calls and handle execution manually.

Where are intermediate tool calls stored when using max_turns?

According to the source code in aisuite/client.py (lines 319–327), intermediate tool invocations are stored in response.intermediate_responses, while the accumulated message history is available in response.choices[0].intermediate_messages. This allows you to audit the full conversation flow even after the client resolves all tool calls.

Does aisuite modify the tool call format from the provider?

No, aisuite preserves the raw tool-call information exactly as the underlying provider supplies it. The ToolCall objects appear on the message with the same structure OpenAI uses (name, arguments as JSON string, and id), ensuring compatibility across different model providers in the unified response format.

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 →