@n8n/n8n-nodes-langchain 1.121.0 → 1.122.0

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 (137) hide show
  1. package/dist/nodes/Guardrails/Guardrails.node.js +29 -40
  2. package/dist/nodes/Guardrails/Guardrails.node.js.map +1 -1
  3. package/dist/nodes/Guardrails/actions/execute.js +68 -0
  4. package/dist/nodes/Guardrails/actions/execute.js.map +1 -0
  5. package/dist/nodes/Guardrails/actions/process.js +10 -7
  6. package/dist/nodes/Guardrails/actions/process.js.map +1 -1
  7. package/dist/nodes/Guardrails/description.js +326 -365
  8. package/dist/nodes/Guardrails/description.js.map +1 -1
  9. package/dist/nodes/Guardrails/helpers/configureNodeInputs.js +37 -3
  10. package/dist/nodes/Guardrails/helpers/configureNodeInputs.js.map +1 -1
  11. package/dist/nodes/Guardrails/helpers/model.js.map +1 -1
  12. package/dist/nodes/Guardrails/v1/GuardrailsV1.node.js +59 -0
  13. package/dist/nodes/Guardrails/v1/GuardrailsV1.node.js.map +1 -0
  14. package/dist/nodes/Guardrails/v2/GuardrailsV2.node.js +59 -0
  15. package/dist/nodes/Guardrails/v2/GuardrailsV2.node.js.map +1 -0
  16. package/dist/nodes/ToolExecutor/ToolExecutor.node.js.map +1 -1
  17. package/dist/nodes/agents/Agent/agents/ConversationalAgent/execute.js +1 -1
  18. package/dist/nodes/agents/Agent/agents/ConversationalAgent/execute.js.map +1 -1
  19. package/dist/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.js +3 -85
  20. package/dist/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.js.map +1 -1
  21. package/dist/nodes/agents/Agent/agents/PlanAndExecuteAgent/execute.js +1 -1
  22. package/dist/nodes/agents/Agent/agents/PlanAndExecuteAgent/execute.js.map +1 -1
  23. package/dist/nodes/agents/Agent/agents/ReActAgent/execute.js +1 -1
  24. package/dist/nodes/agents/Agent/agents/ReActAgent/execute.js.map +1 -1
  25. package/dist/nodes/agents/Agent/agents/SqlAgent/execute.js +2 -2
  26. package/dist/nodes/agents/Agent/agents/SqlAgent/execute.js.map +1 -1
  27. package/dist/nodes/agents/Agent/agents/ToolsAgent/V1/execute.js +1 -1
  28. package/dist/nodes/agents/Agent/agents/ToolsAgent/V1/execute.js.map +1 -1
  29. package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js +1 -1
  30. package/dist/nodes/agents/Agent/agents/ToolsAgent/V2/execute.js.map +1 -1
  31. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/buildExecutionContext.js.map +1 -1
  32. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/createAgentSequence.js +1 -1
  33. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/createAgentSequence.js.map +1 -1
  34. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/executeBatch.js.map +1 -1
  35. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/finalizeResult.js.map +1 -1
  36. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/prepareItemContext.js.map +1 -1
  37. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/runAgent.js +8 -16
  38. package/dist/nodes/agents/Agent/agents/ToolsAgent/V3/helpers/runAgent.js.map +1 -1
  39. package/dist/nodes/agents/Agent/agents/ToolsAgent/common.js +1 -1
  40. package/dist/nodes/agents/Agent/agents/ToolsAgent/common.js.map +1 -1
  41. package/dist/nodes/agents/Agent/agents/utils.js.map +1 -1
  42. package/dist/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.js +2 -2
  43. package/dist/nodes/agents/OpenAiAssistant/OpenAiAssistant.node.js.map +1 -1
  44. package/dist/nodes/chains/ChainRetrievalQA/processItem.js +2 -2
  45. package/dist/nodes/chains/ChainRetrievalQA/processItem.js.map +1 -1
  46. package/dist/nodes/chains/ChainSummarization/V1/ChainSummarizationV1.node.js +1 -1
  47. package/dist/nodes/chains/ChainSummarization/V1/ChainSummarizationV1.node.js.map +1 -1
  48. package/dist/nodes/chains/ChainSummarization/V2/processItem.js +1 -1
  49. package/dist/nodes/chains/ChainSummarization/V2/processItem.js.map +1 -1
  50. package/dist/nodes/chains/ChainSummarization/helpers.js.map +1 -1
  51. package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js +1 -1
  52. package/dist/nodes/chains/InformationExtractor/InformationExtractor.node.js.map +1 -1
  53. package/dist/nodes/chains/InformationExtractor/processItem.js.map +1 -1
  54. package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js +1 -1
  55. package/dist/nodes/chains/SentimentAnalysis/SentimentAnalysis.node.js.map +1 -1
  56. package/dist/nodes/chains/TextClassifier/TextClassifier.node.js +1 -1
  57. package/dist/nodes/chains/TextClassifier/TextClassifier.node.js.map +1 -1
  58. package/dist/nodes/chains/TextClassifier/processItem.js.map +1 -1
  59. package/dist/nodes/code/Code.node.js +66 -2
  60. package/dist/nodes/code/Code.node.js.map +1 -1
  61. package/dist/nodes/llms/LMOllama/LmOllama.node.js +1 -1
  62. package/dist/nodes/llms/LMOllama/LmOllama.node.js.map +1 -1
  63. package/dist/nodes/mcp/McpClientTool/utils.js +1 -1
  64. package/dist/nodes/mcp/McpClientTool/utils.js.map +1 -1
  65. package/dist/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.js +1 -1
  66. package/dist/nodes/memory/MemoryBufferWindow/MemoryBufferWindow.node.js.map +1 -1
  67. package/dist/nodes/memory/MemoryMongoDbChat/MemoryMongoDbChat.node.js +1 -1
  68. package/dist/nodes/memory/MemoryMongoDbChat/MemoryMongoDbChat.node.js.map +1 -1
  69. package/dist/nodes/memory/MemoryPostgresChat/MemoryPostgresChat.node.js +1 -1
  70. package/dist/nodes/memory/MemoryPostgresChat/MemoryPostgresChat.node.js.map +1 -1
  71. package/dist/nodes/memory/MemoryRedisChat/MemoryRedisChat.node.js +1 -1
  72. package/dist/nodes/memory/MemoryRedisChat/MemoryRedisChat.node.js.map +1 -1
  73. package/dist/nodes/memory/MemoryXata/MemoryXata.node.js +1 -1
  74. package/dist/nodes/memory/MemoryXata/MemoryXata.node.js.map +1 -1
  75. package/dist/nodes/retrievers/RetrieverContextualCompression/RetrieverContextualCompression.node.js +2 -2
  76. package/dist/nodes/retrievers/RetrieverContextualCompression/RetrieverContextualCompression.node.js.map +1 -1
  77. package/dist/nodes/retrievers/RetrieverMultiQuery/RetrieverMultiQuery.node.js +1 -1
  78. package/dist/nodes/retrievers/RetrieverMultiQuery/RetrieverMultiQuery.node.js.map +1 -1
  79. package/dist/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.js +1 -1
  80. package/dist/nodes/retrievers/RetrieverVectorStore/RetrieverVectorStore.node.js.map +1 -1
  81. package/dist/nodes/tools/ToolThink/ToolThink.node.js +1 -1
  82. package/dist/nodes/tools/ToolThink/ToolThink.node.js.map +1 -1
  83. package/dist/nodes/tools/ToolVectorStore/ToolVectorStore.node.js +2 -2
  84. package/dist/nodes/tools/ToolVectorStore/ToolVectorStore.node.js.map +1 -1
  85. package/dist/nodes/tools/ToolWorkflow/v2/utils/WorkflowToolService.js +5 -21
  86. package/dist/nodes/tools/ToolWorkflow/v2/utils/WorkflowToolService.js.map +1 -1
  87. package/dist/nodes/trigger/ChatTrigger/Chat.node.js +2 -2
  88. package/dist/nodes/trigger/ChatTrigger/Chat.node.js.map +1 -1
  89. package/dist/nodes/trigger/ChatTrigger/ChatTrigger.node.js +1 -1
  90. package/dist/nodes/trigger/ChatTrigger/ChatTrigger.node.js.map +1 -1
  91. package/dist/nodes/vector_store/VectorStoreAzureAISearch/VectorStoreAzureAISearch.node.js +65 -17
  92. package/dist/nodes/vector_store/VectorStoreAzureAISearch/VectorStoreAzureAISearch.node.js.map +1 -1
  93. package/dist/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.js.map +1 -1
  94. package/dist/nodes/vector_store/VectorStoreInMemoryInsert/VectorStoreInMemoryInsert.node.js.map +1 -1
  95. package/dist/nodes/vector_store/VectorStoreQdrant/qdrant.svg +23 -19
  96. package/dist/nodes/vector_store/shared/MemoryManager/MemoryCalculator.js.map +1 -1
  97. package/dist/nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.js +1 -1
  98. package/dist/nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.js.map +1 -1
  99. package/dist/nodes/vector_store/shared/MemoryManager/StoreCleanupService.js.map +1 -1
  100. package/dist/nodes/vector_store/shared/MemoryManager/types.js.map +1 -1
  101. package/dist/nodes/vector_store/shared/createVectorStoreNode/operations/retrieveAsToolOperation.js +18 -16
  102. package/dist/nodes/vector_store/shared/createVectorStoreNode/operations/retrieveAsToolOperation.js.map +1 -1
  103. package/dist/nodes/vendors/GoogleGemini/actions/image/edit.operation.js +6 -1
  104. package/dist/nodes/vendors/GoogleGemini/actions/image/edit.operation.js.map +1 -1
  105. package/dist/nodes/vendors/GoogleGemini/actions/image/generate.operation.js +1 -1
  106. package/dist/nodes/vendors/GoogleGemini/actions/image/generate.operation.js.map +1 -1
  107. package/dist/nodes/vendors/GoogleGemini/methods/listSearch.js +23 -8
  108. package/dist/nodes/vendors/GoogleGemini/methods/listSearch.js.map +1 -1
  109. package/dist/nodes/vendors/OpenAi/helpers/utils.js.map +1 -1
  110. package/dist/nodes/vendors/OpenAi/v1/actions/assistant/message.operation.js +2 -2
  111. package/dist/nodes/vendors/OpenAi/v1/actions/assistant/message.operation.js.map +1 -1
  112. package/dist/types/nodes.json +7 -6
  113. package/dist/utils/N8nBinaryLoader.js +2 -2
  114. package/dist/utils/N8nBinaryLoader.js.map +1 -1
  115. package/dist/utils/N8nJsonLoader.js +2 -2
  116. package/dist/utils/N8nJsonLoader.js.map +1 -1
  117. package/dist/utils/N8nTool.js +1 -1
  118. package/dist/utils/N8nTool.js.map +1 -1
  119. package/dist/utils/agent-execution/buildSteps.js +12 -8
  120. package/dist/utils/agent-execution/buildSteps.js.map +1 -1
  121. package/dist/utils/agent-execution/createEngineRequests.js +19 -1
  122. package/dist/utils/agent-execution/createEngineRequests.js.map +1 -1
  123. package/dist/utils/agent-execution/index.js +4 -4
  124. package/dist/utils/agent-execution/index.js.map +1 -1
  125. package/dist/utils/agent-execution/memoryManagement.js +15 -14
  126. package/dist/utils/agent-execution/memoryManagement.js.map +1 -1
  127. package/dist/utils/agent-execution/processEventStream.js +1 -47
  128. package/dist/utils/agent-execution/processEventStream.js.map +1 -1
  129. package/dist/utils/agent-execution/types.js.map +1 -1
  130. package/dist/utils/fromAIToolFactory.js +61 -0
  131. package/dist/utils/fromAIToolFactory.js.map +1 -0
  132. package/dist/utils/helpers.js +1 -1
  133. package/dist/utils/helpers.js.map +1 -1
  134. package/dist/utils/logWrapper.js.map +1 -1
  135. package/dist/utils/output_parsers/N8nStructuredOutputParser.js +1 -1
  136. package/dist/utils/output_parsers/N8nStructuredOutputParser.js.map +1 -1
  137. package/package.json +31 -30
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { Embeddings } from '@langchain/core/embeddings';\nimport type { OpenAIEmbeddings, AzureOpenAIEmbeddings } from '@langchain/openai';\nimport { MemoryVectorStore } from 'langchain/vectorstores/memory';\nimport type { Logger } from 'n8n-workflow';\n\nimport { getConfig, mbToBytes, hoursToMs } from './config';\nimport { MemoryCalculator } from './MemoryCalculator';\nimport { StoreCleanupService } from './StoreCleanupService';\nimport type { VectorStoreMetadata, VectorStoreStats } from './types';\n\n/**\n * Manages in-memory vector stores with memory limits and auto-cleanup\n */\nexport class MemoryVectorStoreManager {\n\tprivate static instance: MemoryVectorStoreManager | null = null;\n\n\t// Storage\n\tprotected vectorStoreBuffer: Map<string, MemoryVectorStore>;\n\n\tprotected storeMetadata: Map<string, VectorStoreMetadata>;\n\n\tprotected memoryUsageBytes: number = 0;\n\n\t// Dependencies\n\tprotected memoryCalculator: MemoryCalculator;\n\n\tprotected cleanupService: StoreCleanupService;\n\n\tprotected static logger: Logger;\n\n\t// Config values\n\tprotected maxMemorySizeBytes: number;\n\n\tprotected inactiveTtlMs: number;\n\n\t// Inactive TTL cleanup timer\n\tprotected ttlCleanupIntervalId: NodeJS.Timeout | null = null;\n\n\tprotected constructor(\n\t\tprotected embeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tprotected logger: Logger,\n\t) {\n\t\t// Initialize storage\n\t\tthis.vectorStoreBuffer = new Map();\n\t\tthis.storeMetadata = new Map();\n\t\tthis.logger = logger;\n\n\t\tconst config = getConfig();\n\t\tthis.maxMemorySizeBytes = mbToBytes(config.maxMemoryMB);\n\t\tthis.inactiveTtlMs = hoursToMs(config.ttlHours);\n\n\t\t// Initialize services\n\t\tthis.memoryCalculator = new MemoryCalculator();\n\t\tthis.cleanupService = new StoreCleanupService(\n\t\t\tthis.maxMemorySizeBytes,\n\t\t\tthis.inactiveTtlMs,\n\t\t\tthis.vectorStoreBuffer,\n\t\t\tthis.storeMetadata,\n\t\t\tthis.handleCleanup.bind(this),\n\t\t);\n\n\t\tthis.setupTtlCleanup();\n\t}\n\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance(\n\t\tembeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tlogger: Logger,\n\t): MemoryVectorStoreManager {\n\t\tif (!MemoryVectorStoreManager.instance) {\n\t\t\tMemoryVectorStoreManager.instance = new MemoryVectorStoreManager(embeddings, logger);\n\t\t} else {\n\t\t\t// We need to update the embeddings in the existing instance.\n\t\t\t// This is important as embeddings instance is wrapped in a logWrapper,\n\t\t\t// which relies on supplyDataFunctions context which changes on each workflow run\n\t\t\tMemoryVectorStoreManager.instance.embeddings = embeddings;\n\t\t\tMemoryVectorStoreManager.instance.vectorStoreBuffer.forEach((vectorStoreInstance) => {\n\t\t\t\tvectorStoreInstance.embeddings = embeddings;\n\t\t\t});\n\t\t}\n\n\t\treturn MemoryVectorStoreManager.instance;\n\t}\n\n\t/**\n\t * Set up timer for TTL-based cleanup\n\t */\n\tprivate setupTtlCleanup(): void {\n\t\t// Skip setup if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cleanup check interval (run every hour)\n\t\tconst CLEANUP_INTERVAL_MS = 60 * 60 * 1000;\n\n\t\t// Clear any existing interval\n\t\tif (this.ttlCleanupIntervalId) {\n\t\t\tclearInterval(this.ttlCleanupIntervalId);\n\t\t}\n\n\t\t// Setup new interval for TTL cleanup\n\t\tthis.ttlCleanupIntervalId = setInterval(() => {\n\t\t\tthis.cleanupService.cleanupInactiveStores();\n\t\t}, CLEANUP_INTERVAL_MS);\n\t}\n\n\t/**\n\t * Handle cleanup events from the cleanup service\n\t */\n\tprivate handleCleanup(removedKeys: string[], freedBytes: number, reason: 'ttl' | 'memory'): void {\n\t\t// Update total memory usage\n\t\tthis.memoryUsageBytes -= freedBytes;\n\n\t\t// Log cleanup event\n\t\tif (reason === 'ttl') {\n\t\t\tconst ttlHours = Math.round(this.inactiveTtlMs / (60 * 60 * 1000));\n\t\t\tthis.logger.info(\n\t\t\t\t`TTL cleanup: removed ${removedKeys.length} inactive vector stores (${ttlHours}h TTL) to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logger.info(\n\t\t\t\t`Memory cleanup: removed ${removedKeys.length} oldest vector stores to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t}\n\t}\n\n\tgetMemoryKeysList(): string[] {\n\t\treturn Array.from(this.vectorStoreBuffer.keys());\n\t}\n\n\t/**\n\t * Get or create a vector store by key\n\t */\n\tasync getVectorStore(memoryKey: string): Promise<MemoryVectorStore> {\n\t\tlet vectorStoreInstance = this.vectorStoreBuffer.get(memoryKey);\n\n\t\tif (!vectorStoreInstance) {\n\t\t\tvectorStoreInstance = await MemoryVectorStore.fromExistingIndex(this.embeddings);\n\t\t\tthis.vectorStoreBuffer.set(memoryKey, vectorStoreInstance);\n\n\t\t\tthis.storeMetadata.set(memoryKey, {\n\t\t\t\tsize: 0,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tlastAccessed: new Date(),\n\t\t\t});\n\t\t} else {\n\t\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.lastAccessed = new Date();\n\t\t\t}\n\t\t}\n\n\t\treturn vectorStoreInstance;\n\t}\n\n\t/**\n\t * Reset a store's metadata when it's cleared\n\t */\n\tprotected clearStoreMetadata(memoryKey: string): void {\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tthis.memoryUsageBytes -= metadata.size;\n\t\t\tmetadata.size = 0;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t}\n\t}\n\n\t/**\n\t * Get memory usage in bytes\n\t */\n\tgetMemoryUsage(): number {\n\t\treturn this.memoryUsageBytes;\n\t}\n\n\t/**\n\t * Get memory usage as a formatted string (MB)\n\t */\n\tgetMemoryUsageFormatted(): string {\n\t\treturn `${Math.round(this.memoryUsageBytes / (1024 * 1024))}MB`;\n\t}\n\n\t/**\n\t * Recalculate memory usage from actual vector store contents\n\t * This ensures tracking accuracy for large stores\n\t */\n\trecalculateMemoryUsage(): void {\n\t\tthis.memoryUsageBytes = 0;\n\n\t\t// Recalculate for each store\n\t\tfor (const [key, vectorStore] of this.vectorStoreBuffer.entries()) {\n\t\t\tconst storeSize = this.memoryCalculator.calculateVectorStoreSize(vectorStore);\n\n\t\t\t// Update metadata\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.size = storeSize;\n\t\t\t\tthis.memoryUsageBytes += storeSize;\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.debug(`Recalculated vector store memory: ${this.getMemoryUsageFormatted()}`);\n\t}\n\n\t/**\n\t * Add documents to a vector store\n\t */\n\tasync addDocuments(\n\t\tmemoryKey: string,\n\t\tdocuments: Document[],\n\t\tclearStore?: boolean,\n\t): Promise<void> {\n\t\tif (clearStore) {\n\t\t\tthis.clearStoreMetadata(memoryKey);\n\t\t\tthis.vectorStoreBuffer.delete(memoryKey);\n\t\t}\n\n\t\t// Fast batch estimation instead of per-document calculation\n\t\tconst estimatedAddedSize = this.memoryCalculator.estimateBatchSize(documents);\n\n\t\t// Clean up old stores if necessary\n\t\tthis.cleanupService.cleanupOldestStores(estimatedAddedSize);\n\n\t\tconst vectorStoreInstance = await this.getVectorStore(memoryKey);\n\n\t\t// Get vector count before adding documents\n\t\tconst vectorCountBefore = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\tawait vectorStoreInstance.addDocuments(documents);\n\n\t\t// Update store metadata and memory tracking\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tmetadata.size += estimatedAddedSize;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t\tthis.memoryUsageBytes += estimatedAddedSize;\n\t\t}\n\n\t\t// Get updated vector count\n\t\tconst vectorCount = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\t// Periodically recalculate actual memory usage to avoid drift\n\t\tif (\n\t\t\t(vectorCount > 0 && vectorCount % 100 === 0) ||\n\t\t\tdocuments.length > 20 ||\n\t\t\t(vectorCountBefore === 0 && vectorCount > 0)\n\t\t) {\n\t\t\tthis.recalculateMemoryUsage();\n\t\t}\n\n\t\t// Logging memory usage\n\t\tconst maxMemoryMB =\n\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t? (this.maxMemorySizeBytes / (1024 * 1024)).toFixed(0)\n\t\t\t\t: 'unlimited';\n\n\t\tthis.logger.debug(\n\t\t\t`Vector store memory: ${this.getMemoryUsageFormatted()}/${maxMemoryMB}MB (${vectorCount} vectors in ${this.vectorStoreBuffer.size} stores)`,\n\t\t);\n\t}\n\n\t/**\n\t * Get statistics about the vector store memory usage\n\t */\n\tgetStats(): VectorStoreStats {\n\t\tconst now = Date.now();\n\t\tlet inactiveStoreCount = 0;\n\n\t\t// Always recalculate when getting stats to ensure accuracy\n\t\tthis.recalculateMemoryUsage();\n\n\t\tconst stats: VectorStoreStats = {\n\t\t\ttotalSizeBytes: this.memoryUsageBytes,\n\t\t\ttotalSizeMB: Math.round((this.memoryUsageBytes / (1024 * 1024)) * 100) / 100,\n\t\t\tpercentOfLimit:\n\t\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t\t? Math.round((this.memoryUsageBytes / this.maxMemorySizeBytes) * 100)\n\t\t\t\t\t: 0,\n\t\t\tmaxMemoryMB: this.maxMemorySizeBytes > 0 ? this.maxMemorySizeBytes / (1024 * 1024) : -1, // -1 indicates unlimited\n\t\t\tstoreCount: this.vectorStoreBuffer.size,\n\t\t\tinactiveStoreCount: 0,\n\t\t\tttlHours: this.inactiveTtlMs > 0 ? this.inactiveTtlMs / (60 * 60 * 1000) : -1, // -1 indicates disabled\n\t\t\tstores: {},\n\t\t};\n\n\t\t// Add stats for each store\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tconst store = this.vectorStoreBuffer.get(key);\n\n\t\t\tif (store) {\n\t\t\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\t\t\tconst inactiveTimeMs = now - lastAccessedTime;\n\t\t\t\tconst isInactive = this.cleanupService.isStoreInactive(metadata);\n\n\t\t\t\tif (isInactive) {\n\t\t\t\t\tinactiveStoreCount++;\n\t\t\t\t}\n\n\t\t\t\tstats.stores[key] = {\n\t\t\t\t\tsizeBytes: metadata.size,\n\t\t\t\t\tsizeMB: Math.round((metadata.size / (1024 * 1024)) * 100) / 100,\n\t\t\t\t\tpercentOfTotal: Math.round((metadata.size / this.memoryUsageBytes) * 100) || 0,\n\t\t\t\t\tvectors: store.memoryVectors?.length || 0,\n\t\t\t\t\tcreatedAt: metadata.createdAt.toISOString(),\n\t\t\t\t\tlastAccessed: metadata.lastAccessed.toISOString(),\n\t\t\t\t\tinactive: isInactive,\n\t\t\t\t\tinactiveForHours: Math.round(inactiveTimeMs / (60 * 60 * 1000)),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tstats.inactiveStoreCount = inactiveStoreCount;\n\n\t\treturn stats;\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/MemoryVectorStoreManager.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { Embeddings } from '@langchain/core/embeddings';\nimport type { OpenAIEmbeddings, AzureOpenAIEmbeddings } from '@langchain/openai';\nimport { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';\nimport type { Logger } from 'n8n-workflow';\n\nimport { getConfig, mbToBytes, hoursToMs } from './config';\nimport { MemoryCalculator } from './MemoryCalculator';\nimport { StoreCleanupService } from './StoreCleanupService';\nimport type { VectorStoreMetadata, VectorStoreStats } from './types';\n\n/**\n * Manages in-memory vector stores with memory limits and auto-cleanup\n */\nexport class MemoryVectorStoreManager {\n\tprivate static instance: MemoryVectorStoreManager | null = null;\n\n\t// Storage\n\tprotected vectorStoreBuffer: Map<string, MemoryVectorStore>;\n\n\tprotected storeMetadata: Map<string, VectorStoreMetadata>;\n\n\tprotected memoryUsageBytes: number = 0;\n\n\t// Dependencies\n\tprotected memoryCalculator: MemoryCalculator;\n\n\tprotected cleanupService: StoreCleanupService;\n\n\tprotected static logger: Logger;\n\n\t// Config values\n\tprotected maxMemorySizeBytes: number;\n\n\tprotected inactiveTtlMs: number;\n\n\t// Inactive TTL cleanup timer\n\tprotected ttlCleanupIntervalId: NodeJS.Timeout | null = null;\n\n\tprotected constructor(\n\t\tprotected embeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tprotected logger: Logger,\n\t) {\n\t\t// Initialize storage\n\t\tthis.vectorStoreBuffer = new Map();\n\t\tthis.storeMetadata = new Map();\n\t\tthis.logger = logger;\n\n\t\tconst config = getConfig();\n\t\tthis.maxMemorySizeBytes = mbToBytes(config.maxMemoryMB);\n\t\tthis.inactiveTtlMs = hoursToMs(config.ttlHours);\n\n\t\t// Initialize services\n\t\tthis.memoryCalculator = new MemoryCalculator();\n\t\tthis.cleanupService = new StoreCleanupService(\n\t\t\tthis.maxMemorySizeBytes,\n\t\t\tthis.inactiveTtlMs,\n\t\t\tthis.vectorStoreBuffer,\n\t\t\tthis.storeMetadata,\n\t\t\tthis.handleCleanup.bind(this),\n\t\t);\n\n\t\tthis.setupTtlCleanup();\n\t}\n\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance(\n\t\tembeddings: Embeddings | OpenAIEmbeddings | AzureOpenAIEmbeddings,\n\t\tlogger: Logger,\n\t): MemoryVectorStoreManager {\n\t\tif (!MemoryVectorStoreManager.instance) {\n\t\t\tMemoryVectorStoreManager.instance = new MemoryVectorStoreManager(embeddings, logger);\n\t\t} else {\n\t\t\t// We need to update the embeddings in the existing instance.\n\t\t\t// This is important as embeddings instance is wrapped in a logWrapper,\n\t\t\t// which relies on supplyDataFunctions context which changes on each workflow run\n\t\t\tMemoryVectorStoreManager.instance.embeddings = embeddings;\n\t\t\tMemoryVectorStoreManager.instance.vectorStoreBuffer.forEach((vectorStoreInstance) => {\n\t\t\t\tvectorStoreInstance.embeddings = embeddings;\n\t\t\t});\n\t\t}\n\n\t\treturn MemoryVectorStoreManager.instance;\n\t}\n\n\t/**\n\t * Set up timer for TTL-based cleanup\n\t */\n\tprivate setupTtlCleanup(): void {\n\t\t// Skip setup if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cleanup check interval (run every hour)\n\t\tconst CLEANUP_INTERVAL_MS = 60 * 60 * 1000;\n\n\t\t// Clear any existing interval\n\t\tif (this.ttlCleanupIntervalId) {\n\t\t\tclearInterval(this.ttlCleanupIntervalId);\n\t\t}\n\n\t\t// Setup new interval for TTL cleanup\n\t\tthis.ttlCleanupIntervalId = setInterval(() => {\n\t\t\tthis.cleanupService.cleanupInactiveStores();\n\t\t}, CLEANUP_INTERVAL_MS);\n\t}\n\n\t/**\n\t * Handle cleanup events from the cleanup service\n\t */\n\tprivate handleCleanup(removedKeys: string[], freedBytes: number, reason: 'ttl' | 'memory'): void {\n\t\t// Update total memory usage\n\t\tthis.memoryUsageBytes -= freedBytes;\n\n\t\t// Log cleanup event\n\t\tif (reason === 'ttl') {\n\t\t\tconst ttlHours = Math.round(this.inactiveTtlMs / (60 * 60 * 1000));\n\t\t\tthis.logger.info(\n\t\t\t\t`TTL cleanup: removed ${removedKeys.length} inactive vector stores (${ttlHours}h TTL) to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t} else {\n\t\t\tthis.logger.info(\n\t\t\t\t`Memory cleanup: removed ${removedKeys.length} oldest vector stores to free ${Math.round(freedBytes / (1024 * 1024))}MB of memory`,\n\t\t\t);\n\t\t}\n\t}\n\n\tgetMemoryKeysList(): string[] {\n\t\treturn Array.from(this.vectorStoreBuffer.keys());\n\t}\n\n\t/**\n\t * Get or create a vector store by key\n\t */\n\tasync getVectorStore(memoryKey: string): Promise<MemoryVectorStore> {\n\t\tlet vectorStoreInstance = this.vectorStoreBuffer.get(memoryKey);\n\n\t\tif (!vectorStoreInstance) {\n\t\t\tvectorStoreInstance = await MemoryVectorStore.fromExistingIndex(this.embeddings);\n\t\t\tthis.vectorStoreBuffer.set(memoryKey, vectorStoreInstance);\n\n\t\t\tthis.storeMetadata.set(memoryKey, {\n\t\t\t\tsize: 0,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tlastAccessed: new Date(),\n\t\t\t});\n\t\t} else {\n\t\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.lastAccessed = new Date();\n\t\t\t}\n\t\t}\n\n\t\treturn vectorStoreInstance;\n\t}\n\n\t/**\n\t * Reset a store's metadata when it's cleared\n\t */\n\tprotected clearStoreMetadata(memoryKey: string): void {\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tthis.memoryUsageBytes -= metadata.size;\n\t\t\tmetadata.size = 0;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t}\n\t}\n\n\t/**\n\t * Get memory usage in bytes\n\t */\n\tgetMemoryUsage(): number {\n\t\treturn this.memoryUsageBytes;\n\t}\n\n\t/**\n\t * Get memory usage as a formatted string (MB)\n\t */\n\tgetMemoryUsageFormatted(): string {\n\t\treturn `${Math.round(this.memoryUsageBytes / (1024 * 1024))}MB`;\n\t}\n\n\t/**\n\t * Recalculate memory usage from actual vector store contents\n\t * This ensures tracking accuracy for large stores\n\t */\n\trecalculateMemoryUsage(): void {\n\t\tthis.memoryUsageBytes = 0;\n\n\t\t// Recalculate for each store\n\t\tfor (const [key, vectorStore] of this.vectorStoreBuffer.entries()) {\n\t\t\tconst storeSize = this.memoryCalculator.calculateVectorStoreSize(vectorStore);\n\n\t\t\t// Update metadata\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tmetadata.size = storeSize;\n\t\t\t\tthis.memoryUsageBytes += storeSize;\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.debug(`Recalculated vector store memory: ${this.getMemoryUsageFormatted()}`);\n\t}\n\n\t/**\n\t * Add documents to a vector store\n\t */\n\tasync addDocuments(\n\t\tmemoryKey: string,\n\t\tdocuments: Document[],\n\t\tclearStore?: boolean,\n\t): Promise<void> {\n\t\tif (clearStore) {\n\t\t\tthis.clearStoreMetadata(memoryKey);\n\t\t\tthis.vectorStoreBuffer.delete(memoryKey);\n\t\t}\n\n\t\t// Fast batch estimation instead of per-document calculation\n\t\tconst estimatedAddedSize = this.memoryCalculator.estimateBatchSize(documents);\n\n\t\t// Clean up old stores if necessary\n\t\tthis.cleanupService.cleanupOldestStores(estimatedAddedSize);\n\n\t\tconst vectorStoreInstance = await this.getVectorStore(memoryKey);\n\n\t\t// Get vector count before adding documents\n\t\tconst vectorCountBefore = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\tawait vectorStoreInstance.addDocuments(documents);\n\n\t\t// Update store metadata and memory tracking\n\t\tconst metadata = this.storeMetadata.get(memoryKey);\n\t\tif (metadata) {\n\t\t\tmetadata.size += estimatedAddedSize;\n\t\t\tmetadata.lastAccessed = new Date();\n\t\t\tthis.memoryUsageBytes += estimatedAddedSize;\n\t\t}\n\n\t\t// Get updated vector count\n\t\tconst vectorCount = vectorStoreInstance.memoryVectors?.length || 0;\n\n\t\t// Periodically recalculate actual memory usage to avoid drift\n\t\tif (\n\t\t\t(vectorCount > 0 && vectorCount % 100 === 0) ||\n\t\t\tdocuments.length > 20 ||\n\t\t\t(vectorCountBefore === 0 && vectorCount > 0)\n\t\t) {\n\t\t\tthis.recalculateMemoryUsage();\n\t\t}\n\n\t\t// Logging memory usage\n\t\tconst maxMemoryMB =\n\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t? (this.maxMemorySizeBytes / (1024 * 1024)).toFixed(0)\n\t\t\t\t: 'unlimited';\n\n\t\tthis.logger.debug(\n\t\t\t`Vector store memory: ${this.getMemoryUsageFormatted()}/${maxMemoryMB}MB (${vectorCount} vectors in ${this.vectorStoreBuffer.size} stores)`,\n\t\t);\n\t}\n\n\t/**\n\t * Get statistics about the vector store memory usage\n\t */\n\tgetStats(): VectorStoreStats {\n\t\tconst now = Date.now();\n\t\tlet inactiveStoreCount = 0;\n\n\t\t// Always recalculate when getting stats to ensure accuracy\n\t\tthis.recalculateMemoryUsage();\n\n\t\tconst stats: VectorStoreStats = {\n\t\t\ttotalSizeBytes: this.memoryUsageBytes,\n\t\t\ttotalSizeMB: Math.round((this.memoryUsageBytes / (1024 * 1024)) * 100) / 100,\n\t\t\tpercentOfLimit:\n\t\t\t\tthis.maxMemorySizeBytes > 0\n\t\t\t\t\t? Math.round((this.memoryUsageBytes / this.maxMemorySizeBytes) * 100)\n\t\t\t\t\t: 0,\n\t\t\tmaxMemoryMB: this.maxMemorySizeBytes > 0 ? this.maxMemorySizeBytes / (1024 * 1024) : -1, // -1 indicates unlimited\n\t\t\tstoreCount: this.vectorStoreBuffer.size,\n\t\t\tinactiveStoreCount: 0,\n\t\t\tttlHours: this.inactiveTtlMs > 0 ? this.inactiveTtlMs / (60 * 60 * 1000) : -1, // -1 indicates disabled\n\t\t\tstores: {},\n\t\t};\n\n\t\t// Add stats for each store\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tconst store = this.vectorStoreBuffer.get(key);\n\n\t\t\tif (store) {\n\t\t\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\t\t\tconst inactiveTimeMs = now - lastAccessedTime;\n\t\t\t\tconst isInactive = this.cleanupService.isStoreInactive(metadata);\n\n\t\t\t\tif (isInactive) {\n\t\t\t\t\tinactiveStoreCount++;\n\t\t\t\t}\n\n\t\t\t\tstats.stores[key] = {\n\t\t\t\t\tsizeBytes: metadata.size,\n\t\t\t\t\tsizeMB: Math.round((metadata.size / (1024 * 1024)) * 100) / 100,\n\t\t\t\t\tpercentOfTotal: Math.round((metadata.size / this.memoryUsageBytes) * 100) || 0,\n\t\t\t\t\tvectors: store.memoryVectors?.length || 0,\n\t\t\t\t\tcreatedAt: metadata.createdAt.toISOString(),\n\t\t\t\t\tlastAccessed: metadata.lastAccessed.toISOString(),\n\t\t\t\t\tinactive: isInactive,\n\t\t\t\t\tinactiveForHours: Math.round(inactiveTimeMs / (60 * 60 * 1000)),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tstats.inactiveStoreCount = inactiveStoreCount;\n\n\t\treturn stats;\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/StoreCleanupService.ts"],"sourcesContent":["import type { MemoryVectorStore } from 'langchain/vectorstores/memory';\n\nimport type { VectorStoreMetadata, IStoreCleanupService } from './types';\n\n/**\n * Service for cleaning up vector stores based on inactivity or memory pressure\n */\nexport class StoreCleanupService implements IStoreCleanupService {\n\t// Cache for oldest stores sorted by creation time\n\tprivate oldestStoreKeys: string[] = [];\n\n\tprivate lastSortTime = 0;\n\n\tprivate readonly CACHE_TTL_MS = 5000; // 5 seconds\n\n\tconstructor(\n\t\tprivate readonly maxMemorySizeBytes: number,\n\t\tprivate readonly inactiveTtlMs: number,\n\t\tprivate readonly vectorStores: Map<string, MemoryVectorStore>,\n\t\tprivate readonly storeMetadata: Map<string, VectorStoreMetadata>,\n\t\tprivate readonly onCleanup: (\n\t\t\tremovedKeys: string[],\n\t\t\tfreedBytes: number,\n\t\t\treason: 'ttl' | 'memory',\n\t\t) => void,\n\t) {}\n\n\t/**\n\t * Check if a store has been inactive for longer than the TTL\n\t */\n\tisStoreInactive(metadata: VectorStoreMetadata): boolean {\n\t\t// If TTL is disabled, nothing is considered inactive\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\treturn now - lastAccessedTime > this.inactiveTtlMs;\n\t}\n\n\t/**\n\t * Remove vector stores that haven't been accessed for longer than TTL\n\t */\n\tcleanupInactiveStores(): void {\n\t\t// Skip if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet freedBytes = 0;\n\t\tconst removedStores: string[] = [];\n\n\t\t// Find and remove inactive stores\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tif (this.isStoreInactive(metadata)) {\n\t\t\t\t// Remove this inactive store\n\t\t\t\tthis.vectorStores.delete(key);\n\t\t\t\tfreedBytes += metadata.size;\n\t\t\t\tremovedStores.push(key);\n\t\t\t}\n\t\t}\n\n\t\t// Remove from metadata after iteration to avoid concurrent modification\n\t\tfor (const key of removedStores) {\n\t\t\tthis.storeMetadata.delete(key);\n\t\t}\n\n\t\t// Invalidate cache if we removed any stores\n\t\tif (removedStores.length > 0) {\n\t\t\tthis.oldestStoreKeys = [];\n\t\t\tthis.onCleanup(removedStores, freedBytes, 'ttl');\n\t\t}\n\t}\n\n\t/**\n\t * Remove the oldest vector stores to free up memory\n\t */\n\tcleanupOldestStores(requiredBytes: number): void {\n\t\t// Skip if memory limit is disabled\n\t\tif (this.maxMemorySizeBytes <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Calculate current total memory usage\n\t\tlet currentMemoryUsage = 0;\n\t\tfor (const metadata of this.storeMetadata.values()) {\n\t\t\tcurrentMemoryUsage += metadata.size;\n\t\t}\n\n\t\t// First, try to clean up inactive stores\n\t\tthis.cleanupInactiveStores();\n\n\t\t// Recalculate memory usage after inactive cleanup\n\t\tcurrentMemoryUsage = 0;\n\t\tfor (const metadata of this.storeMetadata.values()) {\n\t\t\tcurrentMemoryUsage += metadata.size;\n\t\t}\n\n\t\t// If no more cleanup needed, return early\n\t\tif (currentMemoryUsage + requiredBytes <= this.maxMemorySizeBytes) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = Date.now();\n\n\t\t// Reuse cached ordering if available and not stale\n\t\tif (this.oldestStoreKeys.length === 0 || now - this.lastSortTime > this.CACHE_TTL_MS) {\n\t\t\t// Collect and sort store keys by age\n\t\t\tconst stores: Array<[string, number]> = [];\n\n\t\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\t\tstores.push([key, metadata.createdAt.getTime()]);\n\t\t\t}\n\n\t\t\t// Sort by creation time (oldest first)\n\t\t\tstores.sort((a, b) => a[1] - b[1]);\n\n\t\t\t// Extract just the keys\n\t\t\tthis.oldestStoreKeys = stores.map(([key]) => key);\n\t\t\tthis.lastSortTime = now;\n\t\t}\n\n\t\tlet freedBytes = 0;\n\t\tconst removedStores: string[] = [];\n\n\t\t// Remove stores in order until we have enough space\n\t\tfor (const key of this.oldestStoreKeys) {\n\t\t\t// Skip if store no longer exists\n\t\t\tif (!this.storeMetadata.has(key)) continue;\n\n\t\t\t// Stop if we've freed enough space\n\t\t\tif (currentMemoryUsage - freedBytes + requiredBytes <= this.maxMemorySizeBytes) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tthis.vectorStores.delete(key);\n\t\t\t\tfreedBytes += metadata.size;\n\t\t\t\tremovedStores.push(key);\n\t\t\t}\n\t\t}\n\n\t\t// Remove from metadata after iteration to avoid concurrent modification\n\t\tfor (const key of removedStores) {\n\t\t\tthis.storeMetadata.delete(key);\n\t\t}\n\n\t\t// Update our cache if we removed stores\n\t\tif (removedStores.length > 0) {\n\t\t\t// Filter out removed stores from cached keys\n\t\t\tthis.oldestStoreKeys = this.oldestStoreKeys.filter((key) => !removedStores.includes(key));\n\t\t\tthis.onCleanup(removedStores, freedBytes, 'memory');\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/StoreCleanupService.ts"],"sourcesContent":["import type { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';\n\nimport type { VectorStoreMetadata, IStoreCleanupService } from './types';\n\n/**\n * Service for cleaning up vector stores based on inactivity or memory pressure\n */\nexport class StoreCleanupService implements IStoreCleanupService {\n\t// Cache for oldest stores sorted by creation time\n\tprivate oldestStoreKeys: string[] = [];\n\n\tprivate lastSortTime = 0;\n\n\tprivate readonly CACHE_TTL_MS = 5000; // 5 seconds\n\n\tconstructor(\n\t\tprivate readonly maxMemorySizeBytes: number,\n\t\tprivate readonly inactiveTtlMs: number,\n\t\tprivate readonly vectorStores: Map<string, MemoryVectorStore>,\n\t\tprivate readonly storeMetadata: Map<string, VectorStoreMetadata>,\n\t\tprivate readonly onCleanup: (\n\t\t\tremovedKeys: string[],\n\t\t\tfreedBytes: number,\n\t\t\treason: 'ttl' | 'memory',\n\t\t) => void,\n\t) {}\n\n\t/**\n\t * Check if a store has been inactive for longer than the TTL\n\t */\n\tisStoreInactive(metadata: VectorStoreMetadata): boolean {\n\t\t// If TTL is disabled, nothing is considered inactive\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst now = Date.now();\n\t\tconst lastAccessedTime = metadata.lastAccessed.getTime();\n\t\treturn now - lastAccessedTime > this.inactiveTtlMs;\n\t}\n\n\t/**\n\t * Remove vector stores that haven't been accessed for longer than TTL\n\t */\n\tcleanupInactiveStores(): void {\n\t\t// Skip if TTL is disabled\n\t\tif (this.inactiveTtlMs <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet freedBytes = 0;\n\t\tconst removedStores: string[] = [];\n\n\t\t// Find and remove inactive stores\n\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\tif (this.isStoreInactive(metadata)) {\n\t\t\t\t// Remove this inactive store\n\t\t\t\tthis.vectorStores.delete(key);\n\t\t\t\tfreedBytes += metadata.size;\n\t\t\t\tremovedStores.push(key);\n\t\t\t}\n\t\t}\n\n\t\t// Remove from metadata after iteration to avoid concurrent modification\n\t\tfor (const key of removedStores) {\n\t\t\tthis.storeMetadata.delete(key);\n\t\t}\n\n\t\t// Invalidate cache if we removed any stores\n\t\tif (removedStores.length > 0) {\n\t\t\tthis.oldestStoreKeys = [];\n\t\t\tthis.onCleanup(removedStores, freedBytes, 'ttl');\n\t\t}\n\t}\n\n\t/**\n\t * Remove the oldest vector stores to free up memory\n\t */\n\tcleanupOldestStores(requiredBytes: number): void {\n\t\t// Skip if memory limit is disabled\n\t\tif (this.maxMemorySizeBytes <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Calculate current total memory usage\n\t\tlet currentMemoryUsage = 0;\n\t\tfor (const metadata of this.storeMetadata.values()) {\n\t\t\tcurrentMemoryUsage += metadata.size;\n\t\t}\n\n\t\t// First, try to clean up inactive stores\n\t\tthis.cleanupInactiveStores();\n\n\t\t// Recalculate memory usage after inactive cleanup\n\t\tcurrentMemoryUsage = 0;\n\t\tfor (const metadata of this.storeMetadata.values()) {\n\t\t\tcurrentMemoryUsage += metadata.size;\n\t\t}\n\n\t\t// If no more cleanup needed, return early\n\t\tif (currentMemoryUsage + requiredBytes <= this.maxMemorySizeBytes) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst now = Date.now();\n\n\t\t// Reuse cached ordering if available and not stale\n\t\tif (this.oldestStoreKeys.length === 0 || now - this.lastSortTime > this.CACHE_TTL_MS) {\n\t\t\t// Collect and sort store keys by age\n\t\t\tconst stores: Array<[string, number]> = [];\n\n\t\t\tfor (const [key, metadata] of this.storeMetadata.entries()) {\n\t\t\t\tstores.push([key, metadata.createdAt.getTime()]);\n\t\t\t}\n\n\t\t\t// Sort by creation time (oldest first)\n\t\t\tstores.sort((a, b) => a[1] - b[1]);\n\n\t\t\t// Extract just the keys\n\t\t\tthis.oldestStoreKeys = stores.map(([key]) => key);\n\t\t\tthis.lastSortTime = now;\n\t\t}\n\n\t\tlet freedBytes = 0;\n\t\tconst removedStores: string[] = [];\n\n\t\t// Remove stores in order until we have enough space\n\t\tfor (const key of this.oldestStoreKeys) {\n\t\t\t// Skip if store no longer exists\n\t\t\tif (!this.storeMetadata.has(key)) continue;\n\n\t\t\t// Stop if we've freed enough space\n\t\t\tif (currentMemoryUsage - freedBytes + requiredBytes <= this.maxMemorySizeBytes) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst metadata = this.storeMetadata.get(key);\n\t\t\tif (metadata) {\n\t\t\t\tthis.vectorStores.delete(key);\n\t\t\t\tfreedBytes += metadata.size;\n\t\t\t\tremovedStores.push(key);\n\t\t\t}\n\t\t}\n\n\t\t// Remove from metadata after iteration to avoid concurrent modification\n\t\tfor (const key of removedStores) {\n\t\t\tthis.storeMetadata.delete(key);\n\t\t}\n\n\t\t// Update our cache if we removed stores\n\t\tif (removedStores.length > 0) {\n\t\t\t// Filter out removed stores from cached keys\n\t\t\tthis.oldestStoreKeys = this.oldestStoreKeys.filter((key) => !removedStores.includes(key));\n\t\t\tthis.onCleanup(removedStores, freedBytes, 'memory');\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/types.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { MemoryVectorStore } from 'langchain/vectorstores/memory';\n\n/**\n * Configuration options for the memory vector store\n */\nexport interface MemoryVectorStoreConfig {\n\t/**\n\t * Maximum memory size in MB, -1 to disable\n\t */\n\tmaxMemoryMB: number;\n\n\t/**\n\t * TTL for inactive stores in hours, -1 to disable\n\t */\n\tttlHours: number;\n}\n\n/**\n * Vector store metadata for tracking usage\n */\nexport interface VectorStoreMetadata {\n\tsize: number;\n\tcreatedAt: Date;\n\tlastAccessed: Date;\n}\n\n/**\n * Per-store statistics for reporting\n */\nexport interface StoreStats {\n\tsizeBytes: number;\n\tsizeMB: number;\n\tpercentOfTotal: number;\n\tvectors: number;\n\tcreatedAt: string;\n\tlastAccessed: string;\n\tinactive?: boolean;\n\tinactiveForHours?: number;\n}\n\n/**\n * Overall vector store statistics\n */\nexport interface VectorStoreStats {\n\ttotalSizeBytes: number;\n\ttotalSizeMB: number;\n\tpercentOfLimit: number;\n\tmaxMemoryMB: number;\n\tstoreCount: number;\n\tinactiveStoreCount: number;\n\tttlHours: number;\n\tstores: Record<string, StoreStats>;\n}\n\n/**\n * Service for calculating memory usage\n */\nexport interface IMemoryCalculator {\n\testimateBatchSize(documents: Document[]): number;\n\tcalculateVectorStoreSize(vectorStore: MemoryVectorStore): number;\n}\n\n/**\n * Service for cleaning up vector stores\n */\nexport interface IStoreCleanupService {\n\tcleanupInactiveStores(): void;\n\tcleanupOldestStores(requiredBytes: number): void;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../../../nodes/vector_store/shared/MemoryManager/types.ts"],"sourcesContent":["import type { Document } from '@langchain/core/documents';\nimport type { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';\n\n/**\n * Configuration options for the memory vector store\n */\nexport interface MemoryVectorStoreConfig {\n\t/**\n\t * Maximum memory size in MB, -1 to disable\n\t */\n\tmaxMemoryMB: number;\n\n\t/**\n\t * TTL for inactive stores in hours, -1 to disable\n\t */\n\tttlHours: number;\n}\n\n/**\n * Vector store metadata for tracking usage\n */\nexport interface VectorStoreMetadata {\n\tsize: number;\n\tcreatedAt: Date;\n\tlastAccessed: Date;\n}\n\n/**\n * Per-store statistics for reporting\n */\nexport interface StoreStats {\n\tsizeBytes: number;\n\tsizeMB: number;\n\tpercentOfTotal: number;\n\tvectors: number;\n\tcreatedAt: string;\n\tlastAccessed: string;\n\tinactive?: boolean;\n\tinactiveForHours?: number;\n}\n\n/**\n * Overall vector store statistics\n */\nexport interface VectorStoreStats {\n\ttotalSizeBytes: number;\n\ttotalSizeMB: number;\n\tpercentOfLimit: number;\n\tmaxMemoryMB: number;\n\tstoreCount: number;\n\tinactiveStoreCount: number;\n\tttlHours: number;\n\tstores: Record<string, StoreStats>;\n}\n\n/**\n * Service for calculating memory usage\n */\nexport interface IMemoryCalculator {\n\testimateBatchSize(documents: Document[]): number;\n\tcalculateVectorStoreSize(vectorStore: MemoryVectorStore): number;\n}\n\n/**\n * Service for cleaning up vector stores\n */\nexport interface IStoreCleanupService {\n\tcleanupInactiveStores(): void;\n\tcleanupOldestStores(requiredBytes: number): void;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -21,28 +21,30 @@ __export(retrieveAsToolOperation_exports, {
21
21
  handleRetrieveAsToolOperation: () => handleRetrieveAsToolOperation
22
22
  });
