Pydantic AI gives you a clean, typed agent: define an Agent, hand it tools, call agent.run(...), and it loops — model call, tool call, model call — until it produces a validated result. The typed ergonomics are great. What the quickstart doesn't spell out is what the model receives on each pass of that loop.
I read the run graph (pydantic_ai_slim/pydantic_ai/_agent_graph.py on main) to find out. The mechanism is structural, and it's the same shape I found in the OpenAI Agents SDK and smolagents.
One list, appended twice per turn
Each run holds a single mutable conversation list on its state:
message_history: list[_messages.ModelMessage] = dataclasses.field(default_factory=list[_messages.ModelMessage])






