import { NodeConnectionTypes } from 'n8n-workflow'; import type { INodeInputConfiguration, INodeInputFilter, IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, NodeConnectionType, INodeTypeBaseDescription, } from 'n8n-workflow'; import { promptTypeOptions, textFromPreviousNode, textInput } from '@utils/descriptions'; import { toolsAgentProperties } from '../agents/ToolsAgent/V2/description'; import { toolsAgentExecute } from '../agents/ToolsAgent/V2/execute'; // Function used in the inputs expression to figure out which inputs to // display based on the agent type function getInputs(hasOutputParser?: boolean): Array { interface SpecialInput { type: NodeConnectionType; filter?: INodeInputFilter; required?: boolean; } const getInputData = ( inputs: SpecialInput[], ): Array => { const displayNames: { [key: string]: string } = { ai_languageModel: 'Model', ai_memory: 'Memory', ai_tool: 'Tool', ai_outputParser: 'Output Parser', }; return inputs.map(({ type, filter }) => { const isModelType = type === 'ai_languageModel'; let displayName = type in displayNames ? displayNames[type] : undefined; if (isModelType) { displayName = 'Chat Model'; } const input: INodeInputConfiguration = { type, displayName, required: isModelType, maxConnections: ['ai_languageModel', 'ai_memory', 'ai_outputParser'].includes( type as NodeConnectionType, ) ? 1 : undefined, }; if (filter) { input.filter = filter; } return input; }); }; let specialInputs: SpecialInput[] = [ { type: 'ai_languageModel', filter: { nodes: [ '@n8n/n8n-nodes-langchain.lmChatAnthropic', '@n8n/n8n-nodes-langchain.lmChatAzureOpenAi', '@n8n/n8n-nodes-langchain.lmChatAwsBedrock', '@n8n/n8n-nodes-langchain.lmChatMistralCloud', '@n8n/n8n-nodes-langchain.lmChatOllama', '@n8n/n8n-nodes-langchain.lmChatOpenAi', '@n8n/n8n-nodes-langchain.lmChatGroq', '@n8n/n8n-nodes-langchain.lmChatGoogleVertex', '@n8n/n8n-nodes-langchain.lmChatGoogleGemini', '@n8n/n8n-nodes-langchain.lmChatDeepSeek', '@n8n/n8n-nodes-langchain.lmChatOpenRouter', '@n8n/n8n-nodes-langchain.lmChatXAiGrok', '@n8n/n8n-nodes-langchain.code', ], }, }, { type: 'ai_memory', }, { type: 'ai_tool', required: true, }, { type: 'ai_outputParser', }, ]; if (hasOutputParser === false) { specialInputs = specialInputs.filter((input) => input.type !== 'ai_outputParser'); } return ['main', ...getInputData(specialInputs)]; } export class AgentV2 implements INodeType { description: INodeTypeDescription; constructor(baseDescription: INodeTypeBaseDescription) { this.description = { ...baseDescription, version: 2, defaults: { name: 'AI Agent', color: '#404040', }, inputs: `={{ ((hasOutputParser) => { ${getInputs.toString()}; return getInputs(hasOutputParser) })($parameter.hasOutputParser === undefined || $parameter.hasOutputParser === true) }}`, outputs: [NodeConnectionTypes.Main], properties: [ { displayName: 'Tip: Get a feel for agents with our quick tutorial or see an example of how this node works', name: 'notice_tip', type: 'notice', default: '', }, promptTypeOptions, { ...textFromPreviousNode, displayOptions: { show: { promptType: ['auto'], }, }, }, { ...textInput, displayOptions: { show: { promptType: ['define'], }, }, }, { displayName: 'Require Specific Output Format', name: 'hasOutputParser', type: 'boolean', default: false, noDataExpression: true, }, { displayName: `Connect an output parser on the canvas to specify the output format you require`, name: 'notice', type: 'notice', default: '', displayOptions: { show: { hasOutputParser: [true], }, }, }, ...toolsAgentProperties, ], }; } async execute(this: IExecuteFunctions): Promise { return await toolsAgentExecute.call(this); } }