@n8n/n8n-nodes-langchain
Version:

325 lines • 11.9 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ToolCode_node_exports = {};
__export(ToolCode_node_exports, {
ToolCode: () => ToolCode
});
module.exports = __toCommonJS(ToolCode_node_exports);
var import_tools = require("@langchain/core/tools");
var import_config = require("@n8n/config");
var import_di = require("@n8n/di");
var import_JavaScriptSandbox = require("n8n-nodes-base/dist/nodes/Code/JavaScriptSandbox");
var import_JsTaskRunnerSandbox = require("n8n-nodes-base/dist/nodes/Code/JsTaskRunnerSandbox");
var import_PythonTaskRunnerSandbox = require("n8n-nodes-base/dist/nodes/Code/PythonTaskRunnerSandbox");
var import_Sandbox = require("n8n-nodes-base/dist/nodes/Code/Sandbox");
var import_n8n_workflow = require("n8n-workflow");
var import_descriptions = require("../../../utils/descriptions");
var import_schemaParsing = require("../../../utils/schemaParsing");
var import_sharedFields = require("../../../utils/sharedFields");
const jsonSchemaExampleField = (0, import_descriptions.buildJsonSchemaExampleField)({
showExtraProps: { specifyInputSchema: [true] }
});
const jsonSchemaExampleNotice = (0, import_descriptions.buildJsonSchemaExampleNotice)({
showExtraProps: {
specifyInputSchema: [true],
"@version": [{ _cnd: { gte: 1.3 } }]
}
});
const jsonSchemaField = (0, import_descriptions.buildInputSchemaField)({ showExtraProps: { specifyInputSchema: [true] } });
function getTool(ctx, itemIndex, log = true) {
const node = ctx.getNode();
const workflowMode = ctx.getMode();
const runnersConfig = import_di.Container.get(import_config.TaskRunnersConfig);
const isJsRunnerEnabled = runnersConfig.enabled;
const { typeVersion } = node;
const name = typeVersion <= 1.1 ? ctx.getNodeParameter("name", itemIndex) : (0, import_n8n_workflow.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") {
if (isJsRunnerEnabled) {
const sandbox = new import_JsTaskRunnerSandbox.JsTaskRunnerSandbox(
code,
"runOnceForAllItems",
workflowMode,
ctx,
void 0,
{
query
}
);
return await sandbox.runCodeForTool();
} else {
const context = import_Sandbox.getSandboxContext.call(ctx, itemIndex);
context.query = query;
const sandbox = new import_JavaScriptSandbox.JavaScriptSandbox(context, code, ctx.helpers);
sandbox.on(
"output",
workflowMode === "manual" ? ctx.sendMessageToUI.bind(ctx) : (...args) => console.log(`[Workflow "${ctx.getWorkflow().id}"][Node "${node.name}"]`, ...args)
);
return await sandbox.runCode();
}
} else {
const sandbox = new import_PythonTaskRunnerSandbox.PythonTaskRunnerSandbox(
code,
"runOnceForAllItems",
workflowMode,
ctx,
{
query
}
);
return await sandbox.runCodeForTool();
}
};
const toolHandler = async (query) => {
const { index } = log ? ctx.addInputData(import_n8n_workflow.NodeConnectionTypes.AiTool, [[{ json: { query } }]]) : { index: 0 };
let response = "";
let executionError;
try {
response = await runFunction(query);
} catch (error) {
executionError = new import_n8n_workflow.NodeOperationError(ctx.getNode(), error);
response = `There was an error: "${executionError.message}"`;
}
if (typeof response === "number") {
response = response.toString();
}
if (typeof response !== "string") {
executionError = new import_n8n_workflow.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(import_n8n_workflow.NodeConnectionTypes.AiTool, index, executionError);
} else if (log) {
void ctx.addOutputData(import_n8n_workflow.NodeConnectionTypes.AiTool, index, [[{ json: { response } }]]);
}
return response;
};
const commonToolOptions = {
name,
description,
func: toolHandler
};
let tool = void 0;
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, import_schemaParsing.generateSchemaFromExample)(jsonExample, ctx.getNode().typeVersion >= 1.3) : (0, import_n8n_workflow.jsonParse)(inputSchema);
const zodSchema = (0, import_schemaParsing.convertJsonSchemaToZod)(jsonSchema);
tool = new import_tools.DynamicStructuredTool({
schema: zodSchema,
...commonToolOptions
});
} catch (error) {
throw new import_n8n_workflow.NodeOperationError(
ctx.getNode(),
"Error during parsing of JSON Schema. \n " + error
);
}
} else {
tool = new import_tools.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: [import_n8n_workflow.NodeConnectionTypes.AiTool],
outputNames: ["Tool"],
properties: [
(0, import_sharedFields.getConnectionHintNoticeField)([import_n8n_workflow.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()",
// TODO: Add proper text here later
hint: 'You can access the input the tool receives via the input property "query". The returned value should be a single string.',
// eslint-disable-next-line n8n-nodes-base/node-param-description-missing-final-period
description: "E.g. Converts any text to uppercase",
noDataExpression: true
},
{
displayName: "Python",
name: "pythonCode",
type: "string",
displayOptions: {
show: {
language: ["python"]
}
},
typeOptions: {
editor: "codeNodeEditor",
// TODO: create a separate `pythonEditor` component
editorLanguage: "python"
},
default: "# Example: convert the incoming query to uppercase and return it\nreturn _query.upper()",
// TODO: Add proper text here later
hint: 'You can access the input the tool receives via the input property "_query". The returned value should be a single string.',
// eslint-disable-next-line n8n-nodes-base/node-param-description-missing-final-period
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
},
{ ...import_descriptions.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];
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ToolCode
});
//# sourceMappingURL=ToolCode.node.js.map