From 503caa6393635a56c672a6592747bcb6e034b8a1 Mon Sep 17 00:00:00 2001 From: Google Team Member Date: Wed, 4 Feb 2026 10:12:15 -0800 Subject: [PATCH] feat: Adding validation to BaseAgent and RunConfig PiperOrigin-RevId: 865462678 --- .../java/com/google/adk/agents/BaseAgent.java | 22 +++++++++++++++++++ .../java/com/google/adk/agents/RunConfig.java | 3 +++ .../com/google/adk/agents/BaseAgentTest.java | 15 +++++++++++++ .../com/google/adk/agents/RunConfigTest.java | 8 +++++++ 4 files changed, 48 insertions(+) diff --git a/core/src/main/java/com/google/adk/agents/BaseAgent.java b/core/src/main/java/com/google/adk/agents/BaseAgent.java index 255d59c4d..e7af0d1ea 100644 --- a/core/src/main/java/com/google/adk/agents/BaseAgent.java +++ b/core/src/main/java/com/google/adk/agents/BaseAgent.java @@ -16,7 +16,9 @@ package com.google.adk.agents; +import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.collect.ImmutableList.toImmutableList; +import static java.lang.String.format; import com.google.adk.agents.Callbacks.AfterAgentCallback; import com.google.adk.agents.Callbacks.BeforeAgentCallback; @@ -36,12 +38,17 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import java.util.regex.Pattern; import java.util.stream.Stream; import org.jspecify.annotations.Nullable; /** Base class for all agents. */ public abstract class BaseAgent { + // Pattern for valid agent names. + private static final String IDENTIFIER_REGEX = "^_?[a-zA-Z0-9]*([. _-][a-zA-Z0-9]+)*$"; + private static final Pattern IDENTIFIER_PATTERN = Pattern.compile(IDENTIFIER_REGEX); + /** The agent's name. Must be a unique identifier within the agent tree. */ private final String name; @@ -79,6 +86,7 @@ public BaseAgent( @Nullable List subAgents, @Nullable List beforeAgentCallback, @Nullable List afterAgentCallback) { + validateAgentName(name); this.name = name; this.description = description; this.parentAgent = null; @@ -96,6 +104,20 @@ public BaseAgent( } } + private static void validateAgentName(String name) { + if (isNullOrEmpty(name)) { + throw new IllegalArgumentException("Agent name cannot be null or empty."); + } + if (!IDENTIFIER_PATTERN.matcher(name).matches()) { + throw new IllegalArgumentException( + format("Agent name '%s' does not match regex '%s'.", name, IDENTIFIER_REGEX)); + } + if (name.equals("user")) { + throw new IllegalArgumentException( + "Agent name cannot be 'user'; reserved for end-user input."); + } + } + /** * Gets the agent's unique name. * diff --git a/core/src/main/java/com/google/adk/agents/RunConfig.java b/core/src/main/java/com/google/adk/agents/RunConfig.java index 308169e36..1ca203eaf 100644 --- a/core/src/main/java/com/google/adk/agents/RunConfig.java +++ b/core/src/main/java/com/google/adk/agents/RunConfig.java @@ -134,6 +134,9 @@ public abstract Builder setInputAudioTranscription( public RunConfig build() { RunConfig runConfig = autoBuild(); + if (runConfig.maxLlmCalls() == Integer.MAX_VALUE) { + throw new IllegalArgumentException("maxLlmCalls should be less than Integer.MAX_VALUE."); + } if (runConfig.maxLlmCalls() < 0) { logger.warn( "maxLlmCalls is negative. This will result in no enforcement on total" diff --git a/core/src/test/java/com/google/adk/agents/BaseAgentTest.java b/core/src/test/java/com/google/adk/agents/BaseAgentTest.java index dec66a77c..4afce04ee 100644 --- a/core/src/test/java/com/google/adk/agents/BaseAgentTest.java +++ b/core/src/test/java/com/google/adk/agents/BaseAgentTest.java @@ -17,6 +17,7 @@ package com.google.adk.agents; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import com.google.adk.agents.Callbacks.AfterAgentCallback; import com.google.adk.agents.Callbacks.BeforeAgentCallback; @@ -336,4 +337,18 @@ public void runLive_invokesRunLiveImpl() { assertThat(results.get(0).content()).hasValue(runLiveImplContent); assertThat(runLiveCallback.wasCalled()).isTrue(); } + + @Test + public void constructor_invalidName_throwsIllegalArgumentException() { + assertThrows( + IllegalArgumentException.class, + () -> new TestBaseAgent("invalid name?", "description", null, null, null)); + } + + @Test + public void constructor_userName_throwsIllegalArgumentException() { + assertThrows( + IllegalArgumentException.class, + () -> new TestBaseAgent("user", "description", null, null, null)); + } } diff --git a/core/src/test/java/com/google/adk/agents/RunConfigTest.java b/core/src/test/java/com/google/adk/agents/RunConfigTest.java index 7b6e7558f..1c416aa72 100644 --- a/core/src/test/java/com/google/adk/agents/RunConfigTest.java +++ b/core/src/test/java/com/google/adk/agents/RunConfigTest.java @@ -17,6 +17,7 @@ package com.google.adk.agents; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import com.google.common.collect.ImmutableList; import com.google.genai.types.AudioTranscriptionConfig; @@ -114,4 +115,11 @@ public void testInputAudioTranscriptionOnly() { assertThat(runConfig.streamingMode()).isEqualTo(RunConfig.StreamingMode.BIDI); assertThat(runConfig.responseModalities()).containsExactly(new Modality(Modality.Known.AUDIO)); } + + @Test + public void testMaxLlmCalls_integerMaxValue_throwsIllegalArgumentException() { + assertThrows( + IllegalArgumentException.class, + () -> RunConfig.builder().setMaxLlmCalls(Integer.MAX_VALUE).build()); + } }