Stream Text
streamText returns an AsyncThrowingStream<AIStreamChunk, Error>. Each chunk contains text and may include usage or finish reason when the provider emits final metadata.
| Need | Use |
|---|---|
| Append text into a view model | Iterate the returned stream and update state per chunk |
| Track analytics | Use onChunk for first-token timing and onFinish for usage |
| Cancel generation | Cancel the Swift Task that is consuming the stream |
| Smooth local demos | Wrap a model with streaming utilities |
| Chat state | Use AIChat when the UI is a normal message list |
Basic Stream
var output = ""
for try await chunk in streamText(
model: model,
prompt: "Write a calm loading message for a finance dashboard."
) {
output += chunk.text
}Use this in SwiftUI by appending chunks to @State, an @Observable view model, or the built-in AIChat helper.
Callbacks
Callbacks are useful when you want side effects without moving all work into the for await loop.
let stream = streamText(
model: model,
prompt: "Generate a three-line release summary.",
onChunk: { chunk in
print("chunk:", chunk.text)
},
onFinish: { response in
print("tokens:", response.usage?.totalTokens ?? 0)
print("finish:", response.finishReason ?? "unknown")
}
)
for try await chunk in stream {
print(chunk.text, terminator: "")
}onFinish receives the accumulated AIResponse.
Cancellation
There is no separate abort object. Use normal Swift task cancellation.
let task = Task {
for try await chunk in streamText(model: model, prompt: "Write a long story.") {
print(chunk.text, terminator: "")
}
}
task.cancel()Provider requests and local stream helpers check cancellation as they yield.
Streaming Chat History
Streaming models also support chat history:
let messages = [
ChatMessage(role: .system, content: "Answer like a concise support engineer."),
ChatMessage(role: .user, content: "Why did my export fail?")
]
for try await chunk in model.stream(messages: messages) {
print(chunk.text, terminator: "")
}Use message management when history needs pruning.