From 8f8fba8263a6f96007d27e43ac18a3f8921d3cd5 Mon Sep 17 00:00:00 2001 From: Lucio Lelii Date: Fri, 25 Sep 2026 19:08:31 +0200 Subject: [PATCH] Offer an LLM node's required tools only once it has MCP servers The tools a node must have used successfully are checked by the loop that bound MCP servers start; a node without one runs a single call and never looks at them. The editor showed the field regardless, inviting a setting that could do nothing. It now appears once the node has an MCP server, through a visible-when rule that can say "once this holds something" - the same present rule enabled-when already had. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../configurations/JsonSchemaProducer.java | 3 ++ .../configurations/LLMBlockConfiguration.java | 3 ++ .../annotations/UiVisibleWhen.java | 2 ++ .../configurations/LLMBlockSchemaTest.java | 33 +++++++++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 src/test/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockSchemaTest.java diff --git a/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/JsonSchemaProducer.java b/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/JsonSchemaProducer.java index 7c75a87..9dfa977 100644 --- a/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/JsonSchemaProducer.java +++ b/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/JsonSchemaProducer.java @@ -1449,6 +1449,9 @@ public class JsonSchemaProducer { equalsAny.add(value); } } + if (dependency.present()) { + visibleWhen.put("present", true); + } } } diff --git a/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockConfiguration.java b/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockConfiguration.java index 0c27d64..050061f 100644 --- a/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockConfiguration.java +++ b/src/main/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockConfiguration.java @@ -18,6 +18,7 @@ import it.cnr.isti.workflow.manager.configurations.annotations.UiDescription; import it.cnr.isti.workflow.manager.configurations.annotations.UiLabel; import it.cnr.isti.workflow.manager.configurations.annotations.UiOrder; import it.cnr.isti.workflow.manager.configurations.annotations.UiUniqueItemsBy; +import it.cnr.isti.workflow.manager.configurations.annotations.UiVisibleWhen; import it.cnr.isti.workflow.manager.llms.LLMDescriptor; import it.cnr.isti.workflow.manager.mcp.MCPToolServerBinding; import it.cnr.isti.workflow.manager.skills.SkillBinding; @@ -75,6 +76,8 @@ public class LLMBlockConfiguration extends BlockConfiguration { @Structural @Size(max = 16) @UiOrder(70) + // Checked only by the loop MCP servers start, so without one there is nothing it could apply to. + @UiVisibleWhen(field = "mcpServers", present = true) @UiLabel("Required successful MCP tools") @UiDescription("Tool names that must each complete successfully before this node can finish. Use this for agents that must prove work, for example start_service, browser_navigate and browser_snapshot.") @JsonProperty(required = false) diff --git a/src/main/java/it/cnr/isti/workflow/manager/configurations/annotations/UiVisibleWhen.java b/src/main/java/it/cnr/isti/workflow/manager/configurations/annotations/UiVisibleWhen.java index 2a04df1..5d1001d 100644 --- a/src/main/java/it/cnr/isti/workflow/manager/configurations/annotations/UiVisibleWhen.java +++ b/src/main/java/it/cnr/isti/workflow/manager/configurations/annotations/UiVisibleWhen.java @@ -26,4 +26,6 @@ public @interface UiVisibleWhen { String equals() default ""; String[] equalsAny() default {}; + /** Shown only once {@link #field()} holds something: a text that is not blank, a list with an item. */ + boolean present() default false; } diff --git a/src/test/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockSchemaTest.java b/src/test/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockSchemaTest.java new file mode 100644 index 0000000..9ad9a4c --- /dev/null +++ b/src/test/java/it/cnr/isti/workflow/manager/blocks/configurations/LLMBlockSchemaTest.java @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2025-2026 Lucio Lelii - ISTI-CNR +// SPDX-License-Identifier: AGPL-3.0-or-later +// Attribution term under AGPL-3.0 section 7(b): see LICENSE-ADDENDUM. + +package it.cnr.isti.workflow.manager.blocks.configurations; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.TestPropertySource; + +import tools.jackson.databind.JsonNode; + +/** What the editor is told about an LLM node's fields. */ +@SpringBootTest +@TestPropertySource(locations = "classpath:test.properties") +class LLMBlockSchemaTest { + + @Autowired + private JsonSchemaProducer schemaProducer; + + @Test + void theRequiredToolsAreOfferedOnlyToANodeThatHasMcpServersToCall() { + JsonNode schema = schemaProducer.generateSchemaNode(LLMBlockConfiguration.class); + + JsonNode visibleWhen = schema.get("properties").get("requiredSuccessfulMcpTools").get("x-ui-visible-when"); + + assertEquals("mcpServers", visibleWhen.get("field").asText()); + assertEquals(true, visibleWhen.get("present").asBoolean()); + } +}