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

Message history: continuing a conversation

Each run starts from nothing. To continue a conversation, pass the earlier run's messages as message_history, and the model sees them before the new ticket.

This model function answers with every customer message it was sent:

Example
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))
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.

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.

Where a conversation lives

The agent keeps nothing between runs. Your app holds the list: in memory for a script, in a database for a web app, keyed by the conversation. Lesson 15 turns it into JSON for that.

Every run sends the whole history again, so a long conversation costs more with each message. history_processors on the agent can trim or summarise old messages before they are sent.

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().

This is what real progress feels like.