stream method

  1. @override
Stream<ChatChunk> stream(
  1. ChatRequest request, {
  2. AgenticContext? context,
})
override

Generates an answer incrementally.

The stream ends after a chunk with a ChatChunk.finishReason. Cancelling the subscription must close the underlying connection: an abandoned streaming request that keeps generating is billed in full.

Collect the result with stream(request).collect() when you want the streaming transport but not the incremental updates.

Implementation

@override
Stream<ChatChunk> stream(
  ChatRequest request, {
  AgenticContext? context,
}) async* {
  _requests.add(request);
  if (latency > Duration.zero) {
    await (context?.clock ?? const SystemClock()).delay(latency);
  }
  context?.throwIfCancelled();

  final turn = _nextTurn();
  if (turn.error case final error?) throw error;

  if (turn.chunks case final chunks?) {
    for (final chunk in chunks) {
      context?.throwIfCancelled();
      yield chunk;
    }
    return;
  }

  final response = turn.response!;
  final message = response.message;
  if (message.reasoning case final reasoning?) {
    yield ChatChunk.reasoning(reasoning);
  }
  // Split into words so a test can observe more than one chunk without the
  // script having to spell them out.
  for (final word in _wordsOf(message.text)) {
    context?.throwIfCancelled();
    yield ChatChunk.text(word);
  }
  for (var i = 0; i < message.toolCalls.length; i++) {
    final call = message.toolCalls[i];
    yield ChatChunk.tool(
      ToolCallDelta(
        index: i,
        id: call.id,
        name: call.name,
        argumentsDelta: call.argumentsJson,
      ),
    );
  }
  yield ChatChunk(
    finishReason: response.finishReason,
    usage: response.usage,
    modelId: response.modelId,
  );
}