Skip to content

Commit d204294

Browse files
google-genai-botcopybara-github
authored andcommitted
fix: Ensure function call ID is populated before building list of long running function calls
PiperOrigin-RevId: 784745132
1 parent 9bd2bd6 commit d204294

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import com.google.adk.tools.ToolContext;
4040
import com.google.common.collect.ImmutableList;
4141
import com.google.common.collect.Iterables;
42-
import com.google.genai.types.FunctionCall;
4342
import com.google.genai.types.FunctionResponse;
4443
import io.opentelemetry.api.trace.Span;
4544
import io.opentelemetry.api.trace.StatusCode;
@@ -621,11 +620,10 @@ private Event buildModelResponseEvent(
621620

622621
Event event = eventBuilder.build();
623622

624-
ImmutableList<FunctionCall> functionCalls = event.functionCalls();
625-
if (!functionCalls.isEmpty()) {
623+
if (!event.functionCalls().isEmpty()) {
626624
Functions.populateClientFunctionCallId(event);
627625
Set<String> longRunningToolIds =
628-
Functions.getLongRunningFunctionCalls(functionCalls, llmRequest.tools());
626+
Functions.getLongRunningFunctionCalls(event.functionCalls(), llmRequest.tools());
629627
if (!longRunningToolIds.isEmpty()) {
630628
event.setLongRunningToolIds(Optional.of(longRunningToolIds));
631629
}

core/src/test/java/com/google/adk/flows/llmflows/BaseLlmFlowTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,39 @@ public void run_withFunctionCallsAndMaxSteps_stopsAfterMaxSteps() {
135135
Content.fromParts(Part.fromFunctionResponse("my_function", testResponse)));
136136
}
137137

138+
@Test
139+
public void run_withLongRunningFunctionCall_returnsCorrectEventsWithLongRunningToolIds() {
140+
Content firstContent =
141+
Content.fromParts(
142+
Part.fromText("LLM response with function call"),
143+
Part.fromFunctionCall("my_function", ImmutableMap.of("arg1", "value1")));
144+
Content secondContent =
145+
Content.fromParts(Part.fromText("LLM response after function response"));
146+
TestLlm testLlm =
147+
createTestLlm(
148+
Flowable.just(createLlmResponse(firstContent)),
149+
Flowable.just(createLlmResponse(secondContent)));
150+
ImmutableMap<String, Object> testResponse =
151+
ImmutableMap.<String, Object>of("response", "response for my_function");
152+
InvocationContext invocationContext =
153+
createInvocationContext(
154+
createTestAgentBuilder(testLlm)
155+
.tools(ImmutableList.of(new TestLongRunningTool("my_function", testResponse)))
156+
.build());
157+
BaseLlmFlow baseLlmFlow = createBaseLlmFlowWithoutProcessors();
158+
159+
List<Event> events = baseLlmFlow.run(invocationContext).toList().blockingGet();
160+
161+
assertThat(events).hasSize(3);
162+
assertEqualIgnoringFunctionIds(events.get(0).content().get(), firstContent);
163+
assertThat(events.get(0).longRunningToolIds().get())
164+
.contains(events.get(0).functionCalls().get(0).id().get());
165+
assertEqualIgnoringFunctionIds(
166+
events.get(1).content().get(),
167+
Content.fromParts(Part.fromFunctionResponse("my_function", testResponse)));
168+
assertThat(events.get(2).content()).hasValue(secondContent);
169+
}
170+
138171
@Test
139172
public void run_withRequestProcessor_doesNotModifyRequest() {
140173
Content content = Content.fromParts(Part.fromText("LLM response"));
@@ -293,4 +326,23 @@ public Single<Map<String, Object>> runAsync(Map<String, Object> args, ToolContex
293326
return Single.just(response);
294327
}
295328
}
329+
330+
private static class TestLongRunningTool extends BaseTool {
331+
private final Map<String, Object> response;
332+
333+
TestLongRunningTool(String name, Map<String, Object> response) {
334+
super(name, "tool description for " + name, /* isLongRunning= */ true);
335+
this.response = response;
336+
}
337+
338+
@Override
339+
public Optional<FunctionDeclaration> declaration() {
340+
return Optional.of(FunctionDeclaration.builder().name(name()).build());
341+
}
342+
343+
@Override
344+
public Single<Map<String, Object>> runAsync(Map<String, Object> args, ToolContext toolContext) {
345+
return Single.just(response);
346+
}
347+
}
296348
}

0 commit comments

Comments
 (0)