UNPKG

@n8n/n8n-nodes-langchain

Version:

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

276 lines 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ToolCode = void 0; const tools_1 = require("@langchain/core/tools"); const JsTaskRunnerSandbox_1 = require("n8n-nodes-base/dist/nodes/Code/JsTaskRunnerSandbox"); const PythonTaskRunnerSandbox_1 = require("n8n-nodes-base/dist/nodes/Code/PythonTaskRunnerSandbox"); const n8n_workflow_1 = require("n8n-workflow"); const descriptions_1 = require("../../../utils/descriptions"); const schemaParsing_1 = require("../../../utils/schemaParsing"); const ai_utilities_1 = require("@n8n/ai-utilities"); const jsonSchemaExampleField = (0, descriptions_1.buildJsonSchemaExampleField)({ showExtraProps: { specifyInputSchema: [true] }, }); const jsonSchemaExampleNotice = (0, descriptions_1.buildJsonSchemaExampleNotice)({ showExtraProps: { specifyInputSchema: [true], '@version': [{ _cnd: { gte: 1.3 } }], }, }); const jsonSchemaField = (0, descriptions_1.buildInputSchemaField)({ showExtraProps: { specifyInputSchema: [true] } }); function getTool(ctx, itemIndex, log = true) { const node = ctx.getNode(); const workflowMode = ctx.getMode(); const { typeVersion } = node; const name = typeVersion <= 1.1 ? ctx.getNodeParameter('name', itemIndex) : (0, n8n_workflow_1.nodeNameToToolName)(node); const description = ctx.getNodeParameter('description', itemIndex); const useSchema = ctx.getNodeParameter('specifyInputSchema', itemIndex); const language = ctx.getNodeParameter('language', itemIndex); let code = ''; if (language === 'javaScript') { code = ctx.getNodeParameter('jsCode', itemIndex); } else { code = ctx.getNodeParameter('pythonCode', itemIndex); } const runFunction = async (query) => { if (language === 'javaScript') { const sandbox = new JsTaskRunnerSandbox_1.JsTaskRunnerSandbox(workflowMode, ctx, undefined, { query, }); return await sandbox.runCodeForTool(code); } else { const sandbox = new PythonTaskRunnerSandbox_1.PythonTaskRunnerSandbox(code, 'runOnceForAllItems', workflowMode, ctx, { query, }); return await sandbox.runCodeForTool(); } }; const toolHandler = async (query) => { const { index } = log ? ctx.addInputData(n8n_workflow_1.NodeConnectionTypes.AiTool, [[{ json: { query } }]]) : { index: 0 }; let response = ''; let executionError; try { response = await runFunction(query); } catch (error) { executionError = new n8n_workflow_1.NodeOperationError(ctx.getNode(), error); response = `There was an error: "${executionError.message}"`; } if (typeof response === 'number') { response = response.toString(); } if (typeof response !== 'string') { executionError = new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Wrong output type returned', { description: `The response property should be a string, but it is an ${typeof response}`, }); response = `There was an error: "${executionError.message}"`; } if (executionError && log) { void ctx.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiTool, index, executionError); } else if (log) { void ctx.addOutputData(n8n_workflow_1.NodeConnectionTypes.AiTool, index, [[{ json: { response } }]]); } return response; }; const commonToolOptions = { name, description, func: toolHandler, }; let tool = undefined; if (useSchema) { try { const jsonExample = ctx.getNodeParameter('jsonSchemaExample', itemIndex, ''); const inputSchema = ctx.getNodeParameter('inputSchema', itemIndex, ''); const schemaType = ctx.getNodeParameter('schemaType', itemIndex); const jsonSchema = schemaType === 'fromJson' ? (0, schemaParsing_1.generateSchemaFromExample)(jsonExample, ctx.getNode().typeVersion >= 1.3) : (0, n8n_workflow_1.jsonParse)(inputSchema); const zodSchema = (0, schemaParsing_1.convertJsonSchemaToZod)(jsonSchema); tool = new tools_1.DynamicStructuredTool({ schema: zodSchema, ...commonToolOptions, }); } catch (error) { throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Error during parsing of JSON Schema. \n ' + error); } } else { tool = new tools_1.DynamicTool(commonToolOptions); } return tool; } class ToolCode { constructor() { this.description = { displayName: 'Code Tool', name: 'toolCode', icon: 'fa:code', iconColor: 'black', group: ['transform'], version: [1, 1.1, 1.2, 1.3], description: 'Write a tool in JS or Python', defaults: { name: 'Code Tool', }, codex: { categories: ['AI'], subcategories: { AI: ['Tools'], Tools: ['Recommended Tools'], }, resources: { primaryDocumentation: [ { url: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolcode/', }, ], }, }, inputs: [], outputs: [n8n_workflow_1.NodeConnectionTypes.AiTool], outputNames: ['Tool'], properties: [ (0, ai_utilities_1.getConnectionHintNoticeField)([n8n_workflow_1.NodeConnectionTypes.AiAgent]), { displayName: 'See an example of a conversational agent with custom tool written in JavaScript <a href="/templates/1963" target="_blank">here</a>.', name: 'noticeTemplateExample', type: 'notice', default: '', }, { displayName: 'Name', name: 'name', type: 'string', default: '', placeholder: 'My_Tool', displayOptions: { show: { '@version': [1], }, }, }, { displayName: 'Name', name: 'name', type: 'string', default: '', placeholder: 'e.g. My_Tool', validateType: 'string-alphanumeric', description: 'The name of the function to be called, could contain letters, numbers, and underscores only', displayOptions: { show: { '@version': [1.1], }, }, }, { displayName: 'Description', name: 'description', type: 'string', default: '', placeholder: 'Call this tool to get a random color. The input should be a string with comma separted names of colors to exclude.', typeOptions: { rows: 3, }, }, { displayName: 'Language', name: 'language', type: 'options', noDataExpression: true, options: [ { name: 'JavaScript', value: 'javaScript', }, { name: 'Python (Beta)', value: 'python', }, ], default: 'javaScript', }, { displayName: 'JavaScript', name: 'jsCode', type: 'string', displayOptions: { show: { language: ['javaScript'], }, }, typeOptions: { editor: 'jsEditor', }, default: '// Example: convert the incoming query to uppercase and return it\nreturn query.toUpperCase()', hint: 'You can access the input the tool receives via the input property "query". The returned value should be a single string.', description: 'E.g. Converts any text to uppercase', noDataExpression: true, }, { displayName: 'Python', name: 'pythonCode', type: 'string', displayOptions: { show: { language: ['python'], }, }, typeOptions: { editor: 'codeNodeEditor', editorLanguage: 'python', }, default: '# Example: convert the incoming query to uppercase and return it\nreturn _query.upper()', hint: 'You can access the input the tool receives via the input property "_query". The returned value should be a single string.', description: 'E.g. Converts any text to uppercase', noDataExpression: true, }, { displayName: 'Specify Input Schema', name: 'specifyInputSchema', type: 'boolean', description: 'Whether to specify the schema for the function. This would require the LLM to provide the input in the correct format and would validate it against the schema.', noDataExpression: true, default: false, }, { ...descriptions_1.schemaTypeField, displayOptions: { show: { specifyInputSchema: [true] } } }, jsonSchemaExampleField, jsonSchemaExampleNotice, jsonSchemaField, ], }; } async supplyData(itemIndex) { return { response: getTool(this, itemIndex), }; } async execute() { const result = []; const input = this.getInputData(); for (let i = 0; i < input.length; i++) { const item = input[i]; const tool = getTool(this, i, false); result.push({ json: { response: await tool.invoke(item.json), }, pairedItem: { item: i, }, }); } return [result]; } } exports.ToolCode = ToolCode; //# sourceMappingURL=ToolCode.node.js.map