@@ -223,9 +223,24 @@ public Flowable<LlmResponse> generateContent(LlmRequest llmRequest, boolean stre
223223 effectiveModelName , llmRequest .contents (), config );
224224
225225 return Flowable .defer (
226- () ->
227- processRawResponses (
228- Flowable .fromFuture (streamFuture ).flatMapIterable (iterable -> iterable )));
226+ () ->
227+ processRawResponses (
228+ Flowable .fromFuture (streamFuture ).flatMapIterable (iterable -> iterable )))
229+ .filter (
230+ llmResponse ->
231+ llmResponse
232+ .content ()
233+ .flatMap (Content ::parts )
234+ .map (
235+ parts ->
236+ !parts .isEmpty ()
237+ && parts .stream ()
238+ .anyMatch (
239+ p ->
240+ p .functionCall ().isPresent ()
241+ || p .functionResponse ().isPresent ()
242+ || p .text ().map (t -> !t .isBlank ()).orElse (false )))
243+ .orElse (false ));
229244 } else {
230245 logger .debug ("Sending generateContent request to model {}" , effectiveModelName );
231246 return Flowable .fromFuture (
@@ -253,15 +268,16 @@ static Flowable<LlmResponse> processRawResponses(Flowable<GenerateContentRespons
253268 Optional <Part > part = GeminiUtil .getPart0FromLlmResponse (currentProcessedLlmResponse );
254269 String currentTextChunk = part .flatMap (Part ::text ).orElse ("" );
255270
256- if (!currentTextChunk .isEmpty ()) {
271+ if (!currentTextChunk .isBlank ()) {
257272 if (part .get ().thought ().orElse (false )) {
258273 accumulatedThoughtText .append (currentTextChunk );
274+ responsesToEmit .add (
275+ thinkingResponseFromText (currentTextChunk ).toBuilder ().partial (true ).build ());
259276 } else {
260277 accumulatedText .append (currentTextChunk );
278+ responsesToEmit .add (
279+ responseFromText (currentTextChunk ).toBuilder ().partial (true ).build ());
261280 }
262- LlmResponse partialResponse =
263- currentProcessedLlmResponse .toBuilder ().partial (true ).build ();
264- responsesToEmit .add (partialResponse );
265281 } else {
266282 if (accumulatedThoughtText .length () > 0
267283 && GeminiUtil .shouldEmitAccumulatedText (currentProcessedLlmResponse )) {
@@ -284,22 +300,28 @@ static Flowable<LlmResponse> processRawResponses(Flowable<GenerateContentRespons
284300 .concatWith (
285301 Flowable .defer (
286302 () -> {
287- if (accumulatedText .length () > 0 && lastRawResponseHolder [0 ] != null ) {
288- GenerateContentResponse finalRawResp = lastRawResponseHolder [0 ];
289- boolean isStop =
290- finalRawResp
291- .candidates ()
292- .flatMap (candidates -> candidates .stream ().findFirst ())
293- .flatMap (Candidate ::finishReason )
294- .map (
295- finishReason -> finishReason .knownEnum () == FinishReason .Known .STOP )
296- .orElse (false );
297-
298- if (isStop ) {
299- LlmResponse finalAggregatedTextResponse =
300- responseFromText (accumulatedText .toString ());
301- return Flowable .just (finalAggregatedTextResponse );
303+ GenerateContentResponse finalRawResp = lastRawResponseHolder [0 ];
304+ if (finalRawResp == null ) {
305+ return Flowable .empty ();
306+ }
307+ boolean isStop =
308+ finalRawResp
309+ .candidates ()
310+ .flatMap (candidates -> candidates .stream ().findFirst ())
311+ .flatMap (Candidate ::finishReason )
312+ .map (finishReason -> finishReason .knownEnum () == FinishReason .Known .STOP )
313+ .orElse (false );
314+
315+ if (isStop ) {
316+ List <LlmResponse > finalResponses = new ArrayList <>();
317+ if (accumulatedThoughtText .length () > 0 ) {
318+ finalResponses .add (
319+ thinkingResponseFromText (accumulatedThoughtText .toString ()));
320+ }
321+ if (accumulatedText .length () > 0 ) {
322+ finalResponses .add (responseFromText (accumulatedText .toString ()));
302323 }
324+ return Flowable .fromIterable (finalResponses );
303325 }
304326 return Flowable .empty ();
305327 }));
0 commit comments