Concepts · ai
Messages
Message struct, roles, provenance, reading text, stop reasons, and the Prompt type
- Building or manipulating conversation history
- Working with message roles or content blocks
- Deciding what a reader may see and what only the model reads
This page gives the conversation message model used by the SDK. A Message carries content blocks, role metadata, and role-specific fields. Messages are the primary data structure that flows through the SDK.
Roles
The three roles are user, assistant, and tool_result. Role-specific fields use zero values when they do not apply. Assistant messages carry provider metadata and token usage. Tool result messages carry the call ID and tool name that they answer.
Design: flat struct with role-specific fields
The SDK uses one Message struct instead of separate role types. This keeps slices homogeneous as []Message. It simplifies serialization and matches the wire format of most provider APIs. The tradeoff is that some fields have no meaning for some roles. Go’s zero values handle that cleanly.
Provenance: where a message came from
Injected says who put a message in the history. The zero value, InjectionNone, means the caller or the model, so an ordinary message needs no thought. InjectionMeta and InjectionEphemeral both mean an injector added it. Origin names that injector, and the SDK never interprets it.
Three consumers read the one field and each applies its own rule:
| Consumer | InjectionNone | InjectionMeta | InjectionEphemeral |
|---|---|---|---|
| The model | reads | reads | reads |
| A reader | shows | hides | hides |
| A store | keeps | keeps | skips |
So the two injected flavors differ in one thing: durability. Meta survives a restart, and ephemeral does not. Use ephemeral for what is true only right now, such as a reminder built from live state.
Design: the flag is on the message, not on the entry that wraps it. A message reaches a UI as a stream event long before anything persists it. With the flag one layer up, on the session entry, a UI had no structured signal at all and had to guess from the text. See Entries.
Injected context can also ride inside an ordinary message, as an ai.Reminder block. Use that when part of the message is for the reader and part is not.
Reading the text of a message
Text() returns the blocks that carry text — the Text blocks and the Reminder blocks — as []ai.Content, in document order. JoinText(sep) joins those same blocks into one string.
Pick by what you are feeding:
- A provider, or any format that takes one string —
JoinText. The model reads injected context, so the joined result is correct. - A reader: a UI, a transcript, a rendered message — neither. Walk
Contentand keep theai.Textblocks. Both accessors return what the model reads.
Design: Text returns blocks so the caller keeps the choice. A string throws away which kind each block is, and that kind is exactly the decision above. The rule differs per caller, so it is not the SDK’s to make. See Messages (agent) for the full argument.
Constructors
Helper functions such as UserMessage, AssistantMessage, and ToolResultMessage set the correct role and timestamp. Prefer these helpers over direct Message literals.
Stop reasons
StopReason says why generation stopped. Values include natural completion, stop, token limit, length, tool use, tool_use, error, and context cancellation, aborted. The agent loop uses tool_use to decide whether to continue with another turn.
Prompt
Prompt bundles the inputs for a model call. It contains system prompt text, conversation history, and available tool definitions. It maps 1:1 to a provider API call. The agent builds it internally. Direct callers of StreamText and GenerateText construct it themselves.
JSON serialization
Custom MarshalJSON and UnmarshalJSON produce a clean wire format. Content blocks carry a type discriminator. Zero-valued fields are omitted, so an ordinary message writes no injected or origin key. Timestamps use RFC3339Nano. Server-tool calls round-trip the Server, ServerType, and Output fields on ToolCall. The Output field includes Content, Raw, and IsError. Persisted history replays with the same shape that providers produced.
Related
- Content — content block types, including
Reminder - Messages (agent) — how a hook adds a message, and why
Textreturns blocks - Usage — token usage carried on assistant messages
- Tools — tool calling and results