Pydantic AIPydantic AI 2.51 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
29 small wins to finish your pathNext lesson →

Message history: continuing a conversation

message_history is a list of earlier messages you pass to a run, so the model sees the conversation so far before the new ticket. Without it, each run starts from nothing.

Last updated: 28 Sep, 2026 · Pydantic AI 2.51

An agent keeps nothing between runs. To hold a conversation, your app has to carry the earlier messages forward and hand them to the next run. This model function reports every customer message it was sent, so you can see what each run received.

The model that echoes what it was sent

python
from pydantic_ai import Agent, ModelResponse, TextPart
from pydantic_ai.models.function import FunctionModel


def remember(messages, info):
    said = [part.content for message in messages for part in message.parts if part.part_kind == "user-prompt"]
    return ModelResponse(parts=[TextPart(f"You have told me: {said}")])


agent = Agent(FunctionModel(remember))

Two runs with no shared history

Run twice without passing anything between them, and the second run sees only its own prompt.

Example
first = agent.run_sync("My order is A-1001")
print(first.output)

second = agent.run_sync("Where is it?")
print(second.output)

The second run was sent only "Where is it?". A real model would not know which order it is.

Passing the earlier messages forward

Take all_messages() from the first run and pass it as message_history to the second.

Example
first = agent.run_sync("My order is A-1001")
second = agent.run_sync("Where is it?", message_history=first.all_messages())
print(second.output)
print(len(second.all_messages()), len(second.new_messages()))

message_history puts the earlier messages in front of the new prompt. all_messages() on the second run holds all four: the old request and response and the new ones. new_messages() holds only the two this run added, which is what you append when you store a conversation.

all_messages vs new_messages

MethodReturnsUse it to
all_messages()The whole conversation, old and newPass as history into the next run
new_messages()Only what this run addedAppend to what you already store

Where a conversation lives

The agent holds none of this. Your app keeps the list: in memory for a script, in a database for a web app, keyed by the conversation. Saving it as JSON, in the next lesson, lets it outlive the process.

Every run sends the whole history again, so a long conversation costs more with each message. The lesson after next trims that list with a history processor before it is sent.

When you reach for message history

  • A multi-turn chat where a later message refers back to an earlier one.
  • Resuming a conversation the customer left and came back to.
  • Passing a run's messages to another run, as human approval does later in this part.
Watch out. Message history is sent in full on every run, so a growing conversation raises the token cost of each reply. Store new_messages() as you go, and trim the list before the next run once it gets long.
Try it yourself
  • Run a third message with message_history=second.all_messages().
  • Pass first.new_messages() instead of all_messages(). Is anything different here?
  • Print message.kind for every message in second.all_messages().

Every expert started right here.