From 21d7c79ef00fef555afedbef3f38cae60fc145e6 Mon Sep 17 00:00:00 2001 From: Dang Zitou Date: Thu, 13 Aug 2026 03:49:57 +0800 Subject: [PATCH 1/3] fix: preserve raw tool parameter schemas in chat completions --- .../models/chat/ChatCompletionsRequest.java | 6 +++- .../chat/ChatCompletionsRequestTest.java | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java index 0c8cdc006..02c76d2b7 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java @@ -603,7 +603,11 @@ private static void handleTools(GenerateContentConfig config, ChatCompletionsReq FunctionDefinition def = new FunctionDefinition(); def.name = fd.name().orElse(""); def.description = fd.description().orElse(""); - if (fd.parameters().isPresent()) { + if (fd.parametersJsonSchema().isPresent()) { + def.parameters = + objectMapper.convertValue( + fd.parametersJsonSchema().get(), new TypeReference>() {}); + } else if (fd.parameters().isPresent()) { def.parameters = objectMapper.convertValue( fd.parameters().get(), new TypeReference>() {}); diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java index 1bb4c36b2..38b40069b 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java @@ -613,6 +613,40 @@ public void testFromLlmRequest_withAbsentParameters() throws Exception { assertThat(props).isEmpty(); } + @Test + public void testFromLlmRequest_withParametersJsonSchema() throws Exception { + Map jsonSchema = + ImmutableMap.of( + "type", + "object", + "properties", + ImmutableMap.of("jobId", ImmutableMap.of("$ref", "#/$defs/jobId")), + "required", + ImmutableList.of("jobId"), + "$defs", + ImmutableMap.of("jobId", ImmutableMap.of("type", "string"))); + FunctionDeclaration function = + FunctionDeclaration.builder() + .name("analyze_premerge_failures_by_job") + .parametersJsonSchema(jsonSchema) + .build(); + + Tool tool = Tool.builder().functionDeclarations(ImmutableList.of(function)).build(); + GenerateContentConfig config = + GenerateContentConfig.builder().tools(ImmutableList.of(tool)).build(); + LlmRequest llmRequest = + LlmRequest.builder() + .model("openai-compatible-model") + .config(config) + .contents(ImmutableList.of()) + .build(); + + ChatCompletionsRequest request = ChatCompletionsRequest.fromLlmRequest(llmRequest, false); + + assertThat(request.tools).hasSize(1); + assertThat(request.tools.get(0).function.parameters).isEqualTo(jsonSchema); + } + @Test public void testFromLlmRequest_normalizesSchemaTypeToLowerCase() throws Exception { Schema param1Schema = Schema.builder().type("STRING").build(); From 2fd061225a8b3c1b1109456693a5217b747069ab Mon Sep 17 00:00:00 2001 From: Dang Zitou Date: Sun, 30 Aug 2026 22:48:26 +0800 Subject: [PATCH 2/3] fix: preserve empty properties for raw tool schemas --- .../models/chat/ChatCompletionsRequest.java | 3 ++ .../chat/ChatCompletionsRequestTest.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java index 02c76d2b7..77b0ae3c6 100644 --- a/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java +++ b/core/src/main/java/com/google/adk/models/chat/ChatCompletionsRequest.java @@ -607,6 +607,9 @@ private static void handleTools(GenerateContentConfig config, ChatCompletionsReq def.parameters = objectMapper.convertValue( fd.parametersJsonSchema().get(), new TypeReference>() {}); + if (!def.parameters.containsKey("properties")) { + def.parameters.put("properties", ImmutableMap.of()); + } } else if (fd.parameters().isPresent()) { def.parameters = objectMapper.convertValue( diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java index 38b40069b..f97f2198a 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java @@ -37,6 +37,7 @@ import com.google.genai.types.Schema; import com.google.genai.types.Tool; import com.google.genai.types.ToolConfig; +import io.modelcontextprotocol.spec.McpSchema.JsonSchema; import java.util.AbstractMap; import java.util.Base64; import java.util.List; @@ -647,6 +648,34 @@ public void testFromLlmRequest_withParametersJsonSchema() throws Exception { assertThat(request.tools.get(0).function.parameters).isEqualTo(jsonSchema); } + @Test + public void testFromLlmRequest_withZeroArgumentParametersJsonSchema() throws Exception { + JsonSchema jsonSchema = new JsonSchema("object", null, null, null, null, null); + FunctionDeclaration function = + FunctionDeclaration.builder() + .name("zero_argument_tool") + .parametersJsonSchema(jsonSchema) + .build(); + Tool tool = Tool.builder().functionDeclarations(ImmutableList.of(function)).build(); + GenerateContentConfig config = + GenerateContentConfig.builder().tools(ImmutableList.of(tool)).build(); + LlmRequest llmRequest = + LlmRequest.builder() + .model("openai-compatible-model") + .config(config) + .contents(ImmutableList.of()) + .build(); + + ChatCompletionsRequest request = ChatCompletionsRequest.fromLlmRequest(llmRequest, false); + + assertThat(request.tools).hasSize(1); + Map params = (Map) request.tools.get(0).function.parameters; + assertThat(params.get("type")).isEqualTo("object"); + @SuppressWarnings("unchecked") + Map props = (Map) params.get("properties"); + assertThat(props).isEmpty(); + } + @Test public void testFromLlmRequest_normalizesSchemaTypeToLowerCase() throws Exception { Schema param1Schema = Schema.builder().type("STRING").build(); From ce7033262bbae13de9094c0ce23f237abccd1631 Mon Sep 17 00:00:00 2001 From: Dang Zitou Date: Mon, 31 Aug 2026 00:28:20 +0800 Subject: [PATCH 3/3] test: cover MCP raw schema conversion --- .../chat/ChatCompletionsRequestTest.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java index f97f2198a..b1789f823 100644 --- a/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java +++ b/core/src/test/java/com/google/adk/models/chat/ChatCompletionsRequestTest.java @@ -616,16 +616,11 @@ public void testFromLlmRequest_withAbsentParameters() throws Exception { @Test public void testFromLlmRequest_withParametersJsonSchema() throws Exception { - Map jsonSchema = - ImmutableMap.of( - "type", - "object", - "properties", - ImmutableMap.of("jobId", ImmutableMap.of("$ref", "#/$defs/jobId")), - "required", - ImmutableList.of("jobId"), - "$defs", - ImmutableMap.of("jobId", ImmutableMap.of("type", "string"))); + Map properties = + ImmutableMap.of("jobId", ImmutableMap.of("$ref", "#/$defs/jobId")); + Map defs = ImmutableMap.of("jobId", ImmutableMap.of("type", "string")); + JsonSchema jsonSchema = + new JsonSchema("object", properties, ImmutableList.of("jobId"), null, defs, null); FunctionDeclaration function = FunctionDeclaration.builder() .name("analyze_premerge_failures_by_job") @@ -645,7 +640,17 @@ public void testFromLlmRequest_withParametersJsonSchema() throws Exception { ChatCompletionsRequest request = ChatCompletionsRequest.fromLlmRequest(llmRequest, false); assertThat(request.tools).hasSize(1); - assertThat(request.tools.get(0).function.parameters).isEqualTo(jsonSchema); + assertThat(request.tools.get(0).function.parameters) + .isEqualTo( + ImmutableMap.of( + "type", + "object", + "properties", + properties, + "required", + ImmutableList.of("jobId"), + "$defs", + defs)); } @Test