Streaming
Display tokens as the model generates them for a responsive UI, rather than waiting for the complete response.
agent.streamText()
The simplest way to stream. Yields every visible token (both thinking and response) as a plain String:
Swift
for try await text in agent.streamText("Explain how TCP/IP works") {
print(text, terminator: "")
}
print()
SwiftUI Example
Stream tokens into a @State variable for a typewriter effect:
ContentView.swiftSwift
import SwiftUI
import StrandsAgents
struct ContentView: View {
@State private var response = ""
@State private var isStreaming = false
let agent = Agent(model: provider)
var body: some View {
VStack(alignment: .leading, spacing: 16) {
ScrollView {
Text(response)
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
}
Button(isStreaming ? "Streaming..." : "Ask Agent") {
Task { await ask() }
}
.disabled(isStreaming)
}
}
func ask() async {
isStreaming = true
response = ""
do {
for try await text in agent.streamText("Write a short poem about Swift") {
response += text
}
} catch {
response = "Error: \(error.localizedDescription)"
}
isStreaming = false
}
}
agent.stream()
For more control, agent.stream() returns an AsyncThrowingStream<AgentStreamEvent> with typed events for each stage of the agent loop:
| Case | When it fires | Associated value |
|---|---|---|
.textDelta(String) | Each token of model text output | The token string |
.thinkingDelta(String) | Each token inside a thinking block | The token string |
.toolResult(ToolResultBlock) | Tool execution completes | Status + output content |
.contentBlock(ContentBlock) | A complete content block finishes | Text, tool use, or reasoning block |
.modelMessage(Message) | Full model message assembled | The complete message |
.result(AgentResult) | Final response ready | Full result + metrics |
Use this when you want to separate thinking from response, show tool activity, or collect metrics:
Swift
for try await event in agent.stream(prompt) {
switch event {
case .textDelta(let text):
response += text
case .thinkingDelta(let text):
thinkingLog += text
case .toolResult(let result):
statusLine = "Tool \(result.status)"
case .result(let final):
print("Latency: \(final.metrics.totalLatencyMs)ms")
print("Tokens: \(final.usage.totalTokens)")
default:
break
}
}