Skip to content

Commit 6023a50

Browse files
committed
Ensure all property types are translated when converting function calls 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.
1 parent 089a9cb commit 6023a50

2 files changed

Lines changed: 11 additions & 4 deletions

File tree

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,23 @@ 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(FunctionCall.builder().name(functionName).id(functionId).args(args).build())
139140
.build());
140141
}
141142

142143
if (data.containsKey("name") && data.containsKey("response")
143144
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
144145
String functionName = String.valueOf(data.getOrDefault("name", ""));
146+
String functionId = String.valueOf(data.getOrDefault("id", ""));
145147
Map<String, Object> response = coerceToMap(data.get("response"));
146148
return Optional.of(
147149
com.google.genai.types.Part.builder()
148150
.functionResponse(
149-
FunctionResponse.builder().name(functionName).response(response).build())
151+
FunctionResponse.builder().name(functionName).id(functionId).response(response).build())
150152
.build());
151153
}
152154

@@ -167,6 +169,7 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
167169
private static Optional<DataPart> createDataPartFromFunctionCall(FunctionCall functionCall) {
168170
Map<String, Object> data = new HashMap<>();
169171
data.put("name", functionCall.name().orElse(""));
172+
data.put("id", functionCall.id().orElse(""));
170173
data.put("args", functionCall.args().orElse(Map.of()));
171174

172175
Map<String, Object> metadata =
@@ -185,6 +188,7 @@ private static Optional<DataPart> createDataPartFromFunctionResponse(
185188
FunctionResponse functionResponse) {
186189
Map<String, Object> data = new HashMap<>();
187190
data.put("name", functionResponse.name().orElse(""));
191+
data.put("id", functionResponse.id().orElse(""));
188192
data.put("response", functionResponse.response().orElse(Map.of()));
189193

190194
Map<String, Object> metadata =

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ 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(FunctionCall.builder().name("roll_die").id("adk-call-1").args(Map.of("sides", 6)).build())
4747
.build();
4848
Event callEvent =
4949
Event.builder()
@@ -59,7 +59,7 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
5959
Part functionResponsePart =
6060
Part.builder()
6161
.functionResponse(
62-
FunctionResponse.builder().name("roll_die").response(Map.of("result", 3)).build())
62+
FunctionResponse.builder().name("roll_die").id("adk-call-1").response(Map.of("result", 3)).build())
6363
.build();
6464
Event responseEvent =
6565
Event.builder()
@@ -106,11 +106,14 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
106106
assertThat(callDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
107107
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL);
108108
assertThat(callDataPart.getData()).containsEntry("name", "roll_die");
109+
assertThat(callDataPart.getData()).containsEntry("id", "adk-call-1");
109110
assertThat(callDataPart.getData()).containsEntry("args", Map.of("sides", 6));
110111

111112
DataPart responseDataPart = (DataPart) message.getParts().get(2);
112113
assertThat(responseDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
113114
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE);
115+
assertThat(responseDataPart.getData()).containsEntry("name", "roll_die");
116+
assertThat(responseDataPart.getData()).containsEntry("id", "adk-call-1");
114117
assertThat(responseDataPart.getData()).containsEntry("response", Map.of("result", 3));
115118
}
116119

0 commit comments

Comments
 (0)