@n8n/n8n-nodes-langchain 1.99.1 → 1.100.1

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 (32) hide show
  1. package/dist/nodes/agents/Agent/V2/AgentV2.node.js +51 -34
  2. package/dist/nodes/agents/Agent/V2/AgentV2.node.js.map +1 -1
  3. package/dist/nodes/agents/Agent/agents/ToolsAgent/V1/execute.js.map +1 -1
  4. package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js +57 -28
  5. package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js.map +1 -1
  6. package/dist/nodes/agents/Agent/agents/ToolsAgent/common.js +12 -2
  7. package/dist/nodes/agents/Agent/agents/ToolsAgent/common.js.map +1 -1
  8. package/dist/nodes/chains/ChainLLM/methods/chainExecutor.js +13 -4
  9. package/dist/nodes/chains/ChainLLM/methods/chainExecutor.js.map +1 -1
  10. package/dist/nodes/chains/ChainLLM/methods/config.js +32 -0
  11. package/dist/nodes/chains/ChainLLM/methods/config.js.map +1 -1
  12. package/dist/nodes/chains/ChainLLM/methods/processItem.js +38 -6
  13. package/dist/nodes/chains/ChainLLM/methods/processItem.js.map +1 -1
  14. package/dist/nodes/chains/ChainLLM/methods/types.js.map +1 -1
  15. package/dist/nodes/llms/LmChatGoogleGemini/LmChatGoogleGemini.node.js +1 -1
  16. package/dist/nodes/llms/LmChatGoogleGemini/LmChatGoogleGemini.node.js.map +1 -1
  17. package/dist/nodes/llms/N8nLlmTracing.js +2 -6
  18. package/dist/nodes/llms/N8nLlmTracing.js.map +1 -1
  19. package/dist/nodes/text_splitters/TextSplitterTokenSplitter/TokenTextSplitter.js +43 -14
  20. package/dist/nodes/text_splitters/TextSplitterTokenSplitter/TokenTextSplitter.js.map +1 -1
  21. package/dist/nodes/tools/ToolWorkflow/v2/utils/WorkflowToolService.js +74 -41
  22. package/dist/nodes/tools/ToolWorkflow/v2/utils/WorkflowToolService.js.map +1 -1
  23. package/dist/types/nodes.json +7 -7
  24. package/dist/utils/descriptions.js +1 -1
  25. package/dist/utils/descriptions.js.map +1 -1
  26. package/dist/utils/helpers.js +29 -0
  27. package/dist/utils/helpers.js.map +1 -1
  28. package/dist/utils/output_parsers/N8nOutputParser.js +2 -2
  29. package/dist/utils/output_parsers/N8nOutputParser.js.map +1 -1
  30. package/dist/utils/tokenizer/token-estimator.js +119 -0
  31. package/dist/utils/tokenizer/token-estimator.js.map +1 -0
  32. package/package.json +12 -10
@@ -94,7 +94,7 @@ const buildInputSchemaField = (props) => ({
94
94
  }
95
95
  }
