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) <noreply@anthropic.com>
This commit is contained in:
Lucio Lelii 2026-09-25 19:08:31 +02:00
parent acd43f8f1e
commit 8f8fba8263
4 changed files with 41 additions and 0 deletions

View File

@ -1449,6 +1449,9 @@ public class JsonSchemaProducer {
equalsAny.add(value);
}
}
if (dependency.present()) {
visibleWhen.put("present", true);
}
}
}

View File

@ -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<LLMBlockType> {
@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)

View File

@ -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;
}

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2025-2026 Lucio Lelii <lucio.lelii@isti.cnr.it> - 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());
}
}