Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3967cfa
fix: confine config-driven dynamic class loading to intended types
damianmomotgoogle Jul 16, 2026
ba23601
feat: Update 'gen_ai.usage.input_tokens' to include tool used tokens …
google-genai-bot Jul 17, 2026
9caecae
chore(main): release 1.7.0
adk-java-releases-bot Jul 17, 2026
a370034
fix(firestore-session-service): honor appName in getSession/deleteSes…
petrmarinec Jul 20, 2026
f61f952
Merge pull request #1339 from google:release-please--branches--main
copybara-github Jul 20, 2026
edc330d
fix: preserve all parallel function calls on the live (BIDI) connection
kvmilos Jul 20, 2026
2bac57b
chore(main): release 1.7.1-SNAPSHOT
adk-java-releases-bot Jul 20, 2026
8bfa02f
Merge pull request #1366 from google:release-please--branches--main
copybara-github Jul 20, 2026
cf71d7b
fix(mcp): honor stdioServerParams in McpToolset.fromConfig
svetanis Jul 19, 2026
233b83b
fix(core): fallback to name when Agent description is missing
svetanis Apr 28, 2026
737c293
Merge pull request #1360 from svetanis:fix/mcptoolset-fromconfig-stdi…
copybara-github Jul 22, 2026
2b2f25e
Merge pull request #1361 from petrmarinec:fix/firestore-session-appna…
copybara-github Jul 22, 2026
bcb6216
Merge pull request #1164 from svetanis:fix-agent-tool-description
copybara-github Jul 22, 2026
ec2a90b
chore(license): add and repair Apache license headers across Java sou…
kvmilos Jul 23, 2026
ccc84b0
Fix Vertex session user IDs
May 4, 2026
4d19f7d
fix(sessions): apply numRecentEvents and afterTimestamp together in I…
kvmilos Jul 23, 2026
24a4588
fix(sessions): apply afterTimestamp and numRecentEvents together in V…
kvmilos Jul 23, 2026
03b04fa
fix(events): accumulate endOfAgent in EventActions.merge to preserve …
svetanis Jul 24, 2026
882ea5f
Merge pull request #1376 from svetanis:fix/eventactions-endofagent-merge
copybara-github Jul 24, 2026
5f13e58
Merge pull request #1180 from bitmovin-engineering:fix-vertex-session…
copybara-github Jul 24, 2026
8049f7e
fix(codeexecutors): add opt-in strict sandbox to ContainerCodeExecutor
kvmilos Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.6.0"
".": "1.7.0"
}
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)


Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ If you're using Maven, add the following to your dependencies:
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk</artifactId>
<version>1.6.0</version>
<version>1.7.0</version>
</dependency>
<!-- Dev UI -->
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-dev</artifactId>
<version>1.6.0</version>
<version>1.7.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion a2a/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-parent</artifactId>
<version>1.6.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<version>1.7.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
</parent>

<artifactId>google-adk-a2a</artifactId>
Expand Down
16 changes: 16 additions & 0 deletions a2a/src/test/java/com/google/adk/a2a/agent/RemoteA2AAgentTest.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion contrib/firestore-session-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-parent</artifactId>
<version>1.6.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<version>1.7.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<relativePath>../../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ public Maybe<Session> 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());
Expand Down Expand Up @@ -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<com.google.cloud.firestore.QuerySnapshot> eventsQuery =
Expand Down Expand Up @@ -536,9 +556,11 @@ public Single<ListEventsResponse> 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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<String, Object> eventData =
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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<Session> 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<ListEventsResponse> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion contrib/langchain4j/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-parent</artifactId>
<version>1.6.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<version>1.7.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<relativePath>../../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion contrib/planners/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-parent</artifactId>
<version>1.6.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<version>1.7.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<relativePath>../../pom.xml</relativePath>
</parent>

Expand Down
16 changes: 16 additions & 0 deletions contrib/samples/a2a_basic/A2AAgent.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Loading