Messages
In shortReference for Message, the twelve content block types, MediaRef, AnnotationRef and TokenUsages, the typed format for all agent communication.
- 9 min read
- 7 sections
- Updated
- v0.10.0
- Markdown
A Message is the unit of conversation in 10xGraph: a role plus an ordered list of typed content blocks (text, images, tool calls, reasoning and more). Graph nodes, the API and the TypeScript client all exchange this shape. This page lists every field, constructor and block. For the concepts, see State and messages.
Import paths
from tenxgraph.core.state import Message
from tenxgraph.core.state.message_block import (
TextBlock, ImageBlock, AudioBlock, VideoBlock,
DocumentBlock, DataBlock,
ToolCallBlock, RemoteToolCallBlock, ToolResultBlock,
ReasoningBlock, AnnotationBlock, ErrorBlock,
MediaRef, AnnotationRef, ContentBlock,
)
from tenxgraph.core.state.message import TokenUsages, generate_idMost of these names are also exported from tenxgraph.core.state (everything above except RemoteToolCallBlock and generate_id).
Message
A Pydantic model holding one conversation turn. Conversations in graph state are list[Message].
Fields
| Field | Type | Default | Description |
|---|---|---|---|
message_id |
str | int |
auto-generated | Unique message identifier. Generated by generate_id, which honors an ID generator registered in the dependency container. |
role |
"user" | "assistant" | "system" | "tool" |
required | Who sent the message. |
content |
Sequence[ContentBlock] |
required | Ordered list of typed content blocks. |
delta |
bool |
False |
True for streaming intermediate chunks. |
tools_calls |
list[dict] | None |
None |
Raw tool call dicts from the provider SDK. Used internally. |
reasoning |
str | None |
None |
Reasoning trace (marked for removal in the source; use ReasoningBlock in content instead). |
timestamp |
float | None |
current time | UNIX timestamp of message creation. |
metadata |
dict |
{} |
Arbitrary key-value metadata. |
usages |
TokenUsages | None |
None |
Token usage for this message’s LLM call. |
raw |
dict | None |
None |
The raw provider API response. |
parsed_content |
dict | BaseModel | None |
None |
Structured output parsed by the provider converter when the agent uses output_schema. Read it in preference to parsing the text block yourself. |
Constructors and helpers
Use these class methods to build messages without assembling blocks by hand. All of them generate a message_id through generate_id when you do not pass one.
| Method | Signature | Returns |
|---|---|---|
text_message |
(content: str, role="user", message_id: str | None = None) |
Message with one TextBlock. |
tool_message |
(content: Sequence[ContentBlock], message_id: str | None = None, meta: dict | None = None) |
Message with role="tool". |
image_message |
(*, image_url=None, image_base64=None, mime_type="image/png", text=None, role="user", message_id=None) |
Message with an optional text block and an ImageBlock. Raises ValueError if neither image_url nor image_base64 is given. |
multimodal_message |
(content_blocks: Sequence[ContentBlock], role="user", message_id=None) |
Message from your own blocks. |
from_file |
(file_path: str, mime_type=None, text=None, role="user", message_id=None) |
Message with the file base64-encoded inline. Raises FileNotFoundError. |
with_image |
async (data: bytes, mime_type: str, store, text=None, role="user", message_id=None) |
Message whose image is saved to a media store, keeping only a MediaRef. |
with_file |
async (file_path: str, store, mime_type=None, text=None, role="user", message_id=None) |
Same as from_file, but stored through a media store. Raises FileNotFoundError. |
from_file and with_file pick the block type from the MIME type: image/* gives ImageBlock, audio/* gives AudioBlock, video/* gives VideoBlock, anything else gives DocumentBlock. If the MIME type is not passed, it is guessed from the file extension, falling back to application/octet-stream. The store argument is a media store; see Media.
from tenxgraph.core.state import Message
msg = Message.text_message("Hello")
msg = Message.text_message("Hello", role="assistant")
msg = Message.text_message("Hello", role="user", message_id="msg-001")Instance methods
| Method | Returns | Description |
|---|---|---|
text() |
str |
Concatenates the text of every TextBlock and ToolResultBlock in content. Non-string tool outputs are JSON-encoded. Other block types are skipped. |
attach_media(media: MediaRef, as_type) |
None |
Appends an ImageBlock, AudioBlock, VideoBlock or DocumentBlock to content. as_type is "image", "audio", "video" or "document"; anything else raises ValueError. content must be a mutable list. |
Direct construction
from tenxgraph.core.state import Message
from tenxgraph.core.state.message_block import TextBlock
msg = Message(
role="user",
content=[TextBlock(text="Hello, world!")],
metadata={"source": "api"},
)
print(msg.text()) # Hello, world!Content blocks
Every item in Message.content is one of twelve block types. They share a type discriminator field with a fixed literal value, so you can narrow by checking block.type. The union is exported as ContentBlock.
TextBlock
TextBlock(text="Hello, world!")
TextBlock(text="See reference [1].", annotations=[AnnotationRef(url="https://example.com", title="Source")])| Field | Type | Description |
|---|---|---|
type |
"text" |
Discriminator. |
text |
str |
The text content. |
annotations |
list[AnnotationRef] |
Citations or links embedded in the text. |
ImageBlock
ImageBlock(media=MediaRef(kind="url", url="https://example.com/photo.jpg", mime_type="image/jpeg"))
ImageBlock(media=MediaRef(kind="file_id", file_id="file-abc123", mime_type="image/png"))
ImageBlock(media=MediaRef(kind="data", data_base64="...", mime_type="image/png"), alt_text="Chart")| Field | Type | Description |
|---|---|---|
type |
"image" |
Discriminator. |
media |
MediaRef |
Reference to the image. |
alt_text |
str | None |
Accessibility text. |
bbox |
list[float] | None |
Bounding box [x1, y1, x2, y2]. |
AudioBlock
AudioBlock(
media=MediaRef(kind="url", url="https://example.com/recording.mp3"),
transcript="Hello, this is a recording.",
)| Field | Type | Description |
|---|---|---|
type |
"audio" |
Discriminator. |
media |
MediaRef |
Reference to the audio. |
transcript |
str | None |
Transcript of the audio content. |
sample_rate |
int | None |
Sample rate in Hz. |
channels |
int | None |
Number of audio channels. |
VideoBlock
VideoBlock(
media=MediaRef(kind="url", url="https://example.com/video.mp4"),
thumbnail=MediaRef(kind="url", url="https://example.com/thumb.jpg"),
)| Field | Type | Description |
|---|---|---|
type |
"video" |
Discriminator. |
media |
MediaRef |
Reference to the video. |
thumbnail |
MediaRef | None |
Thumbnail image reference. |
DocumentBlock
DocumentBlock(
media=MediaRef(kind="file_id", file_id="file-def456", mime_type="application/pdf"),
excerpt="This report covers Q4 earnings...",
pages=[1, 2, 3],
)| Field | Type | Description |
|---|---|---|
type |
"document" |
Discriminator. |
media |
MediaRef |
Reference to the document file. |
text |
str | None |
Extracted full text content. |
pages |
list[int] | None |
Relevant page numbers. |
excerpt |
str | None |
Short excerpt/preview. |
DataBlock
DataBlock(mime_type="application/json", data_base64="eyJrZXkiOiAidmFsdWUifQ==")| Field | Type | Description |
|---|---|---|
type |
"data" |
Discriminator. |
mime_type |
str |
MIME type of the data. |
data_base64 |
str | None |
Base64-encoded payload. |
media |
MediaRef | None |
External media reference. |
ToolCallBlock
Added by the agent when the LLM requests a tool call. Application code usually does not construct these directly.
ToolCallBlock(id="call_abc", name="get_weather", args={"location": "London"})| Field | Type | Description |
|---|---|---|
type |
"tool_call" |
Discriminator. |
id |
str |
Tool call ID (matches the corresponding ToolResultBlock). |
name |
str |
Tool function name. |
args |
dict |
Arguments dict. |
tool_type |
str | None |
Optional type hint e.g. "web_search", "computer_use". |
RemoteToolCallBlock
Sent by the server to the TypeScript client when a tool needs to run in the browser. Do not construct manually.
| Field | Type | Description |
|---|---|---|
type |
"remote_tool_call" |
Discriminator. |
id |
str |
Call ID. |
name |
str |
Configured remote-tool name with a matching client handler. |
args |
dict |
Arguments. |
tool_type |
str |
Defaults to "remote". |
ToolResultBlock
The result of a tool call execution. Constructed by ToolNode and returned to the LLM.
ToolResultBlock(call_id="call_abc", output={"order_id": "A1001", "status": "shipped"}, is_error=False)| Field | Type | Description |
|---|---|---|
type |
"tool_result" |
Discriminator. |
call_id |
str |
Matches the ToolCallBlock.id this is a response to. |
output |
Any |
The result returned by the tool (string, dict, MediaRef or a list of blocks). |
is_error |
bool |
True if the tool execution failed. Default False. |
status |
"completed" | "failed" | None |
Status of the tool call. |
ReasoningBlock
Exposes a reasoning model’s thinking trace when the provider returns one.
| Field | Type | Description |
|---|---|---|
type |
"reasoning" |
Discriminator. |
summary |
str |
Summary of the reasoning. |
details |
list[str] | None |
Detailed reasoning steps. |
AnnotationBlock
Structured annotation or citation attached to a text response.
| Field | Type | Description |
|---|---|---|
type |
"annotation" |
Discriminator. |
kind |
"citation" | "note" |
Kind of annotation. Default "citation". |
refs |
list[AnnotationRef] |
Annotation references. |
spans |
list[tuple[int, int]] | None |
Spans covered by the annotation. |
ErrorBlock
Represents an error that occurred during execution.
| Field | Type | Description |
|---|---|---|
type |
"error" |
Discriminator. |
message |
str |
Error message. |
code |
str | None |
Optional error code. |
data |
dict | None |
Additional error data. |
MediaRef
A reference to binary media that is stored by URL, provider file ID or inline base64. The kind field (default "url") says which of url, file_id or data_base64 holds the content.
# By URL
MediaRef(kind="url", url="https://cdn.example.com/image.png", mime_type="image/png")
# By provider file ID (OpenAI/Gemini uploaded file)
MediaRef(kind="file_id", file_id="file-abc123", mime_type="image/png")
# Inline base64 (small files only; prefer a media store for larger ones)
MediaRef(kind="data", data_base64="iVBORw0KGgo...", mime_type="image/png")Fields
| Field | Type | Description |
|---|---|---|
kind |
"url" | "file_id" | "data" |
Reference type discriminator. |
url |
str | None |
HTTP(S) URL or graph://media/{key} for offloaded media. |
file_id |
str | None |
Provider-managed file ID (OpenAI Files API, Gemini File API). |
data_base64 |
str | None |
Base64-encoded content. Use only for small payloads. |
mime_type |
str | None |
MIME type, e.g. "image/jpeg", "application/pdf". |
size_bytes |
int | None |
File size hint. |
sha256 |
str | None |
Content hash for integrity verification. |
filename |
str | None |
Original filename. |
width |
int | None |
Image width in pixels. |
height |
int | None |
Image height in pixels. |
duration_ms |
int | None |
Audio/video duration in milliseconds. |
page |
int | None |
Page number for documents. |
AnnotationRef
A pointer to the source of a citation or note, used by TextBlock.annotations and AnnotationBlock.refs.
AnnotationRef(url="https://arxiv.org/abs/2303.08774", title="GPT-4 Technical Report", page=1)| Field | Type | Description |
|---|---|---|
url |
str | None |
Source URL. |
file_id |
str | None |
File reference. |
page |
int | None |
Page number. |
index |
int | None |
Index position in the source. |
title |
str | None |
Display title. |
TokenUsages
Token counts for a single LLM response, stored on Message.usages.
usages = TokenUsages(
completion_tokens=150,
prompt_tokens=320,
total_tokens=470,
)| Field | Type | Default | Description |
|---|---|---|---|
completion_tokens |
int |
required | Tokens generated in the response. |
prompt_tokens |
int |
required | Tokens in the input prompt. |
total_tokens |
int |
required | Total tokens for the call, as reported by the provider. |
reasoning_tokens |
int |
0 |
Tokens used for extended reasoning (reasoning models). |
cache_creation_input_tokens |
int |
0 |
Prompt cache write tokens (Anthropic-style). |
cache_read_input_tokens |
int |
0 |
Prompt cache read tokens. |
image_tokens |
int | None |
0 |
Image modality tokens (multimodal models). |
audio_tokens |
int | None |
0 |
Audio modality tokens. |
Inspect the blocks in a message
Check block.type to narrow a block to its class and read its fields. This example builds a message in memory so it runs without a model.
from tenxgraph.core.state import Message
from tenxgraph.core.state.message_block import TextBlock, ToolCallBlock
msg = Message(
role="assistant",
content=[
TextBlock(text="Checking the weather."),
ToolCallBlock(id="call_1", name="get_weather", args={"location": "London"}),
],
)
for block in msg.content:
if block.type == "text":
print(block.text)
elif block.type == "tool_call":
print(f"Called {block.name}({block.args})")With a compiled graph, the same loop works on the messages in the result: result["messages"] after app.invoke(...). See State for the state object.