96
96
  }`,
97
- noDataExpression: true,
97
+ noDataExpression: false,
98
98
  typeOptions: {
99
99
  rows: 10
100
100
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../utils/descriptions.ts"],"sourcesContent":["import type { DisplayCondition, INodeProperties, NodeParameterValue } from 'n8n-workflow';\n\nexport const schemaTypeField: INodeProperties = {\n\tdisplayName: 'Schema Type',\n\tname: 'schemaType',\n\ttype: 'options',\n\tnoDataExpression: true,\n\toptions: [\n\t\t{\n\t\t\tname: 'Generate From JSON Example',\n\t\t\tvalue: 'fromJson',\n\t\t\tdescription: 'Generate a schema from an example JSON object',\n\t\t},\n\t\t{\n\t\t\tname: 'Define using JSON Schema',\n\t\t\tvalue: 'manual',\n\t\t\tdescription: 'Define the JSON schema manually',\n\t\t},\n\t],\n\tdefault: 'fromJson',\n\tdescription: 'How to specify the schema for the function',\n};\n\n/**\n * Returns a field for inputting a JSON example that can be used to generate the schema.\n * @param props\n */\nexport const buildJsonSchemaExampleField = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName: 'JSON Example',\n\tname: 'jsonSchemaExample',\n\ttype: 'json',\n\tdefault: `{\n\t\"some_input\": \"some_value\"\n}`,\n\tnoDataExpression: true,\n\ttypeOptions: {\n\t\trows: 10,\n\t},\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['fromJson'],\n\t\t},\n\t},\n\tdescription: 'Example JSON object to use to generate the schema',\n});\n\n/**\n * Returns a notice field about the generated schema properties being required by default.\n * @param props\n */\nexport const buildJsonSchemaExampleNotice = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName:\n\t\t\"All properties will be required. To make them optional, use the 'JSON Schema' schema type instead\",\n\tname: 'notice',\n\ttype: 'notice',\n\tdefault: '',\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['fromJson'],\n\t\t},\n\t},\n});\n\nexport const jsonSchemaExampleField = buildJsonSchemaExampleField();\n\nexport const buildInputSchemaField = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName: 'Input Schema',\n\tname: 'inputSchema',\n\ttype: 'json',\n\tdefault: `{\n\"type\": \"object\",\n\"properties\": {\n\t\"some_input\": {\n\t\t\"type\": \"string\",\n\t\t\"description\": \"Some input to the function\"\n\t\t}\n\t}\n}`,\n\tnoDataExpression: true,\n\ttypeOptions: {\n\t\trows: 10,\n\t},\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['manual'],\n\t\t},\n\t},\n\tdescription: 'Schema to use for the function',\n\thint: 'Use <a target=\"_blank\" href=\"https://json-schema.org/\">JSON Schema</a> format (<a target=\"_blank\" href=\"https://json-schema.org/learn/miscellaneous-examples.html\">examples</a>). $refs syntax is currently not supported.',\n});\n\nexport const inputSchemaField = buildInputSchemaField();\n\nexport const promptTypeOptions: INodeProperties = {\n\tdisplayName: 'Source for Prompt (User Message)',\n\tname: 'promptType',\n\ttype: 'options',\n\toptions: [\n\t\t{\n\t\t\tname: 'Connected Chat Trigger Node',\n\t\t\tvalue: 'auto',\n\t\t\tdescription:\n\t\t\t\t\"Looks for an input field called 'chatInput' that is coming from a directly connected Chat Trigger\",\n\t\t},\n\t\t{\n\t\t\tname: 'Define below',\n\t\t\tvalue: 'define',\n\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t},\n\t],\n\tdefault: 'auto',\n};\n\nexport const textInput: INodeProperties = {\n\tdisplayName: 'Prompt (User Message)',\n\tname: 'text',\n\ttype: 'string',\n\trequired: true,\n\tdefault: '',\n\tplaceholder: 'e.g. Hello, how can you help me?',\n\ttypeOptions: {\n\t\trows: 2,\n\t},\n};\n\nexport const textFromPreviousNode: INodeProperties = {\n\tdisplayName: 'Prompt (User Message)',\n\tname: 'text',\n\ttype: 'string',\n\trequired: true,\n\tdefault: '={{ $json.chatInput }}',\n\ttypeOptions: {\n\t\trows: 2,\n\t},\n\tdisabledOptions: { show: { promptType: ['auto'] } },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,kBAAmC;AAAA,EAC/C,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,kBAAkB;AAAA,EAClB,SAAS;AAAA,IACR;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAAA,EACA,SAAS;AAAA,EACT,aAAa;AACd;AAMO,MAAM,8BAA8B,CAAC,WAEpB;AAAA,EACvB,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA;AAAA;AAAA,EAGT,kBAAkB;AAAA,EAClB,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,UAAU;AAAA,IACxB;AAAA,EACD;AAAA,EACA,aAAa;AACd;AAMO,MAAM,+BAA+B,CAAC,WAErB;AAAA,EACvB,aACC;AAAA,EACD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,UAAU;AAAA,IACxB;AAAA,EACD;AACD;AAEO,MAAM,yBAAyB,4BAA4B;AAE3D,MAAM,wBAAwB,CAAC,WAEd;AAAA,EACvB,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,kBAAkB;AAAA,EAClB,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,QAAQ;AAAA,IACtB;AAAA,EACD;AAAA,EACA,aAAa;AAAA,EACb,MAAM;AACP;AAEO,MAAM,mBAAmB,sBAAsB;AAE/C,MAAM,oBAAqC;AAAA,EACjD,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,IACR;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACC;AAAA,IACF;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAAA,EACA,SAAS;AACV;AAEO,MAAM,YAA6B;AAAA,EACzC,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AACD;AAEO,MAAM,uBAAwC;AAAA,EACpD,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,iBAAiB,EAAE,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,EAAE;AACnD;","names":[]}
1
+ {"version":3,"sources":["../../utils/descriptions.ts"],"sourcesContent":["import type { DisplayCondition, INodeProperties, NodeParameterValue } from 'n8n-workflow';\n\nexport const schemaTypeField: INodeProperties = {\n\tdisplayName: 'Schema Type',\n\tname: 'schemaType',\n\ttype: 'options',\n\tnoDataExpression: true,\n\toptions: [\n\t\t{\n\t\t\tname: 'Generate From JSON Example',\n\t\t\tvalue: 'fromJson',\n\t\t\tdescription: 'Generate a schema from an example JSON object',\n\t\t},\n\t\t{\n\t\t\tname: 'Define using JSON Schema',\n\t\t\tvalue: 'manual',\n\t\t\tdescription: 'Define the JSON schema manually',\n\t\t},\n\t],\n\tdefault: 'fromJson',\n\tdescription: 'How to specify the schema for the function',\n};\n\n/**\n * Returns a field for inputting a JSON example that can be used to generate the schema.\n * @param props\n */\nexport const buildJsonSchemaExampleField = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName: 'JSON Example',\n\tname: 'jsonSchemaExample',\n\ttype: 'json',\n\tdefault: `{\n\t\"some_input\": \"some_value\"\n}`,\n\tnoDataExpression: true,\n\ttypeOptions: {\n\t\trows: 10,\n\t},\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['fromJson'],\n\t\t},\n\t},\n\tdescription: 'Example JSON object to use to generate the schema',\n});\n\n/**\n * Returns a notice field about the generated schema properties being required by default.\n * @param props\n */\nexport const buildJsonSchemaExampleNotice = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName:\n\t\t\"All properties will be required. To make them optional, use the 'JSON Schema' schema type instead\",\n\tname: 'notice',\n\ttype: 'notice',\n\tdefault: '',\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['fromJson'],\n\t\t},\n\t},\n});\n\nexport const jsonSchemaExampleField = buildJsonSchemaExampleField();\n\nexport const buildInputSchemaField = (props?: {\n\tshowExtraProps?: Record<string, Array<NodeParameterValue | DisplayCondition> | undefined>;\n}): INodeProperties => ({\n\tdisplayName: 'Input Schema',\n\tname: 'inputSchema',\n\ttype: 'json',\n\tdefault: `{\n\"type\": \"object\",\n\"properties\": {\n\t\"some_input\": {\n\t\t\"type\": \"string\",\n\t\t\"description\": \"Some input to the function\"\n\t\t}\n\t}\n}`,\n\tnoDataExpression: false,\n\ttypeOptions: {\n\t\trows: 10,\n\t},\n\tdisplayOptions: {\n\t\tshow: {\n\t\t\t...props?.showExtraProps,\n\t\t\tschemaType: ['manual'],\n\t\t},\n\t},\n\tdescription: 'Schema to use for the function',\n\thint: 'Use <a target=\"_blank\" href=\"https://json-schema.org/\">JSON Schema</a> format (<a target=\"_blank\" href=\"https://json-schema.org/learn/miscellaneous-examples.html\">examples</a>). $refs syntax is currently not supported.',\n});\n\nexport const inputSchemaField = buildInputSchemaField();\n\nexport const promptTypeOptions: INodeProperties = {\n\tdisplayName: 'Source for Prompt (User Message)',\n\tname: 'promptType',\n\ttype: 'options',\n\toptions: [\n\t\t{\n\t\t\tname: 'Connected Chat Trigger Node',\n\t\t\tvalue: 'auto',\n\t\t\tdescription:\n\t\t\t\t\"Looks for an input field called 'chatInput' that is coming from a directly connected Chat Trigger\",\n\t\t},\n\t\t{\n\t\t\tname: 'Define below',\n\t\t\tvalue: 'define',\n\t\t\tdescription: 'Use an expression to reference data in previous nodes or enter static text',\n\t\t},\n\t],\n\tdefault: 'auto',\n};\n\nexport const textInput: INodeProperties = {\n\tdisplayName: 'Prompt (User Message)',\n\tname: 'text',\n\ttype: 'string',\n\trequired: true,\n\tdefault: '',\n\tplaceholder: 'e.g. Hello, how can you help me?',\n\ttypeOptions: {\n\t\trows: 2,\n\t},\n};\n\nexport const textFromPreviousNode: INodeProperties = {\n\tdisplayName: 'Prompt (User Message)',\n\tname: 'text',\n\ttype: 'string',\n\trequired: true,\n\tdefault: '={{ $json.chatInput }}',\n\ttypeOptions: {\n\t\trows: 2,\n\t},\n\tdisabledOptions: { show: { promptType: ['auto'] } },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,kBAAmC;AAAA,EAC/C,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,kBAAkB;AAAA,EAClB,SAAS;AAAA,IACR;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAAA,EACA,SAAS;AAAA,EACT,aAAa;AACd;AAMO,MAAM,8BAA8B,CAAC,WAEpB;AAAA,EACvB,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA;AAAA;AAAA,EAGT,kBAAkB;AAAA,EAClB,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,UAAU;AAAA,IACxB;AAAA,EACD;AAAA,EACA,aAAa;AACd;AAMO,MAAM,+BAA+B,CAAC,WAErB;AAAA,EACvB,aACC;AAAA,EACD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,UAAU;AAAA,IACxB;AAAA,EACD;AACD;AAEO,MAAM,yBAAyB,4BAA4B;AAE3D,MAAM,wBAAwB,CAAC,WAEd;AAAA,EACvB,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,kBAAkB;AAAA,EAClB,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,MACL,GAAG,OAAO;AAAA,MACV,YAAY,CAAC,QAAQ;AAAA,IACtB;AAAA,EACD;AAAA,EACA,aAAa;AAAA,EACb,MAAM;AACP;AAEO,MAAM,mBAAmB,sBAAsB;AAE/C,MAAM,oBAAqC;AAAA,EACjD,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,IACR;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACC;AAAA,IACF;AAAA,IACA;AAAA,MACC,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACd;AAAA,EACD;AAAA,EACA,SAAS;AACV;AAEO,MAAM,YAA6B;AAAA,EACzC,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AACD;AAEO,MAAM,uBAAwC;AAAA,EACpD,aAAa;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,aAAa;AAAA,IACZ,MAAM;AAAA,EACP;AAAA,EACA,iBAAiB,EAAE,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,EAAE;AACnD;","names":[]}
@@ -23,6 +23,7 @@ __export(helpers_exports, {
23
23
  getMetadataFiltersValues: () => getMetadataFiltersValues,
24
24
  getPromptInputByType: () => getPromptInputByType,
25
25
  getSessionId: () => getSessionId,
26
+ hasLongSequentialRepeat: () => hasLongSequentialRepeat,
26
27
  isBaseChatMemory: () => isBaseChatMemory,
27
28
  isBaseChatMessageHistory: () => isBaseChatMessageHistory,
28
29
  isChatInstance: () => isChatInstance,
@@ -176,6 +177,33 @@ function unwrapNestedOutput(output) {
176
177
  function nodeNameToToolName(node) {
177
178
  return node.name.replace(/[\s.?!=+#@&*()[\]{}:;,<>\/\\'"^%$]/g, "_").replace(/_+/g, "_");
178
179
  }
180
+ function hasLongSequentialRepeat(text, threshold = 1e3) {
181
+ try {
182
+ if (text === null || typeof text !== "string" || text.length === 0 || threshold <= 0 || text.length < threshold) {
183
+ return false;
184
+ }
185
+ const iterator = text[Symbol.iterator]();
186
+ let prev = iterator.next();
187
+ if (prev.done) {
188
+ return false;
189
+ }
190
+ let count = 1;
191
+ for (const char of iterator) {
192
+ if (char === prev.value) {
193
+ count++;
194
+ if (count >= threshold) {
195
+ return true;
196
+ }
197
+ } else {
198
+ count = 1;
199
+ prev = { value: char, done: false };
200
+ }
201
+ }
202
+ return false;
203
+ } catch (error) {
204
+ return false;
205
+ }
206
+ }
179
207
  // Annotate the CommonJS export names for ESM import in node:
180
208
  0 && (module.exports = {
181
209
  escapeSingleCurlyBrackets,
@@ -183,6 +211,7 @@ function nodeNameToToolName(node) {
183
211
  getMetadataFiltersValues,
184
212
  getPromptInputByType,
185
213
  getSessionId,
214
+ hasLongSequentialRepeat,
186
215
  isBaseChatMemory,
187
216
  isBaseChatMessageHistory,
188
217
  isChatInstance,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../utils/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/agents';\nimport type { BaseChatMemory } from 'langchain/memory';\nimport { NodeConnectionTypes, NodeOperationError, jsonStringify } from 'n8n-workflow';\nimport type {\n\tAiEvent,\n\tINode,\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;\n\ti: number;\n\tpromptTypeKey: string;\n\tinputKey: string;\n}) {\n\tconst { ctx, i, promptTypeKey, inputKey } = options;\n\tconst prompt = ctx.getNodeParameter(promptTypeKey, i) as string;\n\n\tlet input;\n\tif (prompt === 'auto') {\n\t\tinput = ctx.evaluateExpression('{{ $json[\"chatInput\"] }}', i) as string;\n\t} else {\n\t\tinput = ctx.getNodeParameter(inputKey, i) as string;\n\t}\n\n\tif (input === undefined) {\n\t\tthrow new NodeOperationError(ctx.getNode(), 'No prompt specified', {\n\t\t\tdescription:\n\t\t\t\t\"Expected to find the prompt in an input field called 'chatInput' (this is what the chat trigger 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\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,\n\tenforceUniqueNames: boolean,\n\tconvertStructuredTool: boolean = true,\n\tescapeCurlyBrackets: boolean = false,\n) => {\n\tconst connectedTools = (\n\t\t((await ctx.getInputConnectionData(NodeConnectionTypes.AiTool, 0)) as Array<Toolkit | Tool>) ??\n\t\t[]\n\t).flatMap((toolOrToolkit) => {\n\t\tif (toolOrToolkit instanceof Toolkit) {\n\t\t\treturn toolOrToolkit.getTools() as Tool[];\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 * Converts a node name to a valid tool name by replacing special characters with underscores\n * and collapsing consecutive underscores into a single one.\n */\nexport function nodeNameToToolName(node: INode): string {\n\treturn node.name.replace(/[\\s.?!=+#@&*()[\\]{}:;,<>\\/\\\\'\"^%$]/g, '_').replace(/_+/g, '_');\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../utils/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/agents';\nimport type { BaseChatMemory } from 'langchain/memory';\nimport { NodeConnectionTypes, NodeOperationError, jsonStringify } from 'n8n-workflow';\nimport type {\n\tAiEvent,\n\tINode,\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;\n\ti: number;\n\tpromptTypeKey: string;\n\tinputKey: string;\n}) {\n\tconst { ctx, i, promptTypeKey, inputKey } = options;\n\tconst prompt = ctx.getNodeParameter(promptTypeKey, i) as string;\n\n\tlet input;\n\tif (prompt === 'auto') {\n\t\tinput = ctx.evaluateExpression('{{ $json[\"chatInput\"] }}', i) as string;\n\t} else {\n\t\tinput = ctx.getNodeParameter(inputKey, i) as string;\n\t}\n\n\tif (input === undefined) {\n\t\tthrow new NodeOperationError(ctx.getNode(), 'No prompt specified', {\n\t\t\tdescription:\n\t\t\t\t\"Expected to find the prompt in an input field called 'chatInput' (this is what the chat trigger 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\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,\n\tenforceUniqueNames: boolean,\n\tconvertStructuredTool: boolean = true,\n\tescapeCurlyBrackets: boolean = false,\n) => {\n\tconst connectedTools = (\n\t\t((await ctx.getInputConnectionData(NodeConnectionTypes.AiTool, 0)) as Array<Toolkit | Tool>) ??\n\t\t[]\n\t).flatMap((toolOrToolkit) => {\n\t\tif (toolOrToolkit instanceof Toolkit) {\n\t\t\treturn toolOrToolkit.getTools() as Tool[];\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 * Converts a node name to a valid tool name by replacing special characters with underscores\n * and collapsing consecutive underscores into a single one.\n */\nexport function nodeNameToToolName(node: INode): string {\n\treturn node.name.replace(/[\\s.?!=+#@&*()[\\]{}:;,<>\\/\\\\'\"^%$]/g, '_').replace(/_+/g, '_');\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}\n"],"mappings":"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","names":[]}
@@ -28,12 +28,12 @@ var import_n8n_workflow = require("n8n-workflow");
28
28
  var import_N8nItemListOutputParser = require("./N8nItemListOutputParser");
29
29
  var import_N8nOutputFixingParser = require("./N8nOutputFixingParser");
30
30
  var import_N8nStructuredOutputParser = require("./N8nStructuredOutputParser");
31
- async function getOptionalOutputParser(ctx) {
31
+ async function getOptionalOutputParser(ctx, index = 0) {
32
32
  let outputParser;
33
33
  if (ctx.getNodeParameter("hasOutputParser", 0, true) === true) {
34
34
  outputParser = await ctx.getInputConnectionData(
35
35
  import_n8n_workflow.NodeConnectionTypes.AiOutputParser,
36
- 0
36
+ index
37
37
  );
38
38
  }
39
39
  return outputParser;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../utils/output_parsers/N8nOutputParser.ts"],"sourcesContent":["import type { IExecuteFunctions } from 'n8n-workflow';\nimport { NodeConnectionTypes } from 'n8n-workflow';\n\nimport { N8nItemListOutputParser } from './N8nItemListOutputParser';\nimport { N8nOutputFixingParser } from './N8nOutputFixingParser';\nimport { N8nStructuredOutputParser } from './N8nStructuredOutputParser';\n\nexport type N8nOutputParser =\n\t| N8nOutputFixingParser\n\t| N8nStructuredOutputParser\n\t| N8nItemListOutputParser;\n\nexport { N8nOutputFixingParser, N8nItemListOutputParser, N8nStructuredOutputParser };\n\nexport async function getOptionalOutputParser(\n\tctx: IExecuteFunctions,\n): Promise<N8nOutputParser | undefined> {\n\tlet outputParser: N8nOutputParser | undefined;\n\n\tif (ctx.getNodeParameter('hasOutputParser', 0, true) === true) {\n\t\toutputParser = (await ctx.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiOutputParser,\n\t\t\t0,\n\t\t)) as N8nOutputParser;\n\t}\n\n\treturn outputParser;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAoC;AAEpC,qCAAwC;AACxC,mCAAsC;AACtC,uCAA0C;AAS1C,eAAsB,wBACrB,KACuC;AACvC,MAAI;AAEJ,MAAI,IAAI,iBAAiB,mBAAmB,GAAG,IAAI,MAAM,MAAM;AAC9D,mBAAgB,MAAM,IAAI;AAAA,MACzB,wCAAoB;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;","names":[]}
1
+ {"version":3,"sources":["../../../utils/output_parsers/N8nOutputParser.ts"],"sourcesContent":["import type { IExecuteFunctions } from 'n8n-workflow';\nimport { NodeConnectionTypes } from 'n8n-workflow';\n\nimport { N8nItemListOutputParser } from './N8nItemListOutputParser';\nimport { N8nOutputFixingParser } from './N8nOutputFixingParser';\nimport { N8nStructuredOutputParser } from './N8nStructuredOutputParser';\n\nexport type N8nOutputParser =\n\t| N8nOutputFixingParser\n\t| N8nStructuredOutputParser\n\t| N8nItemListOutputParser;\n\nexport { N8nOutputFixingParser, N8nItemListOutputParser, N8nStructuredOutputParser };\n\nexport async function getOptionalOutputParser(\n\tctx: IExecuteFunctions,\n\tindex: number = 0,\n): Promise<N8nOutputParser | undefined> {\n\tlet outputParser: N8nOutputParser | undefined;\n\n\tif (ctx.getNodeParameter('hasOutputParser', 0, true) === true) {\n\t\toutputParser = (await ctx.getInputConnectionData(\n\t\t\tNodeConnectionTypes.AiOutputParser,\n\t\t\tindex,\n\t\t)) as N8nOutputParser;\n\t}\n\n\treturn outputParser;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAoC;AAEpC,qCAAwC;AACxC,mCAAsC;AACtC,uCAA0C;AAS1C,eAAsB,wBACrB,KACA,QAAgB,GACuB;AACvC,MAAI;AAEJ,MAAI,IAAI,iBAAiB,mBAAmB,GAAG,IAAI,MAAM,MAAM;AAC9D,mBAAgB,MAAM,IAAI;AAAA,MACzB,wCAAoB;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;","names":[]}
@@ -0,0 +1,119 @@
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 token_estimator_exports = {};
20
+ __export(token_estimator_exports, {
21
+ estimateTextSplitsByTokens: () => estimateTextSplitsByTokens,
22
+ estimateTokensByCharCount: () => estimateTokensByCharCount,
23
+ estimateTokensFromStringList: () => estimateTokensFromStringList
24
+ });
25
+ module.exports = __toCommonJS(token_estimator_exports);
26
+ var import_tiktoken = require("./tiktoken");
27
+ var import_helpers = require("../helpers");
28
+ const MODEL_CHAR_PER_TOKEN_RATIOS = {
29
+ "gpt-4o": 3.8,
30
+ "gpt-4": 4,
31
+ "gpt-3.5-turbo": 4,
32
+ cl100k_base: 4,
33
+ o200k_base: 3.5,
34
+ p50k_base: 4.2,
35
+ r50k_base: 4.2
36
+ };
37
+ function estimateTokensByCharCount(text, model = "cl100k_base") {
38
+ try {
39
+ if (!text || typeof text !== "string" || text.length === 0) {
40
+ return 0;
41
+ }
42
+ const charsPerToken = MODEL_CHAR_PER_TOKEN_RATIOS[model] || 4;
43
+ if (!Number.isFinite(charsPerToken) || charsPerToken <= 0) {
44
+ const estimatedTokens2 = Math.ceil(text.length / 4);
45
+ return estimatedTokens2;
46
+ }
47
+ const estimatedTokens = Math.ceil(text.length / charsPerToken);
48
+ return estimatedTokens;
49
+ } catch (error) {
50
+ return Math.ceil((text?.length || 0) / 4);
51
+ }
52
+ }
53
+ function estimateTextSplitsByTokens(text, chunkSize, chunkOverlap, model = "cl100k_base") {
54
+ try {
55
+ if (!text || typeof text !== "string" || text.length === 0) {
56
+ return [];
57
+ }
58
+ if (!Number.isFinite(chunkSize) || chunkSize <= 0) {
59
+ return [text];
60
+ }
61
+ const validOverlap = Number.isFinite(chunkOverlap) && chunkOverlap >= 0 ? Math.min(chunkOverlap, chunkSize - 1) : 0;
62
+ const charsPerToken = MODEL_CHAR_PER_TOKEN_RATIOS[model] || 4;
63
+ const chunkSizeInChars = Math.floor(chunkSize * charsPerToken);
64
+ const overlapInChars = Math.floor(validOverlap * charsPerToken);
65
+ const chunks = [];
66
+ let start = 0;
67
+ while (start < text.length) {
68
+ const end = Math.min(start + chunkSizeInChars, text.length);
69
+ chunks.push(text.slice(start, end));
70
+ if (end >= text.length) {
71
+ break;
72
+ }
73
+ start = Math.max(end - overlapInChars, start + 1);
74
+ }
75
+ return chunks;
76
+ } catch (error) {
77
+ return text ? [text] : [];
78
+ }
79
+ }
80
+ async function estimateTokensFromStringList(list, model) {
81
+ try {
82
+ if (!Array.isArray(list)) {
83
+ return 0;
84
+ }
85
+ const encoder = await (0, import_tiktoken.encodingForModel)(model);
86
+ const encodedListLength = await Promise.all(
87
+ list.map(async (text) => {
88
+ try {
89
+ if (!text || typeof text !== "string") {
90
+ return 0;
91
+ }
92
+ if ((0, import_helpers.hasLongSequentialRepeat)(text)) {
93
+ const estimatedTokens = estimateTokensByCharCount(text, model);
94
+ return estimatedTokens;
95
+ }
96
+ try {
97
+ const tokens = encoder.encode(text);
98
+ return tokens.length;
99
+ } catch (encodingError) {
100
+ return estimateTokensByCharCount(text, model);
101
+ }
102
+ } catch (itemError) {
103
+ return 0;
104
+ }
105
+ })
106
+ );
107
+ const totalTokens = encodedListLength.reduce((acc, curr) => acc + curr, 0);
108
+ return totalTokens;
109
+ } catch (error) {
110
+ return 0;
111
+ }
112
+ }
113
+ // Annotate the CommonJS export names for ESM import in node:
114
+ 0 && (module.exports = {
115
+ estimateTextSplitsByTokens,
116
+ estimateTokensByCharCount,
117
+ estimateTokensFromStringList
118
+ });
119
+ //# sourceMappingURL=token-estimator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../utils/tokenizer/token-estimator.ts"],"sourcesContent":["/**\n * Token estimation utilities for handling text without using tiktoken.\n * This is used as a fallback when tiktoken would be too slow (e.g., with repetitive content).\n */\n\nimport type { TiktokenModel } from 'js-tiktoken';\n\nimport { encodingForModel } from './tiktoken';\nimport { hasLongSequentialRepeat } from '../helpers';\n\n/**\n * Model-specific average characters per token ratios.\n * These are approximate values based on typical English text.\n */\nconst MODEL_CHAR_PER_TOKEN_RATIOS: Record<string, number> = {\n\t'gpt-4o': 3.8,\n\t'gpt-4': 4.0,\n\t'gpt-3.5-turbo': 4.0,\n\tcl100k_base: 4.0,\n\to200k_base: 3.5,\n\tp50k_base: 4.2,\n\tr50k_base: 4.2,\n};\n\n/**\n * Estimates the number of tokens in a text based on character count.\n * This is much faster than tiktoken but less accurate.\n *\n * @param text The text to estimate tokens for\n * @param model The model or encoding name (optional)\n * @returns Estimated number of tokens\n */\nexport function estimateTokensByCharCount(text: string, model: string = 'cl100k_base'): number {\n\ttry {\n\t\t// Validate input\n\t\tif (!text || typeof text !== 'string' || text.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Get the ratio for the specific model, or use default\n\t\tconst charsPerToken = MODEL_CHAR_PER_TOKEN_RATIOS[model] || 4.0;\n\n\t\t// Validate ratio\n\t\tif (!Number.isFinite(charsPerToken) || charsPerToken <= 0) {\n\t\t\t// Fallback to default ratio\n\t\t\tconst estimatedTokens = Math.ceil(text.length / 4.0);\n\t\t\treturn estimatedTokens;\n\t\t}\n\n\t\t// Calculate estimated tokens\n\t\tconst estimatedTokens = Math.ceil(text.length / charsPerToken);\n\n\t\treturn estimatedTokens;\n\t} catch (error) {\n\t\t// Return conservative estimate on error\n\t\treturn Math.ceil((text?.length || 0) / 4.0);\n\t}\n}\n\n/**\n * Estimates tokens for text splitting purposes.\n * Returns chunk boundaries based on character positions rather than token positions.\n *\n * @param text The text to split\n * @param chunkSize Target chunk size in tokens\n * @param chunkOverlap Overlap between chunks in tokens\n * @param model The model or encoding name (optional)\n * @returns Array of text chunks\n */\nexport function estimateTextSplitsByTokens(\n\ttext: string,\n\tchunkSize: number,\n\tchunkOverlap: number,\n\tmodel: string = 'cl100k_base',\n): string[] {\n\ttry {\n\t\t// Validate inputs\n\t\tif (!text || typeof text !== 'string' || text.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Validate numeric parameters\n\t\tif (!Number.isFinite(chunkSize) || chunkSize <= 0) {\n\t\t\t// Return whole text as single chunk if invalid chunk size\n\t\t\treturn [text];\n\t\t}\n\n\t\t// Ensure overlap is valid and less than chunk size\n\t\tconst validOverlap =\n\t\t\tNumber.isFinite(chunkOverlap) && chunkOverlap >= 0\n\t\t\t\t? Math.min(chunkOverlap, chunkSize - 1)\n\t\t\t\t: 0;\n\n\t\tconst charsPerToken = MODEL_CHAR_PER_TOKEN_RATIOS[model] || 4.0;\n\t\tconst chunkSizeInChars = Math.floor(chunkSize * charsPerToken);\n\t\tconst overlapInChars = Math.floor(validOverlap * charsPerToken);\n\n\t\tconst chunks: string[] = [];\n\t\tlet start = 0;\n\n\t\twhile (start < text.length) {\n\t\t\tconst end = Math.min(start + chunkSizeInChars, text.length);\n\t\t\tchunks.push(text.slice(start, end));\n\n\t\t\tif (end >= text.length) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Move to next chunk with overlap\n\t\t\tstart = Math.max(end - overlapInChars, start + 1);\n\t\t}\n\n\t\treturn chunks;\n\t} catch (error) {\n\t\t// Return text as single chunk on error\n\t\treturn text ? [text] : [];\n\t}\n}\n\n/**\n * Estimates the total number of tokens for a list of strings.\n * Uses tiktoken for normal text but falls back to character-based estimation\n * for repetitive content or on errors.\n *\n * @param list Array of strings to estimate tokens for\n * @param model The model or encoding name to use for estimation\n * @returns Total estimated number of tokens across all strings\n */\nexport async function estimateTokensFromStringList(\n\tlist: string[],\n\tmodel: TiktokenModel,\n): Promise<number> {\n\ttry {\n\t\t// Validate input\n\t\tif (!Array.isArray(list)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst encoder = await encodingForModel(model);\n\t\tconst encodedListLength = await Promise.all(\n\t\t\tlist.map(async (text) => {\n\t\t\t\ttry {\n\t\t\t\t\t// Handle null/undefined text\n\t\t\t\t\tif (!text || typeof text !== 'string') {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check for repetitive content\n\t\t\t\t\tif (hasLongSequentialRepeat(text)) {\n\t\t\t\t\t\tconst estimatedTokens = estimateTokensByCharCount(text, model);\n\t\t\t\t\t\treturn estimatedTokens;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use tiktoken for normal text\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst tokens = encoder.encode(text);\n\t\t\t\t\t\treturn tokens.length;\n\t\t\t\t\t} catch (encodingError) {\n\t\t\t\t\t\t// Fall back to estimation if tiktoken fails\n\t\t\t\t\t\treturn estimateTokensByCharCount(text, model);\n\t\t\t\t\t}\n\t\t\t\t} catch (itemError) {\n\t\t\t\t\t// Return 0 for individual item errors\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\tconst totalTokens = encodedListLength.reduce((acc, curr) => acc + curr, 0);\n\n\t\treturn totalTokens;\n\t} catch (error) {\n\t\t// Return 0 on complete failure\n\t\treturn 0;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAAiC;AACjC,qBAAwC;AAMxC,MAAM,8BAAsD;AAAA,EAC3D,UAAU;AAAA,EACV,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AACZ;AAUO,SAAS,0BAA0B,MAAc,QAAgB,eAAuB;AAC9F,MAAI;AAEH,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,KAAK,WAAW,GAAG;AAC3D,aAAO;AAAA,IACR;AAGA,UAAM,gBAAgB,4BAA4B,KAAK,KAAK;AAG5D,QAAI,CAAC,OAAO,SAAS,aAAa,KAAK,iBAAiB,GAAG;AAE1D,YAAMA,mBAAkB,KAAK,KAAK,KAAK,SAAS,CAAG;AACnD,aAAOA;AAAA,IACR;AAGA,UAAM,kBAAkB,KAAK,KAAK,KAAK,SAAS,aAAa;AAE7D,WAAO;AAAA,EACR,SAAS,OAAO;AAEf,WAAO,KAAK,MAAM,MAAM,UAAU,KAAK,CAAG;AAAA,EAC3C;AACD;AAYO,SAAS,2BACf,MACA,WACA,cACA,QAAgB,eACL;AACX,MAAI;AAEH,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,KAAK,WAAW,GAAG;AAC3D,aAAO,CAAC;AAAA,IACT;AAGA,QAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,GAAG;AAElD,aAAO,CAAC,IAAI;AAAA,IACb;AAGA,UAAM,eACL,OAAO,SAAS,YAAY,KAAK,gBAAgB,IAC9C,KAAK,IAAI,cAAc,YAAY,CAAC,IACpC;AAEJ,UAAM,gBAAgB,4BAA4B,KAAK,KAAK;AAC5D,UAAM,mBAAmB,KAAK,MAAM,YAAY,aAAa;AAC7D,UAAM,iBAAiB,KAAK,MAAM,eAAe,aAAa;AAE9D,UAAM,SAAmB,CAAC;AAC1B,QAAI,QAAQ;AAEZ,WAAO,QAAQ,KAAK,QAAQ;AAC3B,YAAM,MAAM,KAAK,IAAI,QAAQ,kBAAkB,KAAK,MAAM;AAC1D,aAAO,KAAK,KAAK,MAAM,OAAO,GAAG,CAAC;AAElC,UAAI,OAAO,KAAK,QAAQ;AACvB;AAAA,MACD;AAGA,cAAQ,KAAK,IAAI,MAAM,gBAAgB,QAAQ,CAAC;AAAA,IACjD;AAEA,WAAO;AAAA,EACR,SAAS,OAAO;AAEf,WAAO,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,EACzB;AACD;AAWA,eAAsB,6BACrB,MACA,OACkB;AAClB,MAAI;AAEH,QAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACzB,aAAO;AAAA,IACR;AAEA,UAAM,UAAU,UAAM,kCAAiB,KAAK;AAC5C,UAAM,oBAAoB,MAAM,QAAQ;AAAA,MACvC,KAAK,IAAI,OAAO,SAAS;AACxB,YAAI;AAEH,cAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACtC,mBAAO;AAAA,UACR;AAGA,kBAAI,wCAAwB,IAAI,GAAG;AAClC,kBAAM,kBAAkB,0BAA0B,MAAM,KAAK;AAC7D,mBAAO;AAAA,UACR;AAGA,cAAI;AACH,kBAAM,SAAS,QAAQ,OAAO,IAAI;AAClC,mBAAO,OAAO;AAAA,UACf,SAAS,eAAe;AAEvB,mBAAO,0BAA0B,MAAM,KAAK;AAAA,UAC7C;AAAA,QACD,SAAS,WAAW;AAEnB,iBAAO;AAAA,QACR;AAAA,MACD,CAAC;AAAA,IACF;AAEA,UAAM,cAAc,kBAAkB,OAAO,CAAC,KAAK,SAAS,MAAM,MAAM,CAAC;AAEzE,WAAO;AAAA,EACR,SAAS,OAAO;AAEf,WAAO;AAAA,EACR;AACD;","names":["estimatedTokens"]}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@n8n/n8n-nodes-langchain",
3
- "version": "1.99.1",
3
+ "version": "1.100.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "dist",
8
- "LICENSE.md",
9
- "LICENSE_EE.md"
8
+ "LICENSE_EE.md",
9
+ "LICENSE.md"
10
10
  ],
11
11
  "n8n": {
12
12
  "n8nNodesApiVersion": 1,
@@ -136,8 +136,9 @@
136
136
  "@types/pg": "^8.11.6",
137
137
  "@types/sanitize-html": "^2.11.0",
138
138
  "@types/temp": "^0.9.1",
139
- "tsup": "^8.4.0",
140
- "n8n-core": "1.99.0"
139
+ "fast-glob": "3.2.12",
140
+ "tsup": "^8.5.0",
141
+ "n8n-core": "1.100.0"
141
142
  },
142
143
  "dependencies": {
143
144
  "@aws-sdk/client-sso-oidc": "3.808.0",
@@ -199,11 +200,11 @@
199
200
  "tmp-promise": "3.0.3",
200
201
  "zod": "3.25.67",
201
202
  "zod-to-json-schema": "3.23.3",
202
- "@n8n/client-oauth2": "0.26.0",
203
- "@n8n/json-schema-to-zod": "1.3.0",
203
+ "@n8n/client-oauth2": "0.27.0",
204
+ "@n8n/json-schema-to-zod": "1.4.0",
204
205
  "@n8n/typescript-config": "1.2.0",
205
- "n8n-nodes-base": "1.98.1",
206
- "n8n-workflow": "1.97.0"
206
+ "n8n-workflow": "1.98.0",
207
+ "n8n-nodes-base": "1.99.1"
207
208
  },
208
209
  "license": "SEE LICENSE IN LICENSE.md",
209
210
  "homepage": "https://n8n.io",
@@ -220,7 +221,8 @@
220
221
  "dev": "pnpm run watch",
221
222
  "typecheck": "tsc --noEmit",
222
223
  "copy-nodes-json": "node ../../nodes-base/scripts/copy-nodes-json.js .",
223
- "build": "tsup --tsconfig tsconfig.build.json && pnpm copy-nodes-json && tsc-alias -p tsconfig.build.json && cp utils/tokenizer/*.json dist/utils/tokenizer/ && pnpm n8n-copy-static-files && pnpm n8n-generate-metadata",
224
+ "copy-tokenizer-json": "node scripts/copy-tokenizer-json.js .",
225
+ "build": "tsup --tsconfig tsconfig.build.json && pnpm copy-nodes-json && tsc-alias -p tsconfig.build.json && pnpm copy-tokenizer-json && pnpm n8n-copy-static-files && pnpm n8n-generate-metadata",
224
226
  "format": "biome format --write .",
225
227
  "format:check": "biome ci .",
226
228
  "lint": "eslint nodes credentials utils --quiet",