How to Use intermediate_messages for Conversation Continuity in aisuite
aisuite automatically accumulates every model and tool message during multi-turn tool execution in the intermediate_messages attribute, allowing you to prepend this history to subsequent requests to maintain conversation state without manual message reconstruction.
The aisuite library from the andrewyng/aisuite repository provides a unified interface for multiple AI providers. When using tool-calling capabilities with the max_turns parameter, the library tracks the complete dialogue history in intermediate_messages, enabling seamless conversation continuity across discrete API calls.
How intermediate_messages Works Internally
The conversation continuity mechanism is implemented in the tool execution loop within aisuite/client.py. When you invoke client.chat.completions.create() with max_turns greater than zero, the Completions._tool_runner method orchestrates the interaction between the model and any provided tools.
The Tool Execution Loop
During each turn of a multi-turn interaction, the _tool_runner method performs the following sequence:
- Collects messages – Each turn appends the model's reply to
intermediate_messagesand, after a tool call, also appends the tool-generated messages. - Snapshots responses – Raw response objects from each turn are accumulated in
intermediate_responses. - Attaches history – Before returning the final result, the method populates the response object with the full interaction history:
response.intermediate_responses = intermediate_responses[:-1] # all but the final turn
response.choices[0].intermediate_messages = intermediate_messages
These two attributes constitute part of the public API and are documented in the quick-start guide at docs/agents-quickstart.md.
What Gets Stored
The intermediate_messages list contains the complete dialogue sequence including:
- The original user prompt
- Model-generated assistant messages
- Tool call requests from the model
- Tool result messages returned from your functions
Because this collection already contains the complete context, you can resume conversations by simply passing it back to the messages parameter in subsequent calls.
Continuing Conversations with intermediate_messages
To maintain state across multiple API calls, capture the intermediate_messages from the first response and prepend it to new messages in your follow-up request.
Step-by-Step Implementation
from aisuite import Client
# Initialize the client with provider configuration
client = Client(provider_configs={"openai": {"api_key": "YOUR_KEY"}})
# ----------------------------------------------------------------------
# First request – enable tool execution with max_turns
# ----------------------------------------------------------------------
first_response = client.chat.completions.create(
model="openai:gpt-4o-mini",
messages=[{"role": "user", "content": "List the files in the current folder"}],
max_turns=3, # Allow the model to call tools up to 3 times
tools=[my_list_files_tool],
)
# Access the accumulated history
final_answer = first_response.choices[0].message.content
conversation_history = first_response.choices[0].intermediate_messages
print(f"Turns captured: {len(conversation_history)}")
# ----------------------------------------------------------------------
# Continue the conversation – reuse the stored intermediate messages
# ----------------------------------------------------------------------
next_message = {
"role": "user",
"content": "Now read the first file you just listed"
}
second_response = client.chat.completions.create(
model="openai:gpt-4o-mini",
# Prepend the historic messages so the model sees the full context
messages=conversation_history + [next_message],
max_turns=3,
tools=[my_read_file_tool],
)
print(second_response.choices[0].message.content) # Answer referencing earlier file list
Checkpointing for Later Resumption
The intermediate_messages list can be serialized and stored (for example, in a database) to resume conversations later:
import json
# Save state
stored_conversation = json.dumps(first_response.choices[0].intermediate_messages)
# Later or in another process: restore and continue
restored_messages = json.loads(stored_conversation)
continuation = client.chat.completions.create(
model="openai:gpt-4o-mini",
messages=restored_messages + [{"role": "user", "content": "Summarize what we did"}],
max_turns=3,
tools=[my_list_files_tool]
)
Key Implementation Details
The tests/client/test_client.py file contains validation logic confirming that intermediate_messages contains the expected length and content after tool execution. According to the source code in aisuite/client.py (lines 274-351), the _tool_runner method builds the message list incrementally during each turn, ensuring that tool results are automatically formatted according to the provider's expected schema.
When comparing conversation management approaches, using intermediate_messages eliminates the need to manually reconstruct message threads from scratch, while rebuilding from memory requires tracking tool_call_ids and result dictionaries separately.
Summary
intermediate_messagescaptures the complete dialogue including user prompts, model replies, and tool interactions during multi-turn execution.- State preservation is achieved by prepending the saved list to the
messagesparameter in subsequentcreate()calls. - Checkpointing allows you to serialize conversation state and resume later without losing tool execution context.
- Implementation resides in
aisuite/client.pywithin theCompletions._tool_runnermethod, validated by the test suite attests/client/test_client.py.
Frequently Asked Questions
What is the difference between intermediate_messages and intermediate_responses?
intermediate_messages contains the formatted message dictionaries (role, content, tool_calls) suitable for sending back to the model, while intermediate_responses contains the raw response objects from the provider. The messages are what you pass to subsequent API calls; the responses contain metadata like token usage and finish reasons from intermediate turns.
Do I need to manually format tool results when using intermediate_messages?
No. When you use max_turns with tool execution, aisuite automatically formats tool results and appends them to intermediate_messages in the correct schema for your provider. You simply pass the entire intermediate_messages list back to the messages parameter without modification.
Can intermediate_messages be used across different providers?
While intermediate_messages maintains a consistent format within aisuite, switching providers between turns is not recommended because different providers may have incompatible tool call schemas. For best results, continue conversations using the same provider that generated the original intermediate_messages.
How does max_turns affect intermediate_messages population?
The max_turns parameter limits how many tool-execution iterations the _tool_runner performs. Each iteration appends to intermediate_messages, so a higher max_turns value results in a longer message list. If max_turns is not set or is zero, no tool execution occurs and intermediate_messages will only contain the initial user message and final response.
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 →