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();
+ }
+}