Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.adk.events.Event;
import com.google.adk.events.EventActions;
import com.google.adk.events.ToolConfirmation;
import com.google.adk.models.FunctionCallIds;
import com.google.adk.telemetry.Instrumentation;
import com.google.adk.telemetry.Instrumentation.ToolExecution;
import com.google.adk.telemetry.Tracing;
Expand Down Expand Up @@ -60,7 +61,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -72,12 +72,11 @@ public final class Functions {
/** Session state key for storing the security policy outcomes for tool calls. */
public static final String TOOL_CALL_SECURITY_STATES = "adk_tool_call_security_states";

private static final String AF_FUNCTION_CALL_ID_PREFIX = "adk-";
private static final Logger logger = LoggerFactory.getLogger(Functions.class);

/** Generates a unique ID for a function call. */
public static String generateClientFunctionCallId() {
return AF_FUNCTION_CALL_ID_PREFIX + UUID.randomUUID();
return FunctionCallIds.generateClientFunctionCallId();
}

/**
Expand Down
38 changes: 38 additions & 0 deletions core/src/main/java/com/google/adk/models/FunctionCallIds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.adk.models;

import java.util.UUID;

/** Constants and helpers for ADK-generated function call IDs. */
public final class FunctionCallIds {

/** Prefix marking function call IDs the ADK generated client-side. */
private static final String AF_FUNCTION_CALL_ID_PREFIX = "adk-";

/** Returns a new client-side function call ID with the ADK prefix. */
public static String generateClientFunctionCallId() {
return AF_FUNCTION_CALL_ID_PREFIX + UUID.randomUUID();
}

/** Returns whether {@code id} was generated client-side by the ADK. */
public static boolean isClientGeneratedFunctionCallId(String id) {
return id != null && id.startsWith(AF_FUNCTION_CALL_ID_PREFIX);
}

private FunctionCallIds() {}
}
9 changes: 2 additions & 7 deletions core/src/main/java/com/google/adk/models/Gemini.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -401,13 +400,9 @@ private static List<Part> ensureFunctionCallIds(List<Part> parts) {
return result;
}

/**
* Generates a unique client-side function-call ID. Format matches {@code
* com.google.adk.flows.llmflows.Functions#generateClientFunctionCallId()} so downstream code
* that already sees IDs with the {@code "adk-"} prefix continues to work.
*/
/** Generates a unique client-side function-call ID. */
private static String generateClientFunctionCallId() {
return "adk-" + UUID.randomUUID();
return FunctionCallIds.generateClientFunctionCallId();
}

/**
Expand Down
7 changes: 3 additions & 4 deletions core/src/main/java/com/google/adk/models/GeminiUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ public final class GeminiUtil {
"Continue output. DO NOT look at this line. ONLY look at the content before this line and"
+ " system instruction.";

private static final String AF_FUNCTION_CALL_ID_PREFIX = "adk-";

private GeminiUtil() {}

/**
Expand Down Expand Up @@ -174,14 +172,15 @@ public static LlmRequest removeClientFunctionCallId(LlmRequest llmRequest) {
private static Part removeClientFunctionCallIdFromPart(Part part) {
if (part.functionCall().isPresent()
&& part.functionCall().get().id().isPresent()
&& part.functionCall().get().id().get().startsWith(AF_FUNCTION_CALL_ID_PREFIX)) {
&& FunctionCallIds.isClientGeneratedFunctionCallId(part.functionCall().get().id().get())) {
return part.toBuilder()
.functionCall(part.functionCall().get().toBuilder().clearId().build())
.build();
}
if (part.functionResponse().isPresent()
&& part.functionResponse().get().id().isPresent()
&& part.functionResponse().get().id().get().startsWith(AF_FUNCTION_CALL_ID_PREFIX)) {
&& FunctionCallIds.isClientGeneratedFunctionCallId(
part.functionResponse().get().id().get())) {
return part.toBuilder()
.functionResponse(part.functionResponse().get().toBuilder().clearId().build())
.build();
Expand Down
52 changes: 52 additions & 0 deletions core/src/test/java/com/google/adk/models/FunctionCallIdsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.adk.models;

import static com.google.common.truth.Truth.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class FunctionCallIdsTest {

@Test
public void generatedId_isRecognizedAsClientGenerated() {
String id = FunctionCallIds.generateClientFunctionCallId();

assertThat(FunctionCallIds.isClientGeneratedFunctionCallId(id)).isTrue();
}

@Test
public void generateClientFunctionCallId_returnsUniqueIds() {
String first = FunctionCallIds.generateClientFunctionCallId();
String second = FunctionCallIds.generateClientFunctionCallId();

assertThat(first).isNotEqualTo(second);
}

@Test
public void isClientGeneratedFunctionCallId_falseForModelGeneratedId() {
assertThat(FunctionCallIds.isClientGeneratedFunctionCallId("call_123")).isFalse();
}

@Test
public void isClientGeneratedFunctionCallId_falseForNullOrEmpty() {
assertThat(FunctionCallIds.isClientGeneratedFunctionCallId(null)).isFalse();
assertThat(FunctionCallIds.isClientGeneratedFunctionCallId("")).isFalse();
}
}
Loading