fix: recognize dynamic AI Tool nodes in validator (Issue #522) (#526)

When n8n connects any node to an AI Agent's tool slot, it creates a
dynamic Tool variant at runtime (e.g., googleDrive → googleDriveTool).
These don't exist in npm packages, causing false "unknown node type"
errors.

Added validation-time inference: when a *Tool node type is not found,
check if the base node exists. If yes, treat as valid with warning.

Changes:
- workflow-validator.ts: Add INFERRED_TOOL_VARIANT logic
- node-similarity-service.ts: Add 98% confidence for valid Tool variants
- Added 7 unit tests for inferred tool variant functionality

Fixes #522

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Romuald Członkowski <romualdczlonkowski@MacBook-Pro-Romuald.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Romuald Członkowski
2026-01-07 18:09:55 +01:00
committed by GitHub
parent 861005eeed
commit ce2c94c1a5
11 changed files with 425 additions and 7 deletions

View File

@@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeSimilarityService = void 0;
const logger_1 = require("../utils/logger");
const tool_variant_generator_1 = require("./tool-variant-generator");
class NodeSimilarityService {
constructor(repository) {
this.nodeCache = null;
@@ -67,6 +68,22 @@ class NodeSimilarityService {
if (!invalidType || invalidType.trim() === '') {
return [];
}
if (tool_variant_generator_1.ToolVariantGenerator.isToolVariantNodeType(invalidType)) {
const baseNodeType = tool_variant_generator_1.ToolVariantGenerator.getBaseNodeType(invalidType);
if (baseNodeType) {
const baseNode = this.repository.getNode(baseNodeType);
if (baseNode) {
return [{
nodeType: invalidType,
displayName: `${baseNode.displayName} Tool`,
confidence: 0.98,
reason: `Dynamic AI Tool variant of ${baseNode.displayName}`,
category: baseNode.category,
description: 'Runtime-generated Tool variant for AI Agent integration'
}];
}
}
}
const suggestions = [];
const mistakeSuggestion = this.checkCommonMistakes(invalidType);
if (mistakeSuggestion) {