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:
@@ -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']
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user