Persistent Conversations
On this page
Lesson updated November 3, 2026 based on
mistralaiSDK 3.7.0: retrieve a conversation’s history (itsentries) usingclient.beta.conversations.get_history;retrievedoes not exist, andgetreturns only conversation metadata. Source: client-python.
State That Persists Across Exchanges
One of the major advantages of the Agents API over Chat Completions is conversation persistence. You no longer need to manually manage message history—Mistral handles it server-side. Specifically, the list of dictionaries you used to accumulate in a variable, truncate when context overflowed, and rebuild on every process restart disappears from your code. You only need to track one thing: an identifier. And that identifier follows a rule that trips up everyone on their first project.
Starting a Conversation
The conversations.start() method creates a new conversation and sends the first message. The following example also creates the agent that will run it, then gives it a project context you can query over multiple turns.
from mistralai.client import Mistral
import os
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
# Create an agent
agent = client.beta.agents.create(
model="mistral-medium-latest",
name="Project Assistant",
description="Project management assistant.",
instructions="You help organize and track projects. Be structured."
)
# Start the conversation
response = client.beta.conversations.start(
agent_id=agent.id,
inputs="I'm launching a new project to redesign our website. Budget: €50K, deadline: September 2026."
)
print(f"Conversation ID: {response.conversation_id}")
The returned conversation_id is your key to continuing this conversation later. Store it where your application can retrieve it: in a user session, a database, or the support ticket it relates to.
Continuing a Conversation
To add a message to an existing conversation, pass the conversation_id to conversations.append(). Follow the thread in this example: the second question doesn’t repeat the budget or deadline, and the third asks for a schedule without reminding the agent it’s a website redesign. Yet the agent has all that context.
# First exchange
response1 = client.beta.conversations.start(
agent_id=agent.id,
inputs="I'm launching a website redesign project. Budget €50K."
)
# Second exchange — the agent remembers the context
response2 = client.beta.conversations.append(
conversation_id=response1.conversation_id,
inputs="What are the priority steps?"
)
# Third exchange — still in the same context
response3 = client.beta.conversations.append(
conversation_id=response2.conversation_id,
inputs="Draft a schedule for the first 3 months."
)
Look closely at which identifier feeds each call: response2 starts from the ID of response1, response3 from that of response2. This isn’t a quirk; it’s the core mechanism of the API.
The Immutability Mechanism
Every call to conversations.append() returns a new conversation_id. The old one remains readable, but you must use the latest ID for the next append.
# Each append returns a new ID
id_1 = response1.conversation_id # "conv-aaa"
id_2 = response2.conversation_id # "conv-bbb"
id_3 = response3.conversation_id # "conv-ccc"
# Always use the LATEST id to continue
response4 = client.beta.conversations.append(
conversation_id=id_3, # Not id_1 or id_2
inputs="Add client validation milestones."
)
The classic mistake is saving the initial identifier in your database when the user opens the thread, then reusing it as-is for every message. Nothing crashes: the API responds normally, but each question restarts from the context of the first exchange, and your agent seems to have amnesia without any error alerting you. Always overwrite the stored identifier with the one returned in the response.
Reading Conversation History
You can read history at any time, which helps both with debugging and displaying a thread in your interface.
conversation = client.beta.conversations.get_history(
conversation_id=response.conversation_id
)
for entry in conversation.entries:
print(f"[{entry.role}] {entry.type}: {entry.content[:100]}...")
Managing Storage
By default, conversations are stored in the Mistral cloud. The store=False parameter disables this behavior for exchanges your internal policy forbids leaving on a third-party server.
# Ephemeral conversation — nothing is saved
response = client.beta.conversations.start(
agent_id=agent.id,
inputs="Confidential data to analyze...",
store=False
)
The trade-off matches the goal: the conversation isn’t recoverable after the session, and data isn’t kept on Mistral servers. You lose the history playback described above, and your application must handle tracking exchanges itself if needed. Make this decision upfront, not as a last-minute checkbox.
Multi-Turn Conversation Pattern
The skeleton below applies everything above in an interactive loop. The key point is the conversation_id variable, initialized to None: it decides which call to make—start() on the first turn, append() afterward—and it gets reassigned after each response, following the immutability rule.
from mistralai.client import Mistral
import os
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
agent = client.beta.agents.create(
model="mistral-large-latest",
name="Technical Coach",
description="Coach for technical decisions.",
instructions="You are a senior technical coach. Ask questions to understand the context before advising."
)
# Conversation loop
conversation_id = None
while True:
user_input = input("You: ")
if user_input.lower() in ["quit", "exit"]:
break
if conversation_id is None:
response = client.beta.conversations.start(
agent_id=agent.id,
inputs=user_input
)
else:
response = client.beta.conversations.append(
conversation_id=conversation_id,
inputs=user_input
)
conversation_id = response.conversation_id
for entry in response.outputs:
if hasattr(entry, "content"):
print(f"Agent: {entry.content}")
Adapt it to your context by replacing input() with your actual message source—HTTP request, queue message, webhook event—and persisting conversation_id where your application can find it on the next turn.
Key Takeaways
conversations.start()creates a new conversation with a first messageconversations.append()adds a message to an existing conversation- Each append returns a new
conversation_id—always use the latest one store=Falsedisables persistence on Mistral’s side for sensitive data- The agent retains the full conversation context without you needing to resend history