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 5262c8d75..2a0a88415 100644
--- a/README.md
+++ b/README.md
@@ -50,13 +50,13 @@ If you're using Maven, add the following to your dependencies:
com.google.adkgoogle-adk
- 1.6.0
+ 1.7.0com.google.adkgoogle-adk-dev
- 1.6.0
+ 1.7.0
```
diff --git a/a2a/pom.xml b/a2a/pom.xml
index 2c8873439..494c17c15 100644
--- a/a2a/pom.xml
+++ b/a2a/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOTgoogle-adk-a2a
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/pom.xml b/contrib/firestore-session-service/pom.xml
index 6979e1590..6f5442fd5 100644
--- a/contrib/firestore-session-service/pom.xml
+++ b/contrib/firestore-session-service/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../pom.xml
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();
+ }
}
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/langchain4j/pom.xml b/contrib/langchain4j/pom.xml
index 0f4c3b07e..7ae9c7ad3 100644
--- a/contrib/langchain4j/pom.xml
+++ b/contrib/langchain4j/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../pom.xml
diff --git a/contrib/planners/pom.xml b/contrib/planners/pom.xml
index e842f725c..45fc8194e 100644
--- a/contrib/planners/pom.xml
+++ b/contrib/planners/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../pom.xml
diff --git a/contrib/samples/a2a_basic/A2AAgent.java b/contrib/samples/a2a_basic/A2AAgent.java
index 03b0933f3..6b83ab3cd 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_basic/pom.xml b/contrib/samples/a2a_basic/pom.xml
index d584ddf0c..855acf77e 100644
--- a/contrib/samples/a2a_basic/pom.xml
+++ b/contrib/samples/a2a_basic/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT..
diff --git a/contrib/samples/a2a_server/pom.xml b/contrib/samples/a2a_server/pom.xml
index b9715dc1c..e98ae957b 100644
--- a/contrib/samples/a2a_server/pom.xml
+++ b/contrib/samples/a2a_server/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT..
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/pom.xml b/contrib/samples/configagent/pom.xml
index cd29a67c6..eae0a9542 100644
--- a/contrib/samples/configagent/pom.xml
+++ b/contrib/samples/configagent/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT..
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/pom.xml b/contrib/samples/github/adkprtriaging/pom.xml
index 78e9e5473..8bafd9e33 100644
--- a/contrib/samples/github/adkprtriaging/pom.xml
+++ b/contrib/samples/github/adkprtriaging/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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/pom.xml b/contrib/samples/github/adkreleasedocs/pom.xml
index 0ca97ad19..5904a597c 100644
--- a/contrib/samples/github/adkreleasedocs/pom.xml
+++ b/contrib/samples/github/adkreleasedocs/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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/pom.xml b/contrib/samples/github/adkspam/pom.xml
index 74b6aa3cd..9e073518a 100644
--- a/contrib/samples/github/adkspam/pom.xml
+++ b/contrib/samples/github/adkspam/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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/pom.xml b/contrib/samples/github/adkstale/pom.xml
index 118a4bb33..970603818 100644
--- a/contrib/samples/github/adkstale/pom.xml
+++ b/contrib/samples/github/adkstale/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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/pom.xml b/contrib/samples/github/adktriaging/pom.xml
index 059ba5fed..605548f99 100644
--- a/contrib/samples/github/adktriaging/pom.xml
+++ b/contrib/samples/github/adktriaging/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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/pom.xml b/contrib/samples/github/githubtools/pom.xml
index 770586a4f..d3704d964 100644
--- a/contrib/samples/github/githubtools/pom.xml
+++ b/contrib/samples/github/githubtools/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT../..
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 c06812af5..425553afb 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/helloworld/pom.xml b/contrib/samples/helloworld/pom.xml
index 1e504c1b3..9edcfe9a1 100644
--- a/contrib/samples/helloworld/pom.xml
+++ b/contrib/samples/helloworld/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-samples
- ${revision}
+ 1.7.1-SNAPSHOT..
diff --git a/contrib/samples/mcpfilesystem/McpFilesystemAgent.java b/contrib/samples/mcpfilesystem/McpFilesystemAgent.java
index 581c56769..b611acc03 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/contrib/samples/mcpfilesystem/pom.xml b/contrib/samples/mcpfilesystem/pom.xml
index 0a2106d7d..ae20c5fa3 100644
--- a/contrib/samples/mcpfilesystem/pom.xml
+++ b/contrib/samples/mcpfilesystem/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../..
diff --git a/contrib/samples/pom.xml b/contrib/samples/pom.xml
index 300b11f15..514ad2b92 100644
--- a/contrib/samples/pom.xml
+++ b/contrib/samples/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../..
diff --git a/contrib/spring-ai/pom.xml b/contrib/spring-ai/pom.xml
index e44dff62f..eca2e0778 100644
--- a/contrib/spring-ai/pom.xml
+++ b/contrib/spring-ai/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../pom.xml
diff --git a/core/pom.xml b/core/pom.xml
index 243e4ae42..c069739e8 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOTgoogle-adk
@@ -66,11 +66,6 @@
com.google.cloudgoogle-cloud-storage
-
- software.amazon.awssdk
- s3
- 2.42.31
- com.google.genaigoogle-genai
@@ -168,11 +163,6 @@
io.reactivex.rxjava3rxjava
-
- org.json
- json
- 20240303
- io.projectreactorreactor-core
@@ -207,26 +197,36 @@
opentelemetry-sdk-testingtest
-
- com.google.cloud
- google-cloud-bigquery
- 2.40.0
+ com.google.cloud
+ google-cloud-bigquery
+ 2.40.0
+
+
+ org.apache.arrow
+ arrow-vector
+ 17.0.0
- org.apache.arrow
- arrow-vector
- 17.0.0
+ org.apache.arrow
+ arrow-memory-core
+ 17.0.0
- org.apache.arrow
- arrow-memory-core
- 17.0.0
+ org.apache.arrow
+ arrow-memory-netty
+ 17.0.0
+
- org.apache.arrow
- arrow-memory-netty
- 17.0.0
+ software.amazon.awssdk
+ s3
+ 2.42.31
+
+
+ org.json
+ json
+ 20240303com.zaxxer
@@ -335,11 +335,6 @@
maven-surefire-plugin
-
-
- **/VertexAiSessionServiceTest.java
-
-
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/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 e47a1bee3..4bc341ffd 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/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/artifacts/PostgresArtifactService.java b/core/src/main/java/com/google/adk/artifacts/PostgresArtifactService.java
index b95378cea..61de74ecf 100644
--- a/core/src/main/java/com/google/adk/artifacts/PostgresArtifactService.java
+++ b/core/src/main/java/com/google/adk/artifacts/PostgresArtifactService.java
@@ -307,7 +307,7 @@ private void persistToS3AndKafka(
return;
}
String key = buildObjectKey(appName, userId, sessionId, filename, version);
-
+
// Construct an HTTPS URL instead of an s3:// path
String region = getenvOrNull("S3_REGION");
String fileUri;
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..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,9 +1,8 @@
/*
- * 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.
- * 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
@@ -20,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.
@@ -100,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
@@ -126,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 {
@@ -204,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/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/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/GeminiLlmConnection.java b/core/src/main/java/com/google/adk/models/GeminiLlmConnection.java
index fbc9bf3e1..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;
@@ -34,8 +33,11 @@
import com.google.genai.types.LiveServerMessage;
import com.google.genai.types.LiveServerToolCall;
import com.google.genai.types.Part;
+import com.google.genai.types.UsageMetadata;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Flowable;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.processors.PublishProcessor;
import java.net.SocketException;
import java.util.List;
@@ -65,6 +67,7 @@ public final class GeminiLlmConnection implements BaseLlmConnection {
private final CompletableFuture sessionFuture;
private final PublishProcessor responseProcessor = PublishProcessor.create();
private final Flowable responseFlowable = responseProcessor.serialize();
+ private final CompositeDisposable disposables = new CompositeDisposable();
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
@@ -120,88 +123,107 @@ private void handleServerMessage(LiveServerMessage message) {
logger.debug("Received server message: {}", message.toJson());
- Optional llmResponse = convertToServerResponse(message);
- llmResponse.ifPresent(responseProcessor::onNext);
+ Observable llmResponse = convertToServerResponse(message);
+ if (!disposables.add(
+ llmResponse.subscribe(responseProcessor::onNext, responseProcessor::onError))) {
+ logger.warn(
+ "disposables container already disposed, the subscription will be disposed immediately");
+ }
}
/** Converts a server message into the standardized LlmResponse format. */
- static Optional convertToServerResponse(LiveServerMessage message) {
+ static Observable convertToServerResponse(LiveServerMessage message) {
+ return Observable.create(
+ emitter -> {
+ // AtomicBoolean is used to modify state from within lambdas, which
+ // require captured variables to be effectively final.
+ final AtomicBoolean handled = new AtomicBoolean(false);
+ message
+ .serverContent()
+ .ifPresent(
+ serverContent -> {
+ emitter.onNext(createServerContentResponse(serverContent));
+ handled.set(true);
+ });
+ message
+ .toolCall()
+ .ifPresent(
+ toolCall -> {
+ emitter.onNext(createToolCallResponse(toolCall));
+ handled.set(true);
+ });
+ message
+ .usageMetadata()
+ .ifPresent(
+ usageMetadata -> {
+ logger.debug("Received usage metadata: {}", usageMetadata);
+ emitter.onNext(createUsageMetadataResponse(usageMetadata));
+ handled.set(true);
+ });
+ message
+ .toolCallCancellation()
+ .ifPresent(
+ toolCallCancellation -> {
+ logger.debug("Received tool call cancellation: {}", toolCallCancellation);
+ // TODO: implement proper CFC and thus tool call cancellation handling.
+ handled.set(true);
+ });
+ message
+ .setupComplete()
+ .ifPresent(
+ setupComplete -> {
+ logger.debug("Received setup complete.");
+ handled.set(true);
+ });
+
+ if (!handled.get()) {
+ logger.warn("Received unknown or empty server message: {}", message.toJson());
+ emitter.onNext(createUnknownMessageResponse());
+ }
+ emitter.onComplete();
+ });
+ }
+
+ private static LlmResponse createServerContentResponse(LiveServerContent serverContent) {
LlmResponse.Builder builder = LlmResponse.builder();
- boolean hasRelevantData = false;
-
- if (message.serverContent().isPresent()) {
- LiveServerContent serverContent = message.serverContent().get();
- serverContent.modelTurn().ifPresent(builder::content);
- builder
- .partial(serverContent.turnComplete().map(completed -> !completed).orElse(false))
- .turnComplete(serverContent.turnComplete().orElse(false))
- .interrupted(serverContent.interrupted().orElse(null));
- // Gemini can send audio + transcription in the SAME server event.
- // Transcriptions travel in dedicated LlmResponse fields so they never
- // overwrite the audio modelTurn content.
- serverContent.outputTranscription().ifPresent(builder::outputTranscription);
- serverContent.inputTranscription().ifPresent(builder::inputTranscription);
- hasRelevantData = true;
- } else if (message.toolCall().isPresent()) {
- LiveServerToolCall toolCall = message.toolCall().get();
- toolCall
- .functionCalls()
- .ifPresent(
- calls -> {
- for (FunctionCall call : calls) {
- builder.content(
- Content.builder()
- .parts(ImmutableList.of(Part.builder().functionCall(call).build()))
- .build());
- }
- });
- builder.partial(false).turnComplete(false);
- hasRelevantData = true;
- } else if (message.toolCallCancellation().isPresent()) {
- logger.debug("Received tool call cancellation: {}", message.toolCallCancellation().get());
- builder.interrupted(true).turnComplete(true);
- hasRelevantData = true;
- } else if (message.setupComplete().isPresent()) {
- logger.debug("Received setup complete.");
- return Optional.empty();
- } else if (message.sessionResumptionUpdate().isPresent()) {
- logger.debug(
- "Received session resumption update: {}", message.sessionResumptionUpdate().get());
- return Optional.empty();
- } else if (message.goAway().isPresent()) {
- logger.debug("Received go away: {}", message.goAway().get());
- return Optional.empty();
- } else if (message.voiceActivityDetectionSignal().isPresent()) {
- logger.debug(
- "Received voice activity detection signal: {}",
- message.voiceActivityDetectionSignal().get());
- return Optional.empty();
- } else if (message.voiceActivity().isPresent()) {
- logger.debug("Received voice activity: {}", message.voiceActivity().get());
- return Optional.empty();
- } else if (message.usageMetadata().isEmpty()) {
- logger.warn("Received unknown or empty server message: {}", message.toJson());
- builder
- .errorCode(new FinishReason("Unknown server message."))
- .errorMessage("Received unknown server message.");
- hasRelevantData = true;
- }
+ serverContent.modelTurn().ifPresent(builder::content);
+ return builder
+ .partial(serverContent.turnComplete().map(completed -> !completed).orElse(false))
+ .turnComplete(serverContent.turnComplete().orElse(false))
+ .interrupted(serverContent.interrupted().orElse(null))
+ .inputTranscription(serverContent.inputTranscription().orElse(null))
+ .outputTranscription(serverContent.outputTranscription().orElse(null))
+ .build();
+ }
- if (message.usageMetadata().isPresent()) {
- logger.debug("Received usage metadata: {}", message.usageMetadata().get());
- builder.usageMetadata(
- GeminiUtil.toGenerateContentResponseUsageMetadata(message.usageMetadata().get()));
- if (!hasRelevantData) {
- builder.partial(false).turnComplete(false);
- }
- hasRelevantData = true;
- }
+ private static LlmResponse createToolCallResponse(LiveServerToolCall toolCall) {
+ LlmResponse.Builder builder = LlmResponse.builder();
+ toolCall
+ .functionCalls()
+ .ifPresent(
+ calls ->
+ builder.content(
+ Content.builder()
+ .role("model")
+ .parts(
+ calls.stream()
+ .map(call -> Part.builder().functionCall(call).build())
+ .collect(toImmutableList()))
+ .build()));
+ return builder.partial(false).turnComplete(false).build();
+ }
- if (hasRelevantData) {
- return Optional.of(builder.build());
- }
+ private static LlmResponse createUsageMetadataResponse(UsageMetadata usageMetadata) {
+ return LlmResponse.builder()
+ .usageMetadata(GeminiUtil.toGenerateContentResponseUsageMetadata(usageMetadata))
+ .build();
+ }
- return Optional.empty();
+ private static LlmResponse createUnknownMessageResponse() {
+ return LlmResponse.builder()
+ .errorCode(new FinishReason("Unknown server message."))
+ .errorMessage("Received unknown server message.")
+ .build();
}
/** Handles errors that occur *during* the initial connection attempt. */
@@ -265,17 +287,9 @@ private List extractFunctionResponses(Content content) {
public Completable sendRealtime(Blob blob) {
return Completable.fromFuture(
sessionFuture.thenCompose(
- session -> {
- LiveSendRealtimeInputParameters.Builder builder =
- LiveSendRealtimeInputParameters.builder();
- String mimeType = blob.mimeType().orElse("").toLowerCase();
- if (mimeType.startsWith("video/") || mimeType.startsWith("image/")) {
- builder.video(blob);
- } else {
- builder.audio(blob);
- }
- return session.sendRealtimeInput(builder.build());
- }));
+ session ->
+ session.sendRealtimeInput(
+ LiveSendRealtimeInputParameters.builder().media(blob).build())));
}
/** Helper to send client content parameters. */
@@ -324,6 +338,8 @@ private void closeInternal(Throwable throwable) {
} else {
sessionFuture.cancel(false);
}
+
+ disposables.dispose();
}
}
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 9f231f925..3c11310ad 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/runner/Runner.java b/core/src/main/java/com/google/adk/runner/Runner.java
index 4afa72574..e3c30c79b 100644
--- a/core/src/main/java/com/google/adk/runner/Runner.java
+++ b/core/src/main/java/com/google/adk/runner/Runner.java
@@ -791,13 +791,17 @@ protected Flowable runLiveImpl(
updatedInvocationContext
.agent()
.runLive(updatedInvocationContext)
- .doOnNext(event -> this.sessionService.appendEvent(session, event))
.concatMapSingle(
event ->
- updatedInvocationContext
- .pluginManager()
- .onEventCallback(updatedInvocationContext, event)
- .defaultIfEmpty(event))
+ this.sessionService
+ .appendEvent(session, event)
+ .flatMap(
+ persistedEvent ->
+ updatedInvocationContext
+ .pluginManager()
+ .onEventCallback(
+ updatedInvocationContext, persistedEvent)
+ .defaultIfEmpty(persistedEvent)))
// Run afterRunCallback once the live run completes so plugins can flush
// or log aggregates (e.g. total token usage for the session).
.concatWith(
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/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/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/sessions/VertexAiSessionService.java b/core/src/main/java/com/google/adk/sessions/VertexAiSessionService.java
index 6831baefb..92c10cd97 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<>()
@@ -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/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/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/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/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/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 e249f6783..ce607fa8f 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 4cafb9681..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,
@@ -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.
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 1e629665a..6431644b1 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/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 @@
*
*
To enable this loader: {@code adk.agents.loader=compiled}
*
To specify agent source directory: {@code adk.agents.source-dir=/path/to/agents}
+ *
Directory confinement (recommended, off by default): {@code
+ * adk.agents.confine-to-source-dir=true} restricts compiled classes to {@code source-dir}. A
+ * warning is logged while it is disabled.
*
*/
@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/AgentStaticLoaderTest.java b/dev/src/test/java/com/google/adk/web/AgentStaticLoaderTest.java
index 974046e64..4ec6e6f34 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/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/examples/custom_tools/pom.xml b/maven_plugin/examples/custom_tools/pom.xml
index 9ac93932e..82d736187 100644
--- a/maven_plugin/examples/custom_tools/pom.xml
+++ b/maven_plugin/examples/custom_tools/pom.xml
@@ -4,7 +4,7 @@
com.examplecustom-tools-example
- ${revision}
+ 1.7.1-SNAPSHOTjarADK Custom Tools Example
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/examples/simple-agent/pom.xml b/maven_plugin/examples/simple-agent/pom.xml
index fcdfa0a56..50ecdd03d 100644
--- a/maven_plugin/examples/simple-agent/pom.xml
+++ b/maven_plugin/examples/simple-agent/pom.xml
@@ -4,7 +4,7 @@
com.examplesimple-adk-agent
- ${revision}
+ 1.7.1-SNAPSHOTjarSimple ADK Agent Example
diff --git a/maven_plugin/pom.xml b/maven_plugin/pom.xml
index 6715e7c48..9469fa581 100644
--- a/maven_plugin/pom.xml
+++ b/maven_plugin/pom.xml
@@ -5,7 +5,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../pom.xml
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;
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(
diff --git a/pom.xml b/pom.xml
index 04630c937..52475d377 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOTpomGoogle Agent Development Kit Maven Parent POM
@@ -33,14 +33,12 @@
contrib/samplescontrib/plannerscontrib/firestore-session-service
- contrib/sarvam-aitutorials/city-time-weathertutorials/live-audio-single-agenta2a
- 1.6.1-SNAPSHOT17${java.version}UTF-8
@@ -490,31 +488,6 @@
-
- org.codehaus.mojo
- flatten-maven-plugin
- 1.6.0
-
- true
- resolveCiFriendliesOnly
-
-
-
- flatten
- process-resources
-
- flatten
-
-
-
- flatten-clean
- clean
-
- clean
-
-
-
-
diff --git a/tutorials/city-time-weather/pom.xml b/tutorials/city-time-weather/pom.xml
index fba6538bb..aaf1e9640 100644
--- a/tutorials/city-time-weather/pom.xml
+++ b/tutorials/city-time-weather/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 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 7a361a91e..49440394e 100644
--- a/tutorials/live-audio-single-agent/pom.xml
+++ b/tutorials/live-audio-single-agent/pom.xml
@@ -20,7 +20,7 @@
com.google.adkgoogle-adk-parent
- ${revision}
+ 1.7.1-SNAPSHOT../../pom.xml