Skip to content

Commit 0888758

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: add response converters to support multiple A2A client events
PiperOrigin-RevId: 844723044
1 parent dace210 commit 0888758

7 files changed

Lines changed: 564 additions & 98 deletions

File tree

a2a/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<properties>
1717
<java.version>17</java.version>
1818
<maven.compiler.release>${java.version}</maven.compiler.release>
19-
<a2a.sdk.version>0.3.0.Beta1</a2a.sdk.version>
19+
<a2a.sdk.version>0.3.2.Final</a2a.sdk.version>
2020
<google.adk.version>${project.version}</google.adk.version>
2121
<guava.version>33.0.0-jre</guava.version>
2222
<jackson.version>2.19.0</jackson.version>
@@ -89,6 +89,11 @@
8989
<artifactId>a2a-java-sdk-http-client</artifactId>
9090
<version>${a2a.sdk.version}</version>
9191
</dependency>
92+
<dependency>
93+
<groupId>io.github.a2asdk</groupId>
94+
<artifactId>a2a-java-sdk-client</artifactId>
95+
<version>${a2a.sdk.version}</version>
96+
</dependency>
9297
<dependency>
9398
<groupId>junit</groupId>
9499
<artifactId>junit</artifactId>

a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ public final class EventConverter {
2424

2525
private EventConverter() {}
2626

27+
/**
28+
* Aggregation mode for converting events to A2A messages.
29+
*
30+
* <p>AS_IS: Parts are aggregated as-is.
31+
*
32+
* <p>EXTERNAL_HANDOFF: Parts are aggregated as-is, except for function responses, which are
33+
* converted to text parts with the function name and response map.
34+
*/
2735
public enum AggregationMode {
2836
AS_IS,
2937
EXTERNAL_HANDOFF

a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.google.adk.a2a.converters;
22

3+
import static java.util.stream.Collectors.toCollection;
4+
35
import com.fasterxml.jackson.core.JsonProcessingException;
46
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.google.common.collect.ImmutableMap;
58
import com.google.genai.types.Blob;
69
import com.google.genai.types.FileData;
710
import com.google.genai.types.FunctionCall;
@@ -13,8 +16,10 @@
1316
import io.a2a.spec.FileWithBytes;
1417
import io.a2a.spec.FileWithUri;
1518
import io.a2a.spec.TextPart;
19+
import java.util.ArrayList;
1620
import java.util.Base64;
1721
import java.util.HashMap;
22+
import java.util.List;
1823
import java.util.Map;
1924
import java.util.Optional;
2025
import org.slf4j.Logger;
@@ -60,6 +65,13 @@ public static Optional<com.google.genai.types.Part> toGenaiPart(io.a2a.spec.Part
6065
return Optional.empty();
6166
}
6267

68+
public static List<com.google.genai.types.Part> toGenaiParts(List<io.a2a.spec.Part<?>> a2aParts) {
69+
return a2aParts.stream()
70+
.map(PartConverter::toGenaiPart)
71+
.flatMap(Optional::stream)
72+
.collect(toCollection(ArrayList::new));
73+
}
74+
6375
/**
6476
* Convert a Google GenAI Part to an A2A Part.
6577
*
@@ -129,8 +141,8 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
129141

130142
String metadataType = metadata.getOrDefault(A2A_DATA_PART_METADATA_TYPE_KEY, "").toString();
131143

132-
if (data.containsKey("name") && data.containsKey("args")
133-
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL.equals(metadataType)) {
144+
if ((data.containsKey("name") && data.containsKey("args"))
145+
|| metadataType.equals(A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL)) {
134146
String functionName = String.valueOf(data.getOrDefault("name", ""));
135147
String functionId = String.valueOf(data.getOrDefault("id", ""));
136148
Map<String, Object> args = coerceToMap(data.get("args"));
@@ -141,8 +153,8 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
141153
.build());
142154
}
143155

144-
if (data.containsKey("name") && data.containsKey("response")
145-
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
156+
if ((data.containsKey("name") && data.containsKey("response"))
157+
|| metadataType.equals(A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE)) {
146158
String functionName = String.valueOf(data.getOrDefault("name", ""));
147159
String functionId = String.valueOf(data.getOrDefault("id", ""));
148160
Map<String, Object> response = coerceToMap(data.get("response"));
@@ -175,10 +187,10 @@ private static Optional<DataPart> createDataPartFromFunctionCall(FunctionCall fu
175187
Map<String, Object> data = new HashMap<>();
176188
data.put("name", functionCall.name().orElse(""));
177189
data.put("id", functionCall.id().orElse(""));
178-
data.put("args", functionCall.args().orElse(Map.of()));
190+
data.put("args", functionCall.args().orElse(ImmutableMap.of()));
179191

180-
Map<String, Object> metadata =
181-
Map.of(A2A_DATA_PART_METADATA_TYPE_KEY, A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL);
192+
ImmutableMap<String, Object> metadata =
193+
ImmutableMap.of(A2A_DATA_PART_METADATA_TYPE_KEY, A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL);
182194

183195
return Optional.of(new DataPart(data, metadata));
184196
}
@@ -194,10 +206,11 @@ private static Optional<DataPart> createDataPartFromFunctionResponse(
194206
Map<String, Object> data = new HashMap<>();
195207
data.put("name", functionResponse.name().orElse(""));
196208
data.put("id", functionResponse.id().orElse(""));
197-
data.put("response", functionResponse.response().orElse(Map.of()));
209+
data.put("response", functionResponse.response().orElse(ImmutableMap.of()));
198210

199-
Map<String, Object> metadata =
200-
Map.of(A2A_DATA_PART_METADATA_TYPE_KEY, A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE);
211+
ImmutableMap<String, Object> metadata =
212+
ImmutableMap.of(
213+
A2A_DATA_PART_METADATA_TYPE_KEY, A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE);
201214

202215
return Optional.of(new DataPart(data, metadata));
203216
}

a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.adk.events.Event;
44
import com.google.common.collect.ImmutableList;
5+
import com.google.common.collect.ImmutableMap;
56
import com.google.genai.types.Content;
67
import io.a2a.spec.DataPart;
78
import io.a2a.spec.Message;
@@ -159,16 +160,17 @@ public static ImmutableList<Event> convertAggregatedA2aMessageToAdkEvents(
159160

160161
private static String extractAuthorFromMetadata(Part<?> a2aPart) {
161162
if (a2aPart instanceof DataPart dataPart) {
162-
Map<String, Object> metadata = Optional.ofNullable(dataPart.getMetadata()).orElse(Map.of());
163+
Map<String, Object> metadata =
164+
Optional.ofNullable(dataPart.getMetadata()).orElse(ImmutableMap.of());
163165
String type =
164166
metadata.getOrDefault(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY, "").toString();
165-
if (PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL.equals(type)) {
167+
if (type.equals(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL)) {
166168
return "model";
167169
}
168-
if (PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(type)) {
170+
if (type.equals(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE)) {
169171
return "user";
170172
}
171-
Map<String, Object> data = Optional.ofNullable(dataPart.getData()).orElse(Map.of());
173+
Map<String, Object> data = Optional.ofNullable(dataPart.getData()).orElse(ImmutableMap.of());
172174
if (data.containsKey("args")) {
173175
return "model";
174176
}
@@ -193,14 +195,4 @@ private static Event createEvent(
193195
.timestamp(Instant.now().toEpochMilli())
194196
.build();
195197
}
196-
197-
/**
198-
* Convert an A2A Part to a GenAI Part.
199-
*
200-
* @param a2aPart The A2A Part to convert.
201-
* @return Optional containing the converted GenAI Part, or empty if conversion fails.
202-
*/
203-
private static Optional<com.google.genai.types.Part> convertA2aPartToGenAiPart(Part<?> a2aPart) {
204-
return PartConverter.toGenaiPart(a2aPart);
205-
}
206198
}

0 commit comments

Comments
 (0)