Stream Event
Sealed event stream emitted by LanguageModel.stream and surfaced to application code via Agent.stream. Mirrors the v6 stream-part taxonomy (per packages/ai/src/generate-text/stream-text-result.ts in vercel/ai) adapted to Kotlin sealed classes for exhaustive when.
v6 organizes blocks (text, reasoning, tool input) with block IDs so a single message can interleave multiple separate text segments, reasoning blocks, and tool calls without merging them. Each *-start event opens a block by ID; *-delta events grow it; *-end closes it.
providerMetadata (per historical parity gap #11) rides on every content + tool-lifecycle variant — the Map<String, JsonElement>? escape hatch v6 uses for provider-specific payloads (Anthropic thinking signatures + cache_control, OpenAI reasoning effort / logprobs, prompt-cache hints). On-device LiteRT-LM leaves it null; it's the slot a cloud provider fills. Excluded from the pure control singletons (StreamStart, Abort), the terminal Error, and Raw (whose rawValue already IS the provider payload).
Sequence the model can produce in one step:
StreamStart(warnings)
StepStart
TextStart("t1") → TextDelta("t1", "...") → TextEnd("t1")
ReasoningStart("r1") → ReasoningDelta("r1", "...") → ReasoningEnd("r1")
ToolInputStart("ti1", "weather") → ToolInputDelta("ti1", "{...") → ToolInputEnd("ti1")
ToolCall("call_1", "weather", inputJson)
[ToolApprovalRequest("call_1", "weather", inputJson) → loop ends]
[or] ToolResult("call_1", "weather", outputJson)
[or] ToolError("call_1", "weather", message)
TextStart("t2") → TextDelta(...) → TextEnd("t2")
SourcePart(...) → FilePart(...)
Raw(...) — provider-specific escape hatch
StepFinish(stepNumber, finishReason, usage)
...
Finish(totalSteps, finishReason, usage)
Abort | Error — terminal alternativesInheritors
Types
Generation aborted via AbortSignal. Loop unwinds.
Wire-protocol mapping helpers for ai.torad.aisdk.ui.ToUIMessageStream: the StreamEvent→chunk dispatch table plus the JSON-chunk builder and finish-reason mapping. Member-extensions so callers use a member-import, not a loose top-level fn.
Custom UI data part. Encodes to the v6 UI-message chunk shape { type: "data-$name", id?, data, transient? }.
Terminal error. Loop unwinds.
Generated file (image, audio, etc.).
Loop ended — final aggregated finish reason + usage.
Unprocessed provider-specific chunk. Escape hatch for cutting-edge provider features that the SDK doesn't yet wrap in a typed event. Off by default — providers opt in via call params. rawValue already IS the provider payload, so no separate providerMetadata slot.
Provider response metadata that becomes available after the stream request starts. Mirrors v6's response-metadata stream part so StreamTextResult.response can expose IDs, timestamps, model IDs, headers, and retained response bodies.
Citation / web grounding source.
Step ended — aggregated finish reason + usage for that one step. Per historical parity gap #18 (slice), providerMetadata carries provider-specific payloads (Anthropic prompt-cache hints, OpenAI reasoning trace tokens, etc.) so consumers can
New step (one LLM call) began. Emitted at the start of every loop iteration.
Stream began. Emitted exactly once at the very top.
Tool requires approval. Per v6 RPC semantics, the loop ends after emitting this event — the corresponding ai.torad.aisdk.ContentPart.ToolApprovalRequest is added to the assistant message in the result, and the host calls Agent.generate again with a tool message containing ai.torad.aisdk.ContentPart.ToolApprovalResponse to resume.
Final, parsed tool call envelope. Emitted once ToolInputEnd fires and JSON parses.
Tool execution failed. error carries the typed AgentError (NoSuchTool / InvalidToolInput / ToolExecution / ToolCallRepairFailed) so in-process consumers can when (event.error) instead of substring-matching message. @Transient — it's dropped on serialization (AgentError isn't @Serializable); message is the wire-stable rendering and stays the single source of display text.
Incremental input bytes for the in-flight tool call.
Tool input streaming ends — full JSON has been received.
Tool input streaming opens — the model has decided which tool to call.
The host denied a previously requested approval. v6's tool-output-denied (per historical parity gaps #6 + #7). Distinct from ToolError — denial is a CHOICE, not a failure. The matching UI part transitions through ai.torad.aisdk.ui.ToolCallState.OutputDenied.
Tool execution emitted a result. By default this is the final result — appended to the model's message log + dispatched to UI converters.