Skip to content

Commit 5cf5ad9

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 5cf5ad9

2 files changed

Lines changed: 29 additions & 4 deletions

File tree

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,32 @@ 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+
.args(args)
144+
.build())
139145
.build());
140146
}
141147

142148
if (data.containsKey("name") && data.containsKey("response")
143149
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
144150
String functionName = String.valueOf(data.getOrDefault("name", ""));
151+
String functionId = String.valueOf(data.getOrDefault("id", ""));
145152
Map<String, Object> response = coerceToMap(data.get("response"));
146153
return Optional.of(
147154
com.google.genai.types.Part.builder()
148155
.functionResponse(
149-
FunctionResponse.builder().name(functionName).response(response).build())
156+
FunctionResponse.builder()
157+
.name(functionName)
158+
.id(functionId)
159+
.response(response)
160+
.build())
150161
.build());
151162
}
152163

@@ -167,6 +178,7 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
167178
private static Optional<DataPart> createDataPartFromFunctionCall(FunctionCall functionCall) {
168179
Map<String, Object> data = new HashMap<>();
169180
data.put("name", functionCall.name().orElse(""));
181+
data.put("id", functionCall.id().orElse(""));
170182
data.put("args", functionCall.args().orElse(Map.of()));
171183

172184
Map<String, Object> metadata =
@@ -185,6 +197,7 @@ private static Optional<DataPart> createDataPartFromFunctionResponse(
185197
FunctionResponse functionResponse) {
186198
Map<String, Object> data = new HashMap<>();
187199
data.put("name", functionResponse.name().orElse(""));
200+
data.put("id", functionResponse.id().orElse(""));
188201
data.put("response", functionResponse.response().orElse(Map.of()));
189202

190203
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)