n8n-nodes-browser-smart-automation 0.1.1 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/McpClientTool/McpClientTool.node.js +2 -13
  2. package/dist/McpClientTool/McpClientTool.node.js.map +1 -1
  3. package/dist/McpClientTool/utils.js +1 -1
  4. package/dist/McpClientTool/utils.js.map +1 -1
  5. package/dist/McpTrigger/McpTrigger.node.js +1 -1
  6. package/dist/McpTrigger/McpTrigger.node.js.map +1 -1
  7. package/dist/shared/N8nBinaryLoader.js +203 -0
  8. package/dist/shared/N8nBinaryLoader.js.map +1 -0
  9. package/dist/shared/N8nJsonLoader.js +89 -0
  10. package/dist/shared/N8nJsonLoader.js.map +1 -0
  11. package/dist/shared/N8nTool.js +106 -0
  12. package/dist/shared/N8nTool.js.map +1 -0
  13. package/dist/shared/embeddingInputValidation.js +55 -0
  14. package/dist/shared/embeddingInputValidation.js.map +1 -0
  15. package/dist/shared/helpers.js +220 -13
  16. package/dist/shared/helpers.js.map +1 -1
  17. package/dist/shared/httpProxyAgent.js +40 -2
  18. package/dist/shared/httpProxyAgent.js.map +1 -1
  19. package/dist/shared/logWrapper.js +347 -2
  20. package/dist/shared/logWrapper.js.map +1 -1
  21. package/dist/shared/schemaParsing.js +47 -4
  22. package/dist/shared/schemaParsing.js.map +1 -1
  23. package/dist/shared/sharedFields.js +142 -7
  24. package/dist/shared/sharedFields.js.map +1 -1
  25. package/dist/shared/typesN8nTool.js +17 -0
  26. package/dist/shared/typesN8nTool.js.map +1 -0
  27. package/dist/shared/utils.js +1 -1
  28. package/dist/shared/utils.js.map +1 -1
  29. package/package.json +23 -7
  30. package/jest.config.js +0 -24
  31. package/nodes/McpClient/McpClient.node.ts +0 -327
  32. package/nodes/McpClient/__test__/McpClient.node.test.ts +0 -221
  33. package/nodes/McpClient/__test__/utils.test.ts +0 -302
  34. package/nodes/McpClient/listSearch.ts +0 -48
  35. package/nodes/McpClient/resourceMapping.ts +0 -48
  36. package/nodes/McpClient/utils.ts +0 -281
  37. package/nodes/McpClientTool/McpClientTool.node.ts +0 -468
  38. package/nodes/McpClientTool/__test__/McpClientTool.node.test.ts +0 -730
  39. package/nodes/McpClientTool/loadOptions.ts +0 -45
  40. package/nodes/McpClientTool/types.ts +0 -1
  41. package/nodes/McpClientTool/utils.ts +0 -116
  42. package/nodes/McpTrigger/FlushingTransport.ts +0 -61
  43. package/nodes/McpTrigger/McpServer.ts +0 -317
  44. package/nodes/McpTrigger/McpTrigger.node.ts +0 -204
  45. package/nodes/McpTrigger/__test__/FlushingTransport.test.ts +0 -102
  46. package/nodes/McpTrigger/__test__/McpServer.test.ts +0 -532
  47. package/nodes/McpTrigger/__test__/McpTrigger.node.test.ts +0 -171
  48. package/nodes/shared/__test__/utils.test.ts +0 -318
  49. package/nodes/shared/descriptions.ts +0 -65
  50. package/nodes/shared/helpers.ts +0 -31
  51. package/nodes/shared/httpProxyAgent.ts +0 -11
  52. package/nodes/shared/logWrapper.ts +0 -13
  53. package/nodes/shared/schemaParsing.ts +0 -9
  54. package/nodes/shared/sharedFields.ts +0 -20
  55. package/nodes/shared/types.ts +0 -12
  56. package/nodes/shared/utils.ts +0 -296
  57. package/officail/package.json +0 -255
  58. package/tsconfig.json +0 -32
  59. package/tsup.config.ts +0 -13
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var N8nTool_exports = {};
20
+ __export(N8nTool_exports, {
21
+ N8nTool: () => N8nTool,
22
+ prepareFallbackToolDescription: () => prepareFallbackToolDescription
23
+ });
24
+ module.exports = __toCommonJS(N8nTool_exports);
25
+ var import_tools = require("@langchain/core/tools");
26
+ var import_output_parsers = require("@langchain/classic/output_parsers");
27
+ var import_n8n_workflow = require("n8n-workflow");
28
+ var import_zod = require("zod");
29
+ const getSimplifiedType = (schema) => {
30
+ if (schema instanceof import_zod.ZodObject) {
31
+ return "object";
32
+ } else if (schema instanceof import_zod.ZodNumber) {
33
+ return "number";
34
+ } else if (schema instanceof import_zod.ZodBoolean) {
35
+ return "boolean";
36
+ } else if (schema instanceof import_zod.ZodNullable || schema instanceof import_zod.ZodOptional) {
37
+ return getSimplifiedType(schema.unwrap());
38
+ }
39
+ return "string";
40
+ };
41
+ const getParametersDescription = (parameters) => parameters.map(
42
+ ([name, schema]) => `${name}: (description: ${schema.description ?? ""}, type: ${getSimplifiedType(schema)}, required: ${!schema.isOptional()})`
43
+ ).join(",\n ");
44
+ const prepareFallbackToolDescription = (toolDescription, schema) => {
45
+ let description = `${toolDescription}`;
46
+ const toolParameters = Object.entries(schema.shape);
47
+ if (toolParameters.length) {
48
+ description += `
49
+ Tool expects valid stringified JSON object with ${toolParameters.length} properties.
50
+ Property names with description, type and required status:
51
+ ${getParametersDescription(toolParameters)}
52
+ ALL parameters marked as required must be provided`;
53
+ }
54
+ return description;
55
+ };
56
+ class N8nTool extends import_tools.DynamicStructuredTool {
57
+ constructor(context, fields) {
58
+ super(fields);
59
+ this.context = context;
60
+ }
61
+ asDynamicTool() {
62
+ const { name, func, schema, context, description } = this;
63
+ const parser = new import_output_parsers.StructuredOutputParser(schema);
64
+ const wrappedFunc = async function(query) {
65
+ let parsedQuery;
66
+ try {
67
+ parsedQuery = await parser.parse(query);
68
+ } catch (e) {
69
+ let dataFromModel;
70
+ try {
71
+ dataFromModel = (0, import_n8n_workflow.jsonParse)(query, { acceptJSObject: true });
72
+ } catch (error) {
73
+ if (Object.keys(schema.shape).length === 1) {
74
+ const parameterName = Object.keys(schema.shape)[0];
75
+ dataFromModel = { [parameterName]: query };
76
+ } else {
77
+ throw new import_n8n_workflow.NodeOperationError(
78
+ context.getNode(),
79
+ `Input is not a valid JSON: ${error.message}`
80
+ );
81
+ }
82
+ }
83
+ parsedQuery = schema.parse(dataFromModel);
84
+ }
85
+ try {
86
+ const result = await func(parsedQuery);
87
+ return result;
88
+ } catch (e) {
89
+ const { index } = context.addInputData(import_n8n_workflow.NodeConnectionTypes.AiTool, [[{ json: { query } }]]);
90
+ void context.addOutputData(import_n8n_workflow.NodeConnectionTypes.AiTool, index, e);
91
+ return e.toString();
92
+ }
93
+ };
94
+ return new import_tools.DynamicTool({
95
+ name,
96
+ description: prepareFallbackToolDescription(description, schema),
97
+ func: wrappedFunc
98
+ });
99
+ }
100
+ }
101
+ // Annotate the CommonJS export names for ESM import in node:
102
+ 0 && (module.exports = {
103
+ N8nTool,
104
+ prepareFallbackToolDescription
105
+ });
106
+ //# sourceMappingURL=N8nTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../nodes/shared/N8nTool.ts"],"sourcesContent":["import type { DynamicStructuredToolInput } from '@langchain/core/tools';\nimport { DynamicStructuredTool, DynamicTool } from '@langchain/core/tools';\nimport { StructuredOutputParser } from '@langchain/classic/output_parsers';\nimport type { ISupplyDataFunctions, IDataObject } from 'n8n-workflow';\nimport { NodeConnectionTypes, jsonParse, NodeOperationError } from 'n8n-workflow';\nimport type { ZodTypeAny } from 'zod';\nimport { ZodBoolean, ZodNullable, ZodNumber, ZodObject, ZodOptional } from 'zod';\n\nimport type { ZodObjectAny } from './typesN8nTool';\n\nconst getSimplifiedType = (schema: ZodTypeAny) => {\n\tif (schema instanceof ZodObject) {\n\t\treturn 'object';\n\t} else if (schema instanceof ZodNumber) {\n\t\treturn 'number';\n\t} else if (schema instanceof ZodBoolean) {\n\t\treturn 'boolean';\n\t} else if (schema instanceof ZodNullable || schema instanceof ZodOptional) {\n\t\treturn getSimplifiedType(schema.unwrap());\n\t}\n\n\treturn 'string';\n};\n\nconst getParametersDescription = (parameters: Array<[string, ZodTypeAny]>) =>\n\tparameters\n\t\t.map(\n\t\t\t([name, schema]) =>\n\t\t\t\t`${name}: (description: ${schema.description ?? ''}, type: ${getSimplifiedType(schema)}, required: ${!schema.isOptional()})`,\n\t\t)\n\t\t.join(',\\n ');\n\nexport const prepareFallbackToolDescription = (toolDescription: string, schema: ZodObject<any>) => {\n\tlet description = `${toolDescription}`;\n\n\tconst toolParameters = Object.entries<ZodTypeAny>(schema.shape);\n\n\tif (toolParameters.length) {\n\t\tdescription += `\nTool expects valid stringified JSON object with ${toolParameters.length} properties.\nProperty names with description, type and required status:\n${getParametersDescription(toolParameters)}\nALL parameters marked as required must be provided`;\n\t}\n\n\treturn description;\n};\n\nexport class N8nTool extends DynamicStructuredTool<ZodObjectAny> {\n\tconstructor(\n\t\tprivate context: ISupplyDataFunctions,\n\t\tfields: DynamicStructuredToolInput<ZodObjectAny>,\n\t) {\n\t\tsuper(fields);\n\t}\n\n\tasDynamicTool(): DynamicTool {\n\t\tconst { name, func, schema, context, description } = this;\n\n\t\tconst parser = new StructuredOutputParser(schema);\n\n\t\tconst wrappedFunc = async function (query: string) {\n\t\t\tlet parsedQuery: object;\n\n\t\t\t// First we try to parse the query using the structured parser (Zod schema)\n\t\t\ttry {\n\t\t\t\tparsedQuery = await parser.parse(query);\n\t\t\t} catch (e) {\n\t\t\t\t// If we were unable to parse the query using the schema, we try to gracefully handle it\n\t\t\t\tlet dataFromModel;\n\n\t\t\t\ttry {\n\t\t\t\t\t// First we try to parse a JSON with more relaxed rules\n\t\t\t\t\tdataFromModel = jsonParse<IDataObject>(query, { acceptJSObject: true });\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// In case of error,\n\t\t\t\t\t// If model supplied a simple string instead of an object AND only one parameter expected, we try to recover the object structure\n\t\t\t\t\tif (Object.keys(schema.shape).length === 1) {\n\t\t\t\t\t\tconst parameterName = Object.keys(schema.shape)[0];\n\t\t\t\t\t\tdataFromModel = { [parameterName]: query };\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Finally throw an error if we were unable to parse the query\n\t\t\t\t\t\tthrow new NodeOperationError(\n\t\t\t\t\t\t\tcontext.getNode(),\n\t\t\t\t\t\t\t`Input is not a valid JSON: ${error.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If we were able to parse the query with a fallback, we try to validate it using the schema\n\t\t\t\t// Here we will throw an error if the data still does not match the schema\n\t\t\t\tparsedQuery = schema.parse(dataFromModel);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Call tool function with parsed query\n\t\t\t\tconst result = await func(parsedQuery);\n\n\t\t\t\treturn result;\n\t\t\t} catch (e) {\n\t\t\t\tconst { index } = context.addInputData(NodeConnectionTypes.AiTool, [[{ json: { query } }]]);\n\t\t\t\tvoid context.addOutputData(NodeConnectionTypes.AiTool, index, e);\n\n\t\t\t\treturn e.toString();\n\t\t\t}\n\t\t};\n\n\t\treturn new DynamicTool({\n\t\t\tname,\n\t\t\tdescription: prepareFallbackToolDescription(description, schema),\n\t\t\tfunc: wrappedFunc,\n\t\t});\n\t}\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAmD;AACnD,4BAAuC;AAEvC,0BAAmE;AAEnE,iBAA2E;AAI3E,MAAM,oBAAoB,CAAC,WAAuB;AACjD,MAAI,kBAAkB,sBAAW;AAChC,WAAO;AAAA,EACR,WAAW,kBAAkB,sBAAW;AACvC,WAAO;AAAA,EACR,WAAW,kBAAkB,uBAAY;AACxC,WAAO;AAAA,EACR,WAAW,kBAAkB,0BAAe,kBAAkB,wBAAa;AAC1E,WAAO,kBAAkB,OAAO,OAAO,CAAC;AAAA,EACzC;AAEA,SAAO;AACR;AAEA,MAAM,2BAA2B,CAAC,eACjC,WACE;AAAA,EACA,CAAC,CAAC,MAAM,MAAM,MACb,GAAG,IAAI,mBAAmB,OAAO,eAAe,EAAE,WAAW,kBAAkB,MAAM,CAAC,eAAe,CAAC,OAAO,WAAW,CAAC;AAC3H,EACC,KAAK,MAAM;AAEP,MAAM,iCAAiC,CAAC,iBAAyB,WAA2B;AAClG,MAAI,cAAc,GAAG,eAAe;AAEpC,QAAM,iBAAiB,OAAO,QAAoB,OAAO,KAAK;AAE9D,MAAI,eAAe,QAAQ;AAC1B,mBAAe;AAAA,kDACiC,eAAe,MAAM;AAAA;AAAA,EAErE,yBAAyB,cAAc,CAAC;AAAA;AAAA,EAEzC;AAEA,SAAO;AACR;AAEO,MAAM,gBAAgB,mCAAoC;AAAA,EAChE,YACS,SACR,QACC;AACD,UAAM,MAAM;AAHJ;AAAA,EAIT;AAAA,EAEA,gBAA6B;AAC5B,UAAM,EAAE,MAAM,MAAM,QAAQ,SAAS,YAAY,IAAI;AAErD,UAAM,SAAS,IAAI,6CAAuB,MAAM;AAEhD,UAAM,cAAc,eAAgB,OAAe;AAClD,UAAI;AAGJ,UAAI;AACH,sBAAc,MAAM,OAAO,MAAM,KAAK;AAAA,MACvC,SAAS,GAAG;AAEX,YAAI;AAEJ,YAAI;AAEH,8BAAgB,+BAAuB,OAAO,EAAE,gBAAgB,KAAK,CAAC;AAAA,QACvE,SAAS,OAAO;AAGf,cAAI,OAAO,KAAK,OAAO,KAAK,EAAE,WAAW,GAAG;AAC3C,kBAAM,gBAAgB,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC;AACjD,4BAAgB,EAAE,CAAC,aAAa,GAAG,MAAM;AAAA,UAC1C,OAAO;AAEN,kBAAM,IAAI;AAAA,cACT,QAAQ,QAAQ;AAAA,cAChB,8BAA8B,MAAM,OAAO;AAAA,YAC5C;AAAA,UACD;AAAA,QACD;AAIA,sBAAc,OAAO,MAAM,aAAa;AAAA,MACzC;AAEA,UAAI;AAEH,cAAM,SAAS,MAAM,KAAK,WAAW;AAErC,eAAO;AAAA,MACR,SAAS,GAAG;AACX,cAAM,EAAE,MAAM,IAAI,QAAQ,aAAa,wCAAoB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAC1F,aAAK,QAAQ,cAAc,wCAAoB,QAAQ,OAAO,CAAC;AAE/D,eAAO,EAAE,SAAS;AAAA,MACnB;AAAA,IACD;AAEA,WAAO,IAAI,yBAAY;AAAA,MACtB;AAAA,MACA,aAAa,+BAA+B,aAAa,MAAM;AAAA,MAC/D,MAAM;AAAA,IACP,CAAC;AAAA,EACF;AACD;","names":[]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var embeddingInputValidation_exports = {};
20
+ __export(embeddingInputValidation_exports, {
21
+ validateEmbedDocumentsInput: () => validateEmbedDocumentsInput,
22
+ validateEmbedQueryInput: () => validateEmbedQueryInput
23
+ });
24
+ module.exports = __toCommonJS(embeddingInputValidation_exports);
25
+ var import_n8n_workflow = require("n8n-workflow");
26
+ function validateEmbedQueryInput(query, node) {
27
+ if (typeof query !== "string" || query === "") {
28
+ throw new import_n8n_workflow.NodeOperationError(node, "Cannot embed empty or undefined text", {
29
+ description: "The text provided for embedding is empty or undefined. This can happen when: the input expression evaluates to undefined, the AI agent calls a tool without proper arguments, or a required field is missing."
30
+ });
31
+ }
32
+ return query;
33
+ }
34
+ function validateEmbedDocumentsInput(documents, node) {
35
+ if (!Array.isArray(documents)) {
36
+ throw new import_n8n_workflow.NodeOperationError(node, "Documents must be an array", {
37
+ description: "Expected an array of strings to embed."
38
+ });
39
+ }
40
+ const invalidIndex = documents.findIndex(
41
+ (doc) => doc === void 0 || doc === null || doc === ""
42
+ );
43
+ if (invalidIndex !== -1) {
44
+ throw new import_n8n_workflow.NodeOperationError(node, `Invalid document at index ${invalidIndex}`, {
45
+ description: `Document at index ${invalidIndex} is empty or undefined. All documents must be non-empty strings.`
46
+ });
47
+ }
48
+ return documents;
49
+ }
50
+ // Annotate the CommonJS export names for ESM import in node:
51
+ 0 && (module.exports = {
52
+ validateEmbedDocumentsInput,
53
+ validateEmbedQueryInput
54
+ });
55
+ //# sourceMappingURL=embeddingInputValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../nodes/shared/embeddingInputValidation.ts"],"sourcesContent":["import type { INode } from 'n8n-workflow';\nimport { NodeOperationError } from 'n8n-workflow';\n\n/**\n * Validates query input for embedQuery operations.\n * Throws NodeOperationError if query is invalid (undefined, null, or empty string).\n *\n * @param query - The query to validate\n * @param node - The node for error context\n * @returns The validated query string\n * @throws NodeOperationError if query is invalid\n */\nexport function validateEmbedQueryInput(query: unknown, node: INode): string {\n\tif (typeof query !== 'string' || query === '') {\n\t\tthrow new NodeOperationError(node, 'Cannot embed empty or undefined text', {\n\t\t\tdescription:\n\t\t\t\t'The text provided for embedding is empty or undefined. This can happen when: the input expression evaluates to undefined, the AI agent calls a tool without proper arguments, or a required field is missing.',\n\t\t});\n\t}\n\treturn query;\n}\n\n/**\n * Validates documents input for embedDocuments operations.\n * Throws NodeOperationError if documents array is invalid or contains invalid entries.\n *\n * @param documents - The documents array to validate\n * @param node - The node for error context\n * @returns The validated documents array\n * @throws NodeOperationError if documents is not an array or contains invalid entries\n */\nexport function validateEmbedDocumentsInput(documents: unknown, node: INode): string[] {\n\tif (!Array.isArray(documents)) {\n\t\tthrow new NodeOperationError(node, 'Documents must be an array', {\n\t\t\tdescription: 'Expected an array of strings to embed.',\n\t\t});\n\t}\n\n\tconst invalidIndex = documents.findIndex(\n\t\t(doc) => doc === undefined || doc === null || doc === '',\n\t);\n\n\tif (invalidIndex !== -1) {\n\t\tthrow new NodeOperationError(node, `Invalid document at index ${invalidIndex}`, {\n\t\t\tdescription: `Document at index ${invalidIndex} is empty or undefined. All documents must be non-empty strings.`,\n\t\t});\n\t}\n\n\treturn documents;\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAmC;AAW5B,SAAS,wBAAwB,OAAgB,MAAqB;AAC5E,MAAI,OAAO,UAAU,YAAY,UAAU,IAAI;AAC9C,UAAM,IAAI,uCAAmB,MAAM,wCAAwC;AAAA,MAC1E,aACC;AAAA,IACF,CAAC;AAAA,EACF;AACA,SAAO;AACR;AAWO,SAAS,4BAA4B,WAAoB,MAAuB;AACtF,MAAI,CAAC,MAAM,QAAQ,SAAS,GAAG;AAC9B,UAAM,IAAI,uCAAmB,MAAM,8BAA8B;AAAA,MAChE,aAAa;AAAA,IACd,CAAC;AAAA,EACF;AAEA,QAAM,eAAe,UAAU;AAAA,IAC9B,CAAC,QAAQ,QAAQ,UAAa,QAAQ,QAAQ,QAAQ;AAAA,EACvD;AAEA,MAAI,iBAAiB,IAAI;AACxB,UAAM,IAAI,uCAAmB,MAAM,6BAA6B,YAAY,IAAI;AAAA,MAC/E,aAAa,qBAAqB,YAAY;AAAA,IAC/C,CAAC;AAAA,EACF;AAEA,SAAO;AACR;","names":[]}
@@ -18,30 +18,237 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var helpers_exports = {};
20
20
  __export(helpers_exports, {
21
- getConnectedTools: () => getConnectedTools
21
+ escapeSingleCurlyBrackets: () => escapeSingleCurlyBrackets,
22
+ getConnectedTools: () => getConnectedTools,
23
+ getMetadataFiltersValues: () => getMetadataFiltersValues,
24
+ getPromptInputByType: () => getPromptInputByType,
25
+ getSessionId: () => getSessionId,
26
+ hasLongSequentialRepeat: () => hasLongSequentialRepeat,
27
+ isBaseChatMemory: () => isBaseChatMemory,
28
+ isBaseChatMessageHistory: () => isBaseChatMessageHistory,
29
+ isChatInstance: () => isChatInstance,
30
+ isToolsInstance: () => isToolsInstance,
31
+ logAiEvent: () => logAiEvent,
32
+ serializeChatHistory: () => serializeChatHistory,
33
+ unwrapNestedOutput: () => unwrapNestedOutput
22
34
  });
