Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,23 @@ private static Optional<com.google.genai.types.Part> convertDataPartToGenAiPart(
if (data.containsKey("name") && data.containsKey("args")
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL.equals(metadataType)) {
String functionName = String.valueOf(data.getOrDefault("name", ""));
String functionId = String.valueOf(data.getOrDefault("id", ""));
Map<String, Object> args = coerceToMap(data.get("args"));
return Optional.of(
com.google.genai.types.Part.builder()
.functionCall(FunctionCall.builder().name(functionName).args(args).build())
.functionCall(FunctionCall.builder().name(functionName).id(functionId).args(args).build())
.build());
Comment on lines 134 to 140

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This change is a good step, but there are two issues to address for the function call conversion:

  1. Incomplete Conversion: The reverse conversion from a GenAI FunctionCall to an A2A DataPart is missing. The createDataPartFromFunctionCall method should be updated to also handle the id property, otherwise it will be lost. This will also cause the new tests to fail.
  2. Null Handling: The current approach to get the id can result in bugs. If data contains ("id", null), functionId will become the string "null".

Here is a suggested improvement for the null handling. Please also address the missing reverse conversion.

      String functionName = String.valueOf(data.getOrDefault("name", ""));
      Object idObj = data.get("id");
      String functionId = (idObj == null) ? null : String.valueOf(idObj);
      Map<String, Object> args = coerceToMap(data.get("args"));
      return Optional.of(
          com.google.genai.types.Part.builder()
              .functionCall(FunctionCall.builder().name(functionName).id(functionId).args(args).build())
              .build());

}

if (data.containsKey("name") && data.containsKey("response")
|| A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE.equals(metadataType)) {
String functionName = String.valueOf(data.getOrDefault("name", ""));
String functionId = String.valueOf(data.getOrDefault("id", ""));
Map<String, Object> response = coerceToMap(data.get("response"));
return Optional.of(
com.google.genai.types.Part.builder()
.functionResponse(
FunctionResponse.builder().name(functionName).response(response).build())
FunctionResponse.builder().name(functionName).id(functionId).response(response).build())
.build());
Comment on lines 145 to 152

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Similar to the function call, there are two issues to address for the function response conversion:

  1. Incomplete Conversion: The reverse conversion from a GenAI FunctionResponse to an A2A DataPart is missing. The createDataPartFromFunctionResponse method should be updated to also handle the id property.
  2. Null Handling: The id retrieval here can lead to a "null" string ID if the value in the map is null.

Here is a suggested improvement for the null handling. Please also address the missing reverse conversion.

      String functionName = String.valueOf(data.getOrDefault("name", ""));
      Object idObj = data.get("id");
      String functionId = (idObj == null) ? null : String.valueOf(idObj);
      Map<String, Object> response = coerceToMap(data.get("response"));
      return Optional.of(
          com.google.genai.types.Part.builder()
              .functionResponse(
                  FunctionResponse.builder().name(functionName).id(functionId).response(response).build())
              .build());

}

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

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

Map<String, Object> metadata =
Expand Down
7 changes: 5 additions & 2 deletions a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {

Part functionCallPart =
Part.builder()
.functionCall(FunctionCall.builder().name("roll_die").args(Map.of("sides", 6)).build())
.functionCall(FunctionCall.builder().name("roll_die").id("adk-call-1").args(Map.of("sides", 6)).build())
.build();
Event callEvent =
Event.builder()
Expand All @@ -59,7 +59,7 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
Part functionResponsePart =
Part.builder()
.functionResponse(
FunctionResponse.builder().name("roll_die").response(Map.of("result", 3)).build())
FunctionResponse.builder().name("roll_die").id("adk-call-1").response(Map.of("result", 3)).build())
.build();
Event responseEvent =
Event.builder()
Expand Down Expand Up @@ -106,11 +106,14 @@ public void convertEventsToA2AMessage_preservesFunctionCallAndResponseParts() {
assertThat(callDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL);
assertThat(callDataPart.getData()).containsEntry("name", "roll_die");
assertThat(callDataPart.getData()).containsEntry("id", "adk-call-1");
Comment thread
zbirkenbuel marked this conversation as resolved.
assertThat(callDataPart.getData()).containsEntry("args", Map.of("sides", 6));

DataPart responseDataPart = (DataPart) message.getParts().get(2);
assertThat(responseDataPart.getMetadata().get(PartConverter.A2A_DATA_PART_METADATA_TYPE_KEY))
.isEqualTo(PartConverter.A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE);
assertThat(responseDataPart.getData()).containsEntry("name", "roll_die");
assertThat(responseDataPart.getData()).containsEntry("id", "adk-call-1");
assertThat(responseDataPart.getData()).containsEntry("response", Map.of("result", 3));
}

Expand Down
Loading