chatStream method
Stream<ChatStreamEvent>
chatStream(
- List<
ChatMessage> messages, { - List<
Tool> ? tools, - CancelToken? cancelToken,
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
cancelToken
- Optional token to cancel the stream
Returns a stream of chat events
Implementation
@override
Stream<ChatStreamEvent> chatStream(
List<ChatMessage> messages, {
List<Tool>? tools,
CancelToken? cancelToken,
}) 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),
cancelToken: cancelToken,
);
_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'));
}
}