feat: enhance AI tool support and clarify documentation (v2.5.1)

- Update tool descriptions to clarify ANY node can be used as AI tool
- Add get_node_as_tool_info to available tools in README
- Enhance workflow validation tool descriptions for AI connections
- Update README with v2.5.1 release notes
- Remove redundant _General__Scrape_with_HTTP_tool.json file
- Bump version to 2.5.1 in package.json

The key insight: ANY n8n node can be connected to an AI Agent's tool
port, not just those marked with usableAsTool=true. This update makes
that clear throughout the documentation and tool descriptions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
czlonkowski
2025-06-24 15:52:01 +02:00
parent 533b1acc20
commit aad1b69fb1
10 changed files with 737 additions and 146 deletions

View File

@@ -461,6 +461,107 @@ return results;`
description: 'Attach files to the email'
}
]
},
// AI Tool Usage Tasks
'use_google_sheets_as_tool': {
task: 'use_google_sheets_as_tool',
description: 'Use Google Sheets as an AI tool for reading/writing data',
nodeType: 'nodes-base.googleSheets',
configuration: {
operation: 'append',
sheetId: '={{ $fromAI("sheetId", "The Google Sheets ID") }}',
range: '={{ $fromAI("range", "The range to append to, e.g. A:Z") }}',
dataMode: 'autoMap'
},
userMustProvide: [
{
property: 'Google Sheets credentials',
description: 'Configure Google Sheets API credentials in n8n'
},
{
property: 'Tool name in AI Agent',
description: 'Give it a descriptive name like "Log Results to Sheet"'
},
{
property: 'Tool description',
description: 'Describe when and how the AI should use this tool'
}
],
notes: [
'Connect this node to the ai_tool port of an AI Agent node',
'The AI can dynamically determine sheetId and range using $fromAI',
'Works great for logging AI analysis results or reading data for processing'
]
},
'use_slack_as_tool': {
task: 'use_slack_as_tool',
description: 'Use Slack as an AI tool for sending notifications',
nodeType: 'nodes-base.slack',
configuration: {
resource: 'message',
operation: 'post',
channel: '={{ $fromAI("channel", "The Slack channel, e.g. #general") }}',
text: '={{ $fromAI("message", "The message to send") }}',
attachments: []
},
userMustProvide: [
{
property: 'Slack credentials',
description: 'Configure Slack OAuth2 credentials in n8n'
},
{
property: 'Tool configuration in AI Agent',
description: 'Name it something like "Send Slack Notification"'
}
],
notes: [
'Perfect for AI agents that need to notify teams',
'The AI determines channel and message content dynamically',
'Can be enhanced with blocks for rich formatting'
]
},
'multi_tool_ai_agent': {
task: 'multi_tool_ai_agent',
description: 'AI agent with multiple tools for complex automation',
nodeType: 'nodes-langchain.agent',
configuration: {
text: '={{ $json.query }}',
outputType: 'output',
systemMessage: 'You are an intelligent assistant with access to multiple tools. Use them wisely to complete tasks.'
},
userMustProvide: [
{
property: 'AI model credentials',
description: 'OpenAI, Anthropic, or other LLM credentials'
},
{
property: 'Multiple tool nodes',
description: 'Connect various nodes to the ai_tool port'
},
{
property: 'Tool descriptions',
description: 'Clear descriptions for each connected tool'
}
],
optionalEnhancements: [
{
property: 'Memory',
description: 'Add memory nodes for conversation context'
},
{
property: 'Custom tools',
description: 'Create Code nodes as custom tools'
}
],
notes: [
'Connect multiple nodes: HTTP Request, Slack, Google Sheets, etc.',
'Each tool should have a clear, specific purpose',
'Test each tool individually before combining',
'Set N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true for community nodes'
]
}
};
@@ -509,9 +610,10 @@ return results;`
'HTTP/API': ['get_api_data', 'post_json_request', 'call_api_with_auth'],
'Webhooks': ['receive_webhook', 'webhook_with_response'],
'Database': ['query_postgres', 'insert_postgres_data'],
'AI/LangChain': ['chat_with_ai', 'ai_agent_workflow'],
'AI/LangChain': ['chat_with_ai', 'ai_agent_workflow', 'multi_tool_ai_agent'],
'Data Processing': ['transform_data', 'filter_data'],
'Communication': ['send_slack_message', 'send_email']
'Communication': ['send_slack_message', 'send_email'],
'AI Tool Usage': ['use_google_sheets_as_tool', 'use_slack_as_tool', 'multi_tool_ai_agent']
};
}
}

View File

