completeStream method
Sends a completion request and returns a stream of chunks.
Implementation
@override
Stream<AIStreamChunk> completeStream(
List<AIMessage> messages, {
int? maxTokens,
double? temperature,
List<AITool>? tools,
}) async* {
final body =
_buildRequestBody(messages, maxTokens, temperature, tools: tools);
final url =
'$_baseUrl/models/${config.model}:streamGenerateContent?alt=sse&key=${config.apiKey}';
final request = http.Request('POST', Uri.parse(url));
request.headers['Content-Type'] = 'application/json';
request.body = jsonEncode(body);
final streamedResponse = await _httpClient.send(request);
if (streamedResponse.statusCode != 200) {
final responseBody = await streamedResponse.stream.bytesToString();
final json = jsonDecode(responseBody) as Map<String, dynamic>;
throw _parseError(streamedResponse.statusCode, json);
}
await for (final chunk in streamedResponse.stream
.transform(utf8.decoder)
.transform(const LineSplitter())) {
if (chunk.isEmpty) continue;
if (!chunk.startsWith('data: ')) continue;
final jsonStr = chunk.substring(6);
try {
final json = jsonDecode(jsonStr) as Map<String, dynamic>;
final candidates = json['candidates'] as List? ?? [];
if (candidates.isEmpty) continue;
final candidate = candidates.first as Map<String, dynamic>;
final content = candidate['content'] as Map<String, dynamic>?;
final parts = (content?['parts'] as List?) ?? [];
final text = parts
.map((p) => (p as Map<String, dynamic>)['text'] as String? ?? '')
.join();
final finishReason = candidate['finishReason'] as String?;
AIUsage? usage;
final usageMetadata = json['usageMetadata'] as Map<String, dynamic>?;
if (usageMetadata != null) {
usage = AIUsage(
promptTokens: usageMetadata['promptTokenCount'] as int? ?? 0,
completionTokens:
usageMetadata['candidatesTokenCount'] as int? ?? 0,
);
}
if (text.isNotEmpty) {
yield AIStreamChunk(
text: text,
isComplete: finishReason == 'STOP',
finishReason: finishReason,
usage: usage,
provider: name,
model: config.model,
);
}
} on FormatException catch (_) {
// Skip malformed JSON chunks
}
}
}