Implementation:Anthropics Anthropic sdk python MessageParam Accumulation
| Knowledge Sources | |
|---|---|
| Domains | API_Client, LLM |
| Last Updated | 2026-02-15 00:00 GMT |
Overview
This page documents the MessageParam TypedDict and the accumulation pattern used to implement multi-turn conversations with the Anthropic Messages API. Since the API is stateless, the caller builds a growing list of MessageParam dicts that represent the full conversation history and sends it with each request.
API Signature
class MessageParam(TypedDict, total=False):
content: Required[
Union[
str,
Iterable[
Union[
TextBlockParam,
ImageBlockParam,
DocumentBlockParam,
SearchResultBlockParam,
ThinkingBlockParam,
RedactedThinkingBlockParam,
ToolUseBlockParam,
ToolResultBlockParam,
ServerToolUseBlockParam,
WebSearchToolResultBlockParam,
ContentBlock,
]
],
]
]
role: Required[Literal["user", "assistant"]]
Source Location
- File:
src/anthropic/types/message_param.py - Lines: 14-45
Import
from anthropic.types import MessageParam
Parameters
| Parameter | Type | Description |
|---|---|---|
role |
Required[Literal["user", "assistant"]] |
The conversational role. Must alternate between "user" and "assistant". Consecutive same-role messages are automatically merged by the API.
|
content |
Required[Union[str, Iterable[ContentBlockParam]]] |
The message content. A plain str is shorthand for a single text block. The iterable form supports multimodal content (text, images, documents, tool results, thinking blocks, etc.).
|
Content Type Variants
The content field accepts a rich union of block types:
| Block Type | Role | Purpose |
|---|---|---|
TextBlockParam |
user, assistant | Plain text content |
ImageBlockParam |
user | Base64 or URL-referenced images |
DocumentBlockParam |
user | PDF or plain-text documents |
SearchResultBlockParam |
user | Search result context |
ThinkingBlockParam |
assistant | Extended thinking block (pass-through from response) |
RedactedThinkingBlockParam |
assistant | Redacted thinking block (pass-through from response) |
ToolUseBlockParam |
assistant | Tool invocation (pass-through from response) |
ToolResultBlockParam |
user | Tool execution result |
ServerToolUseBlockParam |
assistant | Server-side tool invocation |
WebSearchToolResultBlockParam |
assistant | Web search results |
ContentBlock |
assistant | Direct pass-through of response content blocks |
Accumulation Pattern
The core multi-turn pattern involves maintaining a mutable list and appending messages after each exchange:
from anthropic import Anthropic
from anthropic.types import MessageParam
client = Anthropic()
# Initialize conversation with first user message
messages: list[MessageParam] = [
{"role": "user", "content": "What is Python?"}
]
# Turn 1
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=messages,
)
# Append assistant response -- content blocks pass through directly
messages.append({"role": "assistant", "content": response.content})
# Append next user message
messages.append({"role": "user", "content": "Can you give me an example?"})
# Turn 2 -- sends full conversation history
response2 = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=messages,
)
# Continue accumulating...
messages.append({"role": "assistant", "content": response2.content})
Response-to-Param Compatibility
A key design feature is that ContentBlock (the response union type) is directly accepted in the MessageParam.content union. This means the response's content blocks can be appended without any manual conversion:
# This works because ContentBlock is in the MessageParam content union
messages.append({"role": "assistant", "content": response.content})
# For simple text-only cases, you can also use a string
messages.append({"role": "assistant", "content": response.content[0].text})
Using response.content directly (the full list of content blocks) is recommended over extracting just the text, because it preserves thinking blocks, tool use blocks, and other non-text content that may be important for multi-turn context.
Assistant Prefilling
If the last message in the list has role "assistant", the model continues from that content:
messages = [
{"role": "user", "content": "What's 2+2? Answer with just the number."},
{"role": "assistant", "content": "The answer is "},
]
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=10,
messages=messages,
)
# response.content[0].text might be "4"
Multi-turn with System Prompt
The system prompt is separate from the message list and can be changed between turns:
messages: list[MessageParam] = []
messages.append({"role": "user", "content": "Hello!"})
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system="You are a friendly assistant who speaks casually.",
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": "Tell me about the weather."})
# System prompt can change between turns
response2 = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system="You are a meteorologist who gives detailed forecasts.",
messages=messages,
)
Dependencies
- typing_extensions --
Required,Literal,TypedDict - anthropic.types.text_block_param --
TextBlockParam - anthropic.types.image_block_param --
ImageBlockParam - anthropic.types.document_block_param --
DocumentBlockParam - anthropic.types.tool_use_block_param --
ToolUseBlockParam - anthropic.types.tool_result_block_param --
ToolResultBlockParam - anthropic.types.content_block --
ContentBlock