static GenerateContentResponse aggregateStreamIntoResponse(
      ResponseStream<GenerateContentResponse> responseStream) {
    GenerateContentResponse res = GenerateContentResponse.getDefaultInstance();
    Map<Integer, Candidate> candidates = new HashMap<>();
    Map<Integer, List<Part>> aggregatedContentParts = new HashMap<>();
    Map<Integer, List<Citation>> aggregatedCitationMetadata = new HashMap<>();

    for (GenerateContentResponse response : responseStream) {
      res = response;
      for (Candidate candidate : response.getCandidatesList()) {
        // Keep track of candidates by index
        int index = candidate.getIndex();
        candidates.put(index, candidate);

        // Aggregates parts
        if (candidate.hasContent()) {
          List<Part> parts = candidate.getContent().getPartsList();
          List<Part> aggregatedParts =
              aggregatedContentParts.containsKey(index)
                  ? aggregatedContentParts.get(index)
                  : new ArrayList<>();
          if (aggregatedParts.size() == 0 || parts.size() == 0) {
            aggregatedParts.addAll(parts);
          } else {
            Part aggregatedTailPart = aggregatedParts.get(aggregatedParts.size() - 1);
            Part currentResponseHeadPart = parts.get(0);
            if (!aggregatedTailPart.hasText() || !currentResponseHeadPart.hasText()) {
              aggregatedParts.addAll(parts);
            } else {
              aggregatedParts.remove(aggregatedParts.size() - 1);
              aggregatedParts.add(
                  Part.newBuilder()
                      .setText(aggregatedTailPart.getText() + currentResponseHeadPart.getText())
                      .build());
              aggregatedParts.addAll(parts.subList(1, parts.size()));
            }
          }
          aggregatedContentParts.put(index, aggregatedParts);
        }

        // Aggregates citations
        if (candidate.hasCitationMetadata()) {
          List<Citation> citations = candidate.getCitationMetadata().getCitationsList();
          List<Citation> aggregatedCitations =
              aggregatedCitationMetadata.containsKey(index)
                  ? aggregatedCitationMetadata.get(index)
                  : new ArrayList<>();
          aggregatedCitations.addAll(citations);
          aggregatedCitationMetadata.put(index, aggregatedCitations);
        }
      }
    }

    // Update candidates with aggregated data
    List<Candidate> aggregatedCandidates = new ArrayList<>();
    candidates.forEach(
        (index, candidate) -> {
          Candidate.Builder candidateBuilder = candidate.toBuilder();
          if (aggregatedContentParts.containsKey(index)) {
            candidateBuilder.setContent(
                Content.newBuilder()
                    .setRole("model")
                    .addAllParts(aggregatedContentParts.get(index)));
          }
          if (aggregatedCitationMetadata.containsKey(index)) {
            candidateBuilder.setCitationMetadata(
                CitationMetadata.newBuilder()
                    .addAllCitations(aggregatedCitationMetadata.get(index)));
          }
          aggregatedCandidates.add(candidateBuilder.build());
        });

    res = res.toBuilder().clearCandidates().addAllCandidates(aggregatedCandidates).build();

    return res;
  }
Aggregates a stream of responses into a single GenerateContentResponse.
java-vertexai/google-cloud-vertexai/src/main/java/com/google/cloud/vertexai/generativeai/ResponseHandler.java