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

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}"
EntryWhat it isWhat you read
MessageEntryA message of the user, the model or the system, or a context messagerole, text
ContextMessageA MessageEntry with role="context": a context message the model got with a turn's inputkind: "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
ToolCallEntryA tool call the model madename, the tool's full ID such as client.get_alert, and arguments
ToolResultEntryThe result of a tool callname, content or structured_content, and is_error
UnknownEntryAn entry type your SDK version has no class for, such as the model's reasoningtype, 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())
Output
user: Review transaction monitoring alert 4711.
an entry of type reasoning
an entry of type reasoning
an entry of type reasoning
client.get_alert called with {'alert_id': '4711'}
client.get_alert returned Payment of 9,800 EUR from account FR76-3000-4471 to a beneficiary added 3
minutes earlier, right after a password reset. Flagged: new beneficiary, amount just under 10,000 EUR.
an entry of type reasoning
client.open_case called with {'alert_id': '4711', 'summary': 'Suspicious 9,800 EUR payment from account FR76-3000-4471 ...', 'evidence': [...]}
client.open_case returned CASE-4711
an entry of type reasoning
assistant: Alert 4711 is a suspicious 9,800 EUR payment from account FR76-3000-4471 to a beneficiary added just 3
minutes earlier immediately after a password reset ...

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.

THE TURN'S EVENTSITS ENTRIESEntryAddedEntryCompletedEntryAddedEntryCompletedEntryAddedEntryCompletedEntryAddedTextDelta "Alert 4711 is"TextDelta " a suspicious"TextDelta " 9,800 EUR…"EntryCompleteduser: Review transaction monitoring…MessageEntryclient.get_alert {'alert_id': '4711'}ToolCallEntryclient.get_alert returned Payment…ToolResultEntryassistant · pendingAlert 4711 isa suspicious9,800 EUR…assistant: Alert 4711 is a suspicious…MessageEntryMATCHcase agents.EntryCompleted(entry=entry): entries.append(entry) # only it is finalcase agents.TextDelta(entry_id=entry_id, text=text):case agents.EntryCompleted(entry= agents.MessageEntry() as reply):
Step 1 of 5. The payment reviewer's turn on alert 4711, read event by event. The user's message comes as an agents.EntryAdded, then an agents.EntryCompleted: a MessageEntry.
Start from an earlier conversation

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())
Output
I opened case CASE-4711 for the suspicious payment of 9,800 EUR to a new beneficiary.
()

The agent answered from the history, with no tool call. Pass each entry as a dict:

Entry typeWhat it isIts fields
"message"A messagerole: "user", "assistant" or "system". content: a list of content blocks as dicts, such as {"type": "text", "text": "..."}.
"tool_call"A call the model madetool_call_id, name, arguments
"tool_result"The result of that calltool_call_id, the same as its call's. name, result, or error when the call failed.
"reasoning"The model's reasoningtext

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.