UNPKG

@n8n/n8n-nodes-langchain

Version:

![Banner image](https://user-images.githubusercontent.com/10284570/173569848-c624317f-42b1-45a6-ab09-f0ea3c247648.png)

409 lines 14.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.description = void 0; exports.execute = execute; const n8n_workflow_1 = require("n8n-workflow"); const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema")); const helpers_1 = require("../../../../../utils/helpers"); const transport_1 = require("../../transport"); const descriptions_1 = require("../descriptions"); const properties = [ { displayName: 'Model', name: 'modelId', type: 'options', options: [ { name: 'Qwen3 Max', value: 'qwen3-max', description: 'Most capable model with best performance', }, { name: 'Qwen3 Max (2026-01-23)', value: 'qwen3-max-2026-01-23', description: 'Qwen Max snapshot from 2026-01-23', }, { name: 'Qwen3.5 122B-A10B', value: 'qwen3.5-122b-a10b', description: 'MoE model with 122B total / 10B active parameters', }, { name: 'Qwen3.5 27B', value: 'qwen3.5-27b', description: 'Dense 27B parameter model', }, { name: 'Qwen3.5 35B-A3B', value: 'qwen3.5-35b-a3b', description: 'Small MoE model with 35B total / 3B active parameters', }, { name: 'Qwen3.5 397B-A17B', value: 'qwen3.5-397b-a17b', description: 'Large MoE model with 397B total / 17B active parameters', }, { name: 'Qwen3.5 Flash', value: 'qwen3.5-flash', description: 'Faster, more cost-effective model', }, { name: 'Qwen3.5 Flash (2026-02-23)', value: 'qwen3.5-flash-2026-02-23', description: 'Qwen Flash snapshot from 2026-02-23', }, { name: 'Qwen3.5 Plus', value: 'qwen3.5-plus', description: 'Balanced model with good performance and cost', }, { name: 'Qwen3.5 Plus (2026-02-15)', value: 'qwen3.5-plus-2026-02-15', description: 'Qwen Plus snapshot from 2026-02-15', }, ], default: 'qwen3.5-flash', description: 'The model to use for generation', displayOptions: { show: { '@version': [1] }, }, }, { ...(0, descriptions_1.modelRLC)('textModelSearch'), displayOptions: { show: { '@version': [{ _cnd: { gte: 1.1 } }] }, }, }, { displayName: 'Messages', name: 'messages', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: { messageValues: [ { content: '', role: 'user', }, ], }, placeholder: 'Add Message', options: [ { name: 'messageValues', displayName: 'Message', values: [ { displayName: 'Content', name: 'content', type: 'string', typeOptions: { rows: 4, }, default: '', description: 'The content of the message', }, { displayName: 'Role', name: 'role', type: 'options', options: [ { name: 'User', value: 'user', }, { name: 'Assistant', value: 'assistant', }, ], default: 'user', description: 'The role of the message sender', }, ], }, ], }, { displayName: 'Simplify Output', name: 'simplify', type: 'boolean', default: true, description: 'Whether to return a simplified version of the response instead of the raw data', }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add Option', default: {}, options: [ { displayName: 'Enable Search', name: 'enableSearch', type: 'boolean', default: false, description: 'Whether to enable web search for up-to-date information', }, { displayName: 'Max Tokens', name: 'maxTokens', type: 'number', typeOptions: { minValue: 1, }, default: 2000, description: 'Maximum number of tokens to generate', }, { displayName: 'Max Tools Iterations', name: 'maxToolsIterations', type: 'number', default: 15, description: 'Maximum number of tool-calling iterations before stopping. Set to 0 for unlimited.', }, { displayName: 'Repetition Penalty', name: 'repetitionPenalty', type: 'number', typeOptions: { minValue: 1, maxValue: 2, numberPrecision: 2, }, default: 1.1, description: 'Penalty for token repetition. Higher values reduce repetition.', }, { displayName: 'Seed', name: 'seed', type: 'number', default: 1234, description: 'Random seed for reproducible outputs', }, { displayName: 'Stop Sequences', name: 'stop', type: 'string', default: '', description: 'Comma-separated list of sequences where the API will stop generating', }, { displayName: 'System Message', name: 'system', type: 'string', default: '', placeholder: 'e.g. You are a helpful assistant', }, { displayName: 'Temperature', name: 'temperature', type: 'number', typeOptions: { minValue: 0, maxValue: 2, numberPrecision: 2, }, default: 1, description: 'Controls randomness in the output. Lower values make output more focused and deterministic.', }, { displayName: 'Top K', name: 'topK', type: 'number', typeOptions: { minValue: 1, maxValue: 100, }, default: 50, description: 'Limits the sampling pool to top K tokens', }, { displayName: 'Top P', name: 'topP', type: 'number', typeOptions: { minValue: 0, maxValue: 1, numberPrecision: 2, }, default: 0.9, description: 'Nucleus sampling parameter. Lower values make output more focused.', }, ], }, ]; const displayOptions = { show: { operation: ['message'], resource: ['text'], }, }; exports.description = (0, n8n_workflow_1.updateDisplayOptions)(displayOptions, properties); const TEXT_ONLY_PATTERNS = ['coder', 'math']; function isMultimodalModel(model) { const lower = model.toLowerCase(); return !TEXT_ONLY_PATTERNS.some((pattern) => lower.includes(pattern)); } async function execute(itemIndex) { const nodeVersion = this.getNode().typeVersion; const model = nodeVersion >= 1.1 ? this.getNodeParameter('modelId', itemIndex, '', { extractValue: true }) : this.getNodeParameter('modelId', itemIndex); const messagesParam = this.getNodeParameter('messages', itemIndex); const messages = messagesParam.messageValues || []; const options = this.getNodeParameter('options', itemIndex, {}); const simplify = this.getNodeParameter('simplify', itemIndex, true); const isMultimodal = isMultimodalModel(model); const { tools, connectedTools } = await getTools.call(this); const formattedMessages = isMultimodal ? messages.map((msg) => ({ role: msg.role, content: typeof msg.content === 'string' ? [{ text: msg.content }] : msg.content, })) : messages; if (options.system) { formattedMessages.unshift({ role: 'system', content: isMultimodal ? [{ text: options.system }] : options.system, }); } const body = { model, input: { messages: formattedMessages, }, parameters: {}, }; if (options.temperature !== undefined) { body.parameters.temperature = options.temperature; } if (options.topP !== undefined) { body.parameters.top_p = options.topP; } if (options.topK !== undefined) { body.parameters.top_k = options.topK; } if (options.maxTokens !== undefined) { body.parameters.max_tokens = options.maxTokens; } if (options.repetitionPenalty !== undefined) { body.parameters.repetition_penalty = options.repetitionPenalty; } if (options.stop) { body.parameters.stop = options.stop.split(',').map((s) => s.trim()); } if (options.enableSearch !== undefined) { body.parameters.enable_search = options.enableSearch; } if (options.seed !== undefined) { body.parameters.seed = options.seed; } if (tools.length) { body.parameters.tools = tools; } const endpoint = isMultimodal ? '/api/v1/services/aigc/multimodal-generation/generation' : '/api/v1/services/aigc/text-generation/generation'; let response = await transport_1.apiRequest.call(this, 'POST', endpoint, { body }); const captureUsage = () => { const usage = response?.usage; if (usage) { (0, n8n_workflow_1.accumulateTokenUsage)(this, usage.input_tokens, usage.output_tokens); } }; captureUsage(); const maxToolsIterations = this.getNodeParameter('options.maxToolsIterations', itemIndex, 15); const abortSignal = this.getExecutionCancelSignal(); let currentIteration = 0; while (true) { if (abortSignal?.aborted) { break; } const choice = response.output?.choices?.[0]; const finishReason = choice?.finish_reason; if (finishReason === 'tool_calls') { if (maxToolsIterations > 0 && currentIteration >= maxToolsIterations) { break; } const assistantMessage = choice.message; formattedMessages.push(assistantMessage); await handleToolUse.call(this, assistantMessage.tool_calls, formattedMessages, connectedTools); currentIteration++; } else { break; } response = await transport_1.apiRequest.call(this, 'POST', endpoint, { body }); captureUsage(); } const output = isMultimodal ? response.output?.choices?.[0]?.message?.content?.[0]?.text || '' : response.output?.text || response.output?.choices?.[0]?.message?.content || ''; return { json: simplify ? { content: output } : { content: output, model, usage: response.usage, fullResponse: response, }, pairedItem: itemIndex, }; } async function getTools() { let connectedTools = []; const nodeInputs = this.getNodeInputs(); if (nodeInputs.some((i) => i.type === 'ai_tool')) { connectedTools = await (0, helpers_1.getConnectedTools)(this, true); } const tools = connectedTools.map((t) => ({ type: 'function', function: { name: t.name, description: t.description, parameters: (0, zod_to_json_schema_1.default)(t.schema), }, })); return { tools, connectedTools }; } async function handleToolUse(toolCalls, messages, connectedTools) { if (!toolCalls?.length) { return; } for (const toolCall of toolCalls) { const toolName = toolCall.function.name; let toolInput; try { toolInput = JSON.parse(toolCall.function.arguments); } catch { toolInput = toolCall.function.arguments; } let toolResponse; for (const connectedTool of connectedTools) { if (connectedTool.name === toolName) { toolResponse = await connectedTool.invoke(toolInput); } } if (toolResponse === undefined) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Tool "${toolName}" was called but not found among connected tools`); } messages.push({ role: 'tool', content: typeof toolResponse === 'object' ? JSON.stringify(toolResponse) : String(toolResponse ?? ''), name: toolName, }); } } //# sourceMappingURL=message.operation.js.map