pub enum Block {
Text {
text: String,
},
Thinking {
text: String,
signature: Option<String>,
},
ToolUse {
id: String,
name: String,
input: Value,
},
ToolResult {
tool_use_id: String,
content: String,
is_error: bool,
},
Image {
media_type: String,
data: String,
source: Option<String>,
},
}Expand description
One piece of a message. A single assistant turn is often several blocks: thinking, then text, then one or more tool calls.
PartialEq because session recording decides between “append the new
tail” and “the transcript was rewritten in place” by comparing the
messages a run started from with what it left behind.
Variants§
Text
Thinking
Reasoning. signature is opaque and must be echoed back unchanged when
continuing on the same model.
ToolUse
ToolResult
Image
An image the user put in front of the model.
User turns only, and that is a portability decision rather than a
simplification. Anthropic accepts an image inside a tool_result;
the OpenAI dialect’s role: "tool" messages carry a string and
nothing else, and llama-server is the same. A tool that returned
pixels would therefore work on one backend and silently lose them on
the other — the shape of failure this project keeps finding, in the
one place where the missing thing is what the whole turn was about.
So an image enters the conversation the way a person hands one over,
and encode_message renders it only on a user message.
Not every model has eyes. Provider::vision says whether the one on
the other end does, and a backend that cannot see renders this block
as a line of text naming the file instead — so a run against a
text-only model behaves exactly as it did before this variant
existed, rather than failing on a request it cannot serve.
Fields
media_type: StringAn IANA media type: image/png, image/jpeg, image/gif,
image/webp. Both providers require it and neither sniffs.
data: StringBase64, with no data: prefix. The prefix is a rendering
detail of the OpenAI dialect — anthropic.rs wants the payload
bare — so it belongs to the backend that needs it and not to the
type every backend shares.
source: Option<String>What the file was called where it came from.
Never sent to a provider. It exists because every human-facing
reader of a transcript — mecha sessions, the TUI, recall —
otherwise has a megabyte of base64 and no way to say what it was.
It is also what the text-only rendering names.
Implementations§
Source§impl Block
impl Block
pub fn text(s: impl Into<String>) -> Self
Sourcepub fn image(
media_type: impl Into<String>,
bytes: &[u8],
source: Option<String>,
) -> Self
pub fn image( media_type: impl Into<String>, bytes: &[u8], source: Option<String>, ) -> Self
An image block from raw file bytes.
One encoder, so the data: prefix question is answered once: what
goes in is bare base64, and the one dialect that wants a prefix adds
it at the wire.
Sourcepub fn image_placeholder(media_type: &str, source: Option<&str>) -> String
pub fn image_placeholder(media_type: &str, source: Option<&str>) -> String
How a person, or a model with no eyes, is told an image was here.
Shared so the text-only provider rendering and every transcript reader say the same thing. A reader that invented its own wording would be a second answer to “what was in this turn”.