chatStream method

  1. @override
Stream<ChatStreamEvent> chatStream(
  1. List<ChatMessage> messages, {
  2. List<Tool>? tools,
})
override

Sends a streaming chat request to the provider

messages - The conversation history as a list of chat messages tools - Optional list of tools to use in the chat

Returns a stream of chat events

Implementation

@override
Stream<ChatStreamEvent> chatStream(
  List<ChatMessage> messages, {
  List<Tool>? tools,
}) async* {
  try {
    final requestBody = buildRequestBody(messages, tools, true);

    // Optimized trace logging with condition check
    if (_logger.isLoggable(Level.FINEST)) {
      _logger.finest(
          '$providerName stream request payload: ${jsonEncode(requestBody)}');
    }

    // Log request headers and body for debugging
    if (_logger.isLoggable(Level.FINE)) {
      _logger.fine('$providerName stream request: POST $chatEndpoint');
      _logger.fine(
          '$providerName stream request headers: ${_dio.options.headers}');
    }
    if (_logger.isLoggable(Level.FINE)) {
      _logger.fine(
          '$providerName stream request body: ${jsonEncode(requestBody)}');
    }

    final response = await _dio.post(
      chatEndpoint,
      data: requestBody,
      options: Options(responseType: ResponseType.stream),
    );

    _logger.fine('$providerName stream HTTP status: ${response.statusCode}');

    if (response.statusCode != 200) {
      yield ErrorEvent(
        ProviderError(
            '$providerName API returned status ${response.statusCode}'),
      );
      return;
    }

    final stream = response.data as ResponseBody;

    await for (final chunk in stream.stream.map(utf8.decode)) {
      try {
        // Debug logging for Google provider
        if (providerName == 'Google') {
          _logger.fine('$providerName raw stream chunk: $chunk');
        }

        final events = parseStreamEvents(chunk);
        for (final event in events) {
          yield event;
        }
      } catch (e) {
        // Skip malformed chunks but log them
        _logger.warning('Failed to parse stream chunk: $e');
        _logger.warning('Raw chunk content: $chunk');
        continue;
      }
    }
  } on DioException catch (e) {
    yield ErrorEvent(handleDioError(e));
  } catch (e) {
    yield ErrorEvent(GenericError('Unexpected error: $e'));
  }
}