23
23
  module.exports = __toCommonJS(retrieveAsToolOperation_exports);
24
- var import_tools = require("langchain/tools");
25
- var import_n8n_workflow = require("n8n-workflow");
24
+ var import_fromAIToolFactory = require("../../../../../utils/fromAIToolFactory");
26
25
  var import_helpers = require("../../../../../utils/helpers");
27
- var import_n8n_workflow2 = require("n8n-workflow");
28
26
  var import_logWrapper = require("../../../../../utils/logWrapper");
27
+ var import_n8n_workflow = require("n8n-workflow");
29
28
  async function handleRetrieveAsToolOperation(context, args, embeddings, itemIndex) {
30
29
  const toolDescription = context.getNodeParameter("toolDescription", itemIndex);
31
30
  const node = context.getNode();
32
31
  const { typeVersion } = node;
33
- const toolName = typeVersion < 1.3 ? context.getNodeParameter("toolName", itemIndex) : (0, import_n8n_workflow2.nodeNameToToolName)(node);
34
- const topK = context.getNodeParameter("topK", itemIndex, 4);
35
- const useReranker = context.getNodeParameter("useReranker", itemIndex, false);
36
- const includeDocumentMetadata = context.getNodeParameter(
37
- "includeDocumentMetadata",
38
- itemIndex,
39
- true
40
- );
41
- const filter = (0, import_helpers.getMetadataFiltersValues)(context, itemIndex);
42
- const vectorStoreTool = new import_tools.DynamicTool({
32
+ const toolName = typeVersion < 1.3 ? context.getNodeParameter("toolName", itemIndex) : (0, import_n8n_workflow.nodeNameToToolName)(node);
33
+ const vectorStoreTool = (0, import_fromAIToolFactory.createToolFromNode)(node, {
43
34
  name: toolName,
44
35
  description: toolDescription,
45
- func: async (input) => {
36
+ extraArgs: [{ key: "input", description: "Query to search for. Required" }],
37
+ func: async (query) => {
38
+ const topK = context.getNodeParameter("topK", itemIndex, 4);
39
+ const useReranker = context.getNodeParameter("useReranker", itemIndex, false);
40
+ const includeDocumentMetadata = context.getNodeParameter(
41
+ "includeDocumentMetadata",
42
+ itemIndex,
43
+ true
44
+ );
45
+ const filter = (0, import_helpers.getMetadataFiltersValues)(context, itemIndex);
46
+ const queryString = typeof query === "string" ? query : query.input;
47
+ (0, import_n8n_workflow.assert)(typeof queryString === "string", "Query must be of type string");
46
48
  const vectorStore = await args.getVectorStoreClient(
47
49
  context,
48
50
  void 0,
@@ -50,7 +52,7 @@ async function handleRetrieveAsToolOperation(context, args, embeddings, itemInde
50
52
  itemIndex
51
53
  );
52
54
  try {
53
- const embeddedPrompt = await embeddings.embedQuery(input);
55
+ const embeddedPrompt = await embeddings.embedQuery(queryString);
54
56
  let documents = await vectorStore.similaritySearchVectorWithScore(
55
57
  embeddedPrompt,
56
58
  topK,
@@ -62,7 +64,7 @@ async function handleRetrieveAsToolOperation(context, args, embeddings, itemInde
62
64
  0
63
65
  );
64
66
  const docs = documents.map(([doc]) => doc);
65
- const rerankedDocuments = await reranker.compressDocuments(docs, input);
67
+ const rerankedDocuments = await reranker.compressDocuments(docs, queryString);
66
68
  documents = rerankedDocuments.map((doc) => {
67
69
  const { relevanceScore, ...metadata } = doc.metadata;
68
70
  return [{ ...doc, metadata }, relevanceScore];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../nodes/vector_store/shared/createVectorStoreNode/operations/retrieveAsToolOperation.ts"],"sourcesContent":["import type { Embeddings } from '@langchain/core/embeddings';\nimport type { BaseDocumentCompressor } from '@langchain/core/retrievers/document_compressors';\nimport type { VectorStore } from '@langchain/core/vectorstores';\nimport { DynamicTool } from 'langchain/tools';\nimport { NodeConnectionTypes, type ISupplyDataFunctions, type SupplyData } from 'n8n-workflow';\n\nimport { getMetadataFiltersValues } from '@utils/helpers';\nimport { nodeNameToToolName } from 'n8n-workflow';\nimport { logWrapper } from '@utils/logWrapper';\n\nimport type { VectorStoreNodeConstructorArgs } from '../types';\n\n/**\n * Handles the 'retrieve-as-tool' operation mode\n * Returns a tool that can be used with AI Agent nodes\n */\nexport async function handleRetrieveAsToolOperation<T extends VectorStore = VectorStore>(\n\tcontext: ISupplyDataFunctions,\n\targs: VectorStoreNodeConstructorArgs<T>,\n\tembeddings: Embeddings,\n\titemIndex: number,\n): Promise<SupplyData> {\n\t// Get the tool configuration parameters\n\tconst toolDescription = context.getNodeParameter('toolDescription', itemIndex) as string;\n\n\tconst node = context.getNode();\n\tconst { typeVersion } = node;\n\tconst toolName =\n\t\ttypeVersion < 1.3\n\t\t\t? (context.getNodeParameter('toolName', itemIndex) as string)\n\t\t\t: nodeNameToToolName(node);\n\n\tconst topK = context.getNodeParameter('topK', itemIndex, 4) as number;\n\tconst useReranker = context.getNodeParameter('useReranker', itemIndex, false) as boolean;\n\tconst includeDocumentMetadata = context.getNodeParameter(\n\t\t'includeDocumentMetadata',\n\t\titemIndex,\n\t\ttrue,\n\t) as boolean;\n\n\t// Get metadata filters\n\tconst filter = getMetadataFiltersValues(context, itemIndex);\n\n\t// Create a Dynamic Tool that wraps vector store search functionality\n\tconst vectorStoreTool = new DynamicTool({\n\t\tname: toolName,\n\t\tdescription: toolDescription,\n\t\tfunc: async (input) => {\n\t\t\t// For each tool use, get a fresh vector store client.\n\t\t\t// We don't pass in a filter here only later in the similaritySearchVectorWithScore\n\t\t\t// method to avoid an exception with some vector stores like Supabase or Pinecone(#AI-740)\n\t\t\tconst vectorStore = await args.getVectorStoreClient(\n\t\t\t\tcontext,\n\t\t\t\tundefined,\n\t\t\t\tembeddings,\n\t\t\t\titemIndex,\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\t// Embed the input query\n\t\t\t\tconst embeddedPrompt = await embeddings.embedQuery(input);\n\n\t\t\t\t// Search for similar documents\n\t\t\t\tlet documents = await vectorStore.similaritySearchVectorWithScore(\n\t\t\t\t\tembeddedPrompt,\n\t\t\t\t\ttopK,\n\t\t\t\t\tfilter,\n\t\t\t\t);\n\n\t\t\t\t// If reranker is used, rerank the documents\n\t\t\t\tif (useReranker && documents.length > 0) {\n\t\t\t\t\tconst reranker = (await context.getInputConnectionData(\n\t\t\t\t\t\tNodeConnectionTypes.AiReranker,\n\t\t\t\t\t\t0,\n\t\t\t\t\t)) as BaseDocumentCompressor;\n\n\t\t\t\t\tconst docs = documents.map(([doc]) => doc);\n\t\t\t\t\tconst rerankedDocuments = await reranker.compressDocuments(docs, input);\n\t\t\t\t\tdocuments = rerankedDocuments.map((doc) => {\n\t\t\t\t\t\tconst { relevanceScore, ...metadata } = doc.metadata;\n\t\t\t\t\t\treturn [{ ...doc, metadata }, relevanceScore];\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Format the documents for the tool output\n\t\t\t\treturn documents\n\t\t\t\t\t.map((document) => {\n\t\t\t\t\t\tif (includeDocumentMetadata) {\n\t\t\t\t\t\t\treturn { type: 'text', text: JSON.stringify(document[0]) };\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: JSON.stringify({ pageContent: document[0].pageContent }),\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t\t.filter((document) => !!document);\n\t\t\t} finally {\n\t\t\t\t// Release the vector store client if a release method was provided\n\t\t\t\targs.releaseVectorStoreClient?.(vectorStore);\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the vector store tool with logging wrapper\n\treturn {\n\t\tresponse: logWrapper(vectorStoreTool, context),\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA4B;AAC5B,0BAAgF;AAEhF,qBAAyC;AACzC,IAAAA,uBAAmC;AACnC,wBAA2B;AAQ3B,eAAsB,8BACrB,SACA,MACA,YACA,WACsB;AAEtB,QAAM,kBAAkB,QAAQ,iBAAiB,mBAAmB,SAAS;AAE7E,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,EAAE,YAAY,IAAI;AACxB,QAAM,WACL,cAAc,MACV,QAAQ,iBAAiB,YAAY,SAAS,QAC/C,yCAAmB,IAAI;AAE3B,QAAM,OAAO,QAAQ,iBAAiB,QAAQ,WAAW,CAAC;AAC1D,QAAM,cAAc,QAAQ,iBAAiB,eAAe,WAAW,KAAK;AAC5E,QAAM,0BAA0B,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAGA,QAAM,aAAS,yCAAyB,SAAS,SAAS;AAG1D,QAAM,kBAAkB,IAAI,yBAAY;AAAA,IACvC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM,OAAO,UAAU;AAItB,YAAM,cAAc,MAAM,KAAK;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAEA,UAAI;AAEH,cAAM,iBAAiB,MAAM,WAAW,WAAW,KAAK;AAGxD,YAAI,YAAY,MAAM,YAAY;AAAA,UACjC;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAGA,YAAI,eAAe,UAAU,SAAS,GAAG;AACxC,gBAAM,WAAY,MAAM,QAAQ;AAAA,YAC/B,wCAAoB;AAAA,YACpB;AAAA,UACD;AAEA,gBAAM,OAAO,UAAU,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AACzC,gBAAM,oBAAoB,MAAM,SAAS,kBAAkB,MAAM,KAAK;AACtE,sBAAY,kBAAkB,IAAI,CAAC,QAAQ;AAC1C,kBAAM,EAAE,gBAAgB,GAAG,SAAS,IAAI,IAAI;AAC5C,mBAAO,CAAC,EAAE,GAAG,KAAK,SAAS,GAAG,cAAc;AAAA,UAC7C,CAAC;AAAA,QACF;AAGA,eAAO,UACL,IAAI,CAAC,aAAa;AAClB,cAAI,yBAAyB;AAC5B,mBAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC,EAAE;AAAA,UAC1D;AACA,iBAAO;AAAA,YACN,MAAM;AAAA,YACN,MAAM,KAAK,UAAU,EAAE,aAAa,SAAS,CAAC,EAAE,YAAY,CAAC;AAAA,UAC9D;AAAA,QACD,CAAC,EACA,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ;AAAA,MAClC,UAAE;AAED,aAAK,2BAA2B,WAAW;AAAA,MAC5C;AAAA,IACD;AAAA,EACD,CAAC;AAGD,SAAO;AAAA,IACN,cAAU,8BAAW,iBAAiB,OAAO;AAAA,EAC9C;AACD;","names":["import_n8n_workflow"]}
1
+ {"version":3,"sources":["../../../../../../nodes/vector_store/shared/createVectorStoreNode/operations/retrieveAsToolOperation.ts"],"sourcesContent":["import type { Embeddings } from '@langchain/core/embeddings';\nimport type { BaseDocumentCompressor } from '@langchain/core/retrievers/document_compressors';\nimport type { VectorStore } from '@langchain/core/vectorstores';\nimport { createToolFromNode } from '@utils/fromAIToolFactory';\nimport { getMetadataFiltersValues } from '@utils/helpers';\nimport { logWrapper } from '@utils/logWrapper';\nimport type { ISupplyDataFunctions, SupplyData } from 'n8n-workflow';\nimport { assert, NodeConnectionTypes, nodeNameToToolName } from 'n8n-workflow';\n\nimport type { VectorStoreNodeConstructorArgs } from '../types';\n\n/**\n * Handles the 'retrieve-as-tool' operation mode\n * Returns a tool that can be used with AI Agent nodes\n */\nexport async function handleRetrieveAsToolOperation<T extends VectorStore = VectorStore>(\n\tcontext: ISupplyDataFunctions,\n\targs: VectorStoreNodeConstructorArgs<T>,\n\tembeddings: Embeddings,\n\titemIndex: number,\n): Promise<SupplyData> {\n\t// Get the tool configuration parameters\n\tconst toolDescription = context.getNodeParameter('toolDescription', itemIndex) as string;\n\n\tconst node = context.getNode();\n\tconst { typeVersion } = node;\n\tconst toolName =\n\t\ttypeVersion < 1.3\n\t\t\t? (context.getNodeParameter('toolName', itemIndex) as string)\n\t\t\t: nodeNameToToolName(node);\n\n\t// Create a Dynamic Tool that wraps vector store search functionality\n\tconst vectorStoreTool = createToolFromNode(node, {\n\t\tname: toolName,\n\t\tdescription: toolDescription,\n\t\textraArgs: [{ key: 'input', description: 'Query to search for. Required' }],\n\t\tfunc: async (query) => {\n\t\t\tconst topK = context.getNodeParameter('topK', itemIndex, 4) as number;\n\t\t\tconst useReranker = context.getNodeParameter('useReranker', itemIndex, false) as boolean;\n\t\t\tconst includeDocumentMetadata = context.getNodeParameter(\n\t\t\t\t'includeDocumentMetadata',\n\t\t\t\titemIndex,\n\t\t\t\ttrue,\n\t\t\t) as boolean;\n\n\t\t\t// Get metadata filters\n\t\t\tconst filter = getMetadataFiltersValues(context, itemIndex);\n\n\t\t\t// Extract the query string - it can be either a string (DynamicTool) or an object with 'input' key (DynamicStructuredTool)\n\t\t\tconst queryString = typeof query === 'string' ? query : query.input;\n\t\t\tassert(typeof queryString === 'string', 'Query must be of type string');\n\n\t\t\t// For each tool use, get a fresh vector store client.\n\t\t\t// We don't pass in a filter here only later in the similaritySearchVectorWithScore\n\t\t\t// method to avoid an exception with some vector stores like Supabase or Pinecone(#AI-740)\n\t\t\tconst vectorStore = await args.getVectorStoreClient(\n\t\t\t\tcontext,\n\t\t\t\tundefined,\n\t\t\t\tembeddings,\n\t\t\t\titemIndex,\n\t\t\t);\n\n\t\t\ttry {\n\t\t\t\t// Embed the input query\n\t\t\t\tconst embeddedPrompt = await embeddings.embedQuery(queryString);\n\n\t\t\t\t// Search for similar documents\n\t\t\t\tlet documents = await vectorStore.similaritySearchVectorWithScore(\n\t\t\t\t\tembeddedPrompt,\n\t\t\t\t\ttopK,\n\t\t\t\t\tfilter,\n\t\t\t\t);\n\n\t\t\t\t// If reranker is used, rerank the documents\n\t\t\t\tif (useReranker && documents.length > 0) {\n\t\t\t\t\tconst reranker = (await context.getInputConnectionData(\n\t\t\t\t\t\tNodeConnectionTypes.AiReranker,\n\t\t\t\t\t\t0,\n\t\t\t\t\t)) as BaseDocumentCompressor;\n\n\t\t\t\t\tconst docs = documents.map(([doc]) => doc);\n\t\t\t\t\tconst rerankedDocuments = await reranker.compressDocuments(docs, queryString);\n\t\t\t\t\tdocuments = rerankedDocuments.map((doc) => {\n\t\t\t\t\t\tconst { relevanceScore, ...metadata } = doc.metadata;\n\t\t\t\t\t\treturn [{ ...doc, metadata }, relevanceScore];\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Format the documents for the tool output\n\t\t\t\treturn documents\n\t\t\t\t\t.map((document) => {\n\t\t\t\t\t\tif (includeDocumentMetadata) {\n\t\t\t\t\t\t\treturn { type: 'text', text: JSON.stringify(document[0]) };\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: JSON.stringify({ pageContent: document[0].pageContent }),\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t\t.filter((document) => !!document);\n\t\t\t} finally {\n\t\t\t\t// Release the vector store client if a release method was provided\n\t\t\t\targs.releaseVectorStoreClient?.(vectorStore);\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the vector store tool with logging wrapper\n\treturn {\n\t\tresponse: logWrapper(vectorStoreTool, context),\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,+BAAmC;AACnC,qBAAyC;AACzC,wBAA2B;AAE3B,0BAAgE;AAQhE,eAAsB,8BACrB,SACA,MACA,YACA,WACsB;AAEtB,QAAM,kBAAkB,QAAQ,iBAAiB,mBAAmB,SAAS;AAE7E,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,EAAE,YAAY,IAAI;AACxB,QAAM,WACL,cAAc,MACV,QAAQ,iBAAiB,YAAY,SAAS,QAC/C,wCAAmB,IAAI;AAG3B,QAAM,sBAAkB,6CAAmB,MAAM;AAAA,IAChD,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,CAAC,EAAE,KAAK,SAAS,aAAa,gCAAgC,CAAC;AAAA,IAC1E,MAAM,OAAO,UAAU;AACtB,YAAM,OAAO,QAAQ,iBAAiB,QAAQ,WAAW,CAAC;AAC1D,YAAM,cAAc,QAAQ,iBAAiB,eAAe,WAAW,KAAK;AAC5E,YAAM,0BAA0B,QAAQ;AAAA,QACvC;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAGA,YAAM,aAAS,yCAAyB,SAAS,SAAS;AAG1D,YAAM,cAAc,OAAO,UAAU,WAAW,QAAQ,MAAM;AAC9D,sCAAO,OAAO,gBAAgB,UAAU,8BAA8B;AAKtE,YAAM,cAAc,MAAM,KAAK;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAEA,UAAI;AAEH,cAAM,iBAAiB,MAAM,WAAW,WAAW,WAAW;AAG9D,YAAI,YAAY,MAAM,YAAY;AAAA,UACjC;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAGA,YAAI,eAAe,UAAU,SAAS,GAAG;AACxC,gBAAM,WAAY,MAAM,QAAQ;AAAA,YAC/B,wCAAoB;AAAA,YACpB;AAAA,UACD;AAEA,gBAAM,OAAO,UAAU,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AACzC,gBAAM,oBAAoB,MAAM,SAAS,kBAAkB,MAAM,WAAW;AAC5E,sBAAY,kBAAkB,IAAI,CAAC,QAAQ;AAC1C,kBAAM,EAAE,gBAAgB,GAAG,SAAS,IAAI,IAAI;AAC5C,mBAAO,CAAC,EAAE,GAAG,KAAK,SAAS,GAAG,cAAc;AAAA,UAC7C,CAAC;AAAA,QACF;AAGA,eAAO,UACL,IAAI,CAAC,aAAa;AAClB,cAAI,yBAAyB;AAC5B,mBAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC,EAAE;AAAA,UAC1D;AACA,iBAAO;AAAA,YACN,MAAM;AAAA,YACN,MAAM,KAAK,UAAU,EAAE,aAAa,SAAS,CAAC,EAAE,YAAY,CAAC;AAAA,UAC9D;AAAA,QACD,CAAC,EACA,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ;AAAA,MAClC,UAAE;AAED,aAAK,2BAA2B,WAAW;AAAA,MAC5C;AAAA,IACD;AAAA,EACD,CAAC;AAGD,SAAO;AAAA,IACN,cAAU,8BAAW,iBAAiB,OAAO;AAAA,EAC9C;AACD;","names":[]}
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(edit_operation_exports);
25
25
  var import_n8n_workflow = require("n8n-workflow");
26
26
  var import_utils = require("../../helpers/utils");
27
27
  var import_transport = require("../../transport");
28
+ var import_descriptions = require("../descriptions");
28
29
  function isImagesParameter(param) {
29
30
  if (typeof param !== "object" || param === null) {
30
31
  return false;
@@ -68,6 +69,7 @@ function isGenerateContentResponse(response) {
68
69
  });
69
70
  }
70
71
  const properties = [
72
+ (0, import_descriptions.modelRLC)("imageEditModelSearch"),
71
73
  {
72
74
  displayName: "Prompt",
73
75
  name: "prompt",
@@ -133,6 +135,10 @@ const displayOptions = {
133
135
  const description = (0, import_n8n_workflow.updateDisplayOptions)(displayOptions, properties);
134
136
  async function execute(i) {
135
137
  const prompt = this.getNodeParameter("prompt", i, "");
138
+ let model = this.getNodeParameter("modelId", i, "", { extractValue: true });
139
+ if (!model) {
140
+ model = "models/gemini-2.5-flash-image-preview";
141
+ }
136
142
  const binaryPropertyOutput = this.getNodeParameter("options.binaryPropertyOutput", i, "edited");
137
143
  const outputKey = typeof binaryPropertyOutput === "string" ? binaryPropertyOutput : "data";
138
144
  const imagesParam = this.getNodeParameter("images", i, {
@@ -150,7 +156,6 @@ async function execute(i) {
150
156
  const uploaded = await import_utils.uploadFile.call(this, buf, bin.mimeType);
151
157
  fileParts.push({ fileData: { fileUri: uploaded.fileUri, mimeType: uploaded.mimeType } });
152
158
  }
153
- const model = "models/gemini-2.5-flash-image-preview";
154
159
  const generationConfig = {
155
160
  responseModalities: ["IMAGE"]
156
161
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../nodes/vendors/GoogleGemini/actions/image/edit.operation.ts"],"sourcesContent":["import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow';\nimport { updateDisplayOptions } from 'n8n-workflow';\n\nimport type { GenerateContentResponse } from '../../helpers/interfaces';\nimport { uploadFile } from '../../helpers/utils';\nimport { apiRequest } from '../../transport';\n\ninterface ImagesParameter {\n\tvalues?: Array<{ binaryPropertyName?: string }>;\n}\n\nfunction isImagesParameter(param: unknown): param is ImagesParameter {\n\tif (typeof param !== 'object' || param === null) {\n\t\treturn false;\n\t}\n\n\tconst paramObj = param as Record<string, unknown>;\n\n\tif (!('values' in paramObj)) {\n\t\treturn true; // values is optional\n\t}\n\n\tif (!Array.isArray(paramObj.values)) {\n\t\treturn false;\n\t}\n\n\treturn paramObj.values.every((item: unknown) => {\n\t\tif (typeof item !== 'object' || item === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst itemObj = item as Record<string, unknown>;\n\n\t\tif (!('binaryPropertyName' in itemObj)) {\n\t\t\treturn true; // binaryPropertyName is optional\n\t\t}\n\n\t\treturn (\n\t\t\ttypeof itemObj.binaryPropertyName === 'string' || itemObj.binaryPropertyName === undefined\n\t\t);\n\t});\n}\n\nfunction isGenerateContentResponse(response: unknown): response is GenerateContentResponse {\n\tif (typeof response !== 'object' || response === null) {\n\t\treturn false;\n\t}\n\n\tconst responseObj = response as Record<string, unknown>;\n\n\tif (!('candidates' in responseObj) || !Array.isArray(responseObj.candidates)) {\n\t\treturn false;\n\t}\n\n\treturn responseObj.candidates.every((candidate: unknown) => {\n\t\tif (typeof candidate !== 'object' || candidate === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst candidateObj = candidate as Record<string, unknown>;\n\n\t\tif (\n\t\t\t!('content' in candidateObj) ||\n\t\t\ttypeof candidateObj.content !== 'object' ||\n\t\t\tcandidateObj.content === null\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst contentObj = candidateObj.content as Record<string, unknown>;\n\n\t\treturn 'parts' in contentObj && Array.isArray(contentObj.parts);\n\t});\n}\n\nconst properties: INodeProperties[] = [\n\t{\n\t\tdisplayName: 'Prompt',\n\t\tname: 'prompt',\n\t\ttype: 'string',\n\t\tplaceholder: 'e.g. combine the first image with the second image',\n\t\tdescription: 'Instruction describing how to edit the image',\n\t\tdefault: '',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Images',\n\t\tname: 'images',\n\t\ttype: 'fixedCollection',\n\t\tplaceholder: 'Add Image',\n\t\ttypeOptions: {\n\t\t\tmultipleValues: true,\n\t\t\tmultipleValueButtonText: 'Add Image',\n\t\t},\n\t\tdefault: { values: [{ binaryPropertyName: 'data' }] },\n\t\tdescription: 'Add one or more binary fields to include images with your prompt',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Image',\n\t\t\t\tname: 'values',\n\t\t\t\tvalues: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Binary Field Name',\n\t\t\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: 'data',\n\t\t\t\t\t\tplaceholder: 'e.g. data',\n\t\t\t\t\t\tdescription: 'The name of the binary field containing the image data',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Put Output in Field',\n\t\t\t\tname: 'binaryPropertyOutput',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'edited',\n\t\t\t\thint: 'The name of the output field to put the binary file data in',\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['edit'],\n\t\tresource: ['image'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst prompt = this.getNodeParameter('prompt', i, '');\n\tconst binaryPropertyOutput = this.getNodeParameter('options.binaryPropertyOutput', i, 'edited');\n\tconst outputKey = typeof binaryPropertyOutput === 'string' ? binaryPropertyOutput : 'data';\n\n\t// Collect image binary field names from collection\n\tconst imagesParam = this.getNodeParameter('images', i, {\n\t\tvalues: [{ binaryPropertyName: 'data' }],\n\t});\n\n\tif (!isImagesParameter(imagesParam)) {\n\t\tthrow new Error('Invalid images parameter format');\n\t}\n\n\tconst imagesUi = imagesParam.values ?? [];\n\tconst imageFieldNames = imagesUi\n\t\t.map((v) => v.binaryPropertyName)\n\t\t.filter((n): n is string => Boolean(n));\n\n\t// Upload all images and gather fileData parts\n\tconst fileParts = [] as Array<{ fileData: { fileUri: string; mimeType: string } }>;\n\tfor (const fieldName of imageFieldNames) {\n\t\tconst bin = this.helpers.assertBinaryData(i, fieldName);\n\t\tconst buf = await this.helpers.getBinaryDataBuffer(i, fieldName);\n\t\tconst uploaded = await uploadFile.call(this, buf, bin.mimeType);\n\t\tfileParts.push({ fileData: { fileUri: uploaded.fileUri, mimeType: uploaded.mimeType } });\n\t}\n\n\tconst model = 'models/gemini-2.5-flash-image-preview';\n\tconst generationConfig = {\n\t\tresponseModalities: ['IMAGE'],\n\t};\n\n\tconst body = {\n\t\tcontents: [\n\t\t\t{\n\t\t\t\trole: 'user',\n\t\t\t\tparts: [...fileParts, { text: prompt }],\n\t\t\t},\n\t\t],\n\t\tgenerationConfig,\n\t};\n\n\tconst response: unknown = await apiRequest.call(\n\t\tthis,\n\t\t'POST',\n\t\t`/v1beta/${model}:generateContent`,\n\t\t{\n\t\t\tbody,\n\t\t},\n\t);\n\n\tif (!isGenerateContentResponse(response)) {\n\t\tthrow new Error('Invalid response format from Gemini API');\n\t}\n\n\tconst promises = response.candidates.map(async (candidate) => {\n\t\tconst imagePart = candidate.content.parts.find((part) => 'inlineData' in part);\n\n\t\t// Check if imagePart exists and has inlineData with actual data\n\t\tif (!imagePart?.inlineData?.data) {\n\t\t\tthrow new Error('No image data returned from Gemini API');\n\t\t}\n\n\t\tconst bufferOut = Buffer.from(imagePart.inlineData.data, 'base64');\n\t\tconst binaryOut = await this.helpers.prepareBinaryData(\n\t\t\tbufferOut,\n\t\t\t'image.png',\n\t\t\timagePart.inlineData.mimeType,\n\t\t);\n\t\treturn {\n\t\t\tbinary: {\n\t\t\t\t[outputKey]: binaryOut,\n\t\t\t},\n\t\t\tjson: {\n\t\t\t\t...binaryOut,\n\t\t\t\tdata: undefined,\n\t\t\t},\n\t\t\tpairedItem: { item: i },\n\t\t};\n\t});\n\n\treturn await Promise.all(promises);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../nodes/vendors/GoogleGemini/actions/image/edit.operation.ts"],"sourcesContent":["import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow';\nimport { updateDisplayOptions } from 'n8n-workflow';\n\nimport type { GenerateContentResponse } from '../../helpers/interfaces';\nimport { uploadFile } from '../../helpers/utils';\nimport { apiRequest } from '../../transport';\nimport { modelRLC } from '../descriptions';\n\ninterface ImagesParameter {\n\tvalues?: Array<{ binaryPropertyName?: string }>;\n}\n\nfunction isImagesParameter(param: unknown): param is ImagesParameter {\n\tif (typeof param !== 'object' || param === null) {\n\t\treturn false;\n\t}\n\n\tconst paramObj = param as Record<string, unknown>;\n\n\tif (!('values' in paramObj)) {\n\t\treturn true; // values is optional\n\t}\n\n\tif (!Array.isArray(paramObj.values)) {\n\t\treturn false;\n\t}\n\n\treturn paramObj.values.every((item: unknown) => {\n\t\tif (typeof item !== 'object' || item === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst itemObj = item as Record<string, unknown>;\n\n\t\tif (!('binaryPropertyName' in itemObj)) {\n\t\t\treturn true; // binaryPropertyName is optional\n\t\t}\n\n\t\treturn (\n\t\t\ttypeof itemObj.binaryPropertyName === 'string' || itemObj.binaryPropertyName === undefined\n\t\t);\n\t});\n}\n\nfunction isGenerateContentResponse(response: unknown): response is GenerateContentResponse {\n\tif (typeof response !== 'object' || response === null) {\n\t\treturn false;\n\t}\n\n\tconst responseObj = response as Record<string, unknown>;\n\n\tif (!('candidates' in responseObj) || !Array.isArray(responseObj.candidates)) {\n\t\treturn false;\n\t}\n\n\treturn responseObj.candidates.every((candidate: unknown) => {\n\t\tif (typeof candidate !== 'object' || candidate === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst candidateObj = candidate as Record<string, unknown>;\n\n\t\tif (\n\t\t\t!('content' in candidateObj) ||\n\t\t\ttypeof candidateObj.content !== 'object' ||\n\t\t\tcandidateObj.content === null\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst contentObj = candidateObj.content as Record<string, unknown>;\n\n\t\treturn 'parts' in contentObj && Array.isArray(contentObj.parts);\n\t});\n}\n\nconst properties: INodeProperties[] = [\n\tmodelRLC('imageEditModelSearch'),\n\t{\n\t\tdisplayName: 'Prompt',\n\t\tname: 'prompt',\n\t\ttype: 'string',\n\t\tplaceholder: 'e.g. combine the first image with the second image',\n\t\tdescription: 'Instruction describing how to edit the image',\n\t\tdefault: '',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Images',\n\t\tname: 'images',\n\t\ttype: 'fixedCollection',\n\t\tplaceholder: 'Add Image',\n\t\ttypeOptions: {\n\t\t\tmultipleValues: true,\n\t\t\tmultipleValueButtonText: 'Add Image',\n\t\t},\n\t\tdefault: { values: [{ binaryPropertyName: 'data' }] },\n\t\tdescription: 'Add one or more binary fields to include images with your prompt',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Image',\n\t\t\t\tname: 'values',\n\t\t\t\tvalues: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdisplayName: 'Binary Field Name',\n\t\t\t\t\t\tname: 'binaryPropertyName',\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdefault: 'data',\n\t\t\t\t\t\tplaceholder: 'e.g. data',\n\t\t\t\t\t\tdescription: 'The name of the binary field containing the image data',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Put Output in Field',\n\t\t\t\tname: 'binaryPropertyOutput',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'edited',\n\t\t\t\thint: 'The name of the output field to put the binary file data in',\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['edit'],\n\t\tresource: ['image'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst prompt = this.getNodeParameter('prompt', i, '');\n\tlet model = this.getNodeParameter('modelId', i, '', { extractValue: true }) as string;\n\tif (!model) {\n\t\tmodel = 'models/gemini-2.5-flash-image-preview';\n\t}\n\n\tconst binaryPropertyOutput = this.getNodeParameter('options.binaryPropertyOutput', i, 'edited');\n\tconst outputKey = typeof binaryPropertyOutput === 'string' ? binaryPropertyOutput : 'data';\n\n\t// Collect image binary field names from collection\n\tconst imagesParam = this.getNodeParameter('images', i, {\n\t\tvalues: [{ binaryPropertyName: 'data' }],\n\t});\n\n\tif (!isImagesParameter(imagesParam)) {\n\t\tthrow new Error('Invalid images parameter format');\n\t}\n\n\tconst imagesUi = imagesParam.values ?? [];\n\tconst imageFieldNames = imagesUi\n\t\t.map((v) => v.binaryPropertyName)\n\t\t.filter((n): n is string => Boolean(n));\n\n\t// Upload all images and gather fileData parts\n\tconst fileParts = [] as Array<{ fileData: { fileUri: string; mimeType: string } }>;\n\tfor (const fieldName of imageFieldNames) {\n\t\tconst bin = this.helpers.assertBinaryData(i, fieldName);\n\t\tconst buf = await this.helpers.getBinaryDataBuffer(i, fieldName);\n\t\tconst uploaded = await uploadFile.call(this, buf, bin.mimeType);\n\t\tfileParts.push({ fileData: { fileUri: uploaded.fileUri, mimeType: uploaded.mimeType } });\n\t}\n\n\tconst generationConfig = {\n\t\tresponseModalities: ['IMAGE'],\n\t};\n\n\tconst body = {\n\t\tcontents: [\n\t\t\t{\n\t\t\t\trole: 'user',\n\t\t\t\tparts: [...fileParts, { text: prompt }],\n\t\t\t},\n\t\t],\n\t\tgenerationConfig,\n\t};\n\n\tconst response: unknown = await apiRequest.call(\n\t\tthis,\n\t\t'POST',\n\t\t`/v1beta/${model}:generateContent`,\n\t\t{\n\t\t\tbody,\n\t\t},\n\t);\n\n\tif (!isGenerateContentResponse(response)) {\n\t\tthrow new Error('Invalid response format from Gemini API');\n\t}\n\n\tconst promises = response.candidates.map(async (candidate) => {\n\t\tconst imagePart = candidate.content.parts.find((part) => 'inlineData' in part);\n\n\t\t// Check if imagePart exists and has inlineData with actual data\n\t\tif (!imagePart?.inlineData?.data) {\n\t\t\tthrow new Error('No image data returned from Gemini API');\n\t\t}\n\n\t\tconst bufferOut = Buffer.from(imagePart.inlineData.data, 'base64');\n\t\tconst binaryOut = await this.helpers.prepareBinaryData(\n\t\t\tbufferOut,\n\t\t\t'image.png',\n\t\t\timagePart.inlineData.mimeType,\n\t\t);\n\t\treturn {\n\t\t\tbinary: {\n\t\t\t\t[outputKey]: binaryOut,\n\t\t\t},\n\t\t\tjson: {\n\t\t\t\t...binaryOut,\n\t\t\t\tdata: undefined,\n\t\t\t},\n\t\t\tpairedItem: { item: i },\n\t\t};\n\t});\n\n\treturn await Promise.all(promises);\n}\n"],"mappings":"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","names":[]}
@@ -117,7 +117,7 @@ async function execute(i) {
117
117
  };
118
118
  });
119
119
  return await Promise.all(promises);
120
- } else if (model.includes("imagen") || model.includes("flash-image")) {
120
+ } else if (model.includes("imagen")) {
121
121
  const sampleCount = this.getNodeParameter("options.sampleCount", i, 1);
122
122
  const body = {
123
123
  instances: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../nodes/vendors/GoogleGemini/actions/image/generate.operation.ts"],"sourcesContent":["import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow';\nimport { NodeOperationError, updateDisplayOptions } from 'n8n-workflow';\n\nimport {\n\ttype GenerateContentRequest,\n\ttype GenerateContentResponse,\n\ttype ImagenResponse,\n\tModality,\n} from '../../helpers/interfaces';\nimport { apiRequest } from '../../transport';\nimport { modelRLC } from '../descriptions';\n\nconst properties: INodeProperties[] = [\n\tmodelRLC('imageGenerationModelSearch'),\n\t{\n\t\tdisplayName: 'Prompt',\n\t\tname: 'prompt',\n\t\ttype: 'string',\n\t\tplaceholder: 'e.g. A cute cat eating a dinosaur',\n\t\tdescription: 'A text description of the desired image(s)',\n\t\tdefault: '',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Number of Images',\n\t\t\t\tname: 'sampleCount',\n\t\t\t\tdefault: 1,\n\t\t\t\tdescription:\n\t\t\t\t\t'Number of images to generate. Not supported by Gemini models, supported by Imagen models.',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tminValue: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Put Output in Field',\n\t\t\t\tname: 'binaryPropertyOutput',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\thint: 'The name of the output field to put the binary file data in',\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['generate'],\n\t\tresource: ['image'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst model = this.getNodeParameter('modelId', i, '', { extractValue: true }) as string;\n\tconst prompt = this.getNodeParameter('prompt', i, '') as string;\n\tconst binaryPropertyOutput = this.getNodeParameter(\n\t\t'options.binaryPropertyOutput',\n\t\ti,\n\t\t'data',\n\t) as string;\n\n\tif (model.includes('gemini')) {\n\t\tconst generationConfig = {\n\t\t\tresponseModalities: [Modality.IMAGE, Modality.TEXT],\n\t\t};\n\t\tconst body: GenerateContentRequest = {\n\t\t\tcontents: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user',\n\t\t\t\t\tparts: [{ text: prompt }],\n\t\t\t\t},\n\t\t\t],\n\t\t\tgenerationConfig,\n\t\t};\n\n\t\tconst response = (await apiRequest.call(this, 'POST', `/v1beta/${model}:generateContent`, {\n\t\t\tbody,\n\t\t})) as GenerateContentResponse;\n\t\tconst promises = response.candidates.map(async (candidate) => {\n\t\t\tconst imagePart = candidate.content.parts.find((part) => 'inlineData' in part);\n\t\t\tconst buffer = Buffer.from(imagePart?.inlineData.data ?? '', 'base64');\n\t\t\tconst binaryData = await this.helpers.prepareBinaryData(\n\t\t\t\tbuffer,\n\t\t\t\t'image.png',\n\t\t\t\timagePart?.inlineData.mimeType,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tbinary: {\n\t\t\t\t\t[binaryPropertyOutput]: binaryData,\n\t\t\t\t},\n\t\t\t\tjson: {\n\t\t\t\t\t...binaryData,\n\t\t\t\t\tdata: undefined,\n\t\t\t\t},\n\t\t\t\tpairedItem: { item: i },\n\t\t\t};\n\t\t});\n\n\t\treturn await Promise.all(promises);\n\t} else if (model.includes('imagen') || model.includes('flash-image')) {\n\t\t// Imagen models use a different endpoint and request/response structure\n\t\tconst sampleCount = this.getNodeParameter('options.sampleCount', i, 1) as number;\n\t\tconst body = {\n\t\t\tinstances: [\n\t\t\t\t{\n\t\t\t\t\tprompt,\n\t\t\t\t},\n\t\t\t],\n\t\t\tparameters: {\n\t\t\t\tsampleCount,\n\t\t\t},\n\t\t};\n\t\tconst response = (await apiRequest.call(this, 'POST', `/v1beta/${model}:predict`, {\n\t\t\tbody,\n\t\t})) as ImagenResponse;\n\n\t\tconst promises = response.predictions.map(async (prediction) => {\n\t\t\tconst buffer = Buffer.from(prediction.bytesBase64Encoded ?? '', 'base64');\n\t\t\tconst binaryData = await this.helpers.prepareBinaryData(\n\t\t\t\tbuffer,\n\t\t\t\t'image.png',\n\t\t\t\tprediction.mimeType,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tbinary: {\n\t\t\t\t\t[binaryPropertyOutput]: binaryData,\n\t\t\t\t},\n\t\t\t\tjson: {\n\t\t\t\t\t...binaryData,\n\t\t\t\t\tdata: undefined,\n\t\t\t\t},\n\t\t\t\tpairedItem: { item: i },\n\t\t\t};\n\t\t});\n\n\t\treturn await Promise.all(promises);\n\t}\n\n\tthrow new NodeOperationError(\n\t\tthis.getNode(),\n\t\t`Model ${model} is not supported for image generation`,\n\t\t{\n\t\t\tdescription: 'Please check the model ID and try again.',\n\t\t},\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAyD;AAEzD,wBAKO;AACP,uBAA2B;AAC3B,0BAAyB;AAEzB,MAAM,aAAgC;AAAA,MACrC,8BAAS,4BAA4B;AAAA,EACrC;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,aAAa;AAAA,MACZ,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACR;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACC;AAAA,QACD,MAAM;AAAA,QACN,aAAa;AAAA,UACZ,UAAU;AAAA,QACX;AAAA,MACD;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD;AAEA,MAAM,iBAAiB;AAAA,EACtB,MAAM;AAAA,IACL,WAAW,CAAC,UAAU;AAAA,IACtB,UAAU,CAAC,OAAO;AAAA,EACnB;AACD;AAEO,MAAM,kBAAc,0CAAqB,gBAAgB,UAAU;AAE1E,eAAsB,QAAiC,GAA0C;AAChG,QAAM,QAAQ,KAAK,iBAAiB,WAAW,GAAG,IAAI,EAAE,cAAc,KAAK,CAAC;AAC5E,QAAM,SAAS,KAAK,iBAAiB,UAAU,GAAG,EAAE;AACpD,QAAM,uBAAuB,KAAK;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,MAAI,MAAM,SAAS,QAAQ,GAAG;AAC7B,UAAM,mBAAmB;AAAA,MACxB,oBAAoB,CAAC,2BAAS,OAAO,2BAAS,IAAI;AAAA,IACnD;AACA,UAAM,OAA+B;AAAA,MACpC,UAAU;AAAA,QACT;AAAA,UACC,MAAM;AAAA,UACN,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,QACzB;AAAA,MACD;AAAA,MACA;AAAA,IACD;AAEA,UAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,QAAQ,WAAW,KAAK,oBAAoB;AAAA,MACzF;AAAA,IACD,CAAC;AACD,UAAM,WAAW,SAAS,WAAW,IAAI,OAAO,cAAc;AAC7D,YAAM,YAAY,UAAU,QAAQ,MAAM,KAAK,CAAC,SAAS,gBAAgB,IAAI;AAC7E,YAAM,SAAS,OAAO,KAAK,WAAW,WAAW,QAAQ,IAAI,QAAQ;AACrE,YAAM,aAAa,MAAM,KAAK,QAAQ;AAAA,QACrC;AAAA,QACA;AAAA,QACA,WAAW,WAAW;AAAA,MACvB;AACA,aAAO;AAAA,QACN,QAAQ;AAAA,UACP,CAAC,oBAAoB,GAAG;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,UACL,GAAG;AAAA,UACH,MAAM;AAAA,QACP;AAAA,QACA,YAAY,EAAE,MAAM,EAAE;AAAA,MACvB;AAAA,IACD,CAAC;AAED,WAAO,MAAM,QAAQ,IAAI,QAAQ;AAAA,EAClC,WAAW,MAAM,SAAS,QAAQ,KAAK,MAAM,SAAS,aAAa,GAAG;AAErE,UAAM,cAAc,KAAK,iBAAiB,uBAAuB,GAAG,CAAC;AACrE,UAAM,OAAO;AAAA,MACZ,WAAW;AAAA,QACV;AAAA,UACC;AAAA,QACD;AAAA,MACD;AAAA,MACA,YAAY;AAAA,QACX;AAAA,MACD;AAAA,IACD;AACA,UAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,QAAQ,WAAW,KAAK,YAAY;AAAA,MACjF;AAAA,IACD,CAAC;AAED,UAAM,WAAW,SAAS,YAAY,IAAI,OAAO,eAAe;AAC/D,YAAM,SAAS,OAAO,KAAK,WAAW,sBAAsB,IAAI,QAAQ;AACxE,YAAM,aAAa,MAAM,KAAK,QAAQ;AAAA,QACrC;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACZ;AACA,aAAO;AAAA,QACN,QAAQ;AAAA,UACP,CAAC,oBAAoB,GAAG;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,UACL,GAAG;AAAA,UACH,MAAM;AAAA,QACP;AAAA,QACA,YAAY,EAAE,MAAM,EAAE;AAAA,MACvB;AAAA,IACD,CAAC;AAED,WAAO,MAAM,QAAQ,IAAI,QAAQ;AAAA,EAClC;AAEA,QAAM,IAAI;AAAA,IACT,KAAK,QAAQ;AAAA,IACb,SAAS,KAAK;AAAA,IACd;AAAA,MACC,aAAa;AAAA,IACd;AAAA,EACD;AACD;","names":[]}
1
+ {"version":3,"sources":["../../../../../../nodes/vendors/GoogleGemini/actions/image/generate.operation.ts"],"sourcesContent":["import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow';\nimport { NodeOperationError, updateDisplayOptions } from 'n8n-workflow';\n\nimport {\n\ttype GenerateContentRequest,\n\ttype GenerateContentResponse,\n\ttype ImagenResponse,\n\tModality,\n} from '../../helpers/interfaces';\nimport { apiRequest } from '../../transport';\nimport { modelRLC } from '../descriptions';\n\nconst properties: INodeProperties[] = [\n\tmodelRLC('imageGenerationModelSearch'),\n\t{\n\t\tdisplayName: 'Prompt',\n\t\tname: 'prompt',\n\t\ttype: 'string',\n\t\tplaceholder: 'e.g. A cute cat eating a dinosaur',\n\t\tdescription: 'A text description of the desired image(s)',\n\t\tdefault: '',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Number of Images',\n\t\t\t\tname: 'sampleCount',\n\t\t\t\tdefault: 1,\n\t\t\t\tdescription:\n\t\t\t\t\t'Number of images to generate. Not supported by Gemini models, supported by Imagen models.',\n\t\t\t\ttype: 'number',\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tminValue: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Put Output in Field',\n\t\t\t\tname: 'binaryPropertyOutput',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: 'data',\n\t\t\t\thint: 'The name of the output field to put the binary file data in',\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['generate'],\n\t\tresource: ['image'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst model = this.getNodeParameter('modelId', i, '', { extractValue: true }) as string;\n\tconst prompt = this.getNodeParameter('prompt', i, '') as string;\n\tconst binaryPropertyOutput = this.getNodeParameter(\n\t\t'options.binaryPropertyOutput',\n\t\ti,\n\t\t'data',\n\t) as string;\n\n\tif (model.includes('gemini')) {\n\t\tconst generationConfig = {\n\t\t\tresponseModalities: [Modality.IMAGE, Modality.TEXT],\n\t\t};\n\t\tconst body: GenerateContentRequest = {\n\t\t\tcontents: [\n\t\t\t\t{\n\t\t\t\t\trole: 'user',\n\t\t\t\t\tparts: [{ text: prompt }],\n\t\t\t\t},\n\t\t\t],\n\t\t\tgenerationConfig,\n\t\t};\n\n\t\tconst response = (await apiRequest.call(this, 'POST', `/v1beta/${model}:generateContent`, {\n\t\t\tbody,\n\t\t})) as GenerateContentResponse;\n\t\tconst promises = response.candidates.map(async (candidate) => {\n\t\t\tconst imagePart = candidate.content.parts.find((part) => 'inlineData' in part);\n\t\t\tconst buffer = Buffer.from(imagePart?.inlineData.data ?? '', 'base64');\n\t\t\tconst binaryData = await this.helpers.prepareBinaryData(\n\t\t\t\tbuffer,\n\t\t\t\t'image.png',\n\t\t\t\timagePart?.inlineData.mimeType,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tbinary: {\n\t\t\t\t\t[binaryPropertyOutput]: binaryData,\n\t\t\t\t},\n\t\t\t\tjson: {\n\t\t\t\t\t...binaryData,\n\t\t\t\t\tdata: undefined,\n\t\t\t\t},\n\t\t\t\tpairedItem: { item: i },\n\t\t\t};\n\t\t});\n\n\t\treturn await Promise.all(promises);\n\t} else if (model.includes('imagen')) {\n\t\t// Imagen models use a different endpoint and request/response structure\n\t\tconst sampleCount = this.getNodeParameter('options.sampleCount', i, 1) as number;\n\t\tconst body = {\n\t\t\tinstances: [\n\t\t\t\t{\n\t\t\t\t\tprompt,\n\t\t\t\t},\n\t\t\t],\n\t\t\tparameters: {\n\t\t\t\tsampleCount,\n\t\t\t},\n\t\t};\n\t\tconst response = (await apiRequest.call(this, 'POST', `/v1beta/${model}:predict`, {\n\t\t\tbody,\n\t\t})) as ImagenResponse;\n\n\t\tconst promises = response.predictions.map(async (prediction) => {\n\t\t\tconst buffer = Buffer.from(prediction.bytesBase64Encoded ?? '', 'base64');\n\t\t\tconst binaryData = await this.helpers.prepareBinaryData(\n\t\t\t\tbuffer,\n\t\t\t\t'image.png',\n\t\t\t\tprediction.mimeType,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tbinary: {\n\t\t\t\t\t[binaryPropertyOutput]: binaryData,\n\t\t\t\t},\n\t\t\t\tjson: {\n\t\t\t\t\t...binaryData,\n\t\t\t\t\tdata: undefined,\n\t\t\t\t},\n\t\t\t\tpairedItem: { item: i },\n\t\t\t};\n\t\t});\n\n\t\treturn await Promise.all(promises);\n\t}\n\n\tthrow new NodeOperationError(\n\t\tthis.getNode(),\n\t\t`Model ${model} is not supported for image generation`,\n\t\t{\n\t\t\tdescription: 'Please check the model ID and try again.',\n\t\t},\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAAyD;AAEzD,wBAKO;AACP,uBAA2B;AAC3B,0BAAyB;AAEzB,MAAM,aAAgC;AAAA,MACrC,8BAAS,4BAA4B;AAAA,EACrC;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,aAAa;AAAA,MACZ,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACR;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACC;AAAA,QACD,MAAM;AAAA,QACN,aAAa;AAAA,UACZ,UAAU;AAAA,QACX;AAAA,MACD;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACD;AAEA,MAAM,iBAAiB;AAAA,EACtB,MAAM;AAAA,IACL,WAAW,CAAC,UAAU;AAAA,IACtB,UAAU,CAAC,OAAO;AAAA,EACnB;AACD;AAEO,MAAM,kBAAc,0CAAqB,gBAAgB,UAAU;AAE1E,eAAsB,QAAiC,GAA0C;AAChG,QAAM,QAAQ,KAAK,iBAAiB,WAAW,GAAG,IAAI,EAAE,cAAc,KAAK,CAAC;AAC5E,QAAM,SAAS,KAAK,iBAAiB,UAAU,GAAG,EAAE;AACpD,QAAM,uBAAuB,KAAK;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,MAAI,MAAM,SAAS,QAAQ,GAAG;AAC7B,UAAM,mBAAmB;AAAA,MACxB,oBAAoB,CAAC,2BAAS,OAAO,2BAAS,IAAI;AAAA,IACnD;AACA,UAAM,OAA+B;AAAA,MACpC,UAAU;AAAA,QACT;AAAA,UACC,MAAM;AAAA,UACN,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;AAAA,QACzB;AAAA,MACD;AAAA,MACA;AAAA,IACD;AAEA,UAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,QAAQ,WAAW,KAAK,oBAAoB;AAAA,MACzF;AAAA,IACD,CAAC;AACD,UAAM,WAAW,SAAS,WAAW,IAAI,OAAO,cAAc;AAC7D,YAAM,YAAY,UAAU,QAAQ,MAAM,KAAK,CAAC,SAAS,gBAAgB,IAAI;AAC7E,YAAM,SAAS,OAAO,KAAK,WAAW,WAAW,QAAQ,IAAI,QAAQ;AACrE,YAAM,aAAa,MAAM,KAAK,QAAQ;AAAA,QACrC;AAAA,QACA;AAAA,QACA,WAAW,WAAW;AAAA,MACvB;AACA,aAAO;AAAA,QACN,QAAQ;AAAA,UACP,CAAC,oBAAoB,GAAG;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,UACL,GAAG;AAAA,UACH,MAAM;AAAA,QACP;AAAA,QACA,YAAY,EAAE,MAAM,EAAE;AAAA,MACvB;AAAA,IACD,CAAC;AAED,WAAO,MAAM,QAAQ,IAAI,QAAQ;AAAA,EAClC,WAAW,MAAM,SAAS,QAAQ,GAAG;AAEpC,UAAM,cAAc,KAAK,iBAAiB,uBAAuB,GAAG,CAAC;AACrE,UAAM,OAAO;AAAA,MACZ,WAAW;AAAA,QACV;AAAA,UACC;AAAA,QACD;AAAA,MACD;AAAA,MACA,YAAY;AAAA,QACX;AAAA,MACD;AAAA,IACD;AACA,UAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,QAAQ,WAAW,KAAK,YAAY;AAAA,MACjF;AAAA,IACD,CAAC;AAED,UAAM,WAAW,SAAS,YAAY,IAAI,OAAO,eAAe;AAC/D,YAAM,SAAS,OAAO,KAAK,WAAW,sBAAsB,IAAI,QAAQ;AACxE,YAAM,aAAa,MAAM,KAAK,QAAQ;AAAA,QACrC;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACZ;AACA,aAAO;AAAA,QACN,QAAQ;AAAA,UACP,CAAC,oBAAoB,GAAG;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,UACL,GAAG;AAAA,UACH,MAAM;AAAA,QACP;AAAA,QACA,YAAY,EAAE,MAAM,EAAE;AAAA,MACvB;AAAA,IACD,CAAC;AAED,WAAO,MAAM,QAAQ,IAAI,QAAQ;AAAA,EAClC;AAEA,QAAM,IAAI;AAAA,IACT,KAAK,QAAQ;AAAA,IACb,SAAS,KAAK;AAAA,IACd;AAAA,MACC,aAAa;AAAA,IACd;AAAA,EACD;AACD;","names":[]}
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var listSearch_exports = {};
20
20
  __export(listSearch_exports, {
21
21
  audioModelSearch: () => audioModelSearch,
22
+ imageEditModelSearch: () => imageEditModelSearch,
22
23
  imageGenerationModelSearch: () => imageGenerationModelSearch,
23
24
  modelSearch: () => modelSearch,
24
25
  videoGenerationModelSearch: () => videoGenerationModelSearch
@@ -55,15 +56,28 @@ async function audioModelSearch(filter) {
55
56
  );
56
57
  }
57
58
  async function imageGenerationModelSearch(filter) {
58
- const results = await baseModelSearch.call(
59
- this,
60
- (model) => model.includes("imagen") || model.includes("image-generation") || model.includes("flash-image"),
61
- filter
62
- );
59
+ const rawResult = await baseModelSearch.call(this, (model) => model.includes("image"));
60
+ let results = rawResult.results.map((r) => {
61
+ if (r.name.includes("gemini-2.5-flash-image")) {
62
+ return { name: `${r.name} (Nano Banana)`, value: r.value };
63
+ }
64
+ if (r.name.includes("gemini-3-pro-image")) {
65
+ return { name: `${r.name} (Nano Banana Pro)`, value: r.value };
66
+ }
67
+ return r;
68
+ });
69
+ if (filter) {
70
+ const filterLowerCase = filter.toLowerCase();
71
+ results = results.filter((r) => r.name.toLowerCase().includes(filterLowerCase));
72
+ }
73
+ return {
74
+ results
75
+ };
76
+ }
77
+ async function imageEditModelSearch(filter) {
78
+ const result = await imageGenerationModelSearch.call(this, filter);
63
79
  return {
64
- results: results.results.map(
65
- (r) => r.name.includes("gemini-2.5-flash-image") ? { name: `${r.name} (Nano Banana)`, value: r.value } : r
66
- )
80
+ results: result.results.filter((r) => r.name.toLowerCase().includes("nano banana"))
67
81
  };
68
82
  }
69
83
  async function videoGenerationModelSearch(filter) {
@@ -72,6 +86,7 @@ async function videoGenerationModelSearch(filter) {
72
86
  // Annotate the CommonJS export names for ESM import in node:
73
87
  0 && (module.exports = {
74
88
  audioModelSearch,
89
+ imageEditModelSearch,
75
90
  imageGenerationModelSearch,
76
91
  modelSearch,
77
92
  videoGenerationModelSearch
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/vendors/GoogleGemini/methods/listSearch.ts"],"sourcesContent":["import type { ILoadOptionsFunctions, INodeListSearchResult } from 'n8n-workflow';\n\nimport { apiRequest } from '../transport';\n\nasync function baseModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tmodelFilter: (model: string) => boolean,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\tconst response = (await apiRequest.call(this, 'GET', '/v1beta/models', {\n\t\tqs: {\n\t\t\tpageSize: 1000,\n\t\t},\n\t})) as {\n\t\tmodels: Array<{ name: string }>;\n\t};\n\n\tlet models = response.models.filter((model) => modelFilter(model.name));\n\tif (filter) {\n\t\tmodels = models.filter((model) => model.name.toLowerCase().includes(filter.toLowerCase()));\n\t}\n\n\treturn {\n\t\tresults: models.map((model) => ({ name: model.name, value: model.name })),\n\t};\n}\n\nexport async function modelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(\n\t\tthis,\n\t\t(model) =>\n\t\t\t!model.includes('embedding') &&\n\t\t\t!model.includes('aqa') &&\n\t\t\t!model.includes('image') &&\n\t\t\t!model.includes('vision') &&\n\t\t\t!model.includes('veo') &&\n\t\t\t!model.includes('audio') &&\n\t\t\t!model.includes('tts'),\n\t\tfilter,\n\t);\n}\n\nexport async function audioModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(\n\t\tthis,\n\t\t(model) =>\n\t\t\t!model.includes('embedding') &&\n\t\t\t!model.includes('aqa') &&\n\t\t\t!model.includes('image') &&\n\t\t\t!model.includes('vision') &&\n\t\t\t!model.includes('veo') &&\n\t\t\t!model.includes('tts'), // we don't have a tts operation\n\t\tfilter,\n\t);\n}\n\nexport async function imageGenerationModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\tconst results = await baseModelSearch.call(\n\t\tthis,\n\t\t(model) =>\n\t\t\tmodel.includes('imagen') ||\n\t\t\tmodel.includes('image-generation') ||\n\t\t\tmodel.includes('flash-image'),\n\t\tfilter,\n\t);\n\n\treturn {\n\t\tresults: results.results.map((r) =>\n\t\t\tr.name.includes('gemini-2.5-flash-image')\n\t\t\t\t? { name: `${r.name} (Nano Banana)`, value: r.value }\n\t\t\t\t: r,\n\t\t),\n\t};\n}\n\nexport async function videoGenerationModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(this, (model) => model.includes('veo'), filter);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,uBAA2B;AAE3B,eAAe,gBAEd,aACA,QACiC;AACjC,QAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,OAAO,kBAAkB;AAAA,IACtE,IAAI;AAAA,MACH,UAAU;AAAA,IACX;AAAA,EACD,CAAC;AAID,MAAI,SAAS,SAAS,OAAO,OAAO,CAAC,UAAU,YAAY,MAAM,IAAI,CAAC;AACtE,MAAI,QAAQ;AACX,aAAS,OAAO,OAAO,CAAC,UAAU,MAAM,KAAK,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC,CAAC;AAAA,EAC1F;AAEA,SAAO;AAAA,IACN,SAAS,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,MAAM,MAAM,OAAO,MAAM,KAAK,EAAE;AAAA,EACzE;AACD;AAEA,eAAsB,YAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB;AAAA,IAC5B;AAAA,IACA,CAAC,UACA,CAAC,MAAM,SAAS,WAAW,KAC3B,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,QAAQ,KACxB,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,KAAK;AAAA,IACtB;AAAA,EACD;AACD;AAEA,eAAsB,iBAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB;AAAA,IAC5B;AAAA,IACA,CAAC,UACA,CAAC,MAAM,SAAS,WAAW,KAC3B,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,QAAQ,KACxB,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,KAAK;AAAA;AAAA,IACtB;AAAA,EACD;AACD;AAEA,eAAsB,2BAErB,QACiC;AACjC,QAAM,UAAU,MAAM,gBAAgB;AAAA,IACrC;AAAA,IACA,CAAC,UACA,MAAM,SAAS,QAAQ,KACvB,MAAM,SAAS,kBAAkB,KACjC,MAAM,SAAS,aAAa;AAAA,IAC7B;AAAA,EACD;AAEA,SAAO;AAAA,IACN,SAAS,QAAQ,QAAQ;AAAA,MAAI,CAAC,MAC7B,EAAE,KAAK,SAAS,wBAAwB,IACrC,EAAE,MAAM,GAAG,EAAE,IAAI,kBAAkB,OAAO,EAAE,MAAM,IAClD;AAAA,IACJ;AAAA,EACD;AACD;AAEA,eAAsB,2BAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB,KAAK,MAAM,CAAC,UAAU,MAAM,SAAS,KAAK,GAAG,MAAM;AACjF;","names":[]}
1
+ {"version":3,"sources":["../../../../../nodes/vendors/GoogleGemini/methods/listSearch.ts"],"sourcesContent":["import type { ILoadOptionsFunctions, INodeListSearchResult } from 'n8n-workflow';\n\nimport { apiRequest } from '../transport';\n\nasync function baseModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tmodelFilter: (model: string) => boolean,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\tconst response = (await apiRequest.call(this, 'GET', '/v1beta/models', {\n\t\tqs: {\n\t\t\tpageSize: 1000,\n\t\t},\n\t})) as {\n\t\tmodels: Array<{ name: string }>;\n\t};\n\n\tlet models = response.models.filter((model) => modelFilter(model.name));\n\tif (filter) {\n\t\tmodels = models.filter((model) => model.name.toLowerCase().includes(filter.toLowerCase()));\n\t}\n\n\treturn {\n\t\tresults: models.map((model) => ({ name: model.name, value: model.name })),\n\t};\n}\n\nexport async function modelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(\n\t\tthis,\n\t\t(model) =>\n\t\t\t!model.includes('embedding') &&\n\t\t\t!model.includes('aqa') &&\n\t\t\t!model.includes('image') &&\n\t\t\t!model.includes('vision') &&\n\t\t\t!model.includes('veo') &&\n\t\t\t!model.includes('audio') &&\n\t\t\t!model.includes('tts'),\n\t\tfilter,\n\t);\n}\n\nexport async function audioModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(\n\t\tthis,\n\t\t(model) =>\n\t\t\t!model.includes('embedding') &&\n\t\t\t!model.includes('aqa') &&\n\t\t\t!model.includes('image') &&\n\t\t\t!model.includes('vision') &&\n\t\t\t!model.includes('veo') &&\n\t\t\t!model.includes('tts'), // we don't have a tts operation\n\t\tfilter,\n\t);\n}\n\nexport async function imageGenerationModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\tconst rawResult = await baseModelSearch.call(this, (model) => model.includes('image'));\n\tlet results = rawResult.results.map((r) => {\n\t\tif (r.name.includes('gemini-2.5-flash-image')) {\n\t\t\treturn { name: `${r.name} (Nano Banana)`, value: r.value };\n\t\t}\n\n\t\tif (r.name.includes('gemini-3-pro-image')) {\n\t\t\treturn { name: `${r.name} (Nano Banana Pro)`, value: r.value };\n\t\t}\n\n\t\treturn r;\n\t});\n\n\tif (filter) {\n\t\tconst filterLowerCase = filter.toLowerCase();\n\t\tresults = results.filter((r) => r.name.toLowerCase().includes(filterLowerCase));\n\t}\n\n\treturn {\n\t\tresults,\n\t};\n}\n\nexport async function imageEditModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\tconst result = await imageGenerationModelSearch.call(this, filter);\n\treturn {\n\t\tresults: result.results.filter((r) => r.name.toLowerCase().includes('nano banana')),\n\t};\n}\n\nexport async function videoGenerationModelSearch(\n\tthis: ILoadOptionsFunctions,\n\tfilter?: string,\n): Promise<INodeListSearchResult> {\n\treturn await baseModelSearch.call(this, (model) => model.includes('veo'), filter);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,uBAA2B;AAE3B,eAAe,gBAEd,aACA,QACiC;AACjC,QAAM,WAAY,MAAM,4BAAW,KAAK,MAAM,OAAO,kBAAkB;AAAA,IACtE,IAAI;AAAA,MACH,UAAU;AAAA,IACX;AAAA,EACD,CAAC;AAID,MAAI,SAAS,SAAS,OAAO,OAAO,CAAC,UAAU,YAAY,MAAM,IAAI,CAAC;AACtE,MAAI,QAAQ;AACX,aAAS,OAAO,OAAO,CAAC,UAAU,MAAM,KAAK,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC,CAAC;AAAA,EAC1F;AAEA,SAAO;AAAA,IACN,SAAS,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,MAAM,MAAM,OAAO,MAAM,KAAK,EAAE;AAAA,EACzE;AACD;AAEA,eAAsB,YAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB;AAAA,IAC5B;AAAA,IACA,CAAC,UACA,CAAC,MAAM,SAAS,WAAW,KAC3B,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,QAAQ,KACxB,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,KAAK;AAAA,IACtB;AAAA,EACD;AACD;AAEA,eAAsB,iBAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB;AAAA,IAC5B;AAAA,IACA,CAAC,UACA,CAAC,MAAM,SAAS,WAAW,KAC3B,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,OAAO,KACvB,CAAC,MAAM,SAAS,QAAQ,KACxB,CAAC,MAAM,SAAS,KAAK,KACrB,CAAC,MAAM,SAAS,KAAK;AAAA;AAAA,IACtB;AAAA,EACD;AACD;AAEA,eAAsB,2BAErB,QACiC;AACjC,QAAM,YAAY,MAAM,gBAAgB,KAAK,MAAM,CAAC,UAAU,MAAM,SAAS,OAAO,CAAC;AACrF,MAAI,UAAU,UAAU,QAAQ,IAAI,CAAC,MAAM;AAC1C,QAAI,EAAE,KAAK,SAAS,wBAAwB,GAAG;AAC9C,aAAO,EAAE,MAAM,GAAG,EAAE,IAAI,kBAAkB,OAAO,EAAE,MAAM;AAAA,IAC1D;AAEA,QAAI,EAAE,KAAK,SAAS,oBAAoB,GAAG;AAC1C,aAAO,EAAE,MAAM,GAAG,EAAE,IAAI,sBAAsB,OAAO,EAAE,MAAM;AAAA,IAC9D;AAEA,WAAO;AAAA,EACR,CAAC;AAED,MAAI,QAAQ;AACX,UAAM,kBAAkB,OAAO,YAAY;AAC3C,cAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,YAAY,EAAE,SAAS,eAAe,CAAC;AAAA,EAC/E;AAEA,SAAO;AAAA,IACN;AAAA,EACD;AACD;AAEA,eAAsB,qBAErB,QACiC;AACjC,QAAM,SAAS,MAAM,2BAA2B,KAAK,MAAM,MAAM;AACjE,SAAO;AAAA,IACN,SAAS,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,YAAY,EAAE,SAAS,aAAa,CAAC;AAAA,EACnF;AACD;AAEA,eAAsB,2BAErB,QACiC;AACjC,SAAO,MAAM,gBAAgB,KAAK,MAAM,CAAC,UAAU,MAAM,SAAS,KAAK,GAAG,MAAM;AACjF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/vendors/OpenAi/helpers/utils.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport type { Tool } from '@langchain/core/tools';\nimport type { OpenAIClient } from '@langchain/openai';\nimport type { BufferWindowMemory } from 'langchain/memory';\nimport { isObjectEmpty } from 'n8n-workflow';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\n// Copied from langchain(`langchain/src/tools/convert_to_openai.ts`)\n// since these functions are not exported\n\n/**\n * Formats a `Tool` instance into a format that is compatible\n * with OpenAI's ChatCompletionFunctions. It uses the `zodToJsonSchema`\n * function to convert the schema of the tool into a JSON\n * schema, which is then used as the parameters for the OpenAI function.\n */\nexport function formatToOpenAIFunction(\n\ttool: Tool,\n): OpenAIClient.Chat.ChatCompletionCreateParams.Function {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: zodToJsonSchema(tool.schema),\n\t};\n}\n\nexport function formatToOpenAITool(tool: Tool): OpenAIClient.Chat.ChatCompletionTool {\n\tconst schema = zodToJsonSchema(tool.schema);\n\treturn {\n\t\ttype: 'function',\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: schema,\n\t\t},\n\t};\n}\n\nexport function formatToOpenAIAssistantTool(tool: Tool): OpenAIClient.Beta.AssistantTool {\n\treturn {\n\t\ttype: 'function',\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: zodToJsonSchema(tool.schema),\n\t\t},\n\t};\n}\n\nconst requireStrict = (schema: any) => {\n\tif (!schema.required) {\n\t\treturn false;\n\t}\n\t// when strict:true, Responses API requires `required` to be present and all properties to be included\n\tif (schema.properties) {\n\t\tconst propertyNames = Object.keys(schema.properties);\n\t\tconst somePropertyMissingFromRequired = propertyNames.some(\n\t\t\t(propertyName) => !schema.required.includes(propertyName),\n\t\t);\n\t\tconst requireStrict = !somePropertyMissingFromRequired;\n\t\treturn requireStrict;\n\t}\n\treturn false;\n};\n\nexport function formatToOpenAIResponsesTool(tool: Tool): OpenAIClient.Responses.FunctionTool {\n\tconst schema = zodToJsonSchema(tool.schema) as any;\n\tconst strict = requireStrict(schema);\n\n\t// when strict:true, Responses API requires `additionalProperties` either to be true/false or an object with properties\n\tconst isAdditionalPropertiesEmpty =\n\t\tschema.additionalProperties &&\n\t\ttypeof schema.additionalProperties === 'object' &&\n\t\tisObjectEmpty(schema.additionalProperties);\n\tif (isAdditionalPropertiesEmpty && strict) {\n\t\tschema.additionalProperties = false;\n\t}\n\n\treturn {\n\t\ttype: 'function',\n\t\tname: tool.name,\n\t\tparameters: schema,\n\t\tstrict,\n\t\tdescription: tool.description,\n\t};\n}\n\nexport async function getChatMessages(memory: BufferWindowMemory): Promise<BaseMessage[]> {\n\treturn (await memory.loadMemoryVariables({}))[memory.memoryKey] as BaseMessage[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAA8B;AAC9B,gCAAgC;AAWzB,SAAS,uBACf,MACwD;AACxD,SAAO;AAAA,IACN,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,gBAAY,2CAAgB,KAAK,MAAM;AAAA,EACxC;AACD;AAEO,SAAS,mBAAmB,MAAkD;AACpF,QAAM,aAAS,2CAAgB,KAAK,MAAM;AAC1C,SAAO;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,MACT,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,IACb;AAAA,EACD;AACD;AAEO,SAAS,4BAA4B,MAA6C;AACxF,SAAO;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,MACT,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,gBAAY,2CAAgB,KAAK,MAAM;AAAA,IACxC;AAAA,EACD;AACD;AAEA,MAAM,gBAAgB,CAAC,WAAgB;AACtC,MAAI,CAAC,OAAO,UAAU;AACrB,WAAO;AAAA,EACR;AAEA,MAAI,OAAO,YAAY;AACtB,UAAM,gBAAgB,OAAO,KAAK,OAAO,UAAU;AACnD,UAAM,kCAAkC,cAAc;AAAA,MACrD,CAAC,iBAAiB,CAAC,OAAO,SAAS,SAAS,YAAY;AAAA,IACzD;AACA,UAAMA,iBAAgB,CAAC;AACvB,WAAOA;AAAA,EACR;AACA,SAAO;AACR;AAEO,SAAS,4BAA4B,MAAiD;AAC5F,QAAM,aAAS,2CAAgB,KAAK,MAAM;AAC1C,QAAM,SAAS,cAAc,MAAM;AAGnC,QAAM,8BACL,OAAO,wBACP,OAAO,OAAO,yBAAyB,gBACvC,mCAAc,OAAO,oBAAoB;AAC1C,MAAI,+BAA+B,QAAQ;AAC1C,WAAO,uBAAuB;AAAA,EAC/B;AAEA,SAAO;AAAA,IACN,MAAM;AAAA,IACN,MAAM,KAAK;AAAA,IACX,YAAY;AAAA,IACZ;AAAA,IACA,aAAa,KAAK;AAAA,EACnB;AACD;AAEA,eAAsB,gBAAgB,QAAoD;AACzF,UAAQ,MAAM,OAAO,oBAAoB,CAAC,CAAC,GAAG,OAAO,SAAS;AAC/D;","names":["requireStrict"]}
1
+ {"version":3,"sources":["../../../../../nodes/vendors/OpenAi/helpers/utils.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport type { Tool } from '@langchain/core/tools';\nimport type { OpenAIClient } from '@langchain/openai';\nimport type { BufferWindowMemory } from '@langchain/classic/memory';\nimport { isObjectEmpty } from 'n8n-workflow';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\n// Copied from langchain(`langchain/src/tools/convert_to_openai.ts`)\n// since these functions are not exported\n\n/**\n * Formats a `Tool` instance into a format that is compatible\n * with OpenAI's ChatCompletionFunctions. It uses the `zodToJsonSchema`\n * function to convert the schema of the tool into a JSON\n * schema, which is then used as the parameters for the OpenAI function.\n */\nexport function formatToOpenAIFunction(\n\ttool: Tool,\n): OpenAIClient.Chat.ChatCompletionCreateParams.Function {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: zodToJsonSchema(tool.schema),\n\t};\n}\n\nexport function formatToOpenAITool(tool: Tool): OpenAIClient.Chat.ChatCompletionTool {\n\tconst schema = zodToJsonSchema(tool.schema);\n\treturn {\n\t\ttype: 'function',\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: schema,\n\t\t},\n\t};\n}\n\nexport function formatToOpenAIAssistantTool(tool: Tool): OpenAIClient.Beta.AssistantTool {\n\treturn {\n\t\ttype: 'function',\n\t\tfunction: {\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: zodToJsonSchema(tool.schema),\n\t\t},\n\t};\n}\n\nconst requireStrict = (schema: any) => {\n\tif (!schema.required) {\n\t\treturn false;\n\t}\n\t// when strict:true, Responses API requires `required` to be present and all properties to be included\n\tif (schema.properties) {\n\t\tconst propertyNames = Object.keys(schema.properties);\n\t\tconst somePropertyMissingFromRequired = propertyNames.some(\n\t\t\t(propertyName) => !schema.required.includes(propertyName),\n\t\t);\n\t\tconst requireStrict = !somePropertyMissingFromRequired;\n\t\treturn requireStrict;\n\t}\n\treturn false;\n};\n\nexport function formatToOpenAIResponsesTool(tool: Tool): OpenAIClient.Responses.FunctionTool {\n\tconst schema = zodToJsonSchema(tool.schema) as any;\n\tconst strict = requireStrict(schema);\n\n\t// when strict:true, Responses API requires `additionalProperties` either to be true/false or an object with properties\n\tconst isAdditionalPropertiesEmpty =\n\t\tschema.additionalProperties &&\n\t\ttypeof schema.additionalProperties === 'object' &&\n\t\tisObjectEmpty(schema.additionalProperties);\n\tif (isAdditionalPropertiesEmpty && strict) {\n\t\tschema.additionalProperties = false;\n\t}\n\n\treturn {\n\t\ttype: 'function',\n\t\tname: tool.name,\n\t\tparameters: schema,\n\t\tstrict,\n\t\tdescription: tool.description,\n\t};\n}\n\nexport async function getChatMessages(memory: BufferWindowMemory): Promise<BaseMessage[]> {\n\treturn (await memory.loadMemoryVariables({}))[memory.memoryKey] as BaseMessage[];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,0BAA8B;AAC9B,gCAAgC;AAWzB,SAAS,uBACf,MACwD;AACxD,SAAO;AAAA,IACN,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,gBAAY,2CAAgB,KAAK,MAAM;AAAA,EACxC;AACD;AAEO,SAAS,mBAAmB,MAAkD;AACpF,QAAM,aAAS,2CAAgB,KAAK,MAAM;AAC1C,SAAO;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,MACT,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,IACb;AAAA,EACD;AACD;AAEO,SAAS,4BAA4B,MAA6C;AACxF,SAAO;AAAA,IACN,MAAM;AAAA,IACN,UAAU;AAAA,MACT,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,gBAAY,2CAAgB,KAAK,MAAM;AAAA,IACxC;AAAA,EACD;AACD;AAEA,MAAM,gBAAgB,CAAC,WAAgB;AACtC,MAAI,CAAC,OAAO,UAAU;AACrB,WAAO;AAAA,EACR;AAEA,MAAI,OAAO,YAAY;AACtB,UAAM,gBAAgB,OAAO,KAAK,OAAO,UAAU;AACnD,UAAM,kCAAkC,cAAc;AAAA,MACrD,CAAC,iBAAiB,CAAC,OAAO,SAAS,SAAS,YAAY;AAAA,IACzD;AACA,UAAMA,iBAAgB,CAAC;AACvB,WAAOA;AAAA,EACR;AACA,SAAO;AACR;AAEO,SAAS,4BAA4B,MAAiD;AAC5F,QAAM,aAAS,2CAAgB,KAAK,MAAM;AAC1C,QAAM,SAAS,cAAc,MAAM;AAGnC,QAAM,8BACL,OAAO,wBACP,OAAO,OAAO,yBAAyB,gBACvC,mCAAc,OAAO,oBAAoB;AAC1C,MAAI,+BAA+B,QAAQ;AAC1C,WAAO,uBAAuB;AAAA,EAC/B;AAEA,SAAO;AAAA,IACN,MAAM;AAAA,IACN,MAAM,KAAK;AAAA,IACX,YAAY;AAAA,IACZ;AAAA,IACA,aAAa,KAAK;AAAA,EACnB;AACD;AAEA,eAAsB,gBAAgB,QAAoD;AACzF,UAAQ,MAAM,OAAO,oBAAoB,CAAC,CAAC,GAAG,OAAO,SAAS;AAC/D;","names":["requireStrict"]}
@@ -32,8 +32,8 @@ __export(message_operation_exports, {
32
32
  execute: () => execute
33
33
  });
34
34
  module.exports = __toCommonJS(message_operation_exports);
35
- var import_agents = require("langchain/agents");
36
- var import_openai_assistant = require("langchain/experimental/openai_assistant");
35
+ var import_agents = require("@langchain/classic/agents");
36
+ var import_openai_assistant = require("@langchain/classic/experimental/openai_assistant");
37
37
  var import_omit = __toESM(require("lodash/omit"));
38
38
  var import_n8n_workflow = require("n8n-workflow");
39
39
  var import_openai = require("openai");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../nodes/vendors/OpenAi/v1/actions/assistant/message.operation.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport { AgentExecutor } from 'langchain/agents';\nimport type { OpenAIToolType } from 'langchain/dist/experimental/openai_assistant/schema';\nimport { OpenAIAssistantRunnable } from 'langchain/experimental/openai_assistant';\nimport type { BufferWindowMemory } from 'langchain/memory';\nimport omit from 'lodash/omit';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeProperties,\n} from 'n8n-workflow';\nimport {\n\tApplicationError,\n\tNodeConnectionTypes,\n\tNodeOperationError,\n\tupdateDisplayOptions,\n} from 'n8n-workflow';\nimport { OpenAI as OpenAIClient } from 'openai';\n\nimport { promptTypeOptions } from '@utils/descriptions';\nimport { getConnectedTools, getPromptInputByType } from '@utils/helpers';\nimport { getTracingConfig } from '@utils/tracing';\n\nimport { formatToOpenAIAssistantTool, getChatMessages } from '../../../helpers/utils';\nimport { assistantRLC } from '../descriptions';\nimport { getProxyAgent } from '@utils/httpProxyAgent';\n\nconst properties: INodeProperties[] = [\n\tassistantRLC,\n\t{\n\t\t...promptTypeOptions,\n\t\tname: 'prompt',\n\t},\n\t{\n\t\tdisplayName: 'Prompt (User Message)',\n\t\tname: 'text',\n\t\ttype: 'string',\n\t\tdefault: '',\n\t\tplaceholder: 'e.g. Hello, how can you help me?',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\tprompt: ['define'],\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Memory',\n\t\tname: 'memory',\n\t\ttype: 'options',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tname: 'Use memory connector',\n\t\t\t\tvalue: 'connector',\n\t\t\t\tdescription: 'Connect one of the supported memory nodes',\n\t\t\t},\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased\n\t\t\t\tname: 'Use thread ID',\n\t\t\t\tvalue: 'threadId',\n\t\t\t\tdescription: 'Specify the ID of the thread to continue',\n\t\t\t},\n\t\t],\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\t'@version': [{ _cnd: { gte: 1.6 } }],\n\t\t\t},\n\t\t},\n\t\tdefault: 'connector',\n\t},\n\t{\n\t\tdisplayName: 'Thread ID',\n\t\tname: 'threadId',\n\t\ttype: 'string',\n\t\tdefault: '',\n\t\tplaceholder: '',\n\t\tdescription: 'The ID of the thread to continue, a new thread will be created if not specified',\n\t\thint: 'If the thread ID is empty or undefined a new thread will be created and included in the response',\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\t'@version': [{ _cnd: { gte: 1.6 } }],\n\t\t\t\tmemory: ['threadId'],\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Connect your own custom n8n tools to this node on the canvas',\n\t\tname: 'noticeTools',\n\t\ttype: 'notice',\n\t\tdefault: '',\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\tdescription: 'Additional options to add',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Base URL',\n\t\t\t\tname: 'baseURL',\n\t\t\t\tdefault: 'https://api.openai.com/v1',\n\t\t\t\tdescription: 'Override the default base URL for the API',\n\t\t\t\ttype: 'string',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\thide: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.8 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max Retries',\n\t\t\t\tname: 'maxRetries',\n\t\t\t\tdefault: 2,\n\t\t\t\tdescription: 'Maximum number of retries to attempt',\n\t\t\t\ttype: 'number',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\tname: 'timeout',\n\t\t\t\tdefault: 10000,\n\t\t\t\tdescription: 'Maximum amount of time a request is allowed to take in milliseconds',\n\t\t\t\ttype: 'number',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Preserve Original Tools',\n\t\t\t\tname: 'preserveOriginalTools',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription:\n\t\t\t\t\t'Whether to preserve the original tools of the assistant after the execution of this node, otherwise the tools will be replaced with the connected tools, if any, default is true',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.3 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['message'],\n\t\tresource: ['assistant'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\nconst mapChatMessageToThreadMessage = (\n\tmessage: BaseMessage,\n): OpenAIClient.Beta.Threads.ThreadCreateParams.Message => ({\n\trole: message._getType() === 'ai' ? 'assistant' : 'user',\n\tcontent: message.content.toString(),\n});\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst credentials = await this.getCredentials('openAiApi');\n\tconst nodeVersion = this.getNode().typeVersion;\n\n\tconst input = getPromptInputByType({\n\t\tctx: this,\n\t\ti,\n\t\tinputKey: 'text',\n\t\tpromptTypeKey: 'prompt',\n\t});\n\n\tconst assistantId = this.getNodeParameter('assistantId', i, '', { extractValue: true }) as string;\n\n\tconst options = this.getNodeParameter('options', i, {}) as {\n\t\tbaseURL?: string;\n\t\tmaxRetries: number;\n\t\ttimeout: number;\n\t\tpreserveOriginalTools?: boolean;\n\t};\n\n\tconst baseURL = (options.baseURL ?? credentials.url) as string;\n\n\tconst client = new OpenAIClient({\n\t\tapiKey: credentials.apiKey as string,\n\t\tmaxRetries: options.maxRetries ?? 2,\n\t\ttimeout: options.timeout ?? 10000,\n\t\tbaseURL,\n\t\tfetchOptions: {\n\t\t\tdispatcher: getProxyAgent(baseURL),\n\t\t},\n\t});\n\n\tconst agent = new OpenAIAssistantRunnable({ assistantId, client, asAgent: true });\n\n\tconst tools = await getConnectedTools(this, nodeVersion > 1, false);\n\tlet assistantTools;\n\n\tif (tools.length) {\n\t\tconst transformedConnectedTools = tools?.map(formatToOpenAIAssistantTool) ?? [];\n\t\tconst nativeToolsParsed: OpenAIToolType = [];\n\n\t\tassistantTools = (await client.beta.assistants.retrieve(assistantId)).tools;\n\n\t\tconst useCodeInterpreter = assistantTools.some((tool) => tool.type === 'code_interpreter');\n\t\tif (useCodeInterpreter) {\n\t\t\tnativeToolsParsed.push({\n\t\t\t\ttype: 'code_interpreter',\n\t\t\t});\n\t\t}\n\n\t\tconst useRetrieval = assistantTools.some((tool) => tool.type === 'file_search');\n\t\tif (useRetrieval) {\n\t\t\tnativeToolsParsed.push({\n\t\t\t\ttype: 'file_search',\n\t\t\t});\n\t\t}\n\n\t\tawait client.beta.assistants.update(assistantId, {\n\t\t\ttools: [...nativeToolsParsed, ...transformedConnectedTools],\n\t\t});\n\t}\n\n\tconst agentExecutor = AgentExecutor.fromAgentAndTools({\n\t\tagent,\n\t\ttools: tools ?? [],\n\t});\n\n\tconst useMemoryConnector =\n\t\tnodeVersion >= 1.6 && this.getNodeParameter('memory', i) === 'connector';\n\tconst memory =\n\t\tuseMemoryConnector || nodeVersion < 1.6\n\t\t\t? ((await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as\n\t\t\t\t\t| BufferWindowMemory\n\t\t\t\t\t| undefined)\n\t\t\t: undefined;\n\n\tconst threadId =\n\t\tnodeVersion >= 1.6 && !useMemoryConnector\n\t\t\t? (this.getNodeParameter('threadId', i) as string)\n\t\t\t: undefined;\n\n\tconst chainValues: IDataObject = {\n\t\tcontent: input,\n\t\tsignal: this.getExecutionCancelSignal(),\n\t\ttimeout: options.timeout ?? 10000,\n\t};\n\tlet thread: OpenAIClient.Beta.Threads.Thread;\n\tif (memory) {\n\t\tconst chatMessages = await getChatMessages(memory);\n\n\t\t// Construct a new thread from the chat history to map the memory\n\t\tif (chatMessages.length) {\n\t\t\tconst first32Messages = chatMessages.slice(0, 32);\n\t\t\t// There is a undocumented limit of 32 messages per thread when creating a thread with messages\n\t\t\tconst mappedMessages: OpenAIClient.Beta.Threads.ThreadCreateParams.Message[] =\n\t\t\t\tfirst32Messages.map(mapChatMessageToThreadMessage);\n\n\t\t\tthread = await client.beta.threads.create({ messages: mappedMessages });\n\t\t\tconst overLimitMessages = chatMessages.slice(32).map(mapChatMessageToThreadMessage);\n\n\t\t\t// Send the remaining messages that exceed the limit of 32 sequentially\n\t\t\tfor (const message of overLimitMessages) {\n\t\t\t\tawait client.beta.threads.messages.create(thread.id, message);\n\t\t\t}\n\n\t\t\tchainValues.threadId = thread.id;\n\t\t}\n\t} else if (threadId) {\n\t\tchainValues.threadId = threadId;\n\t}\n\n\tlet filteredResponse: IDataObject = {};\n\ttry {\n\t\tconst response = await agentExecutor.withConfig(getTracingConfig(this)).invoke(chainValues);\n\t\tif (memory) {\n\t\t\tawait memory.saveContext({ input }, { output: response.output });\n\n\t\t\tif (response.threadId && response.runId) {\n\t\t\t\tconst threadRun = await client.beta.threads.runs.retrieve(response.runId, {\n\t\t\t\t\tthread_id: response.threadId,\n\t\t\t\t});\n\t\t\t\tresponse.usage = threadRun.usage;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\toptions.preserveOriginalTools !== false &&\n\t\t\tnodeVersion >= 1.3 &&\n\t\t\t(assistantTools ?? [])?.length\n\t\t) {\n\t\t\tawait client.beta.assistants.update(assistantId, {\n\t\t\t\ttools: assistantTools,\n\t\t\t});\n\t\t}\n\t\t// Remove configuration properties and runId added by Langchain that are not relevant to the user\n\t\tfilteredResponse = omit(response, ['signal', 'timeout', 'content', 'runId']) as IDataObject;\n\t} catch (error) {\n\t\tif (!(error instanceof ApplicationError)) {\n\t\t\tthrow new NodeOperationError(this.getNode(), error.message, { itemIndex: i });\n\t\t}\n\t}\n\n\treturn [{ json: filteredResponse, pairedItem: { item: i } }];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAA8B;AAE9B,8BAAwC;AAExC,kBAAiB;AAOjB,0BAKO;AACP,oBAAuC;AAEvC,0BAAkC;AAClC,qBAAwD;AACxD,qBAAiC;AAEjC,mBAA6D;AAC7D,IAAAA,uBAA6B;AAC7B,4BAA8B;AAE9B,MAAM,aAAgC;AAAA,EACrC;AAAA,EACA;AAAA,IACC,GAAG;AAAA,IACH,MAAM;AAAA,EACP;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,IACb,aAAa;AAAA,MACZ,MAAM;AAAA,IACP;AAAA,IACA,gBAAgB;AAAA,MACf,MAAM;AAAA,QACL,QAAQ,CAAC,QAAQ;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,MACR;AAAA,QACC,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACd;AAAA,MACA;AAAA;AAAA,QAEC,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACd;AAAA,IACD;AAAA,IACA,gBAAgB;AAAA,MACf,MAAM;AAAA,QACL,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,MACpC;AAAA,IACD;AAAA,IACA,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,gBAAgB;AAAA,MACf,MAAM;AAAA,QACL,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,QACnC,QAAQ,CAAC,UAAU;AAAA,MACpB;AAAA,IACD;AAAA,EACD;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,EACV;AAAA,EACA;AAAA,IACC,aAAa;AAAA,IACb,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,IACV,SAAS;AAAA,MACR;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,MAAM;AAAA,QACN,gBAAgB;AAAA,UACf,MAAM;AAAA,YACL,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,UACpC;AAAA,QACD;AAAA,MACD;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,MAAM;AAAA,MACP;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,MAAM;AAAA,MACP;AAAA,MACA;AAAA,QACC,aAAa;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACC;AAAA,QACD,gBAAgB;AAAA,UACf,MAAM;AAAA,YACL,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,UACpC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,MAAM,iBAAiB;AAAA,EACtB,MAAM;AAAA,IACL,WAAW,CAAC,SAAS;AAAA,IACrB,UAAU,CAAC,WAAW;AAAA,EACvB;AACD;AAEO,MAAM,kBAAc,0CAAqB,gBAAgB,UAAU;AAC1E,MAAM,gCAAgC,CACrC,aAC2D;AAAA,EAC3D,MAAM,QAAQ,SAAS,MAAM,OAAO,cAAc;AAAA,EAClD,SAAS,QAAQ,QAAQ,SAAS;AACnC;AAEA,eAAsB,QAAiC,GAA0C;AAChG,QAAM,cAAc,MAAM,KAAK,eAAe,WAAW;AACzD,QAAM,cAAc,KAAK,QAAQ,EAAE;AAEnC,QAAM,YAAQ,qCAAqB;AAAA,IAClC,KAAK;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,eAAe;AAAA,EAChB,CAAC;AAED,QAAM,cAAc,KAAK,iBAAiB,eAAe,GAAG,IAAI,EAAE,cAAc,KAAK,CAAC;AAEtF,QAAM,UAAU,KAAK,iBAAiB,WAAW,GAAG,CAAC,CAAC;AAOtD,QAAM,UAAW,QAAQ,WAAW,YAAY;AAEhD,QAAM,SAAS,IAAI,cAAAC,OAAa;AAAA,IAC/B,QAAQ,YAAY;AAAA,IACpB,YAAY,QAAQ,cAAc;AAAA,IAClC,SAAS,QAAQ,WAAW;AAAA,IAC5B;AAAA,IACA,cAAc;AAAA,MACb,gBAAY,qCAAc,OAAO;AAAA,IAClC;AAAA,EACD,CAAC;AAED,QAAM,QAAQ,IAAI,gDAAwB,EAAE,aAAa,QAAQ,SAAS,KAAK,CAAC;AAEhF,QAAM,QAAQ,UAAM,kCAAkB,MAAM,cAAc,GAAG,KAAK;AAClE,MAAI;AAEJ,MAAI,MAAM,QAAQ;AACjB,UAAM,4BAA4B,OAAO,IAAI,wCAA2B,KAAK,CAAC;AAC9E,UAAM,oBAAoC,CAAC;AAE3C,sBAAkB,MAAM,OAAO,KAAK,WAAW,SAAS,WAAW,GAAG;AAEtE,UAAM,qBAAqB,eAAe,KAAK,CAAC,SAAS,KAAK,SAAS,kBAAkB;AACzF,QAAI,oBAAoB;AACvB,wBAAkB,KAAK;AAAA,QACtB,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,UAAM,eAAe,eAAe,KAAK,CAAC,SAAS,KAAK,SAAS,aAAa;AAC9E,QAAI,cAAc;AACjB,wBAAkB,KAAK;AAAA,QACtB,MAAM;AAAA,MACP,CAAC;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,WAAW,OAAO,aAAa;AAAA,MAChD,OAAO,CAAC,GAAG,mBAAmB,GAAG,yBAAyB;AAAA,IAC3D,CAAC;AAAA,EACF;AAEA,QAAM,gBAAgB,4BAAc,kBAAkB;AAAA,IACrD;AAAA,IACA,OAAO,SAAS,CAAC;AAAA,EAClB,CAAC;AAED,QAAM,qBACL,eAAe,OAAO,KAAK,iBAAiB,UAAU,CAAC,MAAM;AAC9D,QAAM,SACL,sBAAsB,cAAc,MAC/B,MAAM,KAAK,uBAAuB,wCAAoB,UAAU,CAAC,IAGnE;AAEJ,QAAM,WACL,eAAe,OAAO,CAAC,qBACnB,KAAK,iBAAiB,YAAY,CAAC,IACpC;AAEJ,QAAM,cAA2B;AAAA,IAChC,SAAS;AAAA,IACT,QAAQ,KAAK,yBAAyB;AAAA,IACtC,SAAS,QAAQ,WAAW;AAAA,EAC7B;AACA,MAAI;AACJ,MAAI,QAAQ;AACX,UAAM,eAAe,UAAM,8BAAgB,MAAM;AAGjD,QAAI,aAAa,QAAQ;AACxB,YAAM,kBAAkB,aAAa,MAAM,GAAG,EAAE;AAEhD,YAAM,iBACL,gBAAgB,IAAI,6BAA6B;AAElD,eAAS,MAAM,OAAO,KAAK,QAAQ,OAAO,EAAE,UAAU,eAAe,CAAC;AACtE,YAAM,oBAAoB,aAAa,MAAM,EAAE,EAAE,IAAI,6BAA6B;AAGlF,iBAAW,WAAW,mBAAmB;AACxC,cAAM,OAAO,KAAK,QAAQ,SAAS,OAAO,OAAO,IAAI,OAAO;AAAA,MAC7D;AAEA,kBAAY,WAAW,OAAO;AAAA,IAC/B;AAAA,EACD,WAAW,UAAU;AACpB,gBAAY,WAAW;AAAA,EACxB;AAEA,MAAI,mBAAgC,CAAC;AACrC,MAAI;AACH,UAAM,WAAW,MAAM,cAAc,eAAW,iCAAiB,IAAI,CAAC,EAAE,OAAO,WAAW;AAC1F,QAAI,QAAQ;AACX,YAAM,OAAO,YAAY,EAAE,MAAM,GAAG,EAAE,QAAQ,SAAS,OAAO,CAAC;AAE/D,UAAI,SAAS,YAAY,SAAS,OAAO;AACxC,cAAM,YAAY,MAAM,OAAO,KAAK,QAAQ,KAAK,SAAS,SAAS,OAAO;AAAA,UACzE,WAAW,SAAS;AAAA,QACrB,CAAC;AACD,iBAAS,QAAQ,UAAU;AAAA,MAC5B;AAAA,IACD;AAEA,QACC,QAAQ,0BAA0B,SAClC,eAAe,QACd,kBAAkB,CAAC,IAAI,QACvB;AACD,YAAM,OAAO,KAAK,WAAW,OAAO,aAAa;AAAA,QAChD,OAAO;AAAA,MACR,CAAC;AAAA,IACF;AAEA,2BAAmB,YAAAC,SAAK,UAAU,CAAC,UAAU,WAAW,WAAW,OAAO,CAAC;AAAA,EAC5E,SAAS,OAAO;AACf,QAAI,EAAE,iBAAiB,uCAAmB;AACzC,YAAM,IAAI,uCAAmB,KAAK,QAAQ,GAAG,MAAM,SAAS,EAAE,WAAW,EAAE,CAAC;AAAA,IAC7E;AAAA,EACD;AAEA,SAAO,CAAC,EAAE,MAAM,kBAAkB,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;AAC5D;","names":["import_descriptions","OpenAIClient","omit"]}
1
+ {"version":3,"sources":["../../../../../../../nodes/vendors/OpenAi/v1/actions/assistant/message.operation.ts"],"sourcesContent":["import type { BaseMessage } from '@langchain/core/messages';\nimport { AgentExecutor } from '@langchain/classic/agents';\nimport type { OpenAIToolType } from '@langchain/classic/dist/experimental/openai_assistant/schema';\nimport { OpenAIAssistantRunnable } from '@langchain/classic/experimental/openai_assistant';\nimport type { BufferWindowMemory } from '@langchain/classic/memory';\nimport omit from 'lodash/omit';\nimport type {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeProperties,\n} from 'n8n-workflow';\nimport {\n\tApplicationError,\n\tNodeConnectionTypes,\n\tNodeOperationError,\n\tupdateDisplayOptions,\n} from 'n8n-workflow';\nimport { OpenAI as OpenAIClient } from 'openai';\n\nimport { promptTypeOptions } from '@utils/descriptions';\nimport { getConnectedTools, getPromptInputByType } from '@utils/helpers';\nimport { getTracingConfig } from '@utils/tracing';\n\nimport { formatToOpenAIAssistantTool, getChatMessages } from '../../../helpers/utils';\nimport { assistantRLC } from '../descriptions';\nimport { getProxyAgent } from '@utils/httpProxyAgent';\n\nconst properties: INodeProperties[] = [\n\tassistantRLC,\n\t{\n\t\t...promptTypeOptions,\n\t\tname: 'prompt',\n\t},\n\t{\n\t\tdisplayName: 'Prompt (User Message)',\n\t\tname: 'text',\n\t\ttype: 'string',\n\t\tdefault: '',\n\t\tplaceholder: 'e.g. Hello, how can you help me?',\n\t\ttypeOptions: {\n\t\t\trows: 2,\n\t\t},\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\tprompt: ['define'],\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Memory',\n\t\tname: 'memory',\n\t\ttype: 'options',\n\t\toptions: [\n\t\t\t{\n\t\t\t\tname: 'Use memory connector',\n\t\t\t\tvalue: 'connector',\n\t\t\t\tdescription: 'Connect one of the supported memory nodes',\n\t\t\t},\n\t\t\t{\n\t\t\t\t// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased\n\t\t\t\tname: 'Use thread ID',\n\t\t\t\tvalue: 'threadId',\n\t\t\t\tdescription: 'Specify the ID of the thread to continue',\n\t\t\t},\n\t\t],\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\t'@version': [{ _cnd: { gte: 1.6 } }],\n\t\t\t},\n\t\t},\n\t\tdefault: 'connector',\n\t},\n\t{\n\t\tdisplayName: 'Thread ID',\n\t\tname: 'threadId',\n\t\ttype: 'string',\n\t\tdefault: '',\n\t\tplaceholder: '',\n\t\tdescription: 'The ID of the thread to continue, a new thread will be created if not specified',\n\t\thint: 'If the thread ID is empty or undefined a new thread will be created and included in the response',\n\t\tdisplayOptions: {\n\t\t\tshow: {\n\t\t\t\t'@version': [{ _cnd: { gte: 1.6 } }],\n\t\t\t\tmemory: ['threadId'],\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\tdisplayName: 'Connect your own custom n8n tools to this node on the canvas',\n\t\tname: 'noticeTools',\n\t\ttype: 'notice',\n\t\tdefault: '',\n\t},\n\t{\n\t\tdisplayName: 'Options',\n\t\tname: 'options',\n\t\tplaceholder: 'Add Option',\n\t\tdescription: 'Additional options to add',\n\t\ttype: 'collection',\n\t\tdefault: {},\n\t\toptions: [\n\t\t\t{\n\t\t\t\tdisplayName: 'Base URL',\n\t\t\t\tname: 'baseURL',\n\t\t\t\tdefault: 'https://api.openai.com/v1',\n\t\t\t\tdescription: 'Override the default base URL for the API',\n\t\t\t\ttype: 'string',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\thide: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.8 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max Retries',\n\t\t\t\tname: 'maxRetries',\n\t\t\t\tdefault: 2,\n\t\t\t\tdescription: 'Maximum number of retries to attempt',\n\t\t\t\ttype: 'number',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Timeout',\n\t\t\t\tname: 'timeout',\n\t\t\t\tdefault: 10000,\n\t\t\t\tdescription: 'Maximum amount of time a request is allowed to take in milliseconds',\n\t\t\t\ttype: 'number',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Preserve Original Tools',\n\t\t\t\tname: 'preserveOriginalTools',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdescription:\n\t\t\t\t\t'Whether to preserve the original tools of the assistant after the execution of this node, otherwise the tools will be replaced with the connected tools, if any, default is true',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\t'@version': [{ _cnd: { gte: 1.3 } }],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t},\n];\n\nconst displayOptions = {\n\tshow: {\n\t\toperation: ['message'],\n\t\tresource: ['assistant'],\n\t},\n};\n\nexport const description = updateDisplayOptions(displayOptions, properties);\nconst mapChatMessageToThreadMessage = (\n\tmessage: BaseMessage,\n): OpenAIClient.Beta.Threads.ThreadCreateParams.Message => ({\n\trole: message._getType() === 'ai' ? 'assistant' : 'user',\n\tcontent: message.content.toString(),\n});\n\nexport async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {\n\tconst credentials = await this.getCredentials('openAiApi');\n\tconst nodeVersion = this.getNode().typeVersion;\n\n\tconst input = getPromptInputByType({\n\t\tctx: this,\n\t\ti,\n\t\tinputKey: 'text',\n\t\tpromptTypeKey: 'prompt',\n\t});\n\n\tconst assistantId = this.getNodeParameter('assistantId', i, '', { extractValue: true }) as string;\n\n\tconst options = this.getNodeParameter('options', i, {}) as {\n\t\tbaseURL?: string;\n\t\tmaxRetries: number;\n\t\ttimeout: number;\n\t\tpreserveOriginalTools?: boolean;\n\t};\n\n\tconst baseURL = (options.baseURL ?? credentials.url) as string;\n\n\tconst client = new OpenAIClient({\n\t\tapiKey: credentials.apiKey as string,\n\t\tmaxRetries: options.maxRetries ?? 2,\n\t\ttimeout: options.timeout ?? 10000,\n\t\tbaseURL,\n\t\tfetchOptions: {\n\t\t\tdispatcher: getProxyAgent(baseURL),\n\t\t},\n\t});\n\n\tconst agent = new OpenAIAssistantRunnable({ assistantId, client, asAgent: true });\n\n\tconst tools = await getConnectedTools(this, nodeVersion > 1, false);\n\tlet assistantTools;\n\n\tif (tools.length) {\n\t\tconst transformedConnectedTools = tools?.map(formatToOpenAIAssistantTool) ?? [];\n\t\tconst nativeToolsParsed: OpenAIToolType = [];\n\n\t\tassistantTools = (await client.beta.assistants.retrieve(assistantId)).tools;\n\n\t\tconst useCodeInterpreter = assistantTools.some((tool) => tool.type === 'code_interpreter');\n\t\tif (useCodeInterpreter) {\n\t\t\tnativeToolsParsed.push({\n\t\t\t\ttype: 'code_interpreter',\n\t\t\t});\n\t\t}\n\n\t\tconst useRetrieval = assistantTools.some((tool) => tool.type === 'file_search');\n\t\tif (useRetrieval) {\n\t\t\tnativeToolsParsed.push({\n\t\t\t\ttype: 'file_search',\n\t\t\t});\n\t\t}\n\n\t\tawait client.beta.assistants.update(assistantId, {\n\t\t\ttools: [...nativeToolsParsed, ...transformedConnectedTools],\n\t\t});\n\t}\n\n\tconst agentExecutor = AgentExecutor.fromAgentAndTools({\n\t\tagent,\n\t\ttools: tools ?? [],\n\t});\n\n\tconst useMemoryConnector =\n\t\tnodeVersion >= 1.6 && this.getNodeParameter('memory', i) === 'connector';\n\tconst memory =\n\t\tuseMemoryConnector || nodeVersion < 1.6\n\t\t\t? ((await this.getInputConnectionData(NodeConnectionTypes.AiMemory, 0)) as\n\t\t\t\t\t| BufferWindowMemory\n\t\t\t\t\t| undefined)\n\t\t\t: undefined;\n\n\tconst threadId =\n\t\tnodeVersion >= 1.6 && !useMemoryConnector\n\t\t\t? (this.getNodeParameter('threadId', i) as string)\n\t\t\t: undefined;\n\n\tconst chainValues: IDataObject = {\n\t\tcontent: input,\n\t\tsignal: this.getExecutionCancelSignal(),\n\t\ttimeout: options.timeout ?? 10000,\n\t};\n\tlet thread: OpenAIClient.Beta.Threads.Thread;\n\tif (memory) {\n\t\tconst chatMessages = await getChatMessages(memory);\n\n\t\t// Construct a new thread from the chat history to map the memory\n\t\tif (chatMessages.length) {\n\t\t\tconst first32Messages = chatMessages.slice(0, 32);\n\t\t\t// There is a undocumented limit of 32 messages per thread when creating a thread with messages\n\t\t\tconst mappedMessages: OpenAIClient.Beta.Threads.ThreadCreateParams.Message[] =\n\t\t\t\tfirst32Messages.map(mapChatMessageToThreadMessage);\n\n\t\t\tthread = await client.beta.threads.create({ messages: mappedMessages });\n\t\t\tconst overLimitMessages = chatMessages.slice(32).map(mapChatMessageToThreadMessage);\n\n\t\t\t// Send the remaining messages that exceed the limit of 32 sequentially\n\t\t\tfor (const message of overLimitMessages) {\n\t\t\t\tawait client.beta.threads.messages.create(thread.id, message);\n\t\t\t}\n\n\t\t\tchainValues.threadId = thread.id;\n\t\t}\n\t} else if (threadId) {\n\t\tchainValues.threadId = threadId;\n\t}\n\n\tlet filteredResponse: IDataObject = {};\n\ttry {\n\t\tconst response = await agentExecutor.withConfig(getTracingConfig(this)).invoke(chainValues);\n\t\tif (memory) {\n\t\t\tawait memory.saveContext({ input }, { output: response.output });\n\n\t\t\tif (response.threadId && response.runId) {\n\t\t\t\tconst threadRun = await client.beta.threads.runs.retrieve(response.runId, {\n\t\t\t\t\tthread_id: response.threadId,\n\t\t\t\t});\n\t\t\t\tresponse.usage = threadRun.usage;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\toptions.preserveOriginalTools !== false &&\n\t\t\tnodeVersion >= 1.3 &&\n\t\t\t(assistantTools ?? [])?.length\n\t\t) {\n\t\t\tawait client.beta.assistants.update(assistantId, {\n\t\t\t\ttools: assistantTools,\n\t\t\t});\n\t\t}\n\t\t// Remove configuration properties and runId added by Langchain that are not relevant to the user\n\t\tfilteredResponse = omit(response, ['signal', 'timeout', 'content', 'runId']) as IDataObject;\n\t} catch (error) {\n\t\tif (!(error instanceof ApplicationError)) {\n\t\t\tthrow new NodeOperationError(this.getNode(), error.message, { itemIndex: i });\n\t\t}\n\t}\n\n\treturn [{ json: filteredResponse, pairedItem: { item: i } }];\n}\n"],"mappings":"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","names":["import_descriptions","OpenAIClient","omit"]}