---
title: Message History
description: Understand message parts, internal state, validation, repair, and replay.
type: conceptual
summary: Learn the invariants the framework maintains for model-ready message history.
---

# Message History



Message history is the durable contract between your app, providers, tools, and
resume flows.

## Message and part model

Each message has a role and typed parts:

```python
message = ai.user_message(
    "Inspect this mothership diagram.",
    ai.file_part(image_bytes, media_type="image/png"),
)
```

Common parts include text, reasoning, tool calls, tool results, provider tool
returns, hook state, and files.

## Internal messages

Hooks emit `role="internal"` messages with `HookPart` values. They are useful
for UI state and resume flows, but providers do not receive them.

```python
if message.role == "internal":
    hook = message.parts[0]
```

## Tool-call invariants

Provider APIs expect every assistant tool call to have a matching tool result
before the next user or assistant message:

```python
[
    ai.assistant_message(tool_call_part),
    ai.tool_message(tool_result_part),
]
```

Duplicate tool-call IDs, duplicate result IDs, and orphaned tool results are
fatal integrity errors.

## Automatic history repair

Before provider calls, the framework prepares message history in `auto` mode. It
strips internal messages, removes non-model parts, repairs invalid tool args to
`{}`, and inserts error results for missing tool calls when possible.

## Strict validation

Use strict validation in tests or import pipelines when you want repairable
issues to raise:

```python
from ai.types import integrity


integrity.prepare_messages(messages, mode="strict")
```

## Replay markers

Replay markers are runtime-only flags on assistant messages. They let a resumed
agent dispatch existing tool calls without another model request:

```python
if messages[-1].replay:
    async with ai.stream(model, messages) as stream:
        ...
```

Replay flags are excluded from JSON serialization.

## Persisted history

Persist Pydantic JSON, then restore with `Message.model_validate`:

```python
encoded = [message.model_dump(mode="json") for message in stream.messages]
restored = [ai.messages.Message.model_validate(item) for item in encoded]
```

Persist messages after each completed or suspended run. Recreate live runtime
objects, providers, and hooks on the next request.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)