Streaming

Display tokens as the model generates them for a responsive UI, rather than waiting for the complete response.

agent.stream()

agent.stream() returns an AsyncStream<StreamEvent>. Iterate it with for try await to receive events as they happen:

Swift
for try await event in agent.stream("Explain how TCP/IP works") {
    switch event {
    case .textDelta(let token):
        print(token, terminator: "")   // each token as it arrives
    case .result(let final):
        print("\n\nDone.")
    default:
        break
    }
}

Stream Events

The StreamEvent enum covers every stage of the agent loop:

CaseWhen it firesAssociated value
.textDelta(String)Each token of model text outputThe token string
.toolUse(ToolUseBlock)Model decides to call a toolTool name + input
.toolResult(ToolResultBlock)Tool execution completesStatus + output content
.cycleComplete(CycleMetrics)One reasoning cycle finishesLatency, token counts
.result(AgentResult)Final response readyFull result + metrics
.error(Error)Unrecoverable errorThe error

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 event in agent.stream("Write a short poem about Swift") {
                if case .textDelta(let token) = event {
                    response += token
                }
            }
        } catch {
            response = "Error: \(error.localizedDescription)"
        }
        isStreaming = false
    }
}

Showing Tool Activity

Use .toolUse and .toolResult events to give users visibility into what the agent is doing:

Swift
@State private var statusLine = ""

for try await event in agent.stream(prompt) {
    switch event {
    case .textDelta(let token):
        response += token
    case .toolUse(let use):
        statusLine = "Calling \(use.name)…"
    case .toolResult(let res):
        statusLine = res.status == .success ? "Tool completed" : "Tool failed"
    case .result:
        statusLine = ""
    default:
        break
    }
}

Collecting Metrics

The final .result event carries the same AgentResult as a non-streaming run() call, including full metrics:

Swift
for try await event in agent.stream(prompt) {
    if case .result(let final) = event {
        print("Cycles: \(final.metrics.cycleCount)")
        print("Latency: \(final.metrics.totalLatencyMs)ms")
        print("Tokens/sec: \(final.metrics.outputTokensPerSecond)")
        print("Total tokens: \(final.usage.totalTokens)")
    }
}