AIMessagePart
One step an AI agent took while replying, such as a round of reasoning or a tool call.
The agent writes each step as a custom attachment on its reply (ai_reasoning, ai_tool_call), and the order of the attachments is the order of the steps. The final answer stays in the message text and is shown after them.
The kinds of step are open: a new one can appear without breaking your code. Read the ones you know through their typed views (reasoning, toolCall), read kinds of your own from payload, and give anything else a neutral fallback (AIMessagePartItem shows a placeholder). Decoding is lenient: missing fields get defaults, and a step newer than this SDK understands keeps its payload but has no typed view.
// Stream Chat Android moves an attachment's `name` out of `extraData`, so put it back.
val parts = AIMessagePart.parts(
message.attachments.map { it.type.orEmpty() to it.extraData + ("name" to it.name) },
)
for (part in parts) {
part.reasoning?.let { /* … */}
part.toolCall?.let { /* … */}
if (part.kind == AIMessagePart.Kind("ai_citation")) { /* read part.payload */}
}Types
Properties
Whether this SDK has a typed view of the step. A step that is not, from a newer agent or of a kind of your own, still keeps its payload.
What kind of step this is.
The step as a round of reasoning, when it is one this SDK can read.
The step as a tool call, when it is one this SDK can read.