This is an automated email from the ASF dual-hosted git repository.

wenjin272 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new a6213bdb [integration][ollama] Tolerate tool schemas without a 
'required' key (#1026)
a6213bdb is described below

commit a6213bdb7f991544877ab77e00ddf865e9c9d633
Author: Edson <[email protected]>
AuthorDate: Thu Aug 20 03:57:39 2026 -0400

    [integration][ollama] Tolerate tool schemas without a 'required' key (#1026)
---
 .../ollama/OllamaChatModelConnection.java          |   8 +-
 .../ollama/OllamaChatModelConnectionTest.java      | 104 +++++++++++++++++++++
 2 files changed, 110 insertions(+), 2 deletions(-)

diff --git 
a/integrations/chat-models/ollama/src/main/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnection.java
 
b/integrations/chat-models/ollama/src/main/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnection.java
index de6f946f..e86f1277 100644
--- 
a/integrations/chat-models/ollama/src/main/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnection.java
+++ 
b/integrations/chat-models/ollama/src/main/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnection.java
@@ -106,8 +106,9 @@ public class OllamaChatModelConnection extends 
BaseChatModelConnection {
      * @return List of Ollama compatible tool specifications
      * @throws RuntimeException if schema parsing or conversion fails
      */
+    // Package-visible for unit testing of the schema conversion.
     @SuppressWarnings("unchecked")
-    private List<Tools.Tool> convertToOllamaTools(List<Tool> tools) {
+    List<Tools.Tool> convertToOllamaTools(List<Tool> tools) {
         final ObjectMapper mapper = new ObjectMapper();
         final List<Tools.Tool> ollamaTools = new ArrayList<>();
         try {
@@ -118,7 +119,10 @@ public class OllamaChatModelConnection extends 
BaseChatModelConnection {
 
                 final Map<String, Map<String, String>> properties =
                         (Map<String, Map<String, String>>) 
schema.get("properties");
-                final List<String> required = (List<String>) 
schema.get("required");
+                // "required" is optional in JSON Schema, and SchemaUtils only 
emits it when at
+                // least one parameter is required — treat a missing list as 
empty (#1014).
+                final List<String> required =
+                        (List<String>) schema.getOrDefault("required", 
Collections.emptyList());
 
                 Map<String, Tools.Property> propertiesMap = new HashMap<>();
 
diff --git 
a/integrations/chat-models/ollama/src/test/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnectionTest.java
 
b/integrations/chat-models/ollama/src/test/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnectionTest.java
new file mode 100644
index 00000000..06570c29
--- /dev/null
+++ 
b/integrations/chat-models/ollama/src/test/java/org/apache/flink/agents/integrations/chatmodels/ollama/OllamaChatModelConnectionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.flink.agents.integrations.chatmodels.ollama;
+
+import io.github.ollama4j.tools.Tools;
+import org.apache.flink.agents.api.resource.ResourceContext;
+import org.apache.flink.agents.api.resource.ResourceDescriptor;
+import org.apache.flink.agents.api.tools.Tool;
+import org.apache.flink.agents.api.tools.ToolMetadata;
+import org.apache.flink.agents.api.tools.ToolParameters;
+import org.apache.flink.agents.api.tools.ToolResponse;
+import org.apache.flink.agents.api.tools.ToolType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Unit tests for {@link OllamaChatModelConnection}'s tool-schema conversion — 
no network access.
+ */
+class OllamaChatModelConnectionTest {
+
+    private static final ResourceContext NOOP = 
ResourceContext.fromGetResource((a, b) -> null);
+
+    private static OllamaChatModelConnection connection() {
+        ResourceDescriptor desc =
+                
ResourceDescriptor.Builder.newBuilder(OllamaChatModelConnection.class.getName())
+                        .addInitialArgument("endpoint", 
"http://localhost:11434";)
+                        .build();
+        return new OllamaChatModelConnection(desc, NOOP);
+    }
+
+    /** Minimal tool carrying only metadata; never invoked in these tests. */
+    private static final class SchemaOnlyTool extends Tool {
+        SchemaOnlyTool(String inputSchema) {
+            super(new ToolMetadata("add", "Add two numbers.", inputSchema));
+        }
+
+        @Override
+        public ToolType getToolType() {
+            return ToolType.FUNCTION;
+        }
+
+        @Override
+        public ToolResponse call(ToolParameters parameters) {
+            throw new UnsupportedOperationException("not invoked in this 
test");
+        }
+    }
+
+    @Test
+    @DisplayName("A schema without a 'required' key converts with every 
property optional")
+    void testSchemaWithoutRequiredKey() {
+        // SchemaUtils only emits "required" when at least one parameter is 
required, so an
+        // all-optional @Tool produces exactly this shape (#1014).
+        String schema =
+                "{\"type\":\"object\",\"properties\":{"
+                        + 
"\"a\":{\"type\":\"integer\"},\"b\":{\"type\":\"integer\"}}}";
+
+        List<Tools.Tool> converted =
+                connection().convertToOllamaTools(List.of(new 
SchemaOnlyTool(schema)));
+
+        assertThat(converted).hasSize(1);
+        Tools.Tool tool = converted.get(0);
+        assertThat(tool.getToolSpec().getParameters().getProperties())
+                .containsOnlyKeys("a", "b")
+                .allSatisfy((name, property) -> 
assertThat(property.isRequired()).isFalse());
+    }
+
+    @Test
+    @DisplayName("A schema with a 'required' key still marks the listed 
parameters required")
+    void testSchemaWithRequiredKey() {
+        String schema =
+                "{\"type\":\"object\",\"properties\":{"
+                        + 
"\"a\":{\"type\":\"integer\"},\"b\":{\"type\":\"integer\"}},"
+                        + "\"required\":[\"a\"]}";
+
+        List<Tools.Tool> converted =
+                connection().convertToOllamaTools(List.of(new 
SchemaOnlyTool(schema)));
+
+        assertThat(converted).hasSize(1);
+        Tools.Tool tool = converted.get(0);
+        
assertThat(tool.getToolSpec().getParameters().getProperties().get("a").isRequired())
+                .isTrue();
+        
assertThat(tool.getToolSpec().getParameters().getProperties().get("b").isRequired())
+                .isFalse();
+    }
+}

Reply via email to