23
35
  module.exports = __toCommonJS(helpers_exports);
36
+ var import_agents = require("@langchain/classic/agents");
24
37
  var import_n8n_workflow = require("n8n-workflow");
25
- async function getConnectedTools(context, includeBuiltIn = true) {
26
- const tools = [];
38
+ var import_N8nTool = require("./N8nTool");
39
+ function hasMethods(obj, ...methodNames) {
40
+ return methodNames.every(
41
+ (methodName) => typeof obj === "object" && obj !== null && methodName in obj && typeof obj[methodName] === "function"
42
+ );
43
+ }
44
+ function getMetadataFiltersValues(ctx, itemIndex) {
45
+ const options = ctx.getNodeParameter("options", itemIndex, {});
46
+ if (options.metadata) {
47
+ const { metadataValues: metadata } = options.metadata;
48
+ if (metadata.length > 0) {
49
+ return metadata.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});
50
+ }
51
+ }
52
+ if (options.searchFilterJson) {
53
+ return ctx.getNodeParameter("options.searchFilterJson", itemIndex, "", {
54
+ ensureType: "object"
55
+ });
56
+ }
57
+ return void 0;
58
+ }
59
+ function isBaseChatMemory(obj) {
60
+ return hasMethods(obj, "loadMemoryVariables", "saveContext");
61
+ }
62
+ function isBaseChatMessageHistory(obj) {
63
+ return hasMethods(obj, "getMessages", "addMessage");
64
+ }
65
+ function isChatInstance(model) {
66
+ const namespace = model?.lc_namespace ?? [];
67
+ return namespace.includes("chat_models");
68
+ }
69
+ function isToolsInstance(model) {
70
+ const namespace = model?.lc_namespace ?? [];
71
+ return namespace.includes("tools");
72
+ }
73
+ function getPromptInputByType(options) {
74
+ const { ctx, i, promptTypeKey, inputKey } = options;
75
+ const promptType = ctx.getNodeParameter(promptTypeKey, i, "define");
76
+ let input;
77
+ if (promptType === "auto") {
78
+ input = ctx.evaluateExpression('{{ $json["chatInput"] }}', i);
79
+ } else if (promptType === "guardrails") {
80
+ input = ctx.evaluateExpression('{{ $json["guardrailsInput"] }}', i);
81
+ } else {
82
+ input = ctx.getNodeParameter(inputKey, i);
83
+ }
84
+ if (input === void 0) {
85
+ const key = promptType === "auto" ? "chatInput" : "guardrailsInput";
86
+ throw new import_n8n_workflow.NodeOperationError(ctx.getNode(), "No prompt specified", {
87
+ description: `Expected to find the prompt in an input field called '${key}' (this is what the ${promptType === "auto" ? "chat trigger node" : "guardrails node"} node outputs). To use something else, change the 'Prompt' parameter`
88
+ });
89
+ }
90
+ return input;
91
+ }
92
+ function getSessionId(ctx, itemIndex, selectorKey = "sessionIdType", autoSelect = "fromInput", customKey = "sessionKey") {
93
+ let sessionId = "";
94
+ const selectorType = ctx.getNodeParameter(selectorKey, itemIndex);
95
+ if (selectorType === autoSelect) {
96
+ if ("getBodyData" in ctx) {
97
+ const bodyData = ctx.getBodyData() ?? {};
98
+ sessionId = bodyData.sessionId;
99
+ } else {
100
+ sessionId = ctx.evaluateExpression("{{ $json.sessionId }}", itemIndex);
101
+ if (!sessionId || sessionId === void 0) {
102
+ try {
103
+ const chatTrigger = ctx.getChatTrigger();
104
+ if (chatTrigger) {
105
+ sessionId = ctx.evaluateExpression(
106
+ `{{ $('${chatTrigger.name}').first().json.sessionId }}`,
107
+ itemIndex
108
+ );
109
+ }
110
+ } catch (error) {
111
+ }
112
+ }
113
+ }
114
+ if (sessionId === "" || sessionId === void 0) {
115
+ throw new import_n8n_workflow.NodeOperationError(ctx.getNode(), "No session ID found", {
116
+ description: "Expected to find the session ID in an input field called 'sessionId' (this is what the chat trigger node outputs). To use something else, change the 'Session ID' parameter",
117
+ itemIndex
118
+ });
119
+ }
120
+ } else {
121
+ sessionId = ctx.getNodeParameter(customKey, itemIndex, "");
122
+ if (sessionId === "" || sessionId === void 0) {
123
+ throw new import_n8n_workflow.NodeOperationError(ctx.getNode(), "Key parameter is empty", {
124
+ description: "Provide a key to use as session ID in the 'Key' parameter or use the 'Connected Chat Trigger Node' option to use the session ID from your Chat Trigger",
125
+ itemIndex
126
+ });
127
+ }
128
+ }
129
+ return sessionId;
130
+ }
131
+ function logAiEvent(executeFunctions, event, data) {
27
132
  try {
28
- const connectedTools = await context.getInputConnectionData(
29
- import_n8n_workflow.NodeConnectionTypes.AiTool,
30
- 0
31
- );
32
- if (connectedTools) {
33
- if (Array.isArray(connectedTools)) {
34
- tools.push(...connectedTools);
133
+ executeFunctions.logAiEvent(event, data ? (0, import_n8n_workflow.jsonStringify)(data) : void 0);
134
+ } catch (error) {
135
+ executeFunctions.logger.debug(`Error logging AI event: ${event}`);
136
+ }
137
+ }
138
+ function serializeChatHistory(chatHistory) {
139
+ return chatHistory.map((chatMessage) => {
140
+ if (chatMessage._getType() === "human") {
141
+ return `Human: ${chatMessage.content}`;
142
+ } else if (chatMessage._getType() === "ai") {
143
+ return `Assistant: ${chatMessage.content}`;
144
+ } else {
145
+ return `${chatMessage.content}`;
146
+ }
147
+ }).join("\n");
148
+ }
149
+ function escapeSingleCurlyBrackets(text) {
150
+ if (text === void 0) return void 0;
151
+ let result = text;
152
+ result = result.replace(/(?<!{){{{(?!{)/g, "{{{{").replace(/(?<!})}}}(?!})/g, "}}}}").replace(/(?<!{){(?!{)/g, "{{").replace(/(?<!})}(?!})/g, "}}");
153
+ return result;
154
+ }
155
+ const getConnectedTools = async (ctx, enforceUniqueNames, convertStructuredTool = true, escapeCurlyBrackets = false) => {
156
+ const toolkitConnections = await ctx.getInputConnectionData(
157
+ import_n8n_workflow.NodeConnectionTypes.AiTool,
158
+ 0
159
+ );
160
+ const parentNodes = "getParentNodes" in ctx ? ctx.getParentNodes(ctx.getNode().name, {
161
+ connectionType: import_n8n_workflow.NodeConnectionTypes.AiTool,
162
+ depth: 1
163
+ }) : [];
164
+ const connectedTools = (toolkitConnections ?? []).flatMap((toolOrToolkit, index) => {
165
+ if (toolOrToolkit instanceof import_agents.Toolkit) {
166
+ const tools = toolOrToolkit.getTools();
167
+ return tools.map((tool) => {
168
+ const sourceNode = parentNodes[index] ?? tool.name;
169
+ tool.metadata ??= {};
170
+ tool.metadata.isFromToolkit = true;
171
+ tool.metadata.sourceNodeName = sourceNode?.name;
172
+ return tool;
173
+ });
174
+ } else {
175
+ const sourceNode = parentNodes[index] ?? toolOrToolkit.name;
176
+ toolOrToolkit.metadata ??= {};
177
+ toolOrToolkit.metadata.isFromToolkit = false;
178
+ toolOrToolkit.metadata.sourceNodeName = sourceNode?.name;
179
+ }
180
+ return toolOrToolkit;
181
+ });
182
+ if (!enforceUniqueNames) return connectedTools;
183
+ const seenNames = /* @__PURE__ */ new Set();
184
+ const finalTools = [];
185
+ for (const tool of connectedTools) {
186
+ const { name } = tool;
187
+ if (seenNames.has(name)) {
188
+ throw new import_n8n_workflow.NodeOperationError(
189
+ ctx.getNode(),
190
+ `You have multiple tools with the same name: '${name}', please rename them to avoid conflicts`
191
+ );
192
+ }
193
+ seenNames.add(name);
194
+ if (escapeCurlyBrackets) {
195
+ tool.description = escapeSingleCurlyBrackets(tool.description) ?? tool.description;
196
+ }
197
+ if (convertStructuredTool && tool instanceof import_N8nTool.N8nTool) {
198
+ finalTools.push(tool.asDynamicTool());
199
+ } else {
200
+ finalTools.push(tool);
201
+ }
202
+ }
203
+ return finalTools;
204
+ };
205
+ function unwrapNestedOutput(output) {
206
+ if ("output" in output && Object.keys(output).length === 1 && typeof output.output === "object" && output.output !== null && "output" in output.output && Object.keys(output.output).length === 1) {
207
+ return output.output;
208
+ }
209
+ return output;
210
+ }
211
+ function hasLongSequentialRepeat(text, threshold = 1e3) {
212
+ try {
213
+ if (text === null || typeof text !== "string" || text.length === 0 || threshold <= 0 || text.length < threshold) {
214
+ return false;
215
+ }
216
+ const iterator = text[Symbol.iterator]();
217
+ let prev = iterator.next();
218
+ if (prev.done) {
219
+ return false;
220
+ }
221
+ let count = 1;
222
+ for (const char of iterator) {
223
+ if (char === prev.value) {
224
+ count++;
225
+ if (count >= threshold) {
226
+ return true;
227
+ }
35
228
  } else {
36
- tools.push(connectedTools);
229
+ count = 1;
230
+ prev = { value: char, done: false };
37
231
  }
38
232
  }
233
+ return false;
39
234
  } catch (error) {
235
+ return false;
40
236
  }
41
- return tools;
42
237
  }
43
238
  // Annotate the CommonJS export names for ESM import in node:
44
239
  0 && (module.exports = {
45
- getConnectedTools
240
+ escapeSingleCurlyBrackets,
241
+ getConnectedTools,
242
+ getMetadataFiltersValues,
243
+ getPromptInputByType,
244
+ getSessionId,
245
+ hasLongSequentialRepeat,
246
+ isBaseChatMemory,
247
+ isBaseChatMessageHistory,
248
+ isChatInstance,
249
+ isToolsInstance,
250
+ logAiEvent,
251
+ serializeChatHistory,
252
+ unwrapNestedOutput
46
253
  });
47
254
  //# sourceMappingURL=helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../nodes/shared/helpers.ts"],"sourcesContent":["\nimport type { IWebhookFunctions } from 'n8n-workflow';\nimport { NodeConnectionTypes } from 'n8n-workflow';\nimport type { Tool } from '@langchain/core/tools';\n\nexport async function getConnectedTools(\n context: IWebhookFunctions,\n includeBuiltIn: boolean = true\n): Promise<Tool[]> {\n const tools: Tool[] = [];\n \n try {\n // Get tools from connected nodes via the 'Tools' input connection\n const connectedTools = (await context.getInputConnectionData(\n NodeConnectionTypes.AiTool,\n 0,\n )) as Tool[] | Tool | undefined;\n\n if (connectedTools) {\n if (Array.isArray(connectedTools)) {\n tools.push(...connectedTools);\n } else {\n tools.push(connectedTools);\n }\n }\n } catch (error) {\n // No tools connected or error retrieving them - return empty array\n }\n\n return tools;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,0BAAoC;AAGpC,eAAsB,kBAClB,SACA,iBAA0B,MACX;AACf,QAAM,QAAgB,CAAC;AAEvB,MAAI;AAEA,UAAM,iBAAkB,MAAM,QAAQ;AAAA,MAClC,wCAAoB;AAAA,MACpB;AAAA,IACJ;AAEA,QAAI,gBAAgB;AAChB,UAAI,MAAM,QAAQ,cAAc,GAAG;AAC/B,cAAM,KAAK,GAAG,cAAc;AAAA,MAChC,OAAO;AACH,cAAM,KAAK,cAAc;AAAA,MAC7B;AAAA,IACJ;AAAA,EACJ,SAAS,OAAO;AAAA,EAEhB;AAEA,SAAO;AACX;","names":[]}
1
+ {"version":3,"sources":["../../nodes/shared/helpers.ts"],"sourcesContent":["import type { BaseChatMessageHistory } from '@langchain/core/chat_history';\nimport type { BaseChatModel } from '@langchain/core/language_models/chat_models';\nimport type { BaseLLM } from '@langchain/core/language_models/llms';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { Tool } from '@langchain/core/tools';\nimport { Toolkit } from '@langchain/classic/agents';\nimport type { BaseChatMemory } from '@langchain/classic/memory';\nimport { NodeConnectionTypes, NodeOperationError, jsonStringify } from 'n8n-workflow';\nimport type {\n\tAiEvent,\n\tIDataObject,\n\tIExecuteFunctions,\n\tISupplyDataFunctions,\n\tIWebhookFunctions,\n} from 'n8n-workflow';\n\nimport { N8nTool } from './N8nTool';\n\nfunction hasMethods<T>(obj: unknown, ...methodNames: Array<string | symbol>): obj is T {\n\treturn methodNames.every(\n\t\t(methodName) =>\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj !== null &&\n\t\t\tmethodName in obj &&\n\t\t\ttypeof (obj as Record<string | symbol, unknown>)[methodName] === 'function',\n\t);\n}\n\nexport function getMetadataFiltersValues(\n\tctx: IExecuteFunctions | ISupplyDataFunctions,\n\titemIndex: number,\n): Record<string, never> | undefined {\n\tconst options = ctx.getNodeParameter('options', itemIndex, {});\n\n\tif (options.metadata) {\n\t\tconst { metadataValues: metadata } = options.metadata as {\n\t\t\tmetadataValues: Array<{\n\t\t\t\tname: string;\n\t\t\t\tvalue: string;\n\t\t\t}>;\n\t\t};\n\t\tif (metadata.length > 0) {\n\t\t\treturn metadata.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});\n\t\t}\n\t}\n\n\tif (options.searchFilterJson) {\n\t\treturn ctx.getNodeParameter('options.searchFilterJson', itemIndex, '', {\n\t\t\tensureType: 'object',\n\t\t}) as Record<string, never>;\n\t}\n\n\treturn undefined;\n}\n\nexport function isBaseChatMemory(obj: unknown) {\n\treturn hasMethods<BaseChatMemory>(obj, 'loadMemoryVariables', 'saveContext');\n}\n\nexport function isBaseChatMessageHistory(obj: unknown) {\n\treturn hasMethods<BaseChatMessageHistory>(obj, 'getMessages', 'addMessage');\n}\n\nexport function isChatInstance(model: unknown): model is BaseChatModel {\n\tconst namespace = (model as BaseLLM)?.lc_namespace ?? [];\n\n\treturn namespace.includes('chat_models');\n}\n\nexport function isToolsInstance(model: unknown): model is Tool {\n\tconst namespace = (model as Tool)?.lc_namespace ?? [];\n\n\treturn namespace.includes('tools');\n}\n\nexport function getPromptInputByType(options: {\n\tctx: IExecuteFunctions | ISupplyDataFunctions;\n\ti: number;\n\tpromptTypeKey: string;\n\tinputKey: string;\n}) {\n\tconst { ctx, i, promptTypeKey, inputKey } = options;\n\tconst promptType = ctx.getNodeParameter(promptTypeKey, i, 'define') as string;\n\n\tlet input;\n\tif (promptType === 'auto') {\n\t\tinput = ctx.evaluateExpression('{{ $json[\"chatInput\"] }}', i) as string;\n\t} else if (promptType === 'guardrails') {\n\t\tinput = ctx.evaluateExpression('{{ $json[\"guardrailsInput\"] }}', i) as string;\n\t} else {\n\t\tinput = ctx.getNodeParameter(inputKey, i) as string;\n\t}\n\n\tif (input === undefined) {\n\t\tconst key = promptType === 'auto' ? 'chatInput' : 'guardrailsInput';\n\t\tthrow new NodeOperationError(ctx.getNode(), 'No prompt specified', {\n\t\t\tdescription: `Expected to find the prompt in an input field called '${key}' (this is what the ${promptType === 'auto' ? 'chat trigger node' : 'guardrails node'} node outputs). To use something else, change the 'Prompt' parameter`,\n\t\t});\n\t}\n\n\treturn input;\n}\n\nexport function getSessionId(\n\tctx: ISupplyDataFunctions | IWebhookFunctions,\n\titemIndex: number,\n\tselectorKey = 'sessionIdType',\n\tautoSelect = 'fromInput',\n\tcustomKey = 'sessionKey',\n) {\n\tlet sessionId = '';\n\tconst selectorType = ctx.getNodeParameter(selectorKey, itemIndex) as string;\n\n\tif (selectorType === autoSelect) {\n\t\t// If memory node is used in webhook like node(like chat trigger node), it doesn't have access to evaluateExpression\n\t\t// so we try to extract sessionId from the bodyData\n\t\tif ('getBodyData' in ctx) {\n\t\t\tconst bodyData = ctx.getBodyData() ?? {};\n\t\t\tsessionId = bodyData.sessionId as string;\n\t\t} else {\n\t\t\tsessionId = ctx.evaluateExpression('{{ $json.sessionId }}', itemIndex) as string;\n\n\t\t\t// try to get sessionId from chat trigger\n\t\t\tif (!sessionId || sessionId === undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tconst chatTrigger = ctx.getChatTrigger();\n\n\t\t\t\t\tif (chatTrigger) {\n\t\t\t\t\t\tsessionId = ctx.evaluateExpression(\n\t\t\t\t\t\t\t`{{ $('${chatTrigger.name}').first().json.sessionId }}`,\n\t\t\t\t\t\t\titemIndex,\n\t\t\t\t\t\t) as string;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {}\n\t\t\t}\n\t\t}\n\n\t\tif (sessionId === '' || sessionId === undefined) {\n\t\t\tthrow new NodeOperationError(ctx.getNode(), 'No session ID found', {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Expected to find the session ID in an input field called 'sessionId' (this is what the chat trigger node outputs). To use something else, change the 'Session ID' parameter\",\n\t\t\t\titemIndex,\n\t\t\t});\n\t\t}\n\t} else {\n\t\tsessionId = ctx.getNodeParameter(customKey, itemIndex, '') as string;\n\t\tif (sessionId === '' || sessionId === undefined) {\n\t\t\tthrow new NodeOperationError(ctx.getNode(), 'Key parameter is empty', {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Provide a key to use as session ID in the 'Key' parameter or use the 'Connected Chat Trigger Node' option to use the session ID from your Chat Trigger\",\n\t\t\t\titemIndex,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn sessionId;\n}\n\nexport function logAiEvent(\n\texecuteFunctions: IExecuteFunctions | ISupplyDataFunctions,\n\tevent: AiEvent,\n\tdata?: IDataObject,\n) {\n\ttry {\n\t\texecuteFunctions.logAiEvent(event, data ? jsonStringify(data) : undefined);\n\t} catch (error) {\n\t\texecuteFunctions.logger.debug(`Error logging AI event: ${event}`);\n\t}\n}\n\nexport function serializeChatHistory(chatHistory: BaseMessage[]): string {\n\treturn chatHistory\n\t\t.map((chatMessage) => {\n\t\t\tif (chatMessage._getType() === 'human') {\n\t\t\t\treturn `Human: ${chatMessage.content}`;\n\t\t\t} else if (chatMessage._getType() === 'ai') {\n\t\t\t\treturn `Assistant: ${chatMessage.content}`;\n\t\t\t} else {\n\t\t\t\treturn `${chatMessage.content}`;\n\t\t\t}\n\t\t})\n\t\t.join('\\n');\n}\n\nexport function escapeSingleCurlyBrackets(text?: string): string | undefined {\n\tif (text === undefined) return undefined;\n\n\tlet result = text;\n\n\tresult = result\n\t\t// First handle triple brackets to avoid interference with double brackets\n\t\t.replace(/(?<!{){{{(?!{)/g, '{{{{')\n\t\t.replace(/(?<!})}}}(?!})/g, '}}}}')\n\t\t// Then handle single brackets, but only if they're not part of double brackets\n\t\t// Convert single { to {{ if it's not already part of {{ or {{{\n\t\t.replace(/(?<!{){(?!{)/g, '{{')\n\t\t// Convert single } to }} if it's not already part of }} or }}}\n\t\t.replace(/(?<!})}(?!})/g, '}}');\n\n\treturn result;\n}\n\nexport const getConnectedTools = async (\n\tctx: IExecuteFunctions | IWebhookFunctions | ISupplyDataFunctions,\n\tenforceUniqueNames: boolean,\n\tconvertStructuredTool: boolean = true,\n\tescapeCurlyBrackets: boolean = false,\n) => {\n\tconst toolkitConnections = (await ctx.getInputConnectionData(\n\t\tNodeConnectionTypes.AiTool,\n\t\t0,\n\t)) as Array<Toolkit | Tool>;\n\n\t// Get parent nodes to map toolkits to their source nodes\n\tconst parentNodes =\n\t\t'getParentNodes' in ctx\n\t\t\t? ctx.getParentNodes(ctx.getNode().name, {\n\t\t\t\t\tconnectionType: NodeConnectionTypes.AiTool,\n\t\t\t\t\tdepth: 1,\n\t\t\t\t})\n\t\t\t: [];\n\n\tconst connectedTools = (toolkitConnections ?? []).flatMap((toolOrToolkit, index) => {\n\t\tif (toolOrToolkit instanceof Toolkit) {\n\t\t\tconst tools = toolOrToolkit.getTools() as Tool[];\n\t\t\t// Add metadata to each tool from the toolkit\n\t\t\treturn tools.map((tool) => {\n\t\t\t\tconst sourceNode = parentNodes[index] ?? tool.name;\n\n\t\t\t\ttool.metadata ??= {};\n\t\t\t\ttool.metadata.isFromToolkit = true;\n\t\t\t\ttool.metadata.sourceNodeName = sourceNode?.name;\n\t\t\t\treturn tool;\n\t\t\t});\n\t\t} else {\n\t\t\tconst sourceNode = parentNodes[index] ?? toolOrToolkit.name;\n\t\t\ttoolOrToolkit.metadata ??= {};\n\t\t\ttoolOrToolkit.metadata.isFromToolkit = false;\n\t\t\ttoolOrToolkit.metadata.sourceNodeName = sourceNode?.name;\n\t\t}\n\n\t\treturn toolOrToolkit;\n\t});\n\n\tif (!enforceUniqueNames) return connectedTools;\n\n\tconst seenNames = new Set<string>();\n\n\tconst finalTools: Tool[] = [];\n\n\tfor (const tool of connectedTools) {\n\t\tconst { name } = tool;\n\t\tif (seenNames.has(name)) {\n\t\t\tthrow new NodeOperationError(\n\t\t\t\tctx.getNode(),\n\t\t\t\t`You have multiple tools with the same name: '${name}', please rename them to avoid conflicts`,\n\t\t\t);\n\t\t}\n\t\tseenNames.add(name);\n\n\t\tif (escapeCurlyBrackets) {\n\t\t\ttool.description = escapeSingleCurlyBrackets(tool.description) ?? tool.description;\n\t\t}\n\n\t\tif (convertStructuredTool && tool instanceof N8nTool) {\n\t\t\tfinalTools.push(tool.asDynamicTool());\n\t\t} else {\n\t\t\tfinalTools.push(tool);\n\t\t}\n\t}\n\n\treturn finalTools;\n};\n\n/**\n * Sometimes model output is wrapped in an additional object property.\n * This function unwraps the output if it is in the format { output: { output: { ... } } }\n */\nexport function unwrapNestedOutput(output: Record<string, unknown>): Record<string, unknown> {\n\tif (\n\t\t'output' in output &&\n\t\tObject.keys(output).length === 1 &&\n\t\ttypeof output.output === 'object' &&\n\t\toutput.output !== null &&\n\t\t'output' in output.output &&\n\t\tObject.keys(output.output).length === 1\n\t) {\n\t\treturn output.output as Record<string, unknown>;\n\t}\n\n\treturn output;\n}\n\n/**\n * Detects if a text contains a character that repeats sequentially for a specified threshold.\n * This is used to prevent performance issues with tiktoken on highly repetitive content.\n * @param text The text to check\n * @param threshold The minimum number of sequential repeats to detect (default: 1000)\n * @returns true if a character repeats sequentially for at least the threshold amount\n */\nexport function hasLongSequentialRepeat(text: string, threshold = 1000): boolean {\n\ttry {\n\t\t// Validate inputs\n\t\tif (\n\t\t\ttext === null ||\n\t\t\ttypeof text !== 'string' ||\n\t\t\ttext.length === 0 ||\n\t\t\tthreshold <= 0 ||\n\t\t\ttext.length < threshold\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\t// Use string iterator to avoid creating array copy (memory efficient)\n\t\tconst iterator = text[Symbol.iterator]();\n\t\tlet prev = iterator.next();\n\n\t\tif (prev.done) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet count = 1;\n\t\tfor (const char of iterator) {\n\t\t\tif (char === prev.value) {\n\t\t\t\tcount++;\n\t\t\t\tif (count >= threshold) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcount = 1;\n\t\t\t\tprev = { value: char, done: false };\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t} catch (error) {\n\t\t// On any error, return false to allow normal processing\n\t\treturn false;\n\t}\n}"],"mappings":"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","names":[]}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,17 +17,53 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var httpProxyAgent_exports = {};
20
30
  __export(httpProxyAgent_exports, {
31
+ getNodeProxyAgent: () => getNodeProxyAgent,
32
+ getProxyAgent: () => getProxyAgent,
21
33
  proxyFetch: () => proxyFetch
22
34
  });
23
35
  module.exports = __toCommonJS(httpProxyAgent_exports);
24
- async function proxyFetch(url, init) {
25
- return globalThis.fetch(url, init);
36
+ var import_https_proxy_agent = require("https-proxy-agent");
37
+ var import_proxy_from_env = __toESM(require("proxy-from-env"));
38
+ var import_undici = require("undici");
39
+ function getProxyUrlFromEnv(targetUrl) {
40
+ return import_proxy_from_env.default.getProxyForUrl(targetUrl ?? "https://example.nonexistent/");
41
+ }
42
+ function getProxyAgent(targetUrl) {
43
+ const proxyUrl = getProxyUrlFromEnv(targetUrl);
44
+ if (!proxyUrl) {
45
+ return void 0;
46
+ }
47
+ return new import_undici.ProxyAgent(proxyUrl);
48
+ }
49
+ async function proxyFetch(input, init) {
50
+ return await fetch(input, {
51
+ ...init,
52
+ // @ts-expect-error - dispatcher is an undici-specific option not in standard fetch
53
+ dispatcher: getProxyAgent(input.toString())
54
+ });
55
+ }
56
+ function getNodeProxyAgent(targetUrl) {
57
+ const proxyUrl = getProxyUrlFromEnv(targetUrl);
58
+ if (!proxyUrl) {
59
+ return void 0;
60
+ }
61
+ return new import_https_proxy_agent.HttpsProxyAgent(proxyUrl);
26
62
  }
27
63
  // Annotate the CommonJS export names for ESM import in node:
28
64
  0 && (module.exports = {
65
+ getNodeProxyAgent,
66
+ getProxyAgent,
29
67
  proxyFetch
30
68
  });
31
69
  //# sourceMappingURL=httpProxyAgent.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../nodes/shared/httpProxyAgent.ts"],"sourcesContent":["\nimport type { RequestInit, Response } from 'node-fetch';\n\n// Simple pass-through fetch since we don't have the original proxy logic.\n// In a real n8n node, you might want to integrate with n8n's proxy settings.\nexport async function proxyFetch(url: string | URL, init?: RequestInit): Promise<Response> {\n // @ts-ignore - native fetch vs node-fetch types mismatch might occur, but for now we try global fetch or assume node-fetch is available\n // If running in Node 18+, global fetch exists. \n // n8n environments often have fetch.\n return (globalThis.fetch as unknown as typeof fetch)(url as any, init as any);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,eAAsB,WAAW,KAAmB,MAAuC;AAIvF,SAAQ,WAAW,MAAkC,KAAY,IAAW;AAChF;","names":[]}
1
+ {"version":3,"sources":["../../nodes/shared/httpProxyAgent.ts"],"sourcesContent":["import { HttpsProxyAgent } from 'https-proxy-agent';\nimport proxyFromEnv from 'proxy-from-env';\nimport { ProxyAgent } from 'undici';\n\n/**\n * Resolves the proxy URL from environment variables for a given target URL.\n *\n * @param targetUrl - The target URL to check proxy configuration for (optional)\n * @returns The proxy URL string or undefined if no proxy is configured\n *\n * @remarks\n * There are cases where we don't know the target URL in advance (e.g. when we need to provide a proxy agent to ChatAwsBedrock).\n * In such case we use a dummy URL.\n * This will lead to `NO_PROXY` environment variable not being respected, but it is better than not having a proxy agent at all.\n */\nfunction getProxyUrlFromEnv(targetUrl?: string): string {\n\treturn proxyFromEnv.getProxyForUrl(targetUrl ?? 'https://example.nonexistent/');\n}\n\n/**\n * Returns a ProxyAgent or undefined based on the environment variables and target URL.\n * When target URL is not provided, NO_PROXY environment variable is not respected.\n */\nexport function getProxyAgent(targetUrl?: string) {\n\tconst proxyUrl = getProxyUrlFromEnv(targetUrl);\n\n\tif (!proxyUrl) {\n\t\treturn undefined;\n\t}\n\n\treturn new ProxyAgent(proxyUrl);\n}\n\n/**\n * Make a fetch() request with a ProxyAgent if proxy environment variables are set.\n * If no proxy is configured, use the default fetch().\n */\nexport async function proxyFetch(input: string | URL, init?: RequestInit): Promise<Response> {\n\treturn await fetch(input, {\n\t\t...init,\n\t\t// @ts-expect-error - dispatcher is an undici-specific option not in standard fetch\n\t\tdispatcher: getProxyAgent(input.toString()),\n\t});\n}\n\n/**\n * Returns a Node.js HTTP/HTTPS proxy agent for use with AWS SDK v3 clients.\n * AWS SDK v3 requires Node.js http.Agent/https.Agent instances (not undici ProxyAgent).\n *\n * @param targetUrl - The target URL to check proxy configuration for\n * @returns HttpsProxyAgent instance or undefined if no proxy is configured\n */\nexport function getNodeProxyAgent(targetUrl?: string) {\n\tconst proxyUrl = getProxyUrlFromEnv(targetUrl);\n\n\tif (!proxyUrl) {\n\t\treturn undefined;\n\t}\n\n\treturn new HttpsProxyAgent(proxyUrl);\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAAgC;AAChC,4BAAyB;AACzB,oBAA2B;AAa3B,SAAS,mBAAmB,WAA4B;AACvD,SAAO,sBAAAA,QAAa,eAAe,aAAa,8BAA8B;AAC/E;AAMO,SAAS,cAAc,WAAoB;AACjD,QAAM,WAAW,mBAAmB,SAAS;AAE7C,MAAI,CAAC,UAAU;AACd,WAAO;AAAA,EACR;AAEA,SAAO,IAAI,yBAAW,QAAQ;AAC/B;AAMA,eAAsB,WAAW,OAAqB,MAAuC;AAC5F,SAAO,MAAM,MAAM,OAAO;AAAA,IACzB,GAAG;AAAA;AAAA,IAEH,YAAY,cAAc,MAAM,SAAS,CAAC;AAAA,EAC3C,CAAC;AACF;AASO,SAAS,kBAAkB,WAAoB;AACrD,QAAM,WAAW,mBAAmB,SAAS;AAE7C,MAAI,CAAC,UAAU;AACd,WAAO;AAAA,EACR;AAEA,SAAO,IAAI,yCAAgB,QAAQ;AACpC;","names":["proxyFromEnv"]}