UNPKG

@n8n/n8n-nodes-langchain

Version:

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

308 lines 11.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var WorkflowToolService_exports = {}; __export(WorkflowToolService_exports, { WorkflowToolService: () => WorkflowToolService }); module.exports = __toCommonJS(WorkflowToolService_exports); var import_tools = require("@langchain/core/tools"); var import_isArray = __toESM(require("lodash/isArray")); var import_isObject = __toESM(require("lodash/isObject")); var manual = __toESM(require("n8n-nodes-base/dist/nodes/Set/v2/manual.mode")); var import_GenericFunctions = require("n8n-nodes-base/dist/utils/workflowInputsResourceMapping/GenericFunctions"); var import_n8n_workflow = require("n8n-workflow"); var import_fromAIToolFactory = require("../../../../../utils/fromAIToolFactory"); function isNodeExecutionData(data) { return (0, import_isArray.default)(data) && Boolean(data.length) && (0, import_isObject.default)(data[0]) && "json" in data[0]; } class WorkflowToolService { constructor(baseContext, options) { this.baseContext = baseContext; this.returnAllItems = false; const subWorkflowInputs = this.baseContext.getNode().parameters.workflowInputs; this.useSchema = (subWorkflowInputs?.schema ?? []).length > 0; this.returnAllItems = options?.returnAllItems ?? false; } // Creates the tool based on the provided parameters async createTool({ ctx, name, description, itemIndex, manualLogging = true }) { const node = ctx.getNode(); let runIndex = "getNextRunIndex" in ctx ? ctx.getNextRunIndex() : 0; const toolHandler = async (query, runManager) => { let maxTries = 1; if (node.retryOnFail === true) { maxTries = Math.min(5, Math.max(2, node.maxTries ?? 3)); } let waitBetweenTries = 0; if (node.retryOnFail === true) { waitBetweenTries = Math.min(5e3, Math.max(0, node.waitBetweenTries ?? 1e3)); } let lastError; for (let tryIndex = 0; tryIndex < maxTries; tryIndex++) { const localRunIndex = runIndex++; let context = this.baseContext; if ("cloneWith" in this.baseContext) { context = this.baseContext.cloneWith({ runIndex: localRunIndex, inputData: [[{ json: { query } }]] }); } const abortSignal = context.getExecutionCancelSignal?.(); if (abortSignal?.aborted) { return 'There was an error: "Execution was cancelled"'; } if (tryIndex !== 0) { lastError = void 0; if (waitBetweenTries !== 0) { try { await (0, import_n8n_workflow.sleepWithAbort)(waitBetweenTries, abortSignal); } catch (abortError) { return 'There was an error: "Execution was cancelled"'; } } } try { const response = await this.runFunction(context, query, itemIndex, runManager); const processedResponse = this.handleToolResponse(response); let responseData; if (isNodeExecutionData(response)) { responseData = response; } else { const reParsedData = (0, import_n8n_workflow.jsonParse)(processedResponse, { fallbackValue: { response: processedResponse } }); responseData = [{ json: reParsedData }]; } let metadata; if (this.subExecutionId && this.subWorkflowId) { metadata = { subExecution: { executionId: this.subExecutionId, workflowId: this.subWorkflowId } }; } if (manualLogging) { void context.addOutputData( import_n8n_workflow.NodeConnectionTypes.AiTool, localRunIndex, [responseData], metadata ); return processedResponse; } if (metadata && "setMetadata" in context) { void context.setMetadata(metadata); } return responseData; } catch (error) { if (abortSignal?.aborted) { return 'There was an error: "Execution was cancelled"'; } const executionError = error; lastError = executionError; const errorResponse = `There was an error: "${executionError.message}"`; if (manualLogging) { const metadata = (0, import_n8n_workflow.parseErrorMetadata)(error); const errorData = [{ json: { error: errorResponse } }]; void context.addOutputData( import_n8n_workflow.NodeConnectionTypes.AiTool, localRunIndex, [errorData], metadata ); } if (tryIndex === maxTries - 1) { return errorResponse; } } } return `There was an error: ${lastError?.message ?? "Unknown error"}`; }; return this.useSchema ? this.createStructuredTool(name, description, toolHandler) : new import_tools.DynamicTool({ name, description, func: toolHandler }); } handleToolResponse(response) { if (typeof response === "number") { return response.toString(); } if (isNodeExecutionData(response)) { return JSON.stringify( response.map((item) => item.json), null, 2 ); } if ((0, import_isObject.default)(response)) { return JSON.stringify(response, null, 2); } if (typeof response !== "string") { throw new import_n8n_workflow.NodeOperationError(this.baseContext.getNode(), "Wrong output type returned", { description: `The response property should be a string, but it is an ${typeof response}` }); } return response; } /** * Executes specified sub-workflow with provided inputs */ async executeSubWorkflow(context, workflowInfo, items, workflowProxy, runManager) { let receivedData; try { receivedData = await context.executeWorkflow(workflowInfo, items, runManager?.getChild(), { parentExecution: { executionId: workflowProxy.$execution.id, workflowId: workflowProxy.$workflow.id } }); this.subExecutionId = receivedData.executionId; } catch (error) { throw new import_n8n_workflow.NodeOperationError(context.getNode(), error); } let response; if (this.returnAllItems) { response = receivedData?.data?.[0]?.length ? receivedData.data[0] : void 0; } else { response = receivedData?.data?.[0]?.[0]?.json; } if (response === void 0) { throw new import_n8n_workflow.NodeOperationError( context.getNode(), 'There was an error: "The workflow did not return a response"' ); } return { response, subExecutionId: receivedData.executionId }; } /** * Gets the sub-workflow info based on the source and executes it. * This function will be called as part of the tool execution (from the toolHandler) */ async runFunction(context, query, itemIndex, runManager) { const source = context.getNodeParameter("source", itemIndex); const workflowProxy = context.getWorkflowDataProxy(0); const { workflowInfo } = await this.getSubWorkflowInfo( context, source, itemIndex, workflowProxy ); const rawData = this.prepareRawData(context, query, itemIndex); const items = await this.prepareWorkflowItems(context, query, itemIndex, rawData); this.subWorkflowId = workflowInfo.id; const { response } = await this.executeSubWorkflow( context, workflowInfo, items, workflowProxy, runManager ); return response; } /** * Gets the sub-workflow info based on the source (database or parameter) */ async getSubWorkflowInfo(context, source, itemIndex, workflowProxy) { const workflowInfo = {}; let subWorkflowId; if (source === "database") { const { value } = context.getNodeParameter( "workflowId", itemIndex, {} ); workflowInfo.id = value; subWorkflowId = workflowInfo.id; } else if (source === "parameter") { const workflowJson = context.getNodeParameter("workflowJson", itemIndex); try { workflowInfo.code = JSON.parse(workflowJson); subWorkflowId = workflowProxy.$workflow.id; } catch (error) { throw new import_n8n_workflow.NodeOperationError( context.getNode(), `The provided workflow is not valid JSON: "${error.message}"`, { itemIndex } ); } } return { workflowInfo, subWorkflowId }; } prepareRawData(context, query, itemIndex) { const rawData = { query }; const workflowFieldsJson = context.getNodeParameter("fields.values", itemIndex, [], { rawExpressions: true }); for (const entry of workflowFieldsJson) { if (entry.type === "objectValue" && entry.objectValue.startsWith("=")) { rawData[entry.name] = entry.objectValue.replace(/^=+/, ""); } } return rawData; } /** * Prepares the sub-workflow items for execution */ async prepareWorkflowItems(context, query, itemIndex, rawData) { const options = { include: "all" }; let jsonData = typeof query === "object" ? query : { query }; if (this.useSchema) { const currentWorkflowInputs = import_GenericFunctions.getCurrentWorkflowInputData.call(context); jsonData = currentWorkflowInputs[itemIndex].json; } const newItem = await manual.execute.call( context, { json: jsonData }, itemIndex, options, rawData, context.getNode() ); return [newItem]; } /** * Create structured tool by parsing the sub-workflow input schema */ createStructuredTool(name, description, func) { const collectedArguments = (0, import_fromAIToolFactory.extractFromAIParameters)(this.baseContext.getNode().parameters); if (collectedArguments.length === 0) { return new import_tools.DynamicTool({ name, description, func }); } const schema = (0, import_fromAIToolFactory.createZodSchemaFromArgs)(collectedArguments); return new import_tools.DynamicStructuredTool({ schema, name, description, func }); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { WorkflowToolService }); //# sourceMappingURL=WorkflowToolService.js.map