Skip to content

Commit 9e52f62

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 9e52f62

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,28 @@ 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().name(functionName).id(functionId).args(args).build())
139141
.build());
140142
}
141143

142144
if (data.containsKey("name") && data.containsKey("response")
143145
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
144146
String functionName = String.valueOf(data.getOrDefault("name", ""));
147+
String functionId = String.valueOf(data.getOrDefault("id", ""));
145148
Map<String, Object> response = coerceToMap(data.get("response"));
146149
return Optional.of(
147150
com.google.genai.types.Part.builder()
148151
.functionResponse(
149-
FunctionResponse.builder().name(functionName).response(response).build())
152+
FunctionResponse.builder()
153+
.name(functionName)
154+
.id(functionId)
155+
.response(response)
156+
.build())
150157
.build());
151158
}
152159

@@ -167,6 +174,7 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
167174
private static Optional<DataPart> createDataPartFromFunctionCall(FunctionCall functionCall) {
168175
Map<String, Object> data = new HashMap<>();
169176
data.put("name", functionCall.name().orElse(""));
177+
data.put("id", functionCall.id().orElse(""));
170178
data.put("args", functionCall.args().orElse(Map.of()));
171179

172180
Map<String, Object> metadata =
@@ -185,6 +193,7 @@ private static Optional<DataPart> createDataPartFromFunctionResponse(
185193
FunctionResponse functionResponse) {
186194
Map<String, Object> data = new HashMap<>();
187195
data.put("name", functionResponse.name().orElse(""));
196+
data.put("id", functionResponse.id().orElse(""));
188197
data.put("response", functionResponse.response().orElse(Map.of()));
189198

190199
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")
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")
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)