Skip to content

Commit 342f8f5

Browse files
committed
Ensure all properties are copied when converting to a2a
Python and Go implementations of ADK both copy function call and response properties by copying the entire struct automatically. Java does this a property at a time and so was missing the "id" property of the ADK event. Providing these allows downstream agents to properly associate multiple tool calls and responses to the same tool name. Updated EventConverterTest to verify the new field and also verified function name in the response object.
1 parent 089a9cb commit 342f8f5

2 files changed

Lines changed: 30 additions & 4 deletions

File tree

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,33 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
132132
if (data.containsKey("name") && data.containsKey("args")
133133
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL.equals(metadataType)) {
134134
String functionName = String.valueOf(data.getOrDefault("name", ""));
135+
String functionId = String.valueOf(data.getOrDefault("id", ""));
135136
Map<String, Object> args = coerceToMap(data.get("args"));
136137
return Optional.of(
137138
com.google.genai.types.Part.builder()
138-
.functionCall(FunctionCall.builder().name(functionName).args(args).build())
139+
.functionCall(
140+
FunctionCall.builder()
141+
.name(functionName)
142+
.id(functionId)
143+
.id(functionId)
144+
.args(args)
145+
.build())
139146
.build());
140147
}
141148

142149
if (data.containsKey("name") && data.containsKey("response")
143150
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
144151
String functionName = String.valueOf(data.getOrDefault("name", ""));
152+
String functionId = String.valueOf(data.getOrDefault("id", ""));
145153
Map<String, Object> response = coerceToMap(data.get("response"));
146154
return Optional.of(
147155
com.google.genai.types.Part.builder()
148156
.functionResponse(
149-
FunctionResponse.builder().name(functionName).response(response).build())
157+
FunctionResponse.builder()
158+
.name(functionName).id(functionId)
159+
.id(functionId)
160+
.response(response)
161+
.build())
150162
.build());
151163
}
152164

@@ -167,6 +179,7 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
167179
private static Optional<DataPart> createDataPartFromFunctionCall(FunctionCall functionCall) {
168180
Map<String, Object> data = new HashMap<>();
169181
data.put("name", functionCall.name().orElse(""));
182+
data.put("id", functionCall.id().orElse(""));
170183
data.put("args", functionCall.args().orElse(Map.of()));
171184

172185
Map<String, Object> metadata =
@@ -185,6 +198,7 @@ private static Optional<DataPart> createDataPartFromFunctionResponse(
185198
FunctionResponse functionResponse) {
186199
Map<String, Object> data = new HashMap<>();
187200
data.put("name", functionResponse.name().orElse(""));
201+
data.put("id", functionResponse.id().orElse(""));
188202
data.put("response", functionResponse.response().orElse(Map.of()));
189203

190204
Map<String, Object> metadata =

a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
4343

4444
Part functionCallPart =
4545
Part.builder()
46-
.functionCall(FunctionCall.builder().name("roll_die").args(Map.of("sides", 6)).build())
46+
.functionCall(
47+
FunctionCall.builder()
48+
.name("roll_die").id("adk-call-1")
49+
.id("adk-call-1")
50+
.args(Map.of("sides", 6))
51+
.build())
4752
.build();
4853
Event callEvent =
4954
Event.builder()
@@ -59,7 +64,11 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
5964
Part functionResponsePart =
6065
Part.builder()
6166
.functionResponse(
62-
FunctionResponse.builder().name("roll_die").response(Map.of("result", 3)).build())
67+
FunctionResponse.builder()
68+
.name("roll_die").id("adk-call-1")
69+
.id("adk-call-1")
70+
.response(Map.of("result", 3))
71+
.build())
6372
.build();
6473
Event responseEvent =
6574
Event.builder()
@@ -106,11 +115,14 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
106115
assertThat(callDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
107116
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL);
108117
assertThat(callDataPart.getData()).containsEntry("name", "roll_die");
118+
assertThat(callDataPart.getData()).containsEntry("id", "adk-call-1");
109119
assertThat(callDataPart.getData()).containsEntry("args", Map.of("sides", 6));
110120

111121
DataPart responseDataPart = (DataPart) message.getParts().get(2);
112122
assertThat(responseDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
113123
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE);
124+
assertThat(responseDataPart.getData()).containsEntry("name", "roll_die");
125+
assertThat(responseDataPart.getData()).containsEntry("id", "adk-call-1");
114126
assertThat(responseDataPart.getData()).containsEntry("response", Map.of("result", 3));
115127
}
116128

0 commit comments

Comments
 (0)