@@ -26,6 +26,7 @@ interface WorkflowConnection {
[sourceNode: string]: {
main?: Array<Array<{ node: string; type: string; index: number }>>;
error?: Array<Array<{ node: string; type: string; index: number }>>;
ai_tool?: Array<Array<{ node: string; type: string; index: number }>>;
};
}
@@ -340,6 +341,17 @@ export class WorkflowValidator {
'error'
);
}
// Check AI tool outputs
if (outputs.ai_tool) {
this.validateConnectionOutputs(
sourceName,
outputs.ai_tool,
nodeMap,
result,
'ai_tool'
);
}
}
// Check for orphaned nodes (not connected and not triggers)
@@ -360,6 +372,11 @@ export class WorkflowValidator {
if (conn) connectedNodes.add(conn.node);
});
}
if (outputs.ai_tool) {
outputs.ai_tool.flat().forEach(conn => {
if (conn) connectedNodes.add(conn.node);
});
}
});
// Check for orphaned nodes
@@ -400,7 +417,7 @@ export class WorkflowValidator {
outputs: Array<Array<{ node: string; type: string; index: number }>>,
nodeMap: Map<string, WorkflowNode>,
result: WorkflowValidationResult,
outputType: 'main' | 'error'
outputType: 'main' | 'error' | 'ai_tool'
): void {
outputs.forEach((outputConnections, outputIndex) => {
if (!outputConnections) return;
@@ -421,11 +438,57 @@ export class WorkflowValidator {
});
} else {
result.statistics.validConnections++;
// Additional validation for AI tool connections
if (outputType === 'ai_tool') {
this.validateAIToolConnection(sourceName, targetNode, result);
}
}
});
});
}
/**
* Validate AI tool connections
*/
private validateAIToolConnection(
sourceName: string,
targetNode: WorkflowNode,
result: WorkflowValidationResult
): void {
// For AI tool connections, we just need to check if this is being used as a tool
// The source should be an AI Agent connecting to this target node as a tool
// Get target node info to check if it can be used as a tool
let targetNodeInfo = this.nodeRepository.getNode(targetNode.type);
// Try normalized type if not found
if (!targetNodeInfo) {
let normalizedType = targetNode.type;
// Handle n8n-nodes-base -> nodes-base
if (targetNode.type.startsWith('n8n-nodes-base.')) {
normalizedType = targetNode.type.replace('n8n-nodes-base.', 'nodes-base.');
targetNodeInfo = this.nodeRepository.getNode(normalizedType);
}
// Handle @n8n/n8n-nodes-langchain -> nodes-langchain
else if (targetNode.type.startsWith('@n8n/n8n-nodes-langchain.')) {
normalizedType = targetNode.type.replace('@n8n/n8n-nodes-langchain.', 'nodes-langchain.');
targetNodeInfo = this.nodeRepository.getNode(normalizedType);
}
}
if (targetNodeInfo && !targetNodeInfo.isAITool && targetNodeInfo.package !== 'n8n-nodes-base') {
// It's a community node being used as a tool
result.warnings.push({
type: 'warning',
nodeId: targetNode.id,
nodeName: targetNode.name,
message: `Community node "${targetNode.name}" is being used as an AI tool. Ensure N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true is set.`
});
}
}
/**
* Check if workflow has cycles
*/
@@ -446,6 +509,18 @@ export class WorkflowValidator {
if (conn) allTargets.push(conn.node);
});
}
if (connections.error) {
connections.error.flat().forEach(conn => {
if (conn) allTargets.push(conn.node);
});
}
if (connections.ai_tool) {
connections.ai_tool.flat().forEach(conn => {
if (conn) allTargets.push(conn.node);
});
}
for (const target of allTargets) {
if (!visited.has(target)) {
@@ -578,6 +653,38 @@ export class WorkflowValidator {
}
}
}
// Check for AI Agent workflows
const aiAgentNodes = workflow.nodes.filter(n =>
n.type.toLowerCase().includes('agent') ||
n.type.includes('langchain.agent')
);
if (aiAgentNodes.length > 0) {
// Check if AI agents have tools connected
for (const agentNode of aiAgentNodes) {
const connections = workflow.connections[agentNode.name];
if (!connections?.ai_tool || connections.ai_tool.flat().filter(c => c).length === 0) {
result.warnings.push({
type: 'warning',
nodeId: agentNode.id,
nodeName: agentNode.name,
message: 'AI Agent has no tools connected. Consider adding tools to enhance agent capabilities.'
});
}
}
// Check for community nodes used as tools
const hasAIToolConnections = Object.values(workflow.connections).some(
outputs => outputs.ai_tool && outputs.ai_tool.length > 0
);
if (hasAIToolConnections) {
result.suggestions.push(
'For community nodes used as AI tools, ensure N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true is set'
);
}
}
}
/**