Skip to content

Commit cc5263c

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: remove special handling for Gemini 3 function response ordering
PiperOrigin-RevId: 917837583
1 parent cc3b9ce commit cc5263c

7 files changed

Lines changed: 915 additions & 206 deletions

File tree

core/src/main/java/com/google/adk/flows/llmflows/BaseLlmFlow.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,8 @@ private Flowable<Event> buildPostprocessingEvents(
685685

686686
Event modelResponseEvent =
687687
buildModelResponseEvent(baseEventForLlmResponse, llmRequest, updatedResponse);
688-
if (modelResponseEvent.functionCalls().isEmpty()) {
688+
if (modelResponseEvent.functionCalls().isEmpty()
689+
|| modelResponseEvent.partial().orElse(false)) {
689690
return processorEvents.concatWith(Flowable.just(modelResponseEvent));
690691
}
691692

core/src/main/java/com/google/adk/flows/llmflows/Contents.java

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,6 @@ public Single<RequestProcessor.RequestProcessingResult> processRequest(
5757
}
5858
LlmAgent llmAgent = (LlmAgent) context.agent();
5959

60-
String modelName;
61-
try {
62-
modelName = llmAgent.resolvedModel().modelName().orElse("");
63-
} catch (IllegalStateException e) {
64-
modelName = "";
65-
}
66-
6760
ImmutableList<Event> sessionEvents;
6861
synchronized (context.session().events()) {
6962
sessionEvents = ImmutableList.copyOf(context.session().events());
@@ -75,17 +68,13 @@ public Single<RequestProcessor.RequestProcessingResult> processRequest(
7568
request.toBuilder()
7669
.contents(
7770
getCurrentTurnContents(
78-
context.branch().orElse(null),
79-
sessionEvents,
80-
context.agent().name(),
81-
modelName))
71+
context.branch().orElse(null), sessionEvents, context.agent().name()))
8272
.build(),
8373
ImmutableList.of()));
8474
}
8575

8676
ImmutableList<Content> contents =
87-
getContents(
88-
context.branch().orElse(null), sessionEvents, context.agent().name(), modelName);
77+
getContents(context.branch().orElse(null), sessionEvents, context.agent().name());
8978

9079
return Single.just(
9180
RequestProcessor.RequestProcessingResult.create(
@@ -94,19 +83,19 @@ public Single<RequestProcessor.RequestProcessingResult> processRequest(
9483

9584
/** Gets contents for the current turn only (no conversation history). */
9685
private ImmutableList<Content> getCurrentTurnContents(
97-
@Nullable String currentBranch, List<Event> events, String agentName, String modelName) {
86+
@Nullable String currentBranch, List<Event> events, String agentName) {
9887
// Find the latest event that starts the current turn and process from there.
9988
for (int i = events.size() - 1; i >= 0; i--) {
10089
Event event = events.get(i);
10190
if (event.author().equals("user") || isOtherAgentReply(agentName, event)) {
102-
return getContents(currentBranch, events.subList(i, events.size()), agentName, modelName);
91+
return getContents(currentBranch, events.subList(i, events.size()), agentName);
10392
}
10493
}
10594
return ImmutableList.of();
10695
}
10796

10897
private ImmutableList<Content> getContents(
109-
@Nullable String currentBranch, List<Event> events, String agentName, String modelName) {
98+
@Nullable String currentBranch, List<Event> events, String agentName) {
11099
List<Event> filteredEvents = new ArrayList<>();
111100
boolean hasCompactEvent = false;
112101

@@ -148,7 +137,7 @@ private ImmutableList<Content> getContents(
148137
}
149138

150139
List<Event> resultEvents = rearrangeEventsForLatestFunctionResponse(filteredEvents);
151-
resultEvents = rearrangeEventsForAsyncFunctionResponsesInHistory(resultEvents, modelName);
140+
resultEvents = rearrangeEventsForAsyncFunctionResponsesInHistory(resultEvents);
152141

153142
return resultEvents.stream()
154143
.map(Event::content)
@@ -564,8 +553,7 @@ private static List<Event> rearrangeEventsForLatestFunctionResponse(List<Event>
564553
return resultEvents;
565554
}
566555

567-
private static List<Event> rearrangeEventsForAsyncFunctionResponsesInHistory(
568-
List<Event> events, String modelName) {
556+
private static List<Event> rearrangeEventsForAsyncFunctionResponsesInHistory(List<Event> events) {
569557
Map<String, Integer> functionCallIdToResponseEventIndex = new HashMap<>();
570558
for (int i = 0; i < events.size(); i++) {
571559
final int index = i;
@@ -592,11 +580,6 @@ private static List<Event> rearrangeEventsForAsyncFunctionResponsesInHistory(
592580
List<Event> resultEvents = new ArrayList<>();
593581
// Keep track of response events already added to avoid duplicates when merging
594582
Set<Integer> processedResponseIndices = new HashSet<>();
595-
List<Event> responseEventsBuffer = new ArrayList<>();
596-
597-
// Gemini 3 requires function calls to be grouped first and only then function responses:
598-
// FC1 FC2 FR1 FR2
599-
boolean shouldBufferResponseEvents = modelName.contains("gemini-3");
600583

601584
for (int i = 0; i < events.size(); i++) {
602585
Event event = events.get(i);
@@ -641,47 +624,21 @@ private static List<Event> rearrangeEventsForAsyncFunctionResponsesInHistory(
641624

642625
for (int index : sortedIndices) {
643626
if (processedResponseIndices.add(index)) { // Add index and check if it was newly added
644-
responseEventsBuffer.add(events.get(index));
645627
responseEventsToAdd.add(events.get(index));
646628
}
647629
}
648630

649-
if (!shouldBufferResponseEvents) {
650-
if (responseEventsToAdd.size() == 1) {
651-
resultEvents.add(responseEventsToAdd.get(0));
652-
} else if (responseEventsToAdd.size() > 1) {
653-
resultEvents.add(mergeFunctionResponseEvents(responseEventsToAdd));
654-
}
631+
if (responseEventsToAdd.size() == 1) {
632+
resultEvents.add(responseEventsToAdd.get(0));
633+
} else if (responseEventsToAdd.size() > 1) {
634+
resultEvents.add(mergeFunctionResponseEvents(responseEventsToAdd));
655635
}
656636
}
657637
} else {
658-
// gemini-3 specific part: buffer response events
659-
if (shouldBufferResponseEvents) {
660-
if (!responseEventsBuffer.isEmpty()) {
661-
if (responseEventsBuffer.size() == 1) {
662-
resultEvents.add(responseEventsBuffer.get(0));
663-
} else {
664-
resultEvents.add(mergeFunctionResponseEvents(responseEventsBuffer));
665-
}
666-
responseEventsBuffer.clear();
667-
}
668-
}
669638
resultEvents.add(event);
670639
}
671640
}
672641

673-
// gemini-3 specific part: buffer response events
674-
if (shouldBufferResponseEvents) {
675-
if (!responseEventsBuffer.isEmpty()) {
676-
if (responseEventsBuffer.size() == 1) {
677-
resultEvents.add(responseEventsBuffer.get(0));
678-
} else {
679-
resultEvents.add(mergeFunctionResponseEvents(responseEventsBuffer));
680-
}
681-
responseEventsBuffer.clear();
682-
}
683-
}
684-
685642
return resultEvents;
686643
}
687644

0 commit comments

Comments
 (0)