From 3967cfa6297530e8274fad4ab0ec833525c2db69 Mon Sep 17 00:00:00 2001 From: Damian Momot Date: Thu, 16 Jul 2026 06:42:26 -0700 Subject: [PATCH 01/14] fix: confine config-driven dynamic class loading to intended types Config-driven loaders confine every reflectively loaded class to the intended type (BaseTool, BaseToolset, BaseExampleProvider, or the caller's expectedType) before constructing it or reading a static field, so a non-intended type is never instantiated nor its static initializer run (type-confinement, not a sandbox). CompiledAgentLoader also gains source-dir confinement (adk.agents.confine-to-source-dir), keeping compiled agents within source-dir. Type confinement is on by default; source-dir confinement is off by default (with a warning) to avoid breaking existing setups, and will default on in a future release. PiperOrigin-RevId: 948941874 --- .../com/google/adk/agents/ToolResolver.java | 12 ++ .../com/google/adk/tools/ExampleTool.java | 6 + .../google/adk/agents/ToolResolverTest.java | 118 ++++++++++++++++++ .../com/google/adk/tools/ExampleToolTest.java | 28 +++++ .../google/adk/web/CompiledAgentLoader.java | 43 +++++++ .../web/config/AgentLoadingProperties.java | 13 ++ .../adk/web/CompiledAgentLoaderTest.java | 77 ++++++++++++ .../java/com/google/adk/maven/WebMojo.java | 17 ++- 8 files changed, 311 insertions(+), 3 deletions(-) create mode 100644 dev/src/test/java/com/google/adk/web/CompiledAgentLoaderTest.java diff --git a/core/src/main/java/com/google/adk/agents/ToolResolver.java b/core/src/main/java/com/google/adk/agents/ToolResolver.java index 09a3d79c1..ad2b1b7b7 100644 --- a/core/src/main/java/com/google/adk/agents/ToolResolver.java +++ b/core/src/main/java/com/google/adk/agents/ToolResolver.java @@ -273,6 +273,7 @@ static BaseToolset resolveToolsetFromClass( // Try reflection to get class try { Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className); + // Confine to BaseToolset: a non-intended type is never constructed (not a sandbox). if (BaseToolset.class.isAssignableFrom(clazz)) { toolsetClass = clazz.asSubclass(BaseToolset.class); // Optimization: register for reuse @@ -349,6 +350,11 @@ static BaseToolset resolveToolsetInstanceViaReflection(String toolsetName) try { Field field = clazz.getField(fieldName); + // Confine to BaseToolset before field.get() runs its static initializer (not a sandbox). + if (!BaseToolset.class.isAssignableFrom(field.getType())) { + logger.debug("Field {} in class {} is not a BaseToolset field", fieldName, className); + return null; + } if (!Modifier.isStatic(field.getModifiers())) { logger.debug("Field {} in class {} is not static", fieldName, className); return null; @@ -398,6 +404,7 @@ static BaseTool resolveToolFromClass(String className, ToolArgsConfig args, Stri // Try reflection to get class try { Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className); + // Confine to BaseTool: a non-intended type is never constructed (not a sandbox). if (BaseTool.class.isAssignableFrom(clazz)) { toolClass = clazz.asSubclass(BaseTool.class); // Optimization: register for reuse @@ -495,6 +502,11 @@ static BaseTool resolveInstanceViaReflection(String toolName) try { Field field = clazz.getField(fieldName); + // Confine to BaseTool before field.get() runs its static initializer (not a sandbox). + if (!BaseTool.class.isAssignableFrom(field.getType())) { + logger.debug("Field {} in class {} is not a BaseTool field", fieldName, className); + return null; + } if (!Modifier.isStatic(field.getModifiers())) { logger.debug("Field {} in class {} is not static", fieldName, className); return null; diff --git a/core/src/main/java/com/google/adk/tools/ExampleTool.java b/core/src/main/java/com/google/adk/tools/ExampleTool.java index c11259c52..0184c3593 100644 --- a/core/src/main/java/com/google/adk/tools/ExampleTool.java +++ b/core/src/main/java/com/google/adk/tools/ExampleTool.java @@ -135,6 +135,12 @@ private static BaseExampleProvider resolveExampleProvider(String ref) try { Class clazz = Thread.currentThread().getContextClassLoader().loadClass(className); Field field = clazz.getField(fieldName); + // Confine to BaseExampleProvider before field.get() runs its static initializer (not a + // sandbox). + if (!BaseExampleProvider.class.isAssignableFrom(field.getType())) { + throw new ConfigurationException( + "Field '" + fieldName + "' in class '" + className + "' is not a BaseExampleProvider"); + } if (!Modifier.isStatic(field.getModifiers())) { throw new ConfigurationException( "Field '" + fieldName + "' in class '" + className + "' is not static"); diff --git a/core/src/test/java/com/google/adk/agents/ToolResolverTest.java b/core/src/test/java/com/google/adk/agents/ToolResolverTest.java index b4bd70491..c3834ff00 100644 --- a/core/src/test/java/com/google/adk/agents/ToolResolverTest.java +++ b/core/src/test/java/com/google/adk/agents/ToolResolverTest.java @@ -29,6 +29,7 @@ import com.google.genai.types.FunctionDeclaration; import io.reactivex.rxjava3.core.Flowable; import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -209,6 +210,67 @@ public void testResolveToolInstance_withInvalidReflectionPath_returnsNull() { assertThat(resolved).isNull(); } + @Test + public void resolveInstanceViaReflection_nonIntendedType_isRejectedWithoutInitializing() + throws Exception { + // A non-intended type (not a BaseTool) is rejected before the field is read, so its static + // initializer never runs. + String toolName = NonToolWithStaticInit.class.getName() + ".NOT_A_TOOL"; + + BaseTool resolved = ToolResolver.resolveInstanceViaReflection(toolName); + + assertThat(resolved).isNull(); + assertThat(nonToolInitFired.get()).isFalse(); + } + + @Test + public void resolveToolInstance_nonIntendedType_isRejectedWithoutInitializing() { + // Same guarantee through the public resolveToolInstance entry point. + String toolName = NonToolWithStaticInit.class.getName() + ".NOT_A_TOOL"; + + BaseTool resolved = ToolResolver.resolveToolInstance(toolName); + + assertThat(resolved).isNull(); + assertThat(nonToolInitFired.get()).isFalse(); + } + + @Test + public void resolveToolsetInstanceViaReflection_nonIntendedType_isRejectedWithoutInitializing() + throws Exception { + String toolsetName = NonToolsetWithStaticInit.class.getName() + ".NOT_A_TOOLSET"; + + BaseToolset resolved = ToolResolver.resolveToolsetInstanceViaReflection(toolsetName); + + assertThat(resolved).isNull(); + assertThat(nonToolsetInitFired.get()).isFalse(); + } + + @Test + public void resolveInstanceViaReflection_properToolType_stillLoadsEvenWithSideEffects() + throws Exception { + // This guard is type-confinement, not a sandbox: a proper BaseTool type is still loaded and its + // static initializer still runs. Only non-intended types are rejected. + String toolName = SideEffectingProperTool.class.getName() + ".INSTANCE"; + + BaseTool resolved = ToolResolver.resolveInstanceViaReflection(toolName); + + assertThat(resolved).isNotNull(); + assertThat(properToolInitFired.get()).isTrue(); + } + + @Test + public void resolveInstanceViaReflection_holderClassWithToolField_stillResolves() + throws Exception { + // A non-tool holder class exposing a BaseTool-typed static field is still supported (mirrors + // module-level instance references), since the field type is confined to BaseTool. + String toolName = ToolHolder.class.getName() + ".HELD_TOOL"; + + BaseTool resolved = ToolResolver.resolveInstanceViaReflection(toolName); + + assertThat(resolved).isNotNull(); + assertThat(resolved).isSameInstanceAs(ToolHolder.HELD_TOOL); + } + @Test public void testResolveToolFromClass_withFromConfigMethod() throws Exception { String className = TestToolWithFromConfig.class.getName(); @@ -451,6 +513,62 @@ public static final class TestClassWithNonToolField { private TestClassWithNonToolField() {} } + // Side-effect channels flipped by the helper classes' static initializers. They live on the test + // class so assertions can observe them without touching (and thereby initializing) those classes. + private static final AtomicBoolean nonToolInitFired = new AtomicBoolean(false); + private static final AtomicBoolean nonToolsetInitFired = new AtomicBoolean(false); + private static final AtomicBoolean properToolInitFired = new AtomicBoolean(false); + + /** Non-intended type (not a BaseTool) with a side-effecting static initializer. */ + public static final class NonToolWithStaticInit { + public static final String NOT_A_TOOL = "not a tool"; + + static { + nonToolInitFired.set(true); + } + + private NonToolWithStaticInit() {} + } + + /** Non-intended type (not a BaseToolset) with a side-effecting static initializer. */ + public static final class NonToolsetWithStaticInit { + public static final String NOT_A_TOOLSET = "not a toolset"; + + static { + nonToolsetInitFired.set(true); + } + + private NonToolsetWithStaticInit() {} + } + + /** + * A proper BaseTool type with a side-effecting static initializer. Documents that the guard is + * type-confinement, not a sandbox: a class of the intended type is still loaded and initialized. + */ + public static final class SideEffectingProperTool extends BaseTool { + public static final SideEffectingProperTool INSTANCE = new SideEffectingProperTool(); + + static { + properToolInitFired.set(true); + } + + private SideEffectingProperTool() { + super("side_effecting_tool", "Proper tool with a side-effecting static initializer"); + } + + @Override + public Optional declaration() { + return Optional.empty(); + } + } + + /** Non-tool holder exposing a BaseTool-typed static field (module-style reference). */ + public static final class ToolHolder { + public static final BaseTool HELD_TOOL = new TestToolWithDefaultConstructor(); + + private ToolHolder() {} + } + private BaseTool.ToolConfig createToolConfig(String name, BaseTool.ToolArgsConfig args) { return new BaseTool.ToolConfig(name, args); } diff --git a/core/src/test/java/com/google/adk/tools/ExampleToolTest.java b/core/src/test/java/com/google/adk/tools/ExampleToolTest.java index e56afe60b..7f06407fc 100644 --- a/core/src/test/java/com/google/adk/tools/ExampleToolTest.java +++ b/core/src/test/java/com/google/adk/tools/ExampleToolTest.java @@ -33,6 +33,7 @@ import com.google.genai.types.Content; import com.google.genai.types.Part; import io.reactivex.rxjava3.core.Flowable; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -306,6 +307,33 @@ static final class WrongTypeProviderHolder { private WrongTypeProviderHolder() {} } + // Side-effect channel flipped by the helper class's static initializer. It lives on the test + // class so the assertion can observe it without initializing that class. + private static final AtomicBoolean nonProviderInitFired = new AtomicBoolean(false); + + /** Non-intended type (not a BaseExampleProvider) with a side-effecting static initializer. */ + static final class NonProviderWithStaticInit { + public static final String NOT_A_PROVIDER = "not a provider"; + + static { + nonProviderInitFired.set(true); + } + + private NonProviderWithStaticInit() {} + } + + @Test + public void fromConfig_withNonIntendedType_isRejectedWithoutInitializing() { + BaseTool.ToolArgsConfig args = new BaseTool.ToolArgsConfig(); + args.setAdditionalProperty( + "examples", ExampleToolTest.NonProviderWithStaticInit.class.getName() + ".NOT_A_PROVIDER"); + + // A non-intended type is rejected before the field is read, so its static initializer never + // runs. A proper BaseExampleProvider would still load, even if it were modified. + assertThrows(ConfigurationException.class, () -> ExampleTool.fromConfig(args)); + assertThat(nonProviderInitFired.get()).isFalse(); + } + @Test public void declaration_isEmpty() { ExampleTool tool = ExampleTool.builder().build(); diff --git a/dev/src/main/java/com/google/adk/web/CompiledAgentLoader.java b/dev/src/main/java/com/google/adk/web/CompiledAgentLoader.java index 7e7146c20..87f250d8f 100644 --- a/dev/src/main/java/com/google/adk/web/CompiledAgentLoader.java +++ b/dev/src/main/java/com/google/adk/web/CompiledAgentLoader.java @@ -18,6 +18,7 @@ import com.google.adk.agents.BaseAgent; import com.google.adk.web.config.AgentLoadingProperties; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -74,6 +75,9 @@ * */ @Service("agentLoader") @@ -94,6 +98,13 @@ public CompiledAgentLoader(AgentLoadingProperties properties) { // Load path-based agents if (properties.getSourceDir() != null && !properties.getSourceDir().isEmpty()) { + if (!properties.isConfineToSourceDir()) { + logger.warn( + "Directory confinement is disabled (adk.agents.confine-to-source-dir=false); compiled" + + " agents may be loaded from outside the configured source-dir via symlinks or" + + " build-output dirs. Set adk.agents.confine-to-source-dir=true to restrict" + + " loading to the source tree."); + } loadPathBasedAgents(allAgents); } else { logger.warn( @@ -220,6 +231,10 @@ private void loadAgentsFromDirectory(Path directory, Map files = Files.list(directory)) { diff --git a/dev/src/main/java/com/google/adk/web/config/AgentLoadingProperties.java b/dev/src/main/java/com/google/adk/web/config/AgentLoadingProperties.java index 85631a0ae..bfdbca50e 100644 --- a/dev/src/main/java/com/google/adk/web/config/AgentLoadingProperties.java +++ b/dev/src/main/java/com/google/adk/web/config/AgentLoadingProperties.java @@ -26,6 +26,11 @@ public class AgentLoadingProperties { private String sourceDir = "."; private String[] buildOutputDirs = {"target/classes", "build/classes/java/main", "build/classes"}; + // When true, compiled agents are only loaded from within sourceDir, so a build-output dir or + // symlink cannot escape it. Off by default to preserve existing behavior (a warning is logged + // while disabled); a no-op for normal layouts, which already live under sourceDir. + private boolean confineToSourceDir = false; + public String getSourceDir() { return sourceDir; } @@ -41,4 +46,12 @@ public String[] getBuildOutputDirs() { public void setBuildOutputDirs(String[] buildOutputDirs) { this.buildOutputDirs = buildOutputDirs; } + + public boolean isConfineToSourceDir() { + return confineToSourceDir; + } + + public void setConfineToSourceDir(boolean confineToSourceDir) { + this.confineToSourceDir = confineToSourceDir; + } } diff --git a/dev/src/test/java/com/google/adk/web/CompiledAgentLoaderTest.java b/dev/src/test/java/com/google/adk/web/CompiledAgentLoaderTest.java new file mode 100644 index 000000000..ddefbbeb4 --- /dev/null +++ b/dev/src/test/java/com/google/adk/web/CompiledAgentLoaderTest.java @@ -0,0 +1,77 @@ +/* + * 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.web; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.adk.web.config.AgentLoadingProperties; +import java.nio.file.Files; +import java.nio.file.Path; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** Tests for {@link CompiledAgentLoader}, focused on the opt-in directory confinement. */ +public class CompiledAgentLoaderTest { + + @Test + public void confineToSourceDir_defaultsOff() { + // Off by default to preserve existing behavior; a warning is logged recommending it be enabled. + assertFalse(new AgentLoadingProperties().isConfineToSourceDir()); + } + + @Test + public void isDirWithinSourceRoot_confinementOff_allowsOutsideDir(@TempDir Path tmp) + throws Exception { + Path root = Files.createDirectory(tmp.resolve("root")); + Path outside = Files.createDirectory(tmp.resolve("outside")); + CompiledAgentLoader loader = newLoader(root, /* confine= */ false); + + assertTrue(loader.isDirWithinSourceRoot(outside)); + } + + @Test + public void isDirWithinSourceRoot_confinementOn_blocksOutsideAllowsInside(@TempDir Path tmp) + throws Exception { + Path root = Files.createDirectory(tmp.resolve("root")); + Path inside = Files.createDirectories(root.resolve("target").resolve("classes")); + Path outside = Files.createDirectory(tmp.resolve("outside")); + CompiledAgentLoader loader = newLoader(root, /* confine= */ true); + + assertTrue(loader.isDirWithinSourceRoot(inside)); + assertFalse(loader.isDirWithinSourceRoot(outside)); + } + + @Test + public void isDirWithinSourceRoot_confinementOn_blocksSymlinkEscape(@TempDir Path tmp) + throws Exception { + Path root = Files.createDirectory(tmp.resolve("root")); + Path outside = Files.createDirectory(tmp.resolve("outside")); + // A symlink inside the source root that points outside it must not be accepted. + Path escape = Files.createSymbolicLink(root.resolve("escape"), outside); + CompiledAgentLoader loader = newLoader(root, /* confine= */ true); + + assertFalse(loader.isDirWithinSourceRoot(escape)); + } + + private static CompiledAgentLoader newLoader(Path sourceDir, boolean confine) { + AgentLoadingProperties props = new AgentLoadingProperties(); + props.setSourceDir(sourceDir.toString()); + props.setConfineToSourceDir(confine); + return new CompiledAgentLoader(props); + } +} diff --git a/maven_plugin/src/main/java/com/google/adk/maven/WebMojo.java b/maven_plugin/src/main/java/com/google/adk/maven/WebMojo.java index 97c3f1e4a..78935155a 100644 --- a/maven_plugin/src/main/java/com/google/adk/maven/WebMojo.java +++ b/maven_plugin/src/main/java/com/google/adk/maven/WebMojo.java @@ -376,6 +376,16 @@ private T tryLoadFromStaticField(String classAndField, Class expectedType Class clazz = projectClassLoader.loadClass(className); Field field = clazz.getField(fieldName); + // Confine to expectedType before field.get() runs its static initializer (not a sandbox). + if (!expectedType.isAssignableFrom(field.getType())) { + throw new MojoExecutionException( + "Field " + + fieldName + + " in class " + + className + + " is not an instance of " + + expectedType.getSimpleName()); + } Object instance = field.get(null); if (!expectedType.isInstance(instance)) { throw new MojoExecutionException( @@ -410,12 +420,13 @@ private T tryLoadFromConstructor(String className, Class expectedType) throws MojoExecutionException { try { Class clazz = projectClassLoader.loadClass(className); - Object instance = clazz.getDeclaredConstructor().newInstance(); - if (!expectedType.isInstance(instance)) { + // Confine to expectedType before constructing it (not a sandbox). + if (!expectedType.isAssignableFrom(clazz)) { throw new MojoExecutionException( "Class " + className + " does not implement/extend " + expectedType.getSimpleName()); } - return expectedType.cast(instance); + // The isAssignableFrom check above guarantees the constructed instance is an expectedType. + return expectedType.cast(clazz.getDeclaredConstructor().newInstance()); } catch (ClassNotFoundException e) { throw new MojoExecutionException( From ba23601c09927c4827f3a62d5df8e637e2df33d6 Mon Sep 17 00:00:00 2001 From: Google Team Member Date: Thu, 16 Jul 2026 17:36:13 -0700 Subject: [PATCH 02/14] feat: Update 'gen_ai.usage.input_tokens' to include tool used tokens to match python ADK PiperOrigin-RevId: 949268862 --- .../com/google/adk/telemetry/Tracing.java | 10 ++- .../adk/telemetry/ContextPropagationTest.java | 69 +++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/google/adk/telemetry/Tracing.java b/core/src/main/java/com/google/adk/telemetry/Tracing.java index d57e46c54..226d7011c 100644 --- a/core/src/main/java/com/google/adk/telemetry/Tracing.java +++ b/core/src/main/java/com/google/adk/telemetry/Tracing.java @@ -336,9 +336,13 @@ public static void traceCallLlm( .usageMetadata() .ifPresent( usage -> { - usage - .promptTokenCount() - .ifPresent(tokens -> span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, (long) tokens)); + if (usage.promptTokenCount().isPresent() + || usage.toolUsePromptTokenCount().isPresent()) { + span.setAttribute( + GEN_AI_USAGE_INPUT_TOKENS, + (long) usage.promptTokenCount().orElse(0) + + usage.toolUsePromptTokenCount().orElse(0)); + } // According to OpenTelemetry Semantic Conventions: // https://github.com/open-telemetry/semantic-conventions/blob/v1.41.0/docs/registry/attributes/gen-ai.md // gen_ai.usage.reasoning.output_tokens (thoughts_token_count) SHOULD be included in diff --git a/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java b/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java index ecfba4995..33810f081 100644 --- a/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java +++ b/core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java @@ -463,6 +463,75 @@ public void testTraceCallLlm_withReasoningAndCacheTokens() { 15L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.reasoning.output_tokens"))); } + @Test + public void testTraceCallLlm_withToolUsePromptTokens() { + Span span = tracer.spanBuilder("test-tool-use-prompt").startSpan(); + try (Scope scope = span.makeCurrent()) { + LlmRequest llmRequest = + LlmRequest.builder() + .model("gemini-pro") + .contents(ImmutableList.of(Content.fromParts(Part.fromText("hello")))) + .config(GenerateContentConfig.builder().topP(0.9f).maxOutputTokens(100).build()) + .build(); + LlmResponse llmResponse = + LlmResponse.builder() + .content(Content.builder().parts(Part.fromText("world")).build()) + .finishReason(new FinishReason(FinishReason.Known.STOP)) + .usageMetadata( + GenerateContentResponseUsageMetadata.builder() + .promptTokenCount(10) + .toolUsePromptTokenCount(8) + .candidatesTokenCount(20) + .totalTokenCount(38) + .build()) + .build(); + Tracing.traceCallLlm( + span, buildInvocationContext(), "event-1", llmRequest, llmResponse, null); + } finally { + span.end(); + } + List spans = openTelemetryRule.getSpans(); + assertThat(spans).hasSize(1); + SpanData spanData = spans.get(0); + Attributes attrs = spanData.getAttributes(); + assertEquals(18L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.input_tokens"))); + assertEquals(20L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.output_tokens"))); + } + + @Test + public void testTraceCallLlm_withOnlyToolUsePromptTokens() { + Span span = tracer.spanBuilder("test-only-tool-use-prompt").startSpan(); + try (Scope scope = span.makeCurrent()) { + LlmRequest llmRequest = + LlmRequest.builder() + .model("gemini-pro") + .contents(ImmutableList.of(Content.fromParts(Part.fromText("hello")))) + .config(GenerateContentConfig.builder().topP(0.9f).maxOutputTokens(100).build()) + .build(); + LlmResponse llmResponse = + LlmResponse.builder() + .content(Content.builder().parts(Part.fromText("world")).build()) + .finishReason(new FinishReason(FinishReason.Known.STOP)) + .usageMetadata( + GenerateContentResponseUsageMetadata.builder() + .toolUsePromptTokenCount(8) + .candidatesTokenCount(20) + .totalTokenCount(28) + .build()) + .build(); + Tracing.traceCallLlm( + span, buildInvocationContext(), "event-1", llmRequest, llmResponse, null); + } finally { + span.end(); + } + List spans = openTelemetryRule.getSpans(); + assertThat(spans).hasSize(1); + SpanData spanData = spans.get(0); + Attributes attrs = spanData.getAttributes(); + assertEquals(8L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.input_tokens"))); + assertEquals(20L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.output_tokens"))); + } + @Test public void testTraceSendData() { Span span = tracer.spanBuilder("test").startSpan(); From 9caecae71fdb851a52a7a945c19042377f6ae583 Mon Sep 17 00:00:00 2001 From: adk-java-releases-bot Date: Fri, 17 Jul 2026 02:37:49 +0200 Subject: [PATCH 03/14] chore(main): release 1.7.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 27 +++++++++++++++++++ README.md | 4 +-- a2a/pom.xml | 2 +- contrib/firestore-session-service/pom.xml | 2 +- contrib/langchain4j/pom.xml | 2 +- contrib/planners/pom.xml | 2 +- contrib/samples/a2a_basic/pom.xml | 2 +- contrib/samples/a2a_server/pom.xml | 2 +- contrib/samples/configagent/pom.xml | 2 +- contrib/samples/github/adkprtriaging/pom.xml | 2 +- contrib/samples/github/adkreleasedocs/pom.xml | 2 +- contrib/samples/github/adkspam/pom.xml | 2 +- contrib/samples/github/adkstale/pom.xml | 2 +- contrib/samples/github/adktriaging/pom.xml | 2 +- contrib/samples/github/githubtools/pom.xml | 2 +- contrib/samples/helloworld/pom.xml | 2 +- contrib/samples/mcpfilesystem/pom.xml | 2 +- contrib/samples/pom.xml | 2 +- contrib/spring-ai/pom.xml | 2 +- core/pom.xml | 2 +- .../src/main/java/com/google/adk/Version.java | 2 +- dev/pom.xml | 2 +- maven_plugin/examples/custom_tools/pom.xml | 2 +- maven_plugin/examples/simple-agent/pom.xml | 2 +- maven_plugin/pom.xml | 2 +- pom.xml | 2 +- tutorials/city-time-weather/pom.xml | 2 +- tutorials/live-audio-single-agent/pom.xml | 2 +- 29 files changed, 56 insertions(+), 29 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a4f6ddcea..7588679c0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.6.0" + ".": "1.7.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 1120ad2ac..3f717049c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## [1.7.0](https://github.com/google/adk-java/compare/v1.6.0...v1.7.0) (2026-07-17) + + +### Features + +* BQAA Java preview-readiness fixes (redaction, table bootstrap, drop stats) ([c685ece](https://github.com/google/adk-java/commit/c685ece46bffd44adbf228e86a946e3a73d2a624)) +* **flows:** enable forced FC reordering based on gemini-3 model name ([fc95ce7](https://github.com/google/adk-java/commit/fc95ce77507fb83ecb02be17d4692d6305722f28)) +* Propagate A2A metadata to RunConfig for request-scoped access ([285547b](https://github.com/google/adk-java/commit/285547bc91c5f92975eb4ffe7e610a9ff4b4fd07)) +* share a single OkHttpClient with injectable daemon threads across the ADK ([2394a95](https://github.com/google/adk-java/commit/2394a9501a15470eba5a164dadf76fa28aeb649b)) +* Update 'gen_ai.usage.input_tokens' to include tool used tokens to match python ADK ([ba23601](https://github.com/google/adk-java/commit/ba23601c09927c4827f3a62d5df8e637e2df33d6)) + + +### Bug Fixes + +* **agents:** warn when AgentTool config_path escapes agent base directory ([7a4113e](https://github.com/google/adk-java/commit/7a4113e02d04aa17d62aaf3785b00306bb9eb815)) +* Allow -latest model aliases in GoogleSearchTool ([9181ea6](https://github.com/google/adk-java/commit/9181ea6a5e04b195b69e8577c225f7d456cb4164)) +* avoid StackOverflowError in PersistBarrier.awaitPersisted for large steps ([a38b824](https://github.com/google/adk-java/commit/a38b824dba1800e9c58ec8ba74e2b65fb205faf1)) +* **bigquery:** BQAA Java P1 preview-readiness fixes (tracing, lifecycle, redaction, HITL) ([2027a4b](https://github.com/google/adk-java/commit/2027a4b53dba2c660ee20ff0bf87dc1a1e936e43)) +* confine config-driven dynamic class loading to intended types ([3967cfa](https://github.com/google/adk-java/commit/3967cfa6297530e8274fad4ab0ec833525c2db69)) +* correctly reassemble streamed function-call arguments in Gemini streaming ([6bae658](https://github.com/google/adk-java/commit/6bae658b0592aa936e1b48e96ff9f995593ba086)) +* fix Claude MCP tool `inputSchema` by falling back to `parametersJsonSchema` ([760c8da](https://github.com/google/adk-java/commit/760c8da2119103bcad57cbbebdff10619c976eb0)) +* **mcp:** guard empty tool parameters in `adkToMcpToolType` ([66fa921](https://github.com/google/adk-java/commit/66fa921e5af2054b9274100039f4a2cefef7964a)) +* preserve non-client function call IDs in GeminiUtil ([971abb4](https://github.com/google/adk-java/commit/971abb4d8f33df58ac42ac83b3d3f8fc8efba871)) +* preserve provider ChatOptions type to prevent ClassCastException ([5c3d328](https://github.com/google/adk-java/commit/5c3d328cb07eb371cbf809e3263e08fdc5c4c8e5)) +* prevent dropping grounding-only responses in BaseLlmFlow ([4de0d8c](https://github.com/google/adk-java/commit/4de0d8c590a96d218985c4b6bad806021390b4f2)) +* propagate A2A request metadata into the run config in `AgentExecutor` ([410ff81](https://github.com/google/adk-java/commit/410ff810a7126c4ba1abdb5435b1a0c4a9c2fd95)) + ## [1.6.0](https://github.com/google/adk-java/compare/v1.5.0...v1.6.0) (2026-07-06) diff --git a/README.md b/README.md index f573b8e4c..01a668efc 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,13 @@ If you're using Maven, add the following to your dependencies: com.google.adk google-adk - 1.6.0 + 1.7.0 com.google.adk google-adk-dev - 1.6.0 + 1.7.0 ``` diff --git a/a2a/pom.xml b/a2a/pom.xml index 2eec105e2..7dda8674e 100644 --- a/a2a/pom.xml +++ b/a2a/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 google-adk-a2a diff --git a/contrib/firestore-session-service/pom.xml b/contrib/firestore-session-service/pom.xml index 40493453d..bc84b752b 100644 --- a/contrib/firestore-session-service/pom.xml +++ b/contrib/firestore-session-service/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml diff --git a/contrib/langchain4j/pom.xml b/contrib/langchain4j/pom.xml index 848cf711a..6c3436c91 100644 --- a/contrib/langchain4j/pom.xml +++ b/contrib/langchain4j/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml diff --git a/contrib/planners/pom.xml b/contrib/planners/pom.xml index 5a614a752..9fcf7e050 100644 --- a/contrib/planners/pom.xml +++ b/contrib/planners/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml diff --git a/contrib/samples/a2a_basic/pom.xml b/contrib/samples/a2a_basic/pom.xml index 89a3286e9..950e4e55c 100644 --- a/contrib/samples/a2a_basic/pom.xml +++ b/contrib/samples/a2a_basic/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 .. diff --git a/contrib/samples/a2a_server/pom.xml b/contrib/samples/a2a_server/pom.xml index b117671f4..5531356cb 100644 --- a/contrib/samples/a2a_server/pom.xml +++ b/contrib/samples/a2a_server/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 .. diff --git a/contrib/samples/configagent/pom.xml b/contrib/samples/configagent/pom.xml index d8fc4c800..1f6019d15 100644 --- a/contrib/samples/configagent/pom.xml +++ b/contrib/samples/configagent/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 .. diff --git a/contrib/samples/github/adkprtriaging/pom.xml b/contrib/samples/github/adkprtriaging/pom.xml index 8606e9f0f..273f3caa5 100644 --- a/contrib/samples/github/adkprtriaging/pom.xml +++ b/contrib/samples/github/adkprtriaging/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/github/adkreleasedocs/pom.xml b/contrib/samples/github/adkreleasedocs/pom.xml index 5ca5a6289..b91e62075 100644 --- a/contrib/samples/github/adkreleasedocs/pom.xml +++ b/contrib/samples/github/adkreleasedocs/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/github/adkspam/pom.xml b/contrib/samples/github/adkspam/pom.xml index bcaa373b7..d91b057ba 100644 --- a/contrib/samples/github/adkspam/pom.xml +++ b/contrib/samples/github/adkspam/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/github/adkstale/pom.xml b/contrib/samples/github/adkstale/pom.xml index dffb43090..c3f0b512e 100644 --- a/contrib/samples/github/adkstale/pom.xml +++ b/contrib/samples/github/adkstale/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/github/adktriaging/pom.xml b/contrib/samples/github/adktriaging/pom.xml index e5254e173..cbe839ac5 100644 --- a/contrib/samples/github/adktriaging/pom.xml +++ b/contrib/samples/github/adktriaging/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/github/githubtools/pom.xml b/contrib/samples/github/githubtools/pom.xml index 236fdeb06..690ffc09f 100644 --- a/contrib/samples/github/githubtools/pom.xml +++ b/contrib/samples/github/githubtools/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/samples/helloworld/pom.xml b/contrib/samples/helloworld/pom.xml index 9412f791f..08d96a7c8 100644 --- a/contrib/samples/helloworld/pom.xml +++ b/contrib/samples/helloworld/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.6.1-SNAPSHOT + 1.7.0 .. diff --git a/contrib/samples/mcpfilesystem/pom.xml b/contrib/samples/mcpfilesystem/pom.xml index 501d2e9d1..7bbadb21b 100644 --- a/contrib/samples/mcpfilesystem/pom.xml +++ b/contrib/samples/mcpfilesystem/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../.. diff --git a/contrib/samples/pom.xml b/contrib/samples/pom.xml index ae54d0cd6..ab019404d 100644 --- a/contrib/samples/pom.xml +++ b/contrib/samples/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../.. diff --git a/contrib/spring-ai/pom.xml b/contrib/spring-ai/pom.xml index c8685aeef..81c91bc50 100644 --- a/contrib/spring-ai/pom.xml +++ b/contrib/spring-ai/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 7559643f2..92cc522e6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 google-adk diff --git a/core/src/main/java/com/google/adk/Version.java b/core/src/main/java/com/google/adk/Version.java index dc9aa665b..a890d6c61 100644 --- a/core/src/main/java/com/google/adk/Version.java +++ b/core/src/main/java/com/google/adk/Version.java @@ -22,7 +22,7 @@ */ public final class Version { // Don't touch this, release-please should keep it up to date. - public static final String JAVA_ADK_VERSION = "1.6.0"; // x-release-please-released-version + public static final String JAVA_ADK_VERSION = "1.7.0"; // x-release-please-released-version private Version() {} } diff --git a/dev/pom.xml b/dev/pom.xml index 6b460a1b4..284fe226a 100644 --- a/dev/pom.xml +++ b/dev/pom.xml @@ -18,7 +18,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 google-adk-dev diff --git a/maven_plugin/examples/custom_tools/pom.xml b/maven_plugin/examples/custom_tools/pom.xml index ff7c0ee4b..b499cc818 100644 --- a/maven_plugin/examples/custom_tools/pom.xml +++ b/maven_plugin/examples/custom_tools/pom.xml @@ -4,7 +4,7 @@ com.example custom-tools-example - 1.6.1-SNAPSHOT + 1.7.0 jar ADK Custom Tools Example diff --git a/maven_plugin/examples/simple-agent/pom.xml b/maven_plugin/examples/simple-agent/pom.xml index b2b4ccd71..7e9593a38 100644 --- a/maven_plugin/examples/simple-agent/pom.xml +++ b/maven_plugin/examples/simple-agent/pom.xml @@ -4,7 +4,7 @@ com.example simple-adk-agent - 1.6.1-SNAPSHOT + 1.7.0 jar Simple ADK Agent Example diff --git a/maven_plugin/pom.xml b/maven_plugin/pom.xml index 8dbdabb1e..8afe01604 100644 --- a/maven_plugin/pom.xml +++ b/maven_plugin/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../pom.xml diff --git a/pom.xml b/pom.xml index 67bd22c30..111b8ede6 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 pom Google Agent Development Kit Maven Parent POM diff --git a/tutorials/city-time-weather/pom.xml b/tutorials/city-time-weather/pom.xml index 2dfd23bbc..de2091336 100644 --- a/tutorials/city-time-weather/pom.xml +++ b/tutorials/city-time-weather/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml diff --git a/tutorials/live-audio-single-agent/pom.xml b/tutorials/live-audio-single-agent/pom.xml index b4c2e5cfa..1e620e1f3 100644 --- a/tutorials/live-audio-single-agent/pom.xml +++ b/tutorials/live-audio-single-agent/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.6.1-SNAPSHOT + 1.7.0 ../../pom.xml From a370034404135a30e6d55543927699a54992b506 Mon Sep 17 00:00:00 2001 From: petrmarinec <54589756+petrmarinec@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:03:43 +0200 Subject: [PATCH 04/14] fix(firestore-session-service): honor appName in getSession/deleteSession/listEvents FirestoreSessionService stores each session at /{root}/{userId}/sessions/{sessionId}, so the document is keyed only by (userId, sessionId). getSession, deleteSession, and listEvents fetched the document by (userId, sessionId) and never checked the stored appName against the requested one, so a caller could read, list the events of, or delete another application's session for the same user by passing any appName. listSessions already scopes by appName (whereEqualTo(APP_NAME_KEY, appName)). Add the same appName check to getSession, deleteSession, and listEvents, treating a mismatch as "session not found", and add unit tests covering the appName-mismatch cases for all three methods. --- .../adk/sessions/FirestoreSessionService.java | 26 +++++- .../sessions/FirestoreSessionServiceTest.java | 79 ++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/contrib/firestore-session-service/src/main/java/com/google/adk/sessions/FirestoreSessionService.java b/contrib/firestore-session-service/src/main/java/com/google/adk/sessions/FirestoreSessionService.java index db236fc88..f4e68e3ca 100644 --- a/contrib/firestore-session-service/src/main/java/com/google/adk/sessions/FirestoreSessionService.java +++ b/contrib/firestore-session-service/src/main/java/com/google/adk/sessions/FirestoreSessionService.java @@ -177,6 +177,16 @@ public Maybe getSession( return Maybe.empty(); } + // Enforce the (appName, userId, sessionId) scope. The Firestore + // document is keyed only by (userId, sessionId), so without this + // check a caller could read a session that belongs to a different + // application for the same user. Treat an appName mismatch as + // "not found" so cross-application existence is not leaked. + if (!appName.equals(data.get(APP_NAME_KEY))) { + logger.warn("Session {} does not belong to app {}", sessionId, appName); + return Maybe.error(new SessionNotFoundException("Session not found: " + sessionId)); + } + // Fetch events based on config GetSessionConfig config = configOpt.orElseGet(() -> GetSessionConfig.builder().build()); @@ -491,6 +501,16 @@ public Completable deleteSession(String appName, String userId, String sessionId com.google.cloud.firestore.DocumentReference sessionRef = getSessionsCollection(userId).document(sessionId); + // Enforce the (appName, userId, sessionId) scope before deleting. + // The document is keyed only by (userId, sessionId), so without this + // check a caller could delete a session that belongs to a different + // application for the same user. + DocumentSnapshot sessionDoc = sessionRef.get().get(); + if (!sessionDoc.exists() || !appName.equals(sessionDoc.get(APP_NAME_KEY))) { + logger.warn("Session {} not found for app {}; nothing to delete", sessionId, appName); + return; + } + // 1. Fetch all events in the subcollection to delete them in batches. CollectionReference eventsRef = sessionRef.collection(EVENTS_SUBCOLLECTION_NAME); com.google.api.core.ApiFuture eventsQuery = @@ -536,9 +556,11 @@ public Single listEvents(String appName, String userId, Stri getSessionsCollection(userId).document(sessionId).get(); DocumentSnapshot sessionDocument = sessionFuture.get(); // Block for the result - if (!sessionDocument.exists()) { + if (!sessionDocument.exists() || !appName.equals(sessionDocument.get(APP_NAME_KEY))) { logger.warn( - "Session not found for sessionId: {}. Returning empty list of events.", sessionId); + "Session not found for sessionId: {} in app {}. Returning empty list of events.", + sessionId, + appName); throw new SessionNotFoundException(appName + "," + userId + "," + sessionId); } diff --git a/contrib/firestore-session-service/src/test/java/com/google/adk/sessions/FirestoreSessionServiceTest.java b/contrib/firestore-session-service/src/test/java/com/google/adk/sessions/FirestoreSessionServiceTest.java index 43ca6889f..71fa8a7bd 100644 --- a/contrib/firestore-session-service/src/test/java/com/google/adk/sessions/FirestoreSessionServiceTest.java +++ b/contrib/firestore-session-service/src/test/java/com/google/adk/sessions/FirestoreSessionServiceTest.java @@ -273,7 +273,8 @@ void getSession_withAfterTimestamp_appliesFilterToQuery() { when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); when(mockSessionSnapshot.exists()).thenReturn(true); when(mockSessionSnapshot.getReference()).thenReturn(mockSessionDocRef); - when(mockSessionSnapshot.getData()).thenReturn(ImmutableMap.of("state", Map.of())); + when(mockSessionSnapshot.getData()) + .thenReturn(ImmutableMap.of(Constants.KEY_APP_NAME, APP_NAME, "state", Map.of())); when(mockQuery.whereGreaterThan(Constants.KEY_TIMESTAMP, timestamp.toString())) .thenReturn(mockQuery); when(mockQuery.get()).thenReturn(ApiFutures.immediateFuture(mockQuerySnapshot)); @@ -778,6 +779,7 @@ void listEvents_sessionExists_returnsEvents() { when(mockSessionsCollection.document(SESSION_ID)).thenReturn(mockSessionDocRef); when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); when(mockSessionSnapshot.exists()).thenReturn(true); + when(mockSessionSnapshot.get(Constants.KEY_APP_NAME)).thenReturn(APP_NAME); when(mockSessionSnapshot.getReference()).thenReturn(mockSessionDocRef); when(mockQuery.get()).thenReturn(ApiFutures.immediateFuture(mockQuerySnapshot)); Map eventData = @@ -828,6 +830,10 @@ void listEvents_sessionDoesNotExist_throwsException() { void deleteSession_deletesEventsAndSession() { // Arrange when(mockSessionsCollection.document(SESSION_ID)).thenReturn(mockSessionDocRef); + // The ownership check fetches the session document first. + when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); + when(mockSessionSnapshot.exists()).thenReturn(true); + when(mockSessionSnapshot.get(Constants.KEY_APP_NAME)).thenReturn(APP_NAME); when(mockSessionDocRef.collection(Constants.EVENTS_SUBCOLLECTION_NAME)) .thenReturn(mockEventsCollection); when(mockEventsCollection.get()).thenReturn(ApiFutures.immediateFuture(mockQuerySnapshot)); @@ -901,4 +907,75 @@ void listSessions_returnsListOfSessions() { return true; }); } + + // --- appName scope enforcement tests --- + // Sessions are keyed by (userId, sessionId) only, so getSession, deleteSession and listEvents + // must reject a request whose appName does not match the stored session's appName; otherwise one + // application could read, list the events of, or delete another application's session for the + // same user. + + /** Tests that getSession emits an error when the stored appName does not match the request. */ + @Test + void getSession_appNameMismatch_emitsError() { + // Arrange + when(mockSessionsCollection.document(SESSION_ID)).thenReturn(mockSessionDocRef); + when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); + when(mockSessionSnapshot.exists()).thenReturn(true); + when(mockSessionSnapshot.getData()) + .thenReturn( + ImmutableMap.of( + "id", + SESSION_ID, + Constants.KEY_APP_NAME, + "other-app", + "userId", + USER_ID, + "updateTime", + NOW.toString(), + "state", + Collections.emptyMap())); + + // Act + TestObserver testObserver = + sessionService.getSession(APP_NAME, USER_ID, SESSION_ID, Optional.empty()).test(); + + // Assert + testObserver.assertError(SessionNotFoundException.class); + } + + /** Tests that listEvents emits an error when the stored appName does not match the request. */ + @Test + void listEvents_appNameMismatch_emitsError() { + // Arrange + when(mockSessionsCollection.document(SESSION_ID)).thenReturn(mockSessionDocRef); + when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); + when(mockSessionSnapshot.exists()).thenReturn(true); + when(mockSessionSnapshot.get(Constants.KEY_APP_NAME)).thenReturn("other-app"); + + // Act + TestObserver testObserver = + sessionService.listEvents(APP_NAME, USER_ID, SESSION_ID).test(); + + // Assert + testObserver.assertError(SessionNotFoundException.class); + } + + /** + * Tests that deleteSession does not delete when the stored appName does not match the request. + */ + @Test + void deleteSession_appNameMismatch_doesNotDelete() { + // Arrange + when(mockSessionsCollection.document(SESSION_ID)).thenReturn(mockSessionDocRef); + when(mockSessionDocRef.get()).thenReturn(ApiFutures.immediateFuture(mockSessionSnapshot)); + when(mockSessionSnapshot.exists()).thenReturn(true); + when(mockSessionSnapshot.get(Constants.KEY_APP_NAME)).thenReturn("other-app"); + + // Act + sessionService.deleteSession(APP_NAME, USER_ID, SESSION_ID).test().assertComplete(); + + // Assert: the session (belonging to another app) must be left intact. + verify(mockSessionDocRef, never()).delete(); + verify(mockWriteBatch, never()).commit(); + } } From edc330d760d8194058610907e717f13425717d8b Mon Sep 17 00:00:00 2001 From: Kamil Tomaszek Date: Mon, 20 Jul 2026 06:22:31 -0700 Subject: [PATCH 05/14] fix: preserve all parallel function calls on the live (BIDI) connection PiperOrigin-RevId: 950796013 --- .../adk/models/GeminiLlmConnection.java | 14 ++++---- .../adk/models/GeminiLlmConnectionTest.java | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/google/adk/models/GeminiLlmConnection.java b/core/src/main/java/com/google/adk/models/GeminiLlmConnection.java index 1f3d0b8c5..35dadd9fd 100644 --- a/core/src/main/java/com/google/adk/models/GeminiLlmConnection.java +++ b/core/src/main/java/com/google/adk/models/GeminiLlmConnection.java @@ -24,7 +24,6 @@ import com.google.genai.types.Blob; import com.google.genai.types.Content; import com.google.genai.types.FinishReason; -import com.google.genai.types.FunctionCall; import com.google.genai.types.FunctionResponse; import com.google.genai.types.LiveConnectConfig; import com.google.genai.types.LiveSendClientContentParameters; @@ -202,14 +201,15 @@ private static LlmResponse createToolCallResponse(LiveServerToolCall toolCall) { toolCall .functionCalls() .ifPresent( - calls -> { - for (FunctionCall call : calls) { + calls -> builder.content( Content.builder() - .parts(ImmutableList.of(Part.builder().functionCall(call).build())) - .build()); - } - }); + .role("model") + .parts( + calls.stream() + .map(call -> Part.builder().functionCall(call).build()) + .collect(toImmutableList())) + .build())); return builder.partial(false).turnComplete(false).build(); } diff --git a/core/src/test/java/com/google/adk/models/GeminiLlmConnectionTest.java b/core/src/test/java/com/google/adk/models/GeminiLlmConnectionTest.java index a3ac09fe5..b15a65852 100644 --- a/core/src/test/java/com/google/adk/models/GeminiLlmConnectionTest.java +++ b/core/src/test/java/com/google/adk/models/GeminiLlmConnectionTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.genai.types.Content; import com.google.genai.types.FunctionCall; import com.google.genai.types.GenerateContentResponseUsageMetadata; @@ -164,6 +165,7 @@ public void convertToServerResponse_withToolCall_mapsContentWithFunctionCall() { testObserver.assertComplete(); LlmResponse response = testObserver.values().get(0); assertThat(response.content()).isPresent(); + assertThat(response.content().get().role()).hasValue("model"); assertThat(response.content().get().parts()).isPresent(); assertThat(response.content().get().parts().get()).hasSize(1); assertThat(response.content().get().parts().get().get(0).functionCall()).hasValue(functionCall); @@ -171,6 +173,39 @@ public void convertToServerResponse_withToolCall_mapsContentWithFunctionCall() { assertThat(response.turnComplete()).hasValue(false); } + @Test + public void convertToServerResponse_withMultipleFunctionCalls_preservesAllCallsAsParts() { + // Regression test for parallel tool calling on the live/BIDI path: a single toolCall message + // can carry multiple FunctionCalls, and all of them must be preserved (not just the last). + FunctionCall getWeather = + FunctionCall.builder().name("getWeather").args(ImmutableMap.of("city", "Paris")).build(); + FunctionCall getTime = + FunctionCall.builder() + .name("getTime") + .args(ImmutableMap.of("timezone", "Europe/London")) + .build(); + LiveServerToolCall toolCall = + LiveServerToolCall.builder().functionCalls(ImmutableList.of(getWeather, getTime)).build(); + + LiveServerMessage message = LiveServerMessage.builder().toolCall(toolCall).build(); + + TestObserver testObserver = new TestObserver<>(); + + GeminiLlmConnection.convertToServerResponse(message).subscribe(testObserver); + + testObserver.assertValueCount(1); + testObserver.assertComplete(); + LlmResponse response = testObserver.values().get(0); + assertThat(response.content()).isPresent(); + assertThat(response.content().get().role()).hasValue("model"); + assertThat(response.content().get().parts()).isPresent(); + assertThat(response.content().get().parts().get()).hasSize(2); + assertThat(response.content().get().parts().get().get(0).functionCall()).hasValue(getWeather); + assertThat(response.content().get().parts().get().get(1).functionCall()).hasValue(getTime); + assertThat(response.partial()).hasValue(false); + assertThat(response.turnComplete()).hasValue(false); + } + @Test public void convertToServerResponse_withUsageMetadata_mapsGenerateResponseUsageMetadata() { LiveServerMessage message = From 2bac57b2d859e7f1f9851604a751a682babd6127 Mon Sep 17 00:00:00 2001 From: adk-java-releases-bot Date: Mon, 20 Jul 2026 15:23:54 +0200 Subject: [PATCH 06/14] chore(main): release 1.7.1-SNAPSHOT --- a2a/pom.xml | 2 +- contrib/firestore-session-service/pom.xml | 2 +- contrib/langchain4j/pom.xml | 2 +- contrib/planners/pom.xml | 2 +- contrib/samples/a2a_basic/pom.xml | 2 +- contrib/samples/a2a_server/pom.xml | 2 +- contrib/samples/configagent/pom.xml | 2 +- contrib/samples/github/adkprtriaging/pom.xml | 2 +- contrib/samples/github/adkreleasedocs/pom.xml | 2 +- contrib/samples/github/adkspam/pom.xml | 2 +- contrib/samples/github/adkstale/pom.xml | 2 +- contrib/samples/github/adktriaging/pom.xml | 2 +- contrib/samples/github/githubtools/pom.xml | 2 +- contrib/samples/helloworld/pom.xml | 2 +- contrib/samples/mcpfilesystem/pom.xml | 2 +- contrib/samples/pom.xml | 2 +- contrib/spring-ai/pom.xml | 2 +- core/pom.xml | 2 +- dev/pom.xml | 2 +- maven_plugin/examples/custom_tools/pom.xml | 2 +- maven_plugin/examples/simple-agent/pom.xml | 2 +- maven_plugin/pom.xml | 2 +- pom.xml | 2 +- tutorials/city-time-weather/pom.xml | 2 +- tutorials/live-audio-single-agent/pom.xml | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/a2a/pom.xml b/a2a/pom.xml index 7dda8674e..2d6d663d4 100644 --- a/a2a/pom.xml +++ b/a2a/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT google-adk-a2a diff --git a/contrib/firestore-session-service/pom.xml b/contrib/firestore-session-service/pom.xml index bc84b752b..6f5442fd5 100644 --- a/contrib/firestore-session-service/pom.xml +++ b/contrib/firestore-session-service/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml diff --git a/contrib/langchain4j/pom.xml b/contrib/langchain4j/pom.xml index 6c3436c91..7ae9c7ad3 100644 --- a/contrib/langchain4j/pom.xml +++ b/contrib/langchain4j/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml diff --git a/contrib/planners/pom.xml b/contrib/planners/pom.xml index 9fcf7e050..45fc8194e 100644 --- a/contrib/planners/pom.xml +++ b/contrib/planners/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml diff --git a/contrib/samples/a2a_basic/pom.xml b/contrib/samples/a2a_basic/pom.xml index 950e4e55c..855acf77e 100644 --- a/contrib/samples/a2a_basic/pom.xml +++ b/contrib/samples/a2a_basic/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT .. diff --git a/contrib/samples/a2a_server/pom.xml b/contrib/samples/a2a_server/pom.xml index 5531356cb..e98ae957b 100644 --- a/contrib/samples/a2a_server/pom.xml +++ b/contrib/samples/a2a_server/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT .. diff --git a/contrib/samples/configagent/pom.xml b/contrib/samples/configagent/pom.xml index 1f6019d15..eae0a9542 100644 --- a/contrib/samples/configagent/pom.xml +++ b/contrib/samples/configagent/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT .. diff --git a/contrib/samples/github/adkprtriaging/pom.xml b/contrib/samples/github/adkprtriaging/pom.xml index 273f3caa5..8bafd9e33 100644 --- a/contrib/samples/github/adkprtriaging/pom.xml +++ b/contrib/samples/github/adkprtriaging/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/github/adkreleasedocs/pom.xml b/contrib/samples/github/adkreleasedocs/pom.xml index b91e62075..5904a597c 100644 --- a/contrib/samples/github/adkreleasedocs/pom.xml +++ b/contrib/samples/github/adkreleasedocs/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/github/adkspam/pom.xml b/contrib/samples/github/adkspam/pom.xml index d91b057ba..9e073518a 100644 --- a/contrib/samples/github/adkspam/pom.xml +++ b/contrib/samples/github/adkspam/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/github/adkstale/pom.xml b/contrib/samples/github/adkstale/pom.xml index c3f0b512e..970603818 100644 --- a/contrib/samples/github/adkstale/pom.xml +++ b/contrib/samples/github/adkstale/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/github/adktriaging/pom.xml b/contrib/samples/github/adktriaging/pom.xml index cbe839ac5..605548f99 100644 --- a/contrib/samples/github/adktriaging/pom.xml +++ b/contrib/samples/github/adktriaging/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/github/githubtools/pom.xml b/contrib/samples/github/githubtools/pom.xml index 690ffc09f..d3704d964 100644 --- a/contrib/samples/github/githubtools/pom.xml +++ b/contrib/samples/github/githubtools/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/samples/helloworld/pom.xml b/contrib/samples/helloworld/pom.xml index 08d96a7c8..9edcfe9a1 100644 --- a/contrib/samples/helloworld/pom.xml +++ b/contrib/samples/helloworld/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-samples - 1.7.0 + 1.7.1-SNAPSHOT .. diff --git a/contrib/samples/mcpfilesystem/pom.xml b/contrib/samples/mcpfilesystem/pom.xml index 7bbadb21b..ae20c5fa3 100644 --- a/contrib/samples/mcpfilesystem/pom.xml +++ b/contrib/samples/mcpfilesystem/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../.. diff --git a/contrib/samples/pom.xml b/contrib/samples/pom.xml index ab019404d..514ad2b92 100644 --- a/contrib/samples/pom.xml +++ b/contrib/samples/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../.. diff --git a/contrib/spring-ai/pom.xml b/contrib/spring-ai/pom.xml index 81c91bc50..eca2e0778 100644 --- a/contrib/spring-ai/pom.xml +++ b/contrib/spring-ai/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml diff --git a/core/pom.xml b/core/pom.xml index 92cc522e6..c038ff4de 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT google-adk diff --git a/dev/pom.xml b/dev/pom.xml index 284fe226a..0dc29f8ac 100644 --- a/dev/pom.xml +++ b/dev/pom.xml @@ -18,7 +18,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT google-adk-dev diff --git a/maven_plugin/examples/custom_tools/pom.xml b/maven_plugin/examples/custom_tools/pom.xml index b499cc818..82d736187 100644 --- a/maven_plugin/examples/custom_tools/pom.xml +++ b/maven_plugin/examples/custom_tools/pom.xml @@ -4,7 +4,7 @@ com.example custom-tools-example - 1.7.0 + 1.7.1-SNAPSHOT jar ADK Custom Tools Example diff --git a/maven_plugin/examples/simple-agent/pom.xml b/maven_plugin/examples/simple-agent/pom.xml index 7e9593a38..50ecdd03d 100644 --- a/maven_plugin/examples/simple-agent/pom.xml +++ b/maven_plugin/examples/simple-agent/pom.xml @@ -4,7 +4,7 @@ com.example simple-adk-agent - 1.7.0 + 1.7.1-SNAPSHOT jar Simple ADK Agent Example diff --git a/maven_plugin/pom.xml b/maven_plugin/pom.xml index 8afe01604..9469fa581 100644 --- a/maven_plugin/pom.xml +++ b/maven_plugin/pom.xml @@ -5,7 +5,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 111b8ede6..52475d377 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT pom Google Agent Development Kit Maven Parent POM diff --git a/tutorials/city-time-weather/pom.xml b/tutorials/city-time-weather/pom.xml index de2091336..aaf1e9640 100644 --- a/tutorials/city-time-weather/pom.xml +++ b/tutorials/city-time-weather/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml diff --git a/tutorials/live-audio-single-agent/pom.xml b/tutorials/live-audio-single-agent/pom.xml index 1e620e1f3..49440394e 100644 --- a/tutorials/live-audio-single-agent/pom.xml +++ b/tutorials/live-audio-single-agent/pom.xml @@ -20,7 +20,7 @@ com.google.adk google-adk-parent - 1.7.0 + 1.7.1-SNAPSHOT ../../pom.xml From cf71d7bb07398d6fabd3a3ade24f31db98f9f36e Mon Sep 17 00:00:00 2001 From: svetanis Date: Sat, 18 Jul 2026 22:08:46 -0700 Subject: [PATCH 07/14] fix(mcp): honor stdioServerParams in McpToolset.fromConfig --- .../com/google/adk/tools/mcp/McpToolset.java | 22 ++++++++-- .../google/adk/tools/mcp/McpToolsetTest.java | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java b/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java index 4cafb9681..dae35f77e 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java @@ -25,6 +25,7 @@ import com.google.adk.tools.BaseTool; import com.google.adk.tools.BaseToolset; import com.google.adk.tools.ToolPredicate; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Booleans; import io.modelcontextprotocol.client.McpSyncClient; @@ -416,10 +417,7 @@ public static McpToolset fromConfig(BaseTool.ToolConfig config, String configAbs } List toolNames = mcpToolsetConfig.toolFilter(); - Object connectionParameters = - Optional.ofNullable(mcpToolsetConfig.stdioConnectionParams()) - .or(() -> Optional.ofNullable(mcpToolsetConfig.sseServerParams())) - .orElse(mcpToolsetConfig.stdioConnectionParams()); + Object connectionParameters = resolveConnectionParameters(mcpToolsetConfig); // Create McpToolset with McpSessionManager having appropriate connection parameters if (toolNames != null) { @@ -431,4 +429,20 @@ public static McpToolset fromConfig(BaseTool.ToolConfig config, String configAbs throw new ConfigurationException("Failed to parse McpToolsetConfig from ToolArgsConfig", e); } } + + /** + * Resolves the single connection-parameters object from an already-validated config. {@code + * stdioServerParams} is converted to the MCP SDK {@link ServerParameters}, the type {@link + * DefaultMcpTransportBuilder} accepts; the other variants pass through unchanged. + */ + @VisibleForTesting + static Object resolveConnectionParameters(McpToolsetConfig mcpToolsetConfig) { + return Optional.ofNullable(mcpToolsetConfig.stdioConnectionParams()) + .or(() -> Optional.ofNullable(mcpToolsetConfig.sseServerParams())) + .or( + () -> + Optional.ofNullable(mcpToolsetConfig.stdioServerParams()) + .map(StdioServerParameters::toServerParameters)) + .orElseThrow(() -> new IllegalStateException("Validated MCP connection params missing.")); + } } diff --git a/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java b/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java index f00091d2d..164105aa6 100644 --- a/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java +++ b/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java @@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.modelcontextprotocol.client.McpSyncClient; +import io.modelcontextprotocol.client.transport.ServerParameters; import io.modelcontextprotocol.json.McpJsonDefaults; import io.modelcontextprotocol.json.McpJsonMapper; import io.modelcontextprotocol.spec.McpSchema; @@ -369,4 +370,45 @@ public void getTools_succeedsOnLastRetryAttempt() { verify(mockMcpSessionManager, times(3)).createSession(); verify(mockMcpSyncClient, times(3)).listTools(); } + + @Test + public void resolveConnectionParameters_stdioServerParams_convertsToSdkServerParameters() { + McpToolsetConfig config = new McpToolsetConfig(); + config.setStdioServerParams(StdioServerParameters.builder().command("my-command").build()); + + Object resolved = McpToolset.resolveConnectionParameters(config); + + // Regression, Finding 1: this branch used to resolve to null (stdioServerParams was never + // consulted), deferring the failure to an NPE in DefaultMcpTransportBuilder.build(null). + assertThat(resolved).isInstanceOf(ServerParameters.class); + } + + @Test + public void resolveConnectionParameters_sseServerParams_passesThrough() { + McpToolsetConfig config = new McpToolsetConfig(); + SseServerParameters sseParams = + SseServerParameters.builder().url("http://localhost:8080").build(); + config.setSseServerParams(sseParams); + + assertThat(McpToolset.resolveConnectionParameters(config)).isSameInstanceAs(sseParams); + } + + @Test + public void resolveConnectionParameters_stdioConnectionParams_passesThrough() { + McpToolsetConfig config = new McpToolsetConfig(); + StdioConnectionParameters connectionParams = + StdioConnectionParameters.builder() + .serverParams(StdioServerParameters.builder().command("my-command").build()) + .build(); + config.setStdioConnectionParams(connectionParams); + + assertThat(McpToolset.resolveConnectionParameters(config)).isSameInstanceAs(connectionParams); + } + + @Test + public void resolveConnectionParameters_nothingSet_throwsIllegalStateException() { + assertThrows( + IllegalStateException.class, + () -> McpToolset.resolveConnectionParameters(new McpToolsetConfig())); + } } From 233b83bcacc39f7b6a1204a7644a1a5f13557a20 Mon Sep 17 00:00:00 2001 From: svetanis Date: Mon, 27 Apr 2026 21:59:58 -0700 Subject: [PATCH 08/14] fix(core): fallback to name when Agent description is missing Prevents a NullPointerException in the google-genai library when an Agent is defined without a description. Includes a regression test. --- .../java/com/google/adk/tools/AgentTool.java | 9 ++++++++- .../com/google/adk/tools/AgentToolTest.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/adk/tools/AgentTool.java b/core/src/main/java/com/google/adk/tools/AgentTool.java index 66d4a2700..5e8798d0e 100644 --- a/core/src/main/java/com/google/adk/tools/AgentTool.java +++ b/core/src/main/java/com/google/adk/tools/AgentTool.java @@ -31,6 +31,7 @@ import com.google.adk.runner.Runner; import com.google.adk.sessions.State; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.genai.types.Content; @@ -131,8 +132,14 @@ private Optional getOutputSchema(BaseAgent agent) { @Override public Optional declaration() { + + // The genai FunctionDeclaration builder uses Optional.of() internally, which NPEs on a null + // description. Coerce null to an empty string. This matches the Python, Go, and Kotlin ports, + // which send an empty description when the agent has none. + String desc = Strings.nullToEmpty(this.description()); + FunctionDeclaration.Builder builder = - FunctionDeclaration.builder().description(this.description()).name(this.name()); + FunctionDeclaration.builder().description(desc).name(this.name()); Optional agentInputSchema = getInputSchema(agent); diff --git a/core/src/test/java/com/google/adk/tools/AgentToolTest.java b/core/src/test/java/com/google/adk/tools/AgentToolTest.java index b37db6611..755cebc46 100644 --- a/core/src/test/java/com/google/adk/tools/AgentToolTest.java +++ b/core/src/test/java/com/google/adk/tools/AgentToolTest.java @@ -43,6 +43,7 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.core.Maybe; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Before; import org.junit.Test; @@ -882,4 +883,21 @@ private ToolContext createToolContext(BaseAgent agent) { .build()) .build(); } + + @Test + public void declaration_withNullDescription_usesEmptyDescription() { + // Create an agent with a name but NO description + LlmAgent testAgent = + LlmAgent.builder() + .name("TestAgent") + // .description() is intentionally left out + .build(); + + AgentTool tool = AgentTool.create(testAgent); + Optional declaration = tool.declaration(); + assertThat(declaration).isPresent(); + assertThat(declaration.get().name()).hasValue("TestAgent"); + // Matches the Python, Go, and Kotlin ports: a missing description becomes an empty string. + assertThat(declaration.get().description()).hasValue(""); + } } From ec2a90b0e11c525aa95b8a9e0b76a6a0fbf41097 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszek Date: Thu, 23 Jul 2026 02:22:40 -0700 Subject: [PATCH 09/14] chore(license): add and repair Apache license headers across Java sources Ensure every Java source carries the canonical Apache 2.0 header from `java.header`, without changing existing copyright years (the year reflects when a file was created): - Add the header to files that were missing it, using each file's creation year. - Repair malformed headers: drop duplicated/garbled lines and convert `//`-style headers to the required `/* */` block form, preserving the year. PiperOrigin-RevId: 952623369 --- .../adk/a2a/agent/RemoteA2AAgentTest.java | 16 +++++++++++ .../a2a/converters/EventConverterTest.java | 16 +++++++++++ .../adk/a2a/converters/PartConverterTest.java | 16 +++++++++++ .../a2a/converters/ResponseConverterTest.java | 16 +++++++++++ .../adk/a2a/executor/AgentExecutorTest.java | 16 +++++++++++ .../adk/utils/FirestorePropertiesTest.java | 16 +++++++++++ contrib/samples/a2a_basic/A2AAgent.java | 16 +++++++++++ contrib/samples/a2a_basic/A2AAgentRun.java | 16 +++++++++++ .../samples/a2aagent/AgentCardProducer.java | 16 +++++++++++ .../a2aagent/AgentExecutorProducer.java | 16 +++++++++++ .../adk/samples/a2aagent/StartupConfig.java | 16 +++++++++++ .../adk/samples/a2aagent/agent/Agent.java | 16 +++++++++++ .../main/java/com/example/CoreCallbacks.java | 16 +++++++++++ .../java/com/example/CustomDemoRegistry.java | 16 +++++++++++ .../main/java/com/example/CustomDieTool.java | 16 +++++++++++ .../src/main/java/com/example/LifeAgent.java | 28 ++++++++++--------- .../adkprtriaging/AdkPrTriagingAgent.java | 28 ++++++++++--------- .../adkprtriaging/AdkPrTriagingAgentRun.java | 28 ++++++++++--------- .../com/example/adkprtriaging/Settings.java | 28 ++++++++++--------- .../AdkPrTriagingAgentRunTest.java | 28 ++++++++++--------- .../adkprtriaging/AdkPrTriagingAgentTest.java | 28 ++++++++++--------- .../example/adkprtriaging/SettingsTest.java | 28 ++++++++++--------- .../adkdocs/AdkDocsReleaseAnalyzerAgent.java | 28 ++++++++++--------- .../adkdocs/AdkDocsReleaseAnalyzerRun.java | 28 ++++++++++--------- .../java/com/example/adkdocs/Settings.java | 28 ++++++++++--------- .../java/com/example/adkspam/Settings.java | 28 ++++++++++--------- .../example/adkspam/SpamDetectionAgent.java | 28 ++++++++++--------- .../adkspam/SpamDetectionAgentRun.java | 28 ++++++++++--------- .../com/example/adkspam/SettingsTest.java | 28 ++++++++++--------- .../adkspam/SpamDetectionAgentRunTest.java | 28 ++++++++++--------- .../adkspam/SpamDetectionAgentTest.java | 28 ++++++++++--------- .../com/example/adkstale/AdkStaleAgent.java | 28 ++++++++++--------- .../example/adkstale/AdkStaleAgentRun.java | 28 ++++++++++--------- .../example/adkstale/GitHubStaleClient.java | 28 ++++++++++--------- .../java/com/example/adkstale/Settings.java | 28 ++++++++++--------- .../adkstale/AdkStaleAgentRunTest.java | 28 ++++++++++--------- .../example/adkstale/AdkStaleAgentTest.java | 28 ++++++++++--------- .../com/example/adkstale/SettingsTest.java | 28 ++++++++++--------- .../example/adktriaging/AdkTriagingAgent.java | 28 ++++++++++--------- .../adktriaging/AdkTriagingAgentRun.java | 28 ++++++++++--------- .../com/example/adktriaging/Settings.java | 28 ++++++++++--------- .../adktriaging/AdkTriagingAgentRunTest.java | 28 ++++++++++--------- .../adktriaging/AdkTriagingAgentTest.java | 28 ++++++++++--------- .../com/example/adktriaging/SettingsTest.java | 28 ++++++++++--------- .../java/com/example/github/GitHubTools.java | 28 ++++++++++--------- .../samples/helloworld/HelloWorldAgent.java | 28 ++++++++++--------- contrib/samples/helloworld/HelloWorldRun.java | 16 +++++++++++ .../mcpfilesystem/McpFilesystemAgent.java | 28 ++++++++++--------- .../mcpfilesystem/McpFilesystemRun.java | 16 +++++++++++ .../adk/agents/ActiveStreamingTool.java | 1 - .../java/com/google/adk/agents/RunConfig.java | 2 +- .../adk/codeexecutors/CodeExecutionUtils.java | 1 - .../codeexecutors/ContainerCodeExecutor.java | 1 - .../google/adk/events/EventCompaction.java | 16 +++++++++++ .../models/chat/ChatCompletionsClient.java | 2 +- .../models/chat/ChatCompletionsCommon.java | 2 +- .../chat/ChatCompletionsHttpClient.java | 2 +- .../models/chat/ChatCompletionsRequest.java | 2 +- .../models/chat/ChatCompletionsResponse.java | 2 +- .../com/google/adk/sessions/ApiClient.java | 2 +- .../com/google/adk/sessions/ApiResponse.java | 2 +- .../google/adk/sessions/HttpApiClient.java | 2 +- .../google/adk/sessions/HttpApiResponse.java | 2 +- .../google/adk/sessions/VertexAiClient.java | 16 +++++++++++ .../google/adk/summarizer/EventCompactor.java | 16 +++++++++++ .../ApplicationIntegrationToolset.java | 16 +++++++++++ .../ConnectionsClient.java | 16 +++++++++++ .../CredentialsHelper.java | 16 +++++++++++ .../GoogleCredentialsHelper.java | 16 +++++++++++ .../IntegrationClient.java | 16 +++++++++++ .../tools/mcp/DefaultMcpTransportBuilder.java | 16 +++++++++++ .../google/adk/tools/mcp/McpAsyncToolset.java | 2 +- .../adk/tools/mcp/McpServerLogConsumer.java | 2 +- .../com/google/adk/tools/mcp/McpToolset.java | 2 +- .../adk/tools/mcp/McpToolsetException.java | 16 +++++++++++ .../adk/tools/mcp/McpTransportBuilder.java | 16 +++++++++++ .../tools/mcp/StdioConnectionParameters.java | 16 +++++++++++ .../java/com/google/adk/utils/AgentEnums.java | 16 +++++++++++ .../BuiltInCodeExecutorTest.java | 16 +++++++++++ .../chat/ChatCompletionsCommonTest.java | 16 +++++++++++ .../chat/ChatCompletionsHttpClientTest.java | 2 +- .../chat/ChatCompletionsRequestTest.java | 2 +- .../chat/ChatCompletionsResponseTest.java | 5 ++-- .../google/adk/sessions/MockApiAnswer.java | 16 +++++++++++ .../sessions/SessionJsonConverterTest.java | 16 +++++++++++ .../com/google/adk/sessions/SessionTest.java | 16 +++++++++++ .../com/google/adk/sessions/StateTest.java | 16 +++++++++++ .../sessions/VertexAiSessionServiceTest.java | 16 +++++++++++ .../com/google/adk/tools/BaseToolTest.java | 16 +++++++++++ .../com/google/adk/tools/BaseToolsetTest.java | 16 +++++++++++ .../adk/tools/GoogleSearchAgentToolTest.java | 16 +++++++++++ .../adk/tools/LoadArtifactsToolTest.java | 16 +++++++++++ .../tools/LongRunningFunctionToolTest.java | 16 +++++++++++ .../com/google/adk/tools/ToolContextTest.java | 16 +++++++++++ .../tools/VertexAiSearchAgentToolTest.java | 16 +++++++++++ .../adk/tools/VertexAiSearchToolTest.java | 16 +++++++++++ .../ApplicationIntegrationToolsetTest.java | 16 +++++++++++ .../ConnectionsClientTest.java | 16 +++++++++++ .../CredentialsHelperTest.java | 16 +++++++++++ .../IntegrationClientTest.java | 16 +++++++++++ .../IntegrationConnectorToolTest.java | 16 +++++++++++ .../google/adk/tools/mcp/McpToolsetTest.java | 2 +- .../retrieval/VertexAiRagRetrievalTest.java | 16 +++++++++++ .../adk/utils/InstructionUtilsTest.java | 16 +++++++++++ .../google/adk/utils/ModelNameUtilsTest.java | 16 +++++++++++ .../java/com/google/adk/utils/PairsTest.java | 16 +++++++++++ .../java/com/google/adk/web/AgentLoader.java | 16 ++++++----- .../google/adk/web/AgentStaticLoaderTest.java | 16 +++++++++++ .../java/com/example/CustomDieRegistry.java | 16 +++++++++++ .../main/java/com/example/CustomDieTool.java | 16 +++++++++++ .../main/java/com/example/GetWeatherTool.java | 16 +++++++++++ .../com/google/adk/maven/AgentLoader.java | 16 ++++++----- 112 files changed, 1445 insertions(+), 451 deletions(-) diff --git a/a2a/src/test/java/com/google/adk/a2a/agent/RemoteA2AAgentTest.java b/a2a/src/test/java/com/google/adk/a2a/agent/RemoteA2AAgentTest.java index 0609c3b04..8d6c9b062 100644 --- a/a2a/src/test/java/com/google/adk/a2a/agent/RemoteA2AAgentTest.java +++ b/a2a/src/test/java/com/google/adk/a2a/agent/RemoteA2AAgentTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.a2a.agent; import static com.google.common.truth.Truth.assertThat; diff --git a/a2a/src/test/java/com/google/adk/a2a/converters/EventConverterTest.java b/a2a/src/test/java/com/google/adk/a2a/converters/EventConverterTest.java index 207019199..74292618d 100644 --- a/a2a/src/test/java/com/google/adk/a2a/converters/EventConverterTest.java +++ b/a2a/src/test/java/com/google/adk/a2a/converters/EventConverterTest.java @@ -1,3 +1,19 @@ +/* + * 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.a2a.converters; import static com.google.common.truth.Truth.assertThat; diff --git a/a2a/src/test/java/com/google/adk/a2a/converters/PartConverterTest.java b/a2a/src/test/java/com/google/adk/a2a/converters/PartConverterTest.java index 709599a51..0242cdedf 100644 --- a/a2a/src/test/java/com/google/adk/a2a/converters/PartConverterTest.java +++ b/a2a/src/test/java/com/google/adk/a2a/converters/PartConverterTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.a2a.converters; import static com.google.common.truth.Truth.assertThat; diff --git a/a2a/src/test/java/com/google/adk/a2a/converters/ResponseConverterTest.java b/a2a/src/test/java/com/google/adk/a2a/converters/ResponseConverterTest.java index b61b00e1a..20f2d3c10 100644 --- a/a2a/src/test/java/com/google/adk/a2a/converters/ResponseConverterTest.java +++ b/a2a/src/test/java/com/google/adk/a2a/converters/ResponseConverterTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.a2a.converters; import static com.google.common.truth.Truth.assertThat; diff --git a/a2a/src/test/java/com/google/adk/a2a/executor/AgentExecutorTest.java b/a2a/src/test/java/com/google/adk/a2a/executor/AgentExecutorTest.java index 4102c9840..99b12286e 100644 --- a/a2a/src/test/java/com/google/adk/a2a/executor/AgentExecutorTest.java +++ b/a2a/src/test/java/com/google/adk/a2a/executor/AgentExecutorTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.a2a.executor; import static com.google.common.collect.ImmutableList.toImmutableList; diff --git a/contrib/firestore-session-service/src/test/java/com/google/adk/utils/FirestorePropertiesTest.java b/contrib/firestore-session-service/src/test/java/com/google/adk/utils/FirestorePropertiesTest.java index e4bb6aa3b..7f2cfb438 100644 --- a/contrib/firestore-session-service/src/test/java/com/google/adk/utils/FirestorePropertiesTest.java +++ b/contrib/firestore-session-service/src/test/java/com/google/adk/utils/FirestorePropertiesTest.java @@ -1,3 +1,19 @@ +/* + * 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.utils; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/contrib/samples/a2a_basic/A2AAgent.java b/contrib/samples/a2a_basic/A2AAgent.java index e08a87a67..f788070de 100644 --- a/contrib/samples/a2a_basic/A2AAgent.java +++ b/contrib/samples/a2a_basic/A2AAgent.java @@ -1,3 +1,19 @@ +/* + * 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.example.a2a_basic; import com.google.adk.a2a.agent.RemoteA2AAgent; diff --git a/contrib/samples/a2a_basic/A2AAgentRun.java b/contrib/samples/a2a_basic/A2AAgentRun.java index b4a63b026..ad9c9ddbf 100644 --- a/contrib/samples/a2a_basic/A2AAgentRun.java +++ b/contrib/samples/a2a_basic/A2AAgentRun.java @@ -1,3 +1,19 @@ +/* + * 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.example.a2a_basic; import com.google.adk.agents.BaseAgent; diff --git a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentCardProducer.java b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentCardProducer.java index 0937e2512..37073904e 100644 --- a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentCardProducer.java +++ b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentCardProducer.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.samples.a2aagent; import io.a2a.server.PublicAgentCard; diff --git a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentExecutorProducer.java b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentExecutorProducer.java index a367f87b6..b356991fc 100644 --- a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentExecutorProducer.java +++ b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/AgentExecutorProducer.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.samples.a2aagent; import com.google.adk.a2a.executor.AgentExecutorConfig; diff --git a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/StartupConfig.java b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/StartupConfig.java index 0da70b086..e4ec7cfa4 100644 --- a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/StartupConfig.java +++ b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/StartupConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.samples.a2aagent; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; diff --git a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/agent/Agent.java b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/agent/Agent.java index a415f618f..9c20ae6d7 100644 --- a/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/agent/Agent.java +++ b/contrib/samples/a2a_server/src/main/java/com/google/adk/samples/a2aagent/agent/Agent.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.samples.a2aagent.agent; import static java.util.stream.Collectors.joining; diff --git a/contrib/samples/configagent/src/main/java/com/example/CoreCallbacks.java b/contrib/samples/configagent/src/main/java/com/example/CoreCallbacks.java index 8e6211282..db97ee6b4 100644 --- a/contrib/samples/configagent/src/main/java/com/example/CoreCallbacks.java +++ b/contrib/samples/configagent/src/main/java/com/example/CoreCallbacks.java @@ -1,3 +1,19 @@ +/* + * 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.example; import com.google.adk.agents.CallbackContext; diff --git a/contrib/samples/configagent/src/main/java/com/example/CustomDemoRegistry.java b/contrib/samples/configagent/src/main/java/com/example/CustomDemoRegistry.java index 8ef7752d5..f734b6400 100644 --- a/contrib/samples/configagent/src/main/java/com/example/CustomDemoRegistry.java +++ b/contrib/samples/configagent/src/main/java/com/example/CustomDemoRegistry.java @@ -1,3 +1,19 @@ +/* + * 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.example; import com.google.adk.utils.ComponentRegistry; diff --git a/contrib/samples/configagent/src/main/java/com/example/CustomDieTool.java b/contrib/samples/configagent/src/main/java/com/example/CustomDieTool.java index 75af529db..c2ee45790 100644 --- a/contrib/samples/configagent/src/main/java/com/example/CustomDieTool.java +++ b/contrib/samples/configagent/src/main/java/com/example/CustomDieTool.java @@ -1,3 +1,19 @@ +/* + * 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.example; import com.google.adk.examples.Example; diff --git a/contrib/samples/configagent/src/main/java/com/example/LifeAgent.java b/contrib/samples/configagent/src/main/java/com/example/LifeAgent.java index a3bda2e89..2577eaa0e 100644 --- a/contrib/samples/configagent/src/main/java/com/example/LifeAgent.java +++ b/contrib/samples/configagent/src/main/java/com/example/LifeAgent.java @@ -1,16 +1,18 @@ -// 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. +/* + * 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.example; diff --git a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgent.java b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgent.java index 048533704..d2a944b5e 100644 --- a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgent.java +++ b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgent.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgentRun.java b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgentRun.java index 3033e9fed..60a3f7920 100644 --- a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgentRun.java +++ b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/AdkPrTriagingAgentRun.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/Settings.java b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/Settings.java index 143912974..afe37f037 100644 --- a/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/Settings.java +++ b/contrib/samples/github/adkprtriaging/src/main/java/com/example/adkprtriaging/Settings.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import java.io.IOException; diff --git a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentRunTest.java b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentRunTest.java index 573e731dd..47807a407 100644 --- a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentRunTest.java +++ b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentRunTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentTest.java b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentTest.java index b9e21228e..c562d011f 100644 --- a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentTest.java +++ b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/AdkPrTriagingAgentTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/SettingsTest.java b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/SettingsTest.java index 5e78031a1..501a34398 100644 --- a/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/SettingsTest.java +++ b/contrib/samples/github/adkprtriaging/src/test/java/com/example/adkprtriaging/SettingsTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkprtriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java index c032c8b31..c4b81ec35 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkdocs; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java index fdf7d6ac3..97d9638cc 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkdocs; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java index 6172cedad..85466dabc 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkdocs; /** Configuration sourced from environment variables. */ diff --git a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/Settings.java b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/Settings.java index 493515be8..6d5c79d2d 100644 --- a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/Settings.java +++ b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/Settings.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import java.util.Locale; diff --git a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgent.java b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgent.java index 1d45f5ed4..ec4cddd37 100644 --- a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgent.java +++ b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgent.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgentRun.java b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgentRun.java index abc7340c9..7feb35d5d 100644 --- a/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgentRun.java +++ b/contrib/samples/github/adkspam/src/main/java/com/example/adkspam/SpamDetectionAgentRun.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SettingsTest.java b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SettingsTest.java index 63650643a..dfc93099d 100644 --- a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SettingsTest.java +++ b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SettingsTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentRunTest.java b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentRunTest.java index d493fdd17..b14483175 100644 --- a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentRunTest.java +++ b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentRunTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentTest.java b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentTest.java index b4949254a..ec659e562 100644 --- a/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentTest.java +++ b/contrib/samples/github/adkspam/src/test/java/com/example/adkspam/SpamDetectionAgentTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkspam; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgent.java b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgent.java index 57f05171f..869e2d4a9 100644 --- a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgent.java +++ b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgent.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgentRun.java b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgentRun.java index 57ec3d9bd..de31e17b6 100644 --- a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgentRun.java +++ b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/AdkStaleAgentRun.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/GitHubStaleClient.java b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/GitHubStaleClient.java index 72bd54103..27f42e498 100644 --- a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/GitHubStaleClient.java +++ b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/GitHubStaleClient.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import com.fasterxml.jackson.databind.JsonNode; diff --git a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/Settings.java b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/Settings.java index f99a94304..417567bc5 100644 --- a/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/Settings.java +++ b/contrib/samples/github/adkstale/src/main/java/com/example/adkstale/Settings.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import java.util.Locale; diff --git a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentRunTest.java b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentRunTest.java index 3affa9081..233debe98 100644 --- a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentRunTest.java +++ b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentRunTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentTest.java b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentTest.java index 144e9e1d0..af3ff52c0 100644 --- a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentTest.java +++ b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/AdkStaleAgentTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/SettingsTest.java b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/SettingsTest.java index 412fc1d9d..cce82e8b3 100644 --- a/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/SettingsTest.java +++ b/contrib/samples/github/adkstale/src/test/java/com/example/adkstale/SettingsTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adkstale; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgent.java b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgent.java index f293b9994..a0feb84b7 100644 --- a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgent.java +++ b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgent.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import static com.google.common.collect.ImmutableList.toImmutableList; diff --git a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgentRun.java b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgentRun.java index 7f1593c6f..a5e4b5de4 100644 --- a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgentRun.java +++ b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/AdkTriagingAgentRun.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import com.example.github.GitHubTools; diff --git a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/Settings.java b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/Settings.java index 0de7861ab..13ab7a950 100644 --- a/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/Settings.java +++ b/contrib/samples/github/adktriaging/src/main/java/com/example/adktriaging/Settings.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import java.util.Locale; diff --git a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentRunTest.java b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentRunTest.java index 9fb55a8c8..9c95bbe5c 100644 --- a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentRunTest.java +++ b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentRunTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentTest.java b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentTest.java index b58180694..47ac069fb 100644 --- a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentTest.java +++ b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/AdkTriagingAgentTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/SettingsTest.java b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/SettingsTest.java index 65e1fa16f..8457083be 100644 --- a/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/SettingsTest.java +++ b/contrib/samples/github/adktriaging/src/test/java/com/example/adktriaging/SettingsTest.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.adktriaging; import static com.google.common.truth.Truth.assertThat; diff --git a/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java b/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java index 6f934e7a7..be1ac818e 100644 --- a/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java +++ b/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java @@ -1,16 +1,18 @@ -// Copyright 2026 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. +/* + * Copyright 2026 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.example.github; import com.google.adk.tools.Annotations.Schema; diff --git a/contrib/samples/helloworld/HelloWorldAgent.java b/contrib/samples/helloworld/HelloWorldAgent.java index cb949620f..c64c54878 100644 --- a/contrib/samples/helloworld/HelloWorldAgent.java +++ b/contrib/samples/helloworld/HelloWorldAgent.java @@ -1,16 +1,18 @@ -// 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. +/* + * 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.example.helloworld; import com.google.adk.agents.LlmAgent; diff --git a/contrib/samples/helloworld/HelloWorldRun.java b/contrib/samples/helloworld/HelloWorldRun.java index f72b15f2e..143b42da0 100644 --- a/contrib/samples/helloworld/HelloWorldRun.java +++ b/contrib/samples/helloworld/HelloWorldRun.java @@ -1,3 +1,19 @@ +/* + * 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.example.helloworld; import com.google.adk.agents.RunConfig; diff --git a/contrib/samples/mcpfilesystem/McpFilesystemAgent.java b/contrib/samples/mcpfilesystem/McpFilesystemAgent.java index fd35792b8..0dbf52027 100644 --- a/contrib/samples/mcpfilesystem/McpFilesystemAgent.java +++ b/contrib/samples/mcpfilesystem/McpFilesystemAgent.java @@ -1,16 +1,18 @@ -// 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. +/* + * 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.example.mcpfilesystem; import com.google.adk.agents.LlmAgent; diff --git a/contrib/samples/mcpfilesystem/McpFilesystemRun.java b/contrib/samples/mcpfilesystem/McpFilesystemRun.java index a4caa0d31..daee34750 100644 --- a/contrib/samples/mcpfilesystem/McpFilesystemRun.java +++ b/contrib/samples/mcpfilesystem/McpFilesystemRun.java @@ -1,3 +1,19 @@ +/* + * 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.example.mcpfilesystem; import com.google.adk.agents.RunConfig; diff --git a/core/src/main/java/com/google/adk/agents/ActiveStreamingTool.java b/core/src/main/java/com/google/adk/agents/ActiveStreamingTool.java index b0dff0c10..d19e1cd1f 100644 --- a/core/src/main/java/com/google/adk/agents/ActiveStreamingTool.java +++ b/core/src/main/java/com/google/adk/agents/ActiveStreamingTool.java @@ -3,7 +3,6 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with 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 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 3a1617033..bd20b6183 100644 --- a/core/src/main/java/com/google/adk/agents/RunConfig.java +++ b/core/src/main/java/com/google/adk/agents/RunConfig.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/src/main/java/com/google/adk/codeexecutors/CodeExecutionUtils.java b/core/src/main/java/com/google/adk/codeexecutors/CodeExecutionUtils.java index a4d3771c3..a8322b228 100644 --- a/core/src/main/java/com/google/adk/codeexecutors/CodeExecutionUtils.java +++ b/core/src/main/java/com/google/adk/codeexecutors/CodeExecutionUtils.java @@ -3,7 +3,6 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with 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 diff --git a/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java b/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java index 4e75dab75..a16379455 100644 --- a/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java +++ b/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java @@ -3,7 +3,6 @@ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. - * You may not in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 diff --git a/core/src/main/java/com/google/adk/events/EventCompaction.java b/core/src/main/java/com/google/adk/events/EventCompaction.java index 16dcb4d4a..f45fb162a 100644 --- a/core/src/main/java/com/google/adk/events/EventCompaction.java +++ b/core/src/main/java/com/google/adk/events/EventCompaction.java @@ -1,3 +1,19 @@ +/* + * 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.events; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsClient.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsClient.java index b07c9a4ee..8f3990d7a 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsClient.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsClient.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsCommon.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsCommon.java index 530154727..dcde4c548 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsCommon.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsCommon.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsHttpClient.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsHttpClient.java index 236e9b56e..fe9696621 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsHttpClient.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsHttpClient.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java index f9d4adf6e..0c8cdc006 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsResponse.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsResponse.java index 768af850e..04c30dd82 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsResponse.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsResponse.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/sessions/ApiClient.java b/core/src/main/java/com/google/adk/sessions/ApiClient.java index 3b42f6693..0c630e460 100644 --- a/core/src/main/java/com/google/adk/sessions/ApiClient.java +++ b/core/src/main/java/com/google/adk/sessions/ApiClient.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/sessions/ApiResponse.java b/core/src/main/java/com/google/adk/sessions/ApiResponse.java index 018c173a4..7e3393d7d 100644 --- a/core/src/main/java/com/google/adk/sessions/ApiResponse.java +++ b/core/src/main/java/com/google/adk/sessions/ApiResponse.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/sessions/HttpApiClient.java b/core/src/main/java/com/google/adk/sessions/HttpApiClient.java index 3ddb97bda..ffd6d8d36 100644 --- a/core/src/main/java/com/google/adk/sessions/HttpApiClient.java +++ b/core/src/main/java/com/google/adk/sessions/HttpApiClient.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/sessions/HttpApiResponse.java b/core/src/main/java/com/google/adk/sessions/HttpApiResponse.java index aca5eeeae..f98b7a173 100644 --- a/core/src/main/java/com/google/adk/sessions/HttpApiResponse.java +++ b/core/src/main/java/com/google/adk/sessions/HttpApiResponse.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/main/java/com/google/adk/sessions/VertexAiClient.java b/core/src/main/java/com/google/adk/sessions/VertexAiClient.java index 34340bcb9..478b2761b 100644 --- a/core/src/main/java/com/google/adk/sessions/VertexAiClient.java +++ b/core/src/main/java/com/google/adk/sessions/VertexAiClient.java @@ -1,3 +1,19 @@ +/* + * 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.sessions; import static java.util.concurrent.TimeUnit.SECONDS; diff --git a/core/src/main/java/com/google/adk/summarizer/EventCompactor.java b/core/src/main/java/com/google/adk/summarizer/EventCompactor.java index de62bc960..8c055275b 100644 --- a/core/src/main/java/com/google/adk/summarizer/EventCompactor.java +++ b/core/src/main/java/com/google/adk/summarizer/EventCompactor.java @@ -1,3 +1,19 @@ +/* + * 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.summarizer; import com.google.adk.events.Event; diff --git a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolset.java b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolset.java index 83618e3b2..e3bce578f 100644 --- a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolset.java +++ b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolset.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.base.Strings.isNullOrEmpty; diff --git a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClient.java b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClient.java index 36e94a957..8415f034c 100644 --- a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClient.java +++ b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClient.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.base.Strings.isNullOrEmpty; diff --git a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelper.java b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelper.java index c6c26d0af..7b6388074 100644 --- a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelper.java +++ b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools.applicationintegrationtoolset; import com.google.auth.Credentials; diff --git a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/GoogleCredentialsHelper.java b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/GoogleCredentialsHelper.java index c78d91159..044853009 100644 --- a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/GoogleCredentialsHelper.java +++ b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/GoogleCredentialsHelper.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools.applicationintegrationtoolset; import static java.nio.charset.StandardCharsets.UTF_8; diff --git a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClient.java b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClient.java index 3b63429a9..b683c3518 100644 --- a/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClient.java +++ b/core/src/main/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClient.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.base.Strings.isNullOrEmpty; diff --git a/core/src/main/java/com/google/adk/tools/mcp/DefaultMcpTransportBuilder.java b/core/src/main/java/com/google/adk/tools/mcp/DefaultMcpTransportBuilder.java index 6321da813..1e951dbda 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/DefaultMcpTransportBuilder.java +++ b/core/src/main/java/com/google/adk/tools/mcp/DefaultMcpTransportBuilder.java @@ -1,3 +1,19 @@ +/* + * 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.tools.mcp; import static com.google.common.base.Strings.isNullOrEmpty; diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpAsyncToolset.java b/core/src/main/java/com/google/adk/tools/mcp/McpAsyncToolset.java index cb541eccf..543761cd7 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpAsyncToolset.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpAsyncToolset.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpServerLogConsumer.java b/core/src/main/java/com/google/adk/tools/mcp/McpServerLogConsumer.java index 921197061..3b5ba81cb 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpServerLogConsumer.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpServerLogConsumer.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java b/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java index dae35f77e..5ced6c774 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpToolset.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpToolsetException.java b/core/src/main/java/com/google/adk/tools/mcp/McpToolsetException.java index 062fe5e2a..5dfda8ab0 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpToolsetException.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpToolsetException.java @@ -1,3 +1,19 @@ +/* + * 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.tools.mcp; /** Base exception for all errors originating from {@code McpToolset}. */ diff --git a/core/src/main/java/com/google/adk/tools/mcp/McpTransportBuilder.java b/core/src/main/java/com/google/adk/tools/mcp/McpTransportBuilder.java index c44e779c1..8ccd02136 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/McpTransportBuilder.java +++ b/core/src/main/java/com/google/adk/tools/mcp/McpTransportBuilder.java @@ -1,3 +1,19 @@ +/* + * 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.tools.mcp; import io.modelcontextprotocol.spec.McpClientTransport; diff --git a/core/src/main/java/com/google/adk/tools/mcp/StdioConnectionParameters.java b/core/src/main/java/com/google/adk/tools/mcp/StdioConnectionParameters.java index e6a3aa490..3d7fb5c6f 100644 --- a/core/src/main/java/com/google/adk/tools/mcp/StdioConnectionParameters.java +++ b/core/src/main/java/com/google/adk/tools/mcp/StdioConnectionParameters.java @@ -1,3 +1,19 @@ +/* + * 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.tools.mcp; import com.fasterxml.jackson.annotation.JsonCreator; diff --git a/core/src/main/java/com/google/adk/utils/AgentEnums.java b/core/src/main/java/com/google/adk/utils/AgentEnums.java index 05460b540..50f755fee 100644 --- a/core/src/main/java/com/google/adk/utils/AgentEnums.java +++ b/core/src/main/java/com/google/adk/utils/AgentEnums.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.utils; /** Enums for agents. */ diff --git a/core/src/test/java/com/google/adk/codeexecutors/BuiltInCodeExecutorTest.java b/core/src/test/java/com/google/adk/codeexecutors/BuiltInCodeExecutorTest.java index e3e4c660c..b736c6bd8 100644 --- a/core/src/test/java/com/google/adk/codeexecutors/BuiltInCodeExecutorTest.java +++ b/core/src/test/java/com/google/adk/codeexecutors/BuiltInCodeExecutorTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.codeexecutors; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsCommonTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsCommonTest.java index 8ddafe0f9..3f9d556ad 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsCommonTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsCommonTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.chat; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsHttpClientTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsHttpClientTest.java index cdb83393e..dec023804 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsHttpClientTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsHttpClientTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java index ac61fcbcc..1bb4c36b2 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsResponseTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsResponseTest.java index d93486e98..9d7ba4154 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsResponseTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsResponseTest.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -1203,7 +1203,8 @@ public void testChunkCollection_streamingToolCall_backfillsMessageLevelSignature @Test public void testChunkCollection_streamingToolCall_parsesValidJsonArgs() throws Exception { String chunk1 = - "{\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call_1\",\"type\":\"function\",\"function\":{\"name\":\"do_thing\",\"arguments\":\"{\\\"key\\\": \\\"value\\\"}\"}}]}}]}"; + "{\"choices\":[{\"delta\":{\"tool_calls\":[{\"index\":0,\"id\":\"call_1\",\"type\":\"function\",\"function\":{\"name\":\"do_thing\",\"arguments\":\"{\\\"key\\\":" + + " \\\"value\\\"}\"}}]}}]}"; String chunk2 = "{\"choices\":[{\"finish_reason\":\"tool_calls\"}]}"; ImmutableList all = runStream(chunk1, chunk2); diff --git a/core/src/test/java/com/google/adk/sessions/MockApiAnswer.java b/core/src/test/java/com/google/adk/sessions/MockApiAnswer.java index 3744ac05d..36b3d92b9 100644 --- a/core/src/test/java/com/google/adk/sessions/MockApiAnswer.java +++ b/core/src/test/java/com/google/adk/sessions/MockApiAnswer.java @@ -1,3 +1,19 @@ +/* + * 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.sessions; import com.fasterxml.jackson.core.type.TypeReference; diff --git a/core/src/test/java/com/google/adk/sessions/SessionJsonConverterTest.java b/core/src/test/java/com/google/adk/sessions/SessionJsonConverterTest.java index 335f7f1d0..a63e3b38d 100644 --- a/core/src/test/java/com/google/adk/sessions/SessionJsonConverterTest.java +++ b/core/src/test/java/com/google/adk/sessions/SessionJsonConverterTest.java @@ -1,3 +1,19 @@ +/* + * 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.sessions; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/sessions/SessionTest.java b/core/src/test/java/com/google/adk/sessions/SessionTest.java index a96b63acd..b013e71ac 100644 --- a/core/src/test/java/com/google/adk/sessions/SessionTest.java +++ b/core/src/test/java/com/google/adk/sessions/SessionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.sessions; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/sessions/StateTest.java b/core/src/test/java/com/google/adk/sessions/StateTest.java index 295466d1c..238965f1e 100644 --- a/core/src/test/java/com/google/adk/sessions/StateTest.java +++ b/core/src/test/java/com/google/adk/sessions/StateTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.sessions; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java index 6f63efd12..0bfdd4b48 100644 --- a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java +++ b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java @@ -1,3 +1,19 @@ +/* + * 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.sessions; import static com.google.common.collect.ImmutableList.toImmutableList; diff --git a/core/src/test/java/com/google/adk/tools/BaseToolTest.java b/core/src/test/java/com/google/adk/tools/BaseToolTest.java index 513297d93..960e8aab3 100644 --- a/core/src/test/java/com/google/adk/tools/BaseToolTest.java +++ b/core/src/test/java/com/google/adk/tools/BaseToolTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/BaseToolsetTest.java b/core/src/test/java/com/google/adk/tools/BaseToolsetTest.java index bbdf9dd94..e8d0b222d 100644 --- a/core/src/test/java/com/google/adk/tools/BaseToolsetTest.java +++ b/core/src/test/java/com/google/adk/tools/BaseToolsetTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/GoogleSearchAgentToolTest.java b/core/src/test/java/com/google/adk/tools/GoogleSearchAgentToolTest.java index 8305274a1..bac939013 100644 --- a/core/src/test/java/com/google/adk/tools/GoogleSearchAgentToolTest.java +++ b/core/src/test/java/com/google/adk/tools/GoogleSearchAgentToolTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java b/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java index f03e51ec2..e95f9cabb 100644 --- a/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java +++ b/core/src/test/java/com/google/adk/tools/LoadArtifactsToolTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/LongRunningFunctionToolTest.java b/core/src/test/java/com/google/adk/tools/LongRunningFunctionToolTest.java index eda9660ce..a6b51360c 100644 --- a/core/src/test/java/com/google/adk/tools/LongRunningFunctionToolTest.java +++ b/core/src/test/java/com/google/adk/tools/LongRunningFunctionToolTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/ToolContextTest.java b/core/src/test/java/com/google/adk/tools/ToolContextTest.java index f9aae7950..c3cca4dec 100644 --- a/core/src/test/java/com/google/adk/tools/ToolContextTest.java +++ b/core/src/test/java/com/google/adk/tools/ToolContextTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/VertexAiSearchAgentToolTest.java b/core/src/test/java/com/google/adk/tools/VertexAiSearchAgentToolTest.java index a93030735..a78f10bb1 100644 --- a/core/src/test/java/com/google/adk/tools/VertexAiSearchAgentToolTest.java +++ b/core/src/test/java/com/google/adk/tools/VertexAiSearchAgentToolTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/VertexAiSearchToolTest.java b/core/src/test/java/com/google/adk/tools/VertexAiSearchToolTest.java index 81b2e10e2..1b109e1bf 100644 --- a/core/src/test/java/com/google/adk/tools/VertexAiSearchToolTest.java +++ b/core/src/test/java/com/google/adk/tools/VertexAiSearchToolTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolsetTest.java b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolsetTest.java index d57c66141..93c19a4f8 100644 --- a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolsetTest.java +++ b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ApplicationIntegrationToolsetTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClientTest.java b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClientTest.java index d5723e7f1..78a008781 100644 --- a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClientTest.java +++ b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/ConnectionsClientTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelperTest.java b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelperTest.java index 7e6687990..9b071394f 100644 --- a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelperTest.java +++ b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/CredentialsHelperTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2026 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.tools.applicationintegrationtoolset; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClientTest.java b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClientTest.java index 104efe495..41ad8bd70 100644 --- a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClientTest.java +++ b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationClientTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationConnectorToolTest.java b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationConnectorToolTest.java index 4287a8e6b..d964e2af6 100644 --- a/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationConnectorToolTest.java +++ b/core/src/test/java/com/google/adk/tools/applicationintegrationtoolset/IntegrationConnectorToolTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools.applicationintegrationtoolset; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java b/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java index 164105aa6..001e98192 100644 --- a/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java +++ b/core/src/test/java/com/google/adk/tools/mcp/McpToolsetTest.java @@ -5,7 +5,7 @@ * 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 + * 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, diff --git a/core/src/test/java/com/google/adk/tools/retrieval/VertexAiRagRetrievalTest.java b/core/src/test/java/com/google/adk/tools/retrieval/VertexAiRagRetrievalTest.java index 8246751b9..1b8cbf66a 100644 --- a/core/src/test/java/com/google/adk/tools/retrieval/VertexAiRagRetrievalTest.java +++ b/core/src/test/java/com/google/adk/tools/retrieval/VertexAiRagRetrievalTest.java @@ -1,3 +1,19 @@ +/* + * 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.tools.retrieval; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/utils/InstructionUtilsTest.java b/core/src/test/java/com/google/adk/utils/InstructionUtilsTest.java index 48b2531d3..4437b242d 100644 --- a/core/src/test/java/com/google/adk/utils/InstructionUtilsTest.java +++ b/core/src/test/java/com/google/adk/utils/InstructionUtilsTest.java @@ -1,3 +1,19 @@ +/* + * 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.utils; import static com.google.adk.testing.TestUtils.createRootAgent; diff --git a/core/src/test/java/com/google/adk/utils/ModelNameUtilsTest.java b/core/src/test/java/com/google/adk/utils/ModelNameUtilsTest.java index 86bf126f6..0dc573fdd 100644 --- a/core/src/test/java/com/google/adk/utils/ModelNameUtilsTest.java +++ b/core/src/test/java/com/google/adk/utils/ModelNameUtilsTest.java @@ -1,3 +1,19 @@ +/* + * 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.utils; import static com.google.common.truth.Truth.assertThat; diff --git a/core/src/test/java/com/google/adk/utils/PairsTest.java b/core/src/test/java/com/google/adk/utils/PairsTest.java index e10353e71..e90e50331 100644 --- a/core/src/test/java/com/google/adk/utils/PairsTest.java +++ b/core/src/test/java/com/google/adk/utils/PairsTest.java @@ -1,3 +1,19 @@ +/* + * 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.utils; import static org.junit.Assert.assertEquals; diff --git a/dev/src/main/java/com/google/adk/web/AgentLoader.java b/dev/src/main/java/com/google/adk/web/AgentLoader.java index 5294d1d1b..3eb96ce50 100644 --- a/dev/src/main/java/com/google/adk/web/AgentLoader.java +++ b/dev/src/main/java/com/google/adk/web/AgentLoader.java @@ -1,15 +1,17 @@ /* * 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 + * 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 + * 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. + * 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.web; diff --git a/dev/src/test/java/com/google/adk/web/AgentStaticLoaderTest.java b/dev/src/test/java/com/google/adk/web/AgentStaticLoaderTest.java index 37516cebd..d52d75909 100644 --- a/dev/src/test/java/com/google/adk/web/AgentStaticLoaderTest.java +++ b/dev/src/test/java/com/google/adk/web/AgentStaticLoaderTest.java @@ -1,3 +1,19 @@ +/* + * 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.web; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieRegistry.java b/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieRegistry.java index 4d4b94de8..00f92f591 100644 --- a/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieRegistry.java +++ b/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieRegistry.java @@ -1,3 +1,19 @@ +/* + * 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.example; import com.google.adk.utils.ComponentRegistry; diff --git a/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieTool.java b/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieTool.java index 71def3687..f1e27002c 100644 --- a/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieTool.java +++ b/maven_plugin/examples/custom_tools/src/main/java/com/example/CustomDieTool.java @@ -1,3 +1,19 @@ +/* + * 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.example; import com.google.adk.tools.Annotations.Schema; diff --git a/maven_plugin/examples/custom_tools/src/main/java/com/example/GetWeatherTool.java b/maven_plugin/examples/custom_tools/src/main/java/com/example/GetWeatherTool.java index 2c28a919d..679ec55bb 100644 --- a/maven_plugin/examples/custom_tools/src/main/java/com/example/GetWeatherTool.java +++ b/maven_plugin/examples/custom_tools/src/main/java/com/example/GetWeatherTool.java @@ -1,3 +1,19 @@ +/* + * 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.example; import static com.google.common.base.Strings.isNullOrEmpty; diff --git a/maven_plugin/src/main/java/com/google/adk/maven/AgentLoader.java b/maven_plugin/src/main/java/com/google/adk/maven/AgentLoader.java index 44b2a1ddb..9e51bfcfc 100644 --- a/maven_plugin/src/main/java/com/google/adk/maven/AgentLoader.java +++ b/maven_plugin/src/main/java/com/google/adk/maven/AgentLoader.java @@ -1,15 +1,17 @@ /* * 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 + * 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 + * 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. + * 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.maven; From ccc84b001bb978e7cda5949cd8e0c65d8647074d Mon Sep 17 00:00:00 2001 From: Roland Kakonyi Date: Mon, 4 May 2026 10:35:57 +0200 Subject: [PATCH 10/14] Fix Vertex session user IDs --- .../adk/sessions/VertexAiSessionService.java | 2 +- .../sessions/VertexAiSessionServiceTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java b/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java index 6831baefb..246e48498 100644 --- a/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java +++ b/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java @@ -148,7 +148,7 @@ private ListSessionsResponse parseListSessionsResponse( Session session = Session.builder(sessionId) .appName(appName) - .userId(userId) + .userId((String) apiSession.get("userId")) .state( apiSession.get("sessionState") == null ? new ConcurrentHashMap<>() diff --git a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java index 0bfdd4b48..ffa5b184f 100644 --- a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java +++ b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java @@ -295,6 +295,34 @@ public void listSessions_success() { assertThat(sessionsList).hasSize(2); ImmutableList ids = sessionsList.stream().map(Session::id).collect(toImmutableList()); assertThat(ids).containsExactly("1", "2"); + ImmutableList userIds = + sessionsList.stream().map(Session::userId).collect(toImmutableList()); + assertThat(userIds).containsExactly("user", "user"); + } + + @Test + public void listSessions_usesResponseUserId() throws Exception { + when(mockApiClient.request( + "GET", "reasoningEngines/123/sessions?filter=user_id%3D%22user1%22", "")) + .thenAnswer( + new MockApiAnswer( + """ + { + "sessions": [ + { + "name": "projects/test-project/locations/test-location/reasoningEngines/123/sessions/3", + "userId": "user2", + "updateTime": "2024-12-14T12:12:12.123456Z" + } + ] + }\ + """)); + + ListSessionsResponse sessions = + vertexAiSessionService.listSessions("123", "user1").blockingGet(); + + assertThat(sessions.sessions()).hasSize(1); + assertThat(sessions.sessions().get(0).userId()).isEqualTo("user2"); } @Test From 4d19f7d92becff955de12e2a58bc6bb23f14492d Mon Sep 17 00:00:00 2001 From: Kamil Tomaszek Date: Thu, 23 Jul 2026 06:32:16 -0700 Subject: [PATCH 11/14] fix(sessions): apply numRecentEvents and afterTimestamp together in InMemorySessionService `getSession` applied `afterTimestamp` only when `numRecentEvents` was unset, so the two `GetSessionConfig` filters could not be combined. Apply `numRecentEvents` first, then `afterTimestamp`, so both compose. Mirrors Python and Go, which already apply both. PiperOrigin-RevId: 952725154 --- .../adk/sessions/InMemorySessionService.java | 12 +++++----- .../sessions/InMemorySessionServiceTest.java | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java b/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java index 72a14cc4d..e54289b76 100644 --- a/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java +++ b/core/src/main/java/com/google/adk/sessions/InMemorySessionService.java @@ -150,12 +150,12 @@ public Maybe getSession( } }); - // Only apply timestamp filter if numRecentEvents was not applied - if (config.numRecentEvents().isEmpty() && config.afterTimestamp().isPresent()) { - Instant threshold = config.afterTimestamp().get(); - - eventsInCopy.removeIf(event -> getInstantFromEvent(event).isBefore(threshold)); - } + // Then drop events before afterTimestamp, so both filters compose. + config + .afterTimestamp() + .ifPresent( + threshold -> + eventsInCopy.removeIf(event -> getInstantFromEvent(event).isBefore(threshold))); // Merge state into the potentially filtered copy and return return Maybe.just(mergeWithGlobalState(appName, userId, sessionCopy)); diff --git a/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java b/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java index 6a271efac..58c445641 100644 --- a/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java +++ b/core/src/test/java/com/google/adk/sessions/InMemorySessionServiceTest.java @@ -317,4 +317,27 @@ public void deleteSession_doesNotRemoveUserMapWhenOtherSessionsExist() throws Ex assertThat(sessions.get("app-name").get("user-id")).isNotNull(); assertThat(sessions.get("app-name").get("user-id")).hasSize(1); } + + @Test + public void getSession_numRecentEventsAndAfterTimestamp_appliesBothFilters() { + InMemorySessionService sessionService = new InMemorySessionService(); + Session session = sessionService.createSession("app", "user").blockingGet(); + for (long ts : new long[] {100, 200, 300, 400, 500}) { + var unused = + sessionService.appendEvent(session, Event.builder().timestamp(ts).build()).blockingGet(); + } + GetSessionConfig config = + GetSessionConfig.builder() + .numRecentEvents(4) + .afterTimestamp(Instant.ofEpochMilli(300)) + .build(); + + Session retrieved = + sessionService.getSession("app", "user", session.id(), Optional.of(config)).blockingGet(); + + // numRecentEvents keeps 200..500, then afterTimestamp drops 200; the pre-fix code kept 200. + assertThat(retrieved.events().stream().map(Event::timestamp)) + .containsExactly(300L, 400L, 500L) + .inOrder(); + } } From 24a4588004228d6117d9ab4a45ce93be4c952d3c Mon Sep 17 00:00:00 2001 From: Kamil Tomaszek Date: Thu, 23 Jul 2026 08:07:48 -0700 Subject: [PATCH 12/14] fix(sessions): apply afterTimestamp and numRecentEvents together in VertexAiSessionService `getSession` gated the server-side `timestamp>=` filter on `numRecentEvents` being absent, so the two `GetSessionConfig` filters could not be combined. Send the `afterTimestamp` filter whenever it is set and still trim to `numRecentEvents` client-side, so both compose. Mirrors the Go port, which already applies both. PiperOrigin-RevId: 952765675 --- .../adk/sessions/VertexAiSessionService.java | 9 ++-- .../sessions/VertexAiSessionServiceTest.java | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java b/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java index 6831baefb..c1a665e80 100644 --- a/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java +++ b/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java @@ -249,14 +249,11 @@ public Maybe getSession( } /** - * Builds the server-side events filter for {@code afterTimestamp}, mirroring the Python and Go - * implementations (inclusive {@code timestamp>=}). The filter is only applied when {@code - * numRecentEvents} is not set, matching the precedence in {@link #filterEvents}. + * Inclusive server-side {@code timestamp>=} filter for {@code afterTimestamp}, or null. Applied + * independently of {@code numRecentEvents} (see {@link #filterEvents}), so both filters compose. */ private static @Nullable String afterTimestampFilter(Optional config) { - if (config.isPresent() - && config.get().numRecentEvents().isEmpty() - && config.get().afterTimestamp().isPresent()) { + if (config.isPresent() && config.get().afterTimestamp().isPresent()) { return "timestamp>=\"" + config.get().afterTimestamp().get() + "\""; } return null; diff --git a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java index 0bfdd4b48..2271db132 100644 --- a/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java +++ b/core/src/test/java/com/google/adk/sessions/VertexAiSessionServiceTest.java @@ -587,6 +587,52 @@ public void getSession_numRecentEventsConfig_returnsMostRecentEvents() { assertThat(session.events().stream().map(Event::id)).containsExactly("e2", "e3").inOrder(); } + @Test + public void getSession_afterTimestampNarrowerThanNumRecentEvents_appliesBothFilters() { + sessionMap.put("10", mockSessionJson("10", "2024-12-12T12:00:30.000000Z")); + eventMap.put( + "10", + mockEventsJson( + mockEventJson("e1", "2024-12-12T12:00:05.000000Z"), + mockEventJson("e2", "2024-12-12T12:00:10.000000Z"), + mockEventJson("e3", "2024-12-12T12:00:15.000000Z"), + mockEventJson("e4", "2024-12-12T12:00:20.000000Z"))); + GetSessionConfig config = + GetSessionConfig.builder() + .afterTimestamp(Instant.parse("2024-12-12T12:00:15.000000Z")) + .numRecentEvents(3) + .build(); + + Session session = + vertexAiSessionService.getSession("123", "user", "10", Optional.of(config)).blockingGet(); + + // afterTimestamp must be applied: without it, numRecentEvents(3) would keep e2, e3, e4. + assertThat(session.events().stream().map(Event::id)).containsExactly("e3", "e4").inOrder(); + } + + @Test + public void getSession_numRecentEventsNarrowerThanAfterTimestamp_appliesBothFilters() { + sessionMap.put("11", mockSessionJson("11", "2024-12-12T12:00:30.000000Z")); + eventMap.put( + "11", + mockEventsJson( + mockEventJson("e1", "2024-12-12T12:00:05.000000Z"), + mockEventJson("e2", "2024-12-12T12:00:10.000000Z"), + mockEventJson("e3", "2024-12-12T12:00:15.000000Z"), + mockEventJson("e4", "2024-12-12T12:00:20.000000Z"))); + GetSessionConfig config = + GetSessionConfig.builder() + .afterTimestamp(Instant.parse("2024-12-12T12:00:10.000000Z")) + .numRecentEvents(2) + .build(); + + Session session = + vertexAiSessionService.getSession("123", "user", "11", Optional.of(config)).blockingGet(); + + // afterTimestamp keeps e2, e3, e4; numRecentEvents must then trim to the 2 most recent. + assertThat(session.events().stream().map(Event::id)).containsExactly("e3", "e4").inOrder(); + } + private static String mockSessionJson(String sessionId, String updateTime) { return String.format( """ From 03b04fa2b17b8b9fc508add4d1013e83a4975cfe Mon Sep 17 00:00:00 2001 From: svetanis Date: Thu, 23 Jul 2026 23:12:23 -0700 Subject: [PATCH 13/14] fix(events): accumulate endOfAgent in EventActions.merge to preserve parallel stop requests --- .../java/com/google/adk/events/EventActions.java | 2 +- .../com/google/adk/events/EventActionsTest.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/adk/events/EventActions.java b/core/src/main/java/com/google/adk/events/EventActions.java index c3c921be5..cde23c10e 100644 --- a/core/src/main/java/com/google/adk/events/EventActions.java +++ b/core/src/main/java/com/google/adk/events/EventActions.java @@ -393,7 +393,7 @@ public Builder merge(EventActions other) { other.escalate().ifPresent(this::escalate); this.requestedAuthConfigs.putAll(other.requestedAuthConfigs()); this.requestedToolConfirmations.putAll(other.requestedToolConfirmations()); - this.endOfAgent = other.endOfAgent(); + this.endOfAgent = this.endOfAgent || other.endOfAgent(); other.compaction().ifPresent(this::compaction); return this; } diff --git a/core/src/test/java/com/google/adk/events/EventActionsTest.java b/core/src/test/java/com/google/adk/events/EventActionsTest.java index 4b542c0e9..c5949caf7 100644 --- a/core/src/test/java/com/google/adk/events/EventActionsTest.java +++ b/core/src/test/java/com/google/adk/events/EventActionsTest.java @@ -111,6 +111,20 @@ public void merge_mergesAllFields() { assertThat(merged.compaction()).hasValue(COMPACTION); } + @Test + public void merge_endOfAgentIsOrderIndependent() { + // A tool that ends the invocation, and one that leaves the flag at its default false. Folding + // parallel tool responses must keep endOfAgent set whichever order they are merged in. + EventActions requestsStop = EventActions.builder().endOfAgent(true).build(); + EventActions leavesUnset = EventActions.builder().build(); + + EventActions stopFirst = EventActions.builder().merge(requestsStop).merge(leavesUnset).build(); + EventActions stopLast = EventActions.builder().merge(leavesUnset).merge(requestsStop).build(); + + assertThat(stopFirst.endOfAgent()).isTrue(); + assertThat(stopLast.endOfAgent()).isTrue(); + } + @Test public void setArtifactDelta_copiesRegularMap() { EventActions eventActions = new EventActions(); From 8049f7e5362ca654bf3706ea465f8d1021ee0346 Mon Sep 17 00:00:00 2001 From: Kamil Tomaszek Date: Tue, 28 Jul 2026 05:28:05 -0700 Subject: [PATCH 14/14] fix(codeexecutors): add opt-in strict sandbox to ContainerCodeExecutor PiperOrigin-RevId: 955201053 --- .../codeexecutors/ContainerCodeExecutor.java | 383 ++++++++++++++---- .../ContainerCodeExecutorTest.java | 311 ++++++++++++++ 2 files changed, 615 insertions(+), 79 deletions(-) create mode 100644 core/src/test/java/com/google/adk/codeexecutors/ContainerCodeExecutorTest.java diff --git a/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java b/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java index a16379455..5d6460823 100644 --- a/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java +++ b/core/src/main/java/com/google/adk/codeexecutors/ContainerCodeExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 Google LLC + * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,33 +19,87 @@ import static java.util.Objects.requireNonNullElse; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.ExecCreateCmdResponse; -import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.Capability; +import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.command.ExecStartResultCallback; import com.google.adk.agents.InvocationContext; import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionInput; import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionResult; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** A code executor that uses a custom container to execute code. */ -public class ContainerCodeExecutor extends BaseCodeExecutor { +/** + * A code executor that runs code in a Docker container. + * + *

Code is run via {@code docker exec} (as in ADK Python), so the image only needs {@code + * python3} on its PATH; any image {@code ENTRYPOINT} is bypassed. By default a single container is + * created on first use and reused for every {@link #executeCode} call, as in ADK Python. With the + * strict sandbox enabled, each execution instead runs in a fresh container that is force-removed + * afterwards, so one execution cannot observe or affect another's environment. + * + *

Sandboxing is opt-in. By default the execution container is unrestricted (network + * enabled, writable filesystem, no resource or time limits), matching the previous behavior so + * existing callers are not broken; a warning is logged when it is used this way. Call {@link + * #setStrictSandbox(boolean) setStrictSandbox(true)} to harden each container: no network (unless + * re-enabled via {@link #setNetworkEnabled(boolean)}), all Linux capabilities dropped, no privilege + * escalation, a read-only root filesystem with a small writable {@code /tmp} tmpfs, memory/PID + * limits, and a wall-clock execution timeout. Strict sandboxing becomes the default in ADK 2.0. + * + *

The execution timeout and memory limit used by the strict sandbox are configurable via {@link + * #setExecutionTimeoutSeconds(long)} and {@link #setMemoryLimitBytes(long)}. + * + *

This executor holds a {@link DockerClient}; call {@link #close()} (or rely on the registered + * JVM shutdown hook) to release its connections and threads. As with ADK Python, an abrupt JVM + * termination (e.g. SIGKILL) during an execution may leave a container behind. + */ +public class ContainerCodeExecutor extends BaseCodeExecutor implements AutoCloseable { private static final Logger logger = LoggerFactory.getLogger(ContainerCodeExecutor.class); private static final String DEFAULT_IMAGE_TAG = "adk-code-executor:latest"; + /** Default memory limit for each execution container (512 MiB). */ + private static final long DEFAULT_MEMORY_LIMIT_BYTES = 512L * 1024 * 1024; + + /** Maximum number of processes/threads allowed inside an execution container. */ + private static final long PIDS_LIMIT = 128L; + + /** Default max wall-clock time a single execution may run before its container is killed. */ + private static final long DEFAULT_EXECUTION_TIMEOUT_SECONDS = 60L; + private final String baseUrl; private final String image; private final String dockerPath; private final DockerClient dockerClient; - private Container container; + // Registered by the image/dockerPath constructor as a backstop; removed in close() so a closed + // executor is not retained by the JVM's shutdown-hook list. + private final Thread shutdownHook = new Thread(this::close); + private boolean networkEnabled = false; + private long executionTimeoutSeconds = DEFAULT_EXECUTION_TIMEOUT_SECONDS; + private long memoryLimitBytes = DEFAULT_MEMORY_LIMIT_BYTES; + + // Off by default so this executor does not change behavior for existing callers; a warning is + // logged while it is disabled, and it becomes the default in ADK 2.0. + private boolean strictSandbox = false; + private final AtomicBoolean strictSandboxWarningLogged = new AtomicBoolean(false); + + // Container reused across executions while the strict sandbox is off, preserving the previous + // behavior (and matching ADK Python). Created on first use and removed by close(); the strict + // sandbox uses a fresh, hardened container per execution instead. + private String sharedContainerId; /** * Creates a ContainerCodeExecutor from an image. @@ -99,17 +153,74 @@ public ContainerCodeExecutor(String baseUrl, String image, String dockerPath) { this.baseUrl = baseUrl; this.image = requireNonNullElse(image, DEFAULT_IMAGE_TAG); this.dockerPath = dockerPath == null ? null : Paths.get(dockerPath).toAbsolutePath().toString(); - - if (baseUrl != null) { - var config = - DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost(baseUrl).build(); - this.dockerClient = DockerClientBuilder.getInstance(config).build(); - } else { - this.dockerClient = DockerClientBuilder.getInstance().build(); + this.dockerClient = buildDockerClient(baseUrl); + try { + prepareImage(); + } catch (RuntimeException | Error e) { + // The caller never receives this instance, so it can never call close(); release the client's + // connections and threads here instead of leaking them. + closeDockerClientQuietly(); + throw e; } + // Backstop so the client is released even if callers forget to close() this executor. + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + /** Test-only constructor that injects a Docker client and skips image preparation. */ + @VisibleForTesting + ContainerCodeExecutor(DockerClient dockerClient, String image) { + this.baseUrl = null; + this.image = requireNonNullElse(image, DEFAULT_IMAGE_TAG); + this.dockerPath = null; + this.dockerClient = dockerClient; + } + + /** + * Enables or disables container networking when the strict sandbox is on. In strict mode + * networking is disabled by default so executed code cannot reach the network (including the + * cloud metadata endpoint); pass {@code true} to allow it. Has no effect unless {@link + * #setStrictSandbox(boolean)} is enabled — without the sandbox the container always has network + * access. + */ + public ContainerCodeExecutor setNetworkEnabled(boolean networkEnabled) { + this.networkEnabled = networkEnabled; + return this; + } + + /** + * Sets the maximum wall-clock time (in seconds) a single execution may run, in the strict + * sandbox, before its container is force-removed (killed). Defaults to 60 seconds. Has no effect + * unless {@link #setStrictSandbox(boolean)} is enabled. + */ + public ContainerCodeExecutor setExecutionTimeoutSeconds(long executionTimeoutSeconds) { + this.executionTimeoutSeconds = executionTimeoutSeconds; + return this; + } + + /** + * Sets the per-execution container memory limit, in bytes, used by the strict sandbox. Defaults + * to 512 MiB. Has no effect unless {@link #setStrictSandbox(boolean)} is enabled. + */ + public ContainerCodeExecutor setMemoryLimitBytes(long memoryLimitBytes) { + this.memoryLimitBytes = memoryLimitBytes; + return this; + } - initContainer(); - Runtime.getRuntime().addShutdownHook(new Thread(this::cleanupContainer)); + /** + * Enables the strict sandbox. When enabled, each execution runs in its own fresh container + * (force-removed afterwards) that is hardened: no network (unless re-enabled via {@link + * #setNetworkEnabled(boolean)}), all Linux capabilities dropped, no privilege escalation, a + * read-only root filesystem (writable {@code /tmp} only), memory/PID limits, and a wall-clock + * timeout. While disabled, a single unrestricted container is reused across executions, as + * before. + * + *

Disabled by default so enabling the sandbox is not a breaking change for existing callers. + * While it is disabled a warning is logged, because running untrusted, model-generated code + * without the sandbox is dangerous. Strict sandboxing becomes the default in ADK 2.0. + */ + public ContainerCodeExecutor setStrictSandbox(boolean strictSandbox) { + this.strictSandbox = strictSandbox; + return this; } @Override @@ -125,70 +236,194 @@ public boolean optimizeDataFile() { @Override public CodeExecutionResult executeCode( InvocationContext invocationContext, CodeExecutionInput codeExecutionInput) { + warnIfStrictSandboxDisabled(); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - ExecCreateCmdResponse execCreateCmdResponse = - dockerClient - .execCreateCmd(container.getId()) - .withAttachStdout(true) - .withAttachStderr(true) - .withCmd("python3", "-c", codeExecutionInput.code()) - .exec(); + // The strict sandbox gives each execution its own hardened container, force-removed afterwards, + // so one run cannot observe or affect another's environment. Without it a single unrestricted + // container is created on first use and reused, preserving the previous behavior (and matching + // ADK Python). Code is run via `docker exec`, which needs only `python3` on the image and + // bypasses any ENTRYPOINT. + boolean perExecutionContainer = strictSandbox; + String containerId = + perExecutionContainer ? createAndStartContainer(/* hardened= */ true) : sharedContainer(); try { - dockerClient - .execStartCmd(execCreateCmdResponse.getId()) - .exec(new ExecStartResultCallback(stdout, stderr)) - .awaitCompletion(); + ExecCreateCmdResponse execCreateCmdResponse = + dockerClient + .execCreateCmd(containerId) + .withAttachStdout(true) + .withAttachStderr(true) + .withCmd("python3", "-c", codeExecutionInput.code()) + .exec(); + + boolean completed; + ExecStartResultCallback callback = new ExecStartResultCallback(stdout, stderr); + try { + dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(callback); + if (strictSandbox) { + completed = callback.awaitCompletion(executionTimeoutSeconds, TimeUnit.SECONDS); + } else { + // No execution timeout unless the strict sandbox is enabled, matching prior behavior. + callback.awaitCompletion(); + completed = true; + } + } finally { + closeQuietly(callback); + } + + if (!completed) { + // Force-removing the container in the finally block kills the still-running execution + // (timeouts only apply in the strict sandbox, which always uses a per-execution container). + // Whatever the code printed before being killed is kept: it is often what tells the model + // how far the execution got. + String timedOut = + String.format("Code execution timed out after %d seconds.", executionTimeoutSeconds); + String partialStderr = stderr.toString(StandardCharsets.UTF_8); + return CodeExecutionResult.builder() + .stdout(stdout.toString(StandardCharsets.UTF_8)) + .stderr(partialStderr.isEmpty() ? timedOut : partialStderr + "\n" + timedOut) + .build(); + } + return CodeExecutionResult.builder() + .stdout(stdout.toString(StandardCharsets.UTF_8)) + .stderr(stderr.toString(StandardCharsets.UTF_8)) + .build(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Code execution was interrupted.", e); + } finally { + if (perExecutionContainer) { + removeContainerQuietly(containerId); + } } + } - return CodeExecutionResult.builder() - .stdout(stdout.toString(StandardCharsets.UTF_8)) - .stderr(stderr.toString(StandardCharsets.UTF_8)) - .build(); + /** + * Returns the container shared by all executions while the strict sandbox is off, creating and + * starting it on first use. + */ + private synchronized String sharedContainer() { + if (sharedContainerId == null) { + sharedContainerId = createAndStartContainer(/* hardened= */ false); + } + return sharedContainerId; } - private void buildDockerImage() { - if (dockerPath == null) { - throw new IllegalStateException("Docker path is not set."); + /** + * Creates and starts a container, applying the hardened {@link HostConfig} when {@code hardened} + * is set. Returns its id. + */ + private String createAndStartContainer(boolean hardened) { + var createContainerCmd = + dockerClient.createContainerCmd(image).withTty(true).withAttachStdin(true); + if (hardened) { + createContainerCmd.withHostConfig(sandboxHostConfig()); } - File dockerfile = new File(dockerPath); - if (!dockerfile.exists()) { - throw new UncheckedIOException(new IOException("Invalid Docker path: " + dockerPath)); + CreateContainerResponse createContainerResponse = createContainerCmd.exec(); + String containerId = createContainerResponse.getId(); + dockerClient.startContainerCmd(containerId).exec(); + return containerId; + } + + /** + * Closes the exec output stream, logging rather than propagating a failure. The output has + * already been read by this point, so a teardown error must not fail an otherwise successful + * execution -- nor add an unchecked exception to {@link #executeCode}'s contract. + */ + private void closeQuietly(ExecStartResultCallback callback) { + try { + callback.close(); + } catch (IOException e) { + logger.warn("Failed to close the exec output stream", e); } + } - logger.info("Building Docker image..."); + /** Builds the hardened {@link HostConfig} applied to each execution container in strict mode. */ + @VisibleForTesting + HostConfig sandboxHostConfig() { + HostConfig hostConfig = + HostConfig.newHostConfig() + .withCapDrop(Capability.ALL) + .withReadonlyRootfs(true) + .withSecurityOpts(ImmutableList.of("no-new-privileges")) + .withMemory(memoryLimitBytes) + .withPidsLimit(PIDS_LIMIT) + // A read-only rootfs still needs a small writable scratch space at /tmp. + .withTmpFs(ImmutableMap.of("/tmp", "rw,size=64m")); + if (!networkEnabled) { + hostConfig.withNetworkMode("none"); + } + return hostConfig; + } + + /** + * Logs a warning, at most once per executor, if the strict sandbox is disabled. Returns whether + * the warning was logged. + */ + @VisibleForTesting + boolean warnIfStrictSandboxDisabled() { + if (!strictSandbox && strictSandboxWarningLogged.compareAndSet(false, true)) { + logger.warn( + "ContainerCodeExecutor is running with the strict sandbox disabled (the current default):" + + " executions share one container, which has network access (including the cloud" + + " metadata endpoint), a writable filesystem, and no memory, PID or time limits. If" + + " the code being run is untrusted or model-generated, call setStrictSandbox(true)" + + " to give each execution its own locked-down container. This becomes the default in" + + " ADK 2.0."); + return true; + } + return false; + } + + private void removeContainerQuietly(String containerId) { try { - dockerClient.buildImageCmd(dockerfile).withTag(image).start().awaitCompletion(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Docker image build was interrupted.", e); + dockerClient.removeContainerCmd(containerId).withForce(true).exec(); + } catch (RuntimeException e) { + logger.warn("Failed to remove container {}", containerId, e); } - logger.info("Docker image: {} built.", image); } - private void verifyPythonInstallation() { - ExecCreateCmdResponse execCreateCmdResponse = - dockerClient.execCreateCmd(container.getId()).withCmd("which", "python3").exec(); - ByteArrayOutputStream stdout = new ByteArrayOutputStream(); - ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - try (ExecStartResultCallback callback = new ExecStartResultCallback(stdout, stderr)) { - dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(callback).awaitCompletion(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Python verification was interrupted.", e); + /** + * Removes the shared container, if one was created, and closes the underlying Docker client, + * releasing its connections and threads. + */ + @Override + public synchronized void close() { + if (sharedContainerId != null) { + removeContainerQuietly(sharedContainerId); + sharedContainerId = null; + } + try { + // Unregister the shutdown hook so a closed executor is not retained by the JVM. Throws + // IllegalStateException if the JVM is already shutting down (e.g. close() invoked from the + // hook itself), in which case there is nothing to remove. + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (IllegalStateException e) { + // JVM shutdown already in progress; the hook cannot (and need not) be removed. + } + closeDockerClientQuietly(); + } + + private void closeDockerClientQuietly() { + try { + dockerClient.close(); } catch (IOException e) { - throw new UncheckedIOException(e); + logger.warn("Failed to close docker client", e); } } - private void initContainer() { - if (dockerClient == null) { - throw new IllegalStateException("Docker client is not initialized."); + private static DockerClient buildDockerClient(String baseUrl) { + if (baseUrl != null) { + var config = + DefaultDockerClientConfig.createDefaultConfigBuilder().withDockerHost(baseUrl).build(); + return DockerClientBuilder.getInstance(config).build(); } + return DockerClientBuilder.getInstance().build(); + } + + private void prepareImage() { if (dockerPath != null) { buildDockerImage(); } else { @@ -203,34 +438,24 @@ private void initContainer() { } logger.info("Image {} is available.", image); } - logger.info("Starting container for ContainerCodeExecutor..."); - var createContainerResponse = - dockerClient.createContainerCmd(image).withTty(true).withAttachStdin(true).exec(); - dockerClient.startContainerCmd(createContainerResponse.getId()).exec(); - - var containers = dockerClient.listContainersCmd().withShowAll(true).exec(); - this.container = - containers.stream() - .filter(c -> c.getId().equals(createContainerResponse.getId())) - .findFirst() - .orElseThrow(() -> new IllegalStateException("Failed to find the created container.")); - - logger.info("Container {} started.", container.getId()); - verifyPythonInstallation(); } - private void cleanupContainer() { - if (container == null) { - return; + private void buildDockerImage() { + if (dockerPath == null) { + throw new IllegalStateException("Docker path is not set."); } - logger.info("[Cleanup] Stopping the container..."); - dockerClient.stopContainerCmd(container.getId()).exec(); - dockerClient.removeContainerCmd(container.getId()).exec(); - logger.info("Container {} stopped and removed.", container.getId()); + File dockerfile = new File(dockerPath); + if (!dockerfile.exists()) { + throw new UncheckedIOException(new IOException("Invalid Docker path: " + dockerPath)); + } + + logger.info("Building Docker image..."); try { - dockerClient.close(); - } catch (IOException e) { - logger.warn("Failed to close docker client", e); + dockerClient.buildImageCmd(dockerfile).withTag(image).start().awaitCompletion(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Docker image build was interrupted.", e); } + logger.info("Docker image: {} built.", image); } } diff --git a/core/src/test/java/com/google/adk/codeexecutors/ContainerCodeExecutorTest.java b/core/src/test/java/com/google/adk/codeexecutors/ContainerCodeExecutorTest.java new file mode 100644 index 000000000..d9bcdfd8b --- /dev/null +++ b/core/src/test/java/com/google/adk/codeexecutors/ContainerCodeExecutorTest.java @@ -0,0 +1,311 @@ +/* + * Copyright 2026 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.codeexecutors; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmd; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.api.command.ExecStartCmd; +import com.github.dockerjava.api.command.RemoveContainerCmd; +import com.github.dockerjava.api.command.StartContainerCmd; +import com.github.dockerjava.api.model.Capability; +import com.github.dockerjava.api.model.Frame; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.StreamType; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionInput; +import com.google.adk.codeexecutors.CodeExecutionUtils.CodeExecutionResult; +import java.nio.charset.StandardCharsets; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; + +/** Unit tests for {@link ContainerCodeExecutor}'s sandboxing. */ +@RunWith(JUnit4.class) +public final class ContainerCodeExecutorTest { + + private static final String IMAGE = "adk-code-executor:latest"; + private static final String CONTAINER_ID = "container-123"; + private static final String EXEC_ID = "exec-456"; + + @Test + public void sandboxHostConfig_appliesFullHardening() { + ContainerCodeExecutor executor = new ContainerCodeExecutor(mock(DockerClient.class), IMAGE); + + HostConfig hostConfig = executor.sandboxHostConfig(); + + assertThat(hostConfig.getNetworkMode()).isEqualTo("none"); + assertThat(hostConfig.getCapDrop()).asList().containsExactly(Capability.ALL); + assertThat(hostConfig.getReadonlyRootfs()).isTrue(); + assertThat(hostConfig.getSecurityOpts()).containsExactly("no-new-privileges"); + assertThat(hostConfig.getMemory()).isEqualTo(512L * 1024 * 1024); + assertThat(hostConfig.getPidsLimit()).isEqualTo(128L); + assertThat(hostConfig.getTmpFs()).containsEntry("/tmp", "rw,size=64m"); + } + + @Test + public void sandboxHostConfig_networkEnabled_doesNotForceNoneNetwork() { + ContainerCodeExecutor executor = + new ContainerCodeExecutor(mock(DockerClient.class), IMAGE).setNetworkEnabled(true); + + HostConfig hostConfig = executor.sandboxHostConfig(); + + // When networking is explicitly enabled we leave the network mode at Docker's default. + assertThat(hostConfig.getNetworkMode()).isNull(); + // The other hardening still applies. + assertThat(hostConfig.getCapDrop()).asList().containsExactly(Capability.ALL); + assertThat(hostConfig.getReadonlyRootfs()).isTrue(); + } + + @Test + public void sandboxHostConfig_customMemoryLimit_applied() { + ContainerCodeExecutor executor = + new ContainerCodeExecutor(mock(DockerClient.class), IMAGE) + .setMemoryLimitBytes(256L * 1024 * 1024); + + assertThat(executor.sandboxHostConfig().getMemory()).isEqualTo(256L * 1024 * 1024); + } + + @Test + public void executeCode_strictSandbox_execsInHardenedContainerAndForceRemovesIt() { + DockerClient client = mockDockerClient(/* driveCompletion= */ true); + ContainerCodeExecutor executor = + new ContainerCodeExecutor(client, IMAGE).setStrictSandbox(true); + + CodeExecutionResult result = + executor.executeCode( + /* invocationContext= */ null, + CodeExecutionInput.builder().code("print('hi')").build()); + + CreateContainerCmd createCmd = client.createContainerCmd(IMAGE); + + // The container is created with the hardened HostConfig... + ArgumentCaptor hostConfigCaptor = ArgumentCaptor.forClass(HostConfig.class); + verify(createCmd).withHostConfig(hostConfigCaptor.capture()); + assertThat(hostConfigCaptor.getValue().getNetworkMode()).isEqualTo("none"); + assertThat(hostConfigCaptor.getValue().getReadonlyRootfs()).isTrue(); + + // ...the code runs via docker exec (bypasses ENTRYPOINT; needs only python3)... + ArgumentCaptor cmdCaptor = ArgumentCaptor.forClass(String[].class); + verify(client.execCreateCmd(CONTAINER_ID)).withCmd(cmdCaptor.capture()); + assertThat(cmdCaptor.getValue()) + .asList() + .containsExactly("python3", "-c", "print('hi')") + .inOrder(); + + // ...and the container is force-removed afterwards. + verify(client.startContainerCmd(CONTAINER_ID)).exec(); + verify(client.removeContainerCmd(CONTAINER_ID)).withForce(true); + verify(client.removeContainerCmd(CONTAINER_ID)).exec(); + assertThat(result.stderr()).isEmpty(); + } + + @Test + public void executeCode_timeout_returnsTimeoutResultAndForceRemovesContainer() { + DockerClient client = mockDockerClient(/* driveCompletion= */ false); + ContainerCodeExecutor executor = + new ContainerCodeExecutor(client, IMAGE) + .setStrictSandbox(true) + .setExecutionTimeoutSeconds(1); + + CodeExecutionResult result = + executor.executeCode( + /* invocationContext= */ null, + CodeExecutionInput.builder().code("while True: pass").build()); + + assertThat(result.stderr()).contains("timed out"); + // The runaway container is force-removed, which kills the exec. + verify(client.removeContainerCmd(CONTAINER_ID)).withForce(true); + verify(client.removeContainerCmd(CONTAINER_ID)).exec(); + } + + @Test + public void executeCode_timeout_keepsOutputPrintedBeforeTheKill() { + DockerClient client = mockDockerClient(/* driveCompletion= */ false); + // The code prints something, then hangs until the timeout kills it. + when(client.execStartCmd(EXEC_ID).exec(any())) + .thenAnswer( + invocation -> { + ExecStartResultCallback callback = invocation.getArgument(0); + callback.onNext( + new Frame(StreamType.STDOUT, "step 1 done\n".getBytes(StandardCharsets.UTF_8))); + return callback; + }); + ContainerCodeExecutor executor = + new ContainerCodeExecutor(client, IMAGE) + .setStrictSandbox(true) + .setExecutionTimeoutSeconds(1); + + CodeExecutionResult result = + executor.executeCode( + /* invocationContext= */ null, + CodeExecutionInput.builder().code("print('step 1 done'); while True: pass").build()); + + // Partial output tells the model how far the execution got before it was killed. + assertThat(result.stdout()).contains("step 1 done"); + assertThat(result.stderr()).contains("timed out"); + } + + @Test + public void executeCode_default_doesNotApplyHostConfig() { + DockerClient client = mockDockerClient(/* driveCompletion= */ true); + ContainerCodeExecutor executor = new ContainerCodeExecutor(client, IMAGE); + + CodeExecutionResult result = + executor.executeCode( + /* invocationContext= */ null, + CodeExecutionInput.builder().code("print('hi')").build()); + + // No hardened HostConfig is applied by default, preserving existing behavior... + CreateContainerCmd createCmd = client.createContainerCmd(IMAGE); + verify(createCmd, never()).withHostConfig(any()); + // ...but the code still runs via docker exec. + verify(client.execCreateCmd(CONTAINER_ID)).withCmd(any(String[].class)); + assertThat(result.stderr()).isEmpty(); + } + + @Test + public void executeCode_default_reusesContainerAndKeepsItRunning() { + DockerClient client = mockDockerClient(/* driveCompletion= */ true); + ContainerCodeExecutor executor = new ContainerCodeExecutor(client, IMAGE); + CodeExecutionInput input = CodeExecutionInput.builder().code("print('hi')").build(); + + executor.executeCode(/* invocationContext= */ null, input); + executor.executeCode(/* invocationContext= */ null, input); + + // One container is created and started for both executions, as before (and as in ADK Python), + // so existing callers keep warm-exec latency and a single-container footprint. + verify(client.startContainerCmd(CONTAINER_ID), times(1)).exec(); + // It is left running between executions rather than removed each time. + verify(client.removeContainerCmd(CONTAINER_ID), never()).exec(); + } + + @Test + public void executeCode_strictSandbox_usesFreshContainerPerExecution() { + DockerClient client = mockDockerClient(/* driveCompletion= */ true); + ContainerCodeExecutor executor = + new ContainerCodeExecutor(client, IMAGE).setStrictSandbox(true); + CodeExecutionInput input = CodeExecutionInput.builder().code("print('hi')").build(); + + executor.executeCode(/* invocationContext= */ null, input); + executor.executeCode(/* invocationContext= */ null, input); + + // Each execution gets its own container, force-removed afterwards, so nothing (including + // anything written under /tmp) leaks from one execution to the next. + verify(client.startContainerCmd(CONTAINER_ID), times(2)).exec(); + verify(client.removeContainerCmd(CONTAINER_ID), times(2)).exec(); + } + + @Test + public void close_removesSharedContainer() throws Exception { + DockerClient client = mockDockerClient(/* driveCompletion= */ true); + ContainerCodeExecutor executor = new ContainerCodeExecutor(client, IMAGE); + executor.executeCode( + /* invocationContext= */ null, CodeExecutionInput.builder().code("print('hi')").build()); + + executor.close(); + + verify(client.removeContainerCmd(CONTAINER_ID)).withForce(true); + verify(client.removeContainerCmd(CONTAINER_ID)).exec(); + } + + @Test + public void warnIfStrictSandboxDisabled_sandboxDisabled_warnsOnlyOnce() { + ContainerCodeExecutor executor = new ContainerCodeExecutor(mock(DockerClient.class), IMAGE); + + // The dangerous default is flagged, but only once per executor so it cannot spam the logs. + assertThat(executor.warnIfStrictSandboxDisabled()).isTrue(); + assertThat(executor.warnIfStrictSandboxDisabled()).isFalse(); + } + + @Test + public void warnIfStrictSandboxDisabled_strictSandbox_doesNotWarn() { + ContainerCodeExecutor executor = + new ContainerCodeExecutor(mock(DockerClient.class), IMAGE).setStrictSandbox(true); + + assertThat(executor.warnIfStrictSandboxDisabled()).isFalse(); + } + + @Test + public void close_closesDockerClient() throws Exception { + DockerClient client = mock(DockerClient.class); + ContainerCodeExecutor executor = new ContainerCodeExecutor(client, IMAGE); + + executor.close(); + + verify(client).close(); + } + + /** + * Builds a mock {@link DockerClient} whose create/start/exec/remove chain succeeds. When {@code + * driveCompletion} is true the exec callback is completed immediately so {@code awaitCompletion} + * returns without blocking; otherwise it is left pending so the executor's timeout fires. + */ + private static DockerClient mockDockerClient(boolean driveCompletion) { + DockerClient client = mock(DockerClient.class); + + CreateContainerCmd createCmd = mock(CreateContainerCmd.class); + when(client.createContainerCmd(IMAGE)).thenReturn(createCmd); + when(createCmd.withHostConfig(any())).thenReturn(createCmd); + when(createCmd.withTty(any())).thenReturn(createCmd); + when(createCmd.withAttachStdin(any())).thenReturn(createCmd); + CreateContainerResponse createResponse = mock(CreateContainerResponse.class); + when(createResponse.getId()).thenReturn(CONTAINER_ID); + when(createCmd.exec()).thenReturn(createResponse); + + StartContainerCmd startCmd = mock(StartContainerCmd.class); + when(client.startContainerCmd(CONTAINER_ID)).thenReturn(startCmd); + + ExecCreateCmd execCreateCmd = mock(ExecCreateCmd.class); + when(client.execCreateCmd(CONTAINER_ID)).thenReturn(execCreateCmd); + when(execCreateCmd.withAttachStdout(any())).thenReturn(execCreateCmd); + when(execCreateCmd.withAttachStderr(any())).thenReturn(execCreateCmd); + when(execCreateCmd.withCmd(any(String[].class))).thenReturn(execCreateCmd); + ExecCreateCmdResponse execCreateResponse = mock(ExecCreateCmdResponse.class); + when(execCreateResponse.getId()).thenReturn(EXEC_ID); + when(execCreateCmd.exec()).thenReturn(execCreateResponse); + + ExecStartCmd execStartCmd = mock(ExecStartCmd.class); + when(client.execStartCmd(EXEC_ID)).thenReturn(execStartCmd); + when(execStartCmd.exec(any())) + .thenAnswer( + invocation -> { + ExecStartResultCallback callback = invocation.getArgument(0); + if (driveCompletion) { + callback.onComplete(); + } + return callback; + }); + + RemoveContainerCmd removeCmd = mock(RemoveContainerCmd.class); + when(client.removeContainerCmd(CONTAINER_ID)).thenReturn(removeCmd); + when(removeCmd.withForce(any())).thenReturn(removeCmd); + + return client; + } +}