pub struct StreamEnd {
pub rid: Option<String>,
pub msg_id: Option<String>,
pub revision: Option<u64>,
pub content: String,
pub metadata: StreamMetadata,
pub finish_reason: String,
pub is_final: bool,
pub subagent: Option<String>,
}Expand description
Done streaming.
A single send/regen can emit multiple StreamEnd frames when the
daemon is running a tool loop: one per LLM turn, so clients can render
tool calls as they happen. Only the frame with is_final = true marks
the end of the whole generation — clients that want the final aggregated
result (e.g. collect_stream) must keep reading until they see it.
Older servers that predate the field will serialize nothing; serde’s
default treats missing as true, preserving pre-tool-loop semantics.
Fields§
§rid: Option<String>§msg_id: Option<String>Persisted assistant message id for terminal stream ends.
Present only after the final assistant message has been appended and persisted. Intermediate tool-use boundaries and older servers omit it.
revision: Option<u64>Durable history revision containing msg_id.
content: String§metadata: StreamMetadata§finish_reason: StringWhy the model stopped: “end_turn”, “tool_use”, “max_tokens”, etc.
is_final: boolWhether this is the final StreamEnd for the generation. Intermediate
tool-loop boundaries set this to false; the terminal StreamEnd sets
it to true. Defaults to true so pre-field daemon frames are treated
as terminal (matching historical single-turn behavior).
subagent: Option<String>Sub-agent name when this boundary is from a nested ask_<name> loop; see
StreamStart::subagent. A sub-agent never emits a terminal
(is_final = true) frame, so a tagged StreamEnd never ends the primary
generation.