# How to Use intermediate_messages for Conversation Continuity in aisuite

> Learn how to use intermediate_messages in aisuite to maintain conversation continuity. Automatically accumulate message history and prepend it to subsequent requests for seamless multi-turn tool execution.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-06-15

---

**`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`](https://github.com/andrewyng/aisuite/blob/main/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:

1. **Collects messages** – Each turn appends the model's reply to `intermediate_messages` and, after a tool call, also appends the tool-generated messages.
2. **Snapshots responses** – Raw response objects from each turn are accumulated in `intermediate_responses`.
3. **Attaches history** – Before returning the final result, the method populates the response object with the full interaction history:

```python
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`](https://github.com/andrewyng/aisuite/blob/main/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

```python
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:

```python
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`](https://github.com/andrewyng/aisuite/blob/main/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`](https://github.com/andrewyng/aisuite/blob/main/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_messages`** captures 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 `messages` parameter in subsequent `create()` calls.
- **Checkpointing** allows you to serialize conversation state and resume later without losing tool execution context.
- **Implementation** resides in [`aisuite/client.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/client.py) within the `Completions._tool_runner` method, validated by the test suite at [`tests/client/test_client.py`](https://github.com/andrewyng/aisuite/blob/main/tests/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.