Messages, History, and Streaming

A single agent run answers one question; a conversation needs memory, and a good user experience needs the answer to appear as it's generated. Pydantic AI handles both through its message system — the record of what was said that you pass between runs — and streaming, which delivers typed output progressively. Together they turn one-shot agents into conversational, responsive ones.

The previous posts built agents that run once and return typed output. Real applications need more: conversation (an agent that remembers previous turns) and streaming (output that appears progressively, not all at once). Pydantic AI provides both through its message system and streaming support. This post covers how conversation history works, how you control it, and how streaming delivers responsive output — the pieces that make Pydantic AI agents usable in interactive applications.

Messages: the record of the conversation

Every agent run produces and consumes messages — the structured record of what happened: the user’s input, the model’s responses, tool calls and their results, and system prompts. Pydantic AI exposes these messages on the result of a run, and the key operation is that you can pass the messages from one run as history into the next:

# Illustrative shape — see the Pydantic AI docs for exact API.
result1 = agent.run_sync("My name is Alice.")
result2 = agent.run_sync(
    "What's my name?",
    message_history=result1.new_messages(),   # carry the prior conversation forward
)
print(result2.output)   # knows the name from history

This is how conversation works: an agent run is stateless by itself, but by feeding the messages from prior runs into the next run, you give the agent the conversation’s context. The agent “remembers” not because it holds state, but because you carry the message history forward explicitly. This explicit-history model is deliberate and important — it means you control the conversation state (where it’s stored, what’s included), rather than the framework hiding it in mutable agent state. The messages are data you manage.

Why explicit history matters

Making history explicit data (rather than hidden agent state) has real benefits that reflect the framework’s design values:

The design mirrors good backend practice: keep the component (the agent) stateless and reusable, and carry state (the messages) explicitly. It’s the opposite of a stateful chatbot object, and it’s what makes Pydantic AI agents clean to use in real, multi-user, multi-request applications.

Managing context length

Because you control the message history, you also own the responsibility that comes with it: conversation history grows, and context windows are finite (the lesson from the LLM serving and context-engineering series). Passing an ever-growing history into each run eventually fills the context, raising cost and latency and risking truncation. Since history is explicit data you manage, you handle this the way those series described:

Pydantic AI gives you the messages as manipulable data, so implementing these strategies is straightforward — you shape the message_history you pass forward. The framework doesn’t force a particular strategy (again, you’re in control), which means managing context is your job, but a tractable one because history is explicit, inspectable data rather than opaque internal state.

Streaming: responsive output

The second piece is streaming — delivering the agent’s output progressively as it’s generated, rather than waiting for the complete response. This matters for user experience: as the LLM serving series noted, generation takes time, and streaming makes an application feel responsive by showing output as it arrives instead of a spinner until the end. Pydantic AI supports streaming runs:

Streaming structured output is a notable strength: many frameworks make you pick between “structured but all-at-once” and “streamed but unstructured text,” while Pydantic AI streams and keeps the typed-validation guarantees. For applications that want both a live, responsive feel and reliable typed data, that’s a meaningful capability.

Conversation and responsiveness, the Pydantic AI way

Put together, messages and streaming extend the typed, controlled Pydantic AI model to interactive applications:

Both reflect the framework’s consistent stance: give you control (over state, over how output arrives) with type safety intact, rather than hiding state or forcing a trade-off. This is what makes Pydantic AI practical for real conversational and interactive apps, not just one-shot calls. With conversation and streaming covered, the next post turns to the framework’s standout strength — testing and evaluation — which the typing and dependency injection have been setting up all along.

Key takeaways

Further reading

Sources & References