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 invokearguments: A JSON string containing the parametersid: 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_callsas a list ofToolCallobjects. - Manual extraction requires using
getattr(message, "tool_calls", None)to safely access the attribute, which containsname,arguments, and optionalidfields. - Automatic execution via
max_turnsresolves tool calls internally, leaving the final response with emptytool_callsbut preserving history inintermediate_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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →