ConverseStream returns the same Bedrock event union you already handle:
messageStart → contentBlockStart → contentBlockDelta → contentBlockStop → messageStop → metadata. Under the hood the gateway streams server-sent events;
the SDK translates each chunk into typed Bedrock events, and the final
metadata event always carries token usage and latency.
Streams are never cut off by the request timeout — the timeout applies only
until response headers arrive, so long generations run to completion.
stream_response = client.converse_stream(
modelId="gpt-5.4-mini",
messages=[{"role": "user", "content": [{"text": "Write me a haiku."}]}],
)
for event in stream_response["stream"]: # boto3 parity: response["stream"]
if "contentBlockDelta" in event:
delta = event["contentBlockDelta"]["delta"]
print(delta.get("text", ""), end="", flush=True)
import { ConverseStreamCommand } from "@audacity/sdk";
const { stream } = await client.send(
new ConverseStreamCommand({
modelId: "gpt-5.4-mini",
messages: [{ role: "user", content: [{ text: "Tell me a story" }] }],
})
);
for await (const event of stream) {
if ("contentBlockDelta" in event) {
const delta = event.contentBlockDelta.delta;
if ("text" in delta) process.stdout.write(delta.text);
}
}
streamResp, err := client.ConverseStream(ctx, &audacityruntime.ConverseStreamInput{
ModelId: audacity.String("gpt-5.4-mini"),
Messages: []types.Message{{
Role: types.ConversationRoleUser,
Content: []types.ContentBlock{&types.ContentBlockMemberText{Value: "Tell me a story"}},
}},
})
if err != nil {
log.Fatal(err)
}
stream := streamResp.GetStream()
defer stream.Close()
for event := range stream.Events() {
switch e := event.(type) {
case *types.ConverseStreamOutputMemberContentBlockDelta:
if td, ok := e.Value.Delta.(*types.ContentBlockDeltaMemberText); ok {
fmt.Print(td.Value)
}
case *types.ConverseStreamOutputMemberMetadata:
fmt.Printf("\n[tokens in=%d out=%d latency=%dms]\n",
e.Value.Usage.InputTokens, e.Value.Usage.OutputTokens, e.Value.Metrics.LatencyMs)
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
// Push handler (AWS SDK v2 style)
client.converseStream(
request -> request
.modelId("gpt-5.4-mini")
.messages(Message.builder()
.role(ConversationRole.USER)
.content(ContentBlock.fromText("Tell me a short story."))
.build()),
ConverseStreamHandler.builder()
.onContentBlockDelta(e -> {
if (e.delta().text() != null) System.out.print(e.delta().text());
})
.onMessageStop(e -> System.out.println("\nStop: " + e.stopReason()))
.onMetadata(e -> System.out.printf("Tokens: %d%n", e.usage().totalTokens()))
.build());
// Or a pull-based iterator:
try (var iter = client.converseStreamIterator(request -> request
.modelId("gpt-5.4-mini")
.messages(Message.builder()
.role(ConversationRole.USER)
.content(ContentBlock.fromText("Hello!"))
.build()))) {
while (iter.hasNext()) {
ConverseStreamOutput event = iter.next();
// handle event
}
}
use audacity_sdk::ConverseStreamOutput;
let mut output = client.converse_stream()
.model_id("gpt-5.4-mini")
.messages(
Message::builder()
.role(ConversationRole::User)
.content(ContentBlock::Text("Tell me a joke".into()))
.build()?
)
.send()
.await?;
while let Some(event) = output.stream.recv().await? {
if let ConverseStreamOutput::ContentBlockDelta(e) = event {
if let audacity_sdk::ContentBlockDeltaPayload::Text(t) = e.delta {
print!("{t}");
}
}
}