Skip to content

pydantic_ai.conversation

The state a conversation carries from one run to the next.

Conversation

Everything a conversation carries from one run to the next, in one object.

This is the unit to continue and to store a conversation by. A run’s AgentRunResult.conversation (or a realtime session’s conversation) produces one, and every entry point that starts a run takes it back as conversation=. See Carrying a conversation whole.

Passing message_history= instead still works, but carries only the messages. What it drops is what a conversation reassembled by hand loses: the running usage, without which every turn’s UsageLimits budget starts over from zero; the conversation_id that correlates its runs; and the deferred_tool_requests a paused run is waiting on, which can’t be recovered from the messages.

It serializes like any Pydantic value — as a field on a model of your own, or with ConversationTypeAdapter — with the same fidelity as ModelMessagesTypeAdapter. See Persistence.

Attributes

messages

The conversation so far, in the form message_history= takes.

Type: Annotated[list[_messages.ModelMessage], pydantic.PlainSerializer(_dump_messages_json, when_used=json)] Default: dataclasses.field(default_factory=(list[_messages.ModelMessage]))

usage

Usage accumulated across every run in this conversation.

Only some of this can be recovered from messages after the fact: the token counts and requests are recorded on each ModelResponse, but tool_calls is not, and a history that has since been trimmed no longer accounts for what the dropped turns cost. Carrying it keeps a conversation’s spend true to what was actually spent.

Type: _usage.RunUsage Default: dataclasses.field(default_factory=(_usage.RunUsage))

conversation_id

The identifier every run in this conversation shares, and the key to store it under.

Type: str Default: dataclasses.field(default_factory=(lambda: str(uuid7())))

deferred_tool_requests

The tool calls the conversation is waiting on, if its last run paused for them.

Set when a run ends with DeferredToolRequests as its output: calls that need approval or external execution. The messages show which calls are unanswered, but not which kind of answer each needs or the metadata it was deferred with, so the requests travel with the conversation rather than being rebuilt from it.

Answer them with build_results and pass the results to the next run as deferred_tool_results= alongside the conversation; see Pausing a conversation for deferred tools.

Type: DeferredToolRequests | None Default: None

ConversationTypeAdapter

Pydantic TypeAdapter for (de)serializing a Conversation.

The counterpart of ModelMessagesTypeAdapter for the whole conversation rather than its messages alone.

Type: pydantic.TypeAdapter[Conversation] Default: pydantic.TypeAdapter(Conversation)