Skip to main content
Conversations & Sessions

Streaming Output

By default, a model's reply is delivered as a single complete message at the end of each turn. With streaming output enabled, the SDK pushes fine-grained incremental chunks as the model generates them — useful for typewriter effects, or for rendering reasoning and tool-invocation progress separately.

Enable

Enable partial messages in options (includePartialMessages in TypeScript, include_partial_messages in Python, includePartialMessages(true) in Java):
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Write a short analysis report',
  options: {
    auth: qodercliAuth(),
    includePartialMessages: true,
  },
});
Java has no typed stream events. Incremental chunks arrive as PartialMessage, and you parse the event from rawJson(). The Java examples below use a delta(...) helper to extract the event's delta object; the next two sections reuse it.

Typewriter effect

The model's text reply arrives as a sequence of incremental chunks; printing each chunk as it lands gives a typewriter effect:
for await (const msg of q) {
  if (msg.type === 'stream_event') {
    const delta = msg.event.delta;
    if (delta?.type === 'text_delta') {
      process.stdout.write(delta.text);
    }
  }
}

Reasoning

Reasoning-capable models emit "thinking" chunks before their final reply:
if (delta?.type === 'thinking_delta') {
  process.stdout.write(delta.thinking);
}

Tool invocation arguments

Tool-call arguments are also generated incrementally — for example, you can use this to render the file content the model is writing in real time:
if (delta?.type === 'input_json_delta') {
  process.stdout.write(delta.partial_json);
}

Push consumption (Java)

The Java examples above pull messages one at a time with a cursor. You can also let the SDK push them: messages().consume(handler, executor) calls the handler on the given executor for each message in order, delivering the next message only after the previous one is handled. The returned stage completes normally when the stream ends.
Java
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
    query.messages().consume(msg -> {
        if (msg instanceof PartialMessage) {
            JsonObject delta = delta((PartialMessage) msg);
            if (JsonString.of("text_delta").equals(delta.get("type"))) {
                System.out.print(delta.get("text").asString());
            }
        }
    }, executor).toCompletableFuture().join();
} finally {
    executor.shutdown();
}
Each message stream can be consumed only once. Use either a cursor or consume(); a second subscription throws MessageStreamAlreadyConsumedException. If the handler throws, the stage returned by consume() completes with CallbackExecutionException and the owning query or session is closed. Do not block inside the handler, and do not call the blocking close() there. For the full event structure, see SDK References. For Java message types, see Message Types.