History entries
A session's history is a list of entries: the messages, the tool calls and their results, in order. Read a turn's entries to show or check what the agent did. Start a session from entries you give it to move a conversation into the SDK, for example from another system or an earlier version of your app: the agent continues from a conversation it did not have.
Read a turn's entries
A turn's events hold its entries: each one comes as an agents.EntryAdded when it starts, and as an agents.EntryCompleted once it is whole. agents.MessageEntry, agents.ToolCallEntry, agents.ToolResultEntry and agents.UnknownEntry are the SDK's values for the entries in a session's history: a message, a tool call, a tool's result, and an entry type your SDK version has no class for, such as the model's reasoning or a message from another agent. A context message the model got with a turn's input is an agents.ContextMessage, a MessageEntry with role="context". They are frozen, and you match on them like a record:
import asyncio
from mistralai import agents
from reviewer import payment_reviewer
Entry = agents.MessageEntry | agents.ToolCallEntry | agents.ToolResultEntry | agents.UnknownEntry
def describe(entry: Entry) -> str:
match entry:
case agents.ContextMessage(kind=kind, source=source) as context:
return f"context ({kind}, {source}): {context.text}"
case agents.MessageEntry(role=role) as message:
return f"{role}: {message.text}"
case agents.ToolCallEntry(name, arguments):
return f"{name} called with {arguments}"
case agents.ToolResultEntry(name, content, is_error=True):
return f"{name} failed: {content}"
case agents.ToolResultEntry(name, content, structured_content=output):
return f"{name} returned {content if output is None else output}"
case agents.UnknownEntry(entry_type):
return f"an entry of type {entry_type}"| Entry | What it is | What you read |
|---|---|---|
MessageEntry | A message of the user, the model or the system, or a context message | role, text |
ContextMessage | A MessageEntry with role="context": a context message the model got with a turn's input | kind: "input" for one sent with a message, "capability_source" for one the session added about a tool source. source: that tool source, such as "mistral_connectors:notion", or None for one sent with a message |
ToolCallEntry | A tool call the model made | name, the tool's full ID such as client.get_alert, and arguments |
ToolResultEntry | The result of a tool call | name, content or structured_content, and is_error |
UnknownEntry | An entry type your SDK version has no class for, such as the model's reasoning | type, and raw, the entry unparsed |
Every entry also has an id and a turn_id. History entries in the API reference lists every field.
Replay an ended turn's events and keep the completed entries:
async def entries(session: agents.Session, turn_id: str) -> list[Entry]:
return [
event.entry
async for event in session.turn(turn_id).iter_events()
if isinstance(event, agents.EntryCompleted)
]
async def review() -> None:
session = await payment_reviewer.start_session()
state = await session.run("Review transaction monitoring alert 4711.")
for entry in await entries(session, state.turn_id):
print(describe(entry))
await session.cancel()
asyncio.run(review())The reasoning entries are UnknownEntry values. To list only the tool calls, read the record: a Completed record's tool_calls holds the turn's own calls. To follow the entries while the turn runs, pass on_event=: see Events. To read a session's whole history, read each turn's entries as above, or follow session.iter_events() and stop at the last turn's TurnEnded: it does not end while the session is open.
Start from an earlier conversation
Pass the entries to start_session(history=). Here, the payment reviewer of What an agent is continues a review that another system ran:
import asyncio
from mistralai import agents
from reviewer import payment_reviewer
earlier = [
{"type": "message", "role": "user", "content": [{"type": "text", "text": "Review alert 4711."}]},
{"type": "tool_call", "tool_call_id": "call-1", "name": "get_alert", "arguments": {"alert_id": "4711"}},
{"type": "tool_result", "tool_call_id": "call-1", "name": "get_alert", "result": "Payment of 9,800 EUR to a new beneficiary."},
{"type": "message", "role": "assistant", "content": [{"type": "text", "text": "Alert 4711 looks suspicious: I opened case CASE-4711."}]},
]
async def main() -> None:
session = await payment_reviewer.start_session(history=earlier)
state = await session.run("Which case did you open, and for how much?")
if isinstance(state, agents.Completed):
print(state.text)
print(state.tool_calls)
await session.cancel()
asyncio.run(main())The agent answered from the history, with no tool call. Pass each entry as a dict:
Entry type | What it is | Its fields |
|---|---|---|
"message" | A message | role: "user", "assistant" or "system". content: a list of content blocks as dicts, such as {"type": "text", "text": "..."}. |
"tool_call" | A call the model made | tool_call_id, name, arguments |
"tool_result" | The result of that call | tool_call_id, the same as its call's. name, result, or error when the call failed. |
"reasoning" | The model's reasoning | text |
An entry that does not match these types raises a Pydantic ValidationError, a ValueError, before the session starts.
history= works for an agent that runs in your process. An idempotency key does not check the history: a retried start with other entries returns the first session.
The model reads imported entries as things that happened. Import only history you trust: never a tool result that a user wrote.
Next
- Sessions: find a session again, and set it up for one conversation.
- Turns and the turn record: what the agent's answer holds.
- Events: follow a session while it works.
- API reference: History entries: every entry value and its fields.