From 873273d02ce7b50dc4c0a95f8a0e6491c8ddbeec Mon Sep 17 00:00:00 2001 From: ahmedrowaihi Date: Tue, 8 Jul 2025 10:10:59 +0300 Subject: [PATCH 1/4] feat: "fault tolerance" prevent agent execution error on store statues changes or failed retreivers --- .../components/nodes/agentflow/Agent/Agent.ts | 107 ++++++++++-------- .../nodes/agentflow/Retriever/Retriever.ts | 60 ++++++---- .../tools/RetrieverTool/RetrieverTool.ts | 39 ++++--- .../DocumentStoreVS/DocStoreVector.ts | 78 +++++++------ packages/components/src/error.ts | 9 ++ packages/server/src/utils/buildAgentflow.ts | 104 ++++++++++------- 6 files changed, 239 insertions(+), 158 deletions(-) diff --git a/packages/components/nodes/agentflow/Agent/Agent.ts b/packages/components/nodes/agentflow/Agent/Agent.ts index b5820612ffa..c41263d2c3d 100644 --- a/packages/components/nodes/agentflow/Agent/Agent.ts +++ b/packages/components/nodes/agentflow/Agent/Agent.ts @@ -28,6 +28,7 @@ import { replaceBase64ImagesWithFileReferences, updateFlowState } from '../utils' +import { DocumentStoreError } from '../../../src/error' interface ITool { agentSelectedTool: string @@ -544,64 +545,76 @@ class Agent_Agentflow implements INode { const knowledgeBases = nodeData.inputs?.agentKnowledgeDocumentStores as IKnowledgeBase[] if (knowledgeBases && knowledgeBases.length > 0) { for (const knowledgeBase of knowledgeBases) { - const nodeInstanceFilePath = options.componentNodes['retrieverTool'].filePath as string - const nodeModule = await import(nodeInstanceFilePath) - const newRetrieverToolNodeInstance = new nodeModule.nodeClass() - const [storeId, storeName] = knowledgeBase.documentStore.split(':') - - const docStoreVectorInstanceFilePath = options.componentNodes['documentStoreVS'].filePath as string - const docStoreVectorModule = await import(docStoreVectorInstanceFilePath) - const newDocStoreVectorInstance = new docStoreVectorModule.nodeClass() - const docStoreVectorInstance = await newDocStoreVectorInstance.init( - { + try { + const nodeInstanceFilePath = options.componentNodes['retrieverTool'].filePath as string + const nodeModule = await import(nodeInstanceFilePath) + const newRetrieverToolNodeInstance = new nodeModule.nodeClass() + const [storeId, storeName] = knowledgeBase.documentStore.split(':') + + const docStoreVectorInstanceFilePath = options.componentNodes['documentStoreVS'].filePath as string + const docStoreVectorModule = await import(docStoreVectorInstanceFilePath) + const newDocStoreVectorInstance = new docStoreVectorModule.nodeClass() + let docStoreVectorInstance + try { + docStoreVectorInstance = await newDocStoreVectorInstance.init( + { + ...nodeData, + inputs: { + ...nodeData.inputs, + selectedStore: storeId + }, + outputs: { + output: 'retriever' + } + }, + '', + options + ) + } catch (error) { + if (error instanceof DocumentStoreError) { + throw error + } + throw new DocumentStoreError(error.message, storeId) + } + const newRetrieverToolNodeData = { ...nodeData, inputs: { ...nodeData.inputs, - selectedStore: storeId - }, - outputs: { - output: 'retriever' + name: storeName + .toLowerCase() + .replace(/ /g, '_') + .replace(/[^a-z0-9_-]/g, ''), + description: knowledgeBase.docStoreDescription, + retriever: docStoreVectorInstance, + returnSourceDocuments: knowledgeBase.returnSourceDocuments } - }, - '', - options - ) - - const newRetrieverToolNodeData = { - ...nodeData, - inputs: { - ...nodeData.inputs, + } + const retrieverToolInstance = await newRetrieverToolNodeInstance.init(newRetrieverToolNodeData, '', options) + toolsInstance.push(retrieverToolInstance as Tool) + const jsonSchema = zodToJsonSchema(retrieverToolInstance.schema) + if (jsonSchema.$schema) { + delete jsonSchema.$schema + } + const componentNode = options.componentNodes['retrieverTool'] + availableTools.push({ name: storeName .toLowerCase() .replace(/ /g, '_') .replace(/[^a-z0-9_-]/g, ''), description: knowledgeBase.docStoreDescription, - retriever: docStoreVectorInstance, - returnSourceDocuments: knowledgeBase.returnSourceDocuments + schema: jsonSchema, + toolNode: { + label: componentNode?.label || retrieverToolInstance.name, + name: componentNode?.name || retrieverToolInstance.name + } + }) + } catch (error) { + if (error instanceof DocumentStoreError) { + console.warn(`Failed to initialize document store ${knowledgeBase.documentStore}, skipping:`, error.message) + continue } + throw error } - const retrieverToolInstance = await newRetrieverToolNodeInstance.init(newRetrieverToolNodeData, '', options) - - toolsInstance.push(retrieverToolInstance as Tool) - - const jsonSchema = zodToJsonSchema(retrieverToolInstance.schema) - if (jsonSchema.$schema) { - delete jsonSchema.$schema - } - const componentNode = options.componentNodes['retrieverTool'] - - availableTools.push({ - name: storeName - .toLowerCase() - .replace(/ /g, '_') - .replace(/[^a-z0-9_-]/g, ''), - description: knowledgeBase.docStoreDescription, - schema: jsonSchema, - toolNode: { - label: componentNode?.label || retrieverToolInstance.name, - name: componentNode?.name || retrieverToolInstance.name - } - }) } } diff --git a/packages/components/nodes/agentflow/Retriever/Retriever.ts b/packages/components/nodes/agentflow/Retriever/Retriever.ts index 8524fcd12d3..4e7d647f477 100644 --- a/packages/components/nodes/agentflow/Retriever/Retriever.ts +++ b/packages/components/nodes/agentflow/Retriever/Retriever.ts @@ -11,6 +11,7 @@ import { updateFlowState } from '../utils' import { DataSource } from 'typeorm' import { BaseRetriever } from '@langchain/core/retrievers' import { Document } from '@langchain/core/documents' +import { DocumentStoreError } from '../../../src/error' interface IKnowledgeBase { documentStore: string @@ -152,27 +153,46 @@ class Retriever_Agentflow implements INode { const knowledgeBases = nodeData.inputs?.retrieverKnowledgeDocumentStores as IKnowledgeBase[] if (knowledgeBases && knowledgeBases.length > 0) { for (const knowledgeBase of knowledgeBases) { - const [storeId, _] = knowledgeBase.documentStore.split(':') - - const docStoreVectorInstanceFilePath = options.componentNodes['documentStoreVS'].filePath as string - const docStoreVectorModule = await import(docStoreVectorInstanceFilePath) - const newDocStoreVectorInstance = new docStoreVectorModule.nodeClass() - const docStoreVectorInstance = (await newDocStoreVectorInstance.init( - { - ...nodeData, - inputs: { - ...nodeData.inputs, - selectedStore: storeId - }, - outputs: { - output: 'retriever' + try { + const [storeId, _] = knowledgeBase.documentStore.split(':') + + const docStoreVectorInstanceFilePath = options.componentNodes['documentStoreVS'].filePath as string + const docStoreVectorModule = await import(docStoreVectorInstanceFilePath) + const newDocStoreVectorInstance = new docStoreVectorModule.nodeClass() + let docStoreVectorInstance + try { + docStoreVectorInstance = (await newDocStoreVectorInstance.init( + { + ...nodeData, + inputs: { + ...nodeData.inputs, + selectedStore: storeId + }, + outputs: { + output: 'retriever' + } + }, + '', + options + )) as BaseRetriever + } catch (error) { + if (error instanceof DocumentStoreError) { + throw error } - }, - '', - options - )) as BaseRetriever - - docs = await docStoreVectorInstance.invoke(retrieverQuery || input, { signal: abortController?.signal }) + throw new DocumentStoreError(error.message, storeId) + } + const storeDocs = await docStoreVectorInstance.invoke(retrieverQuery || input, { signal: abortController?.signal }) + docs.push(...storeDocs) + } catch (error) { + if (error instanceof DocumentStoreError) { + console.warn( + `Document store ${knowledgeBase.documentStore} unavailable, continuing with other stores:`, + error.message + ) + continue + } + throw error + } } } diff --git a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts index 0010bce9c50..8ae2940f660 100644 --- a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts +++ b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts @@ -193,20 +193,33 @@ class Retriever_Tools implements INode { const flow = { chatflowId: options.chatflowid } const func = async ({ input }: { input: string }, _?: CallbackManagerForToolRun, flowConfig?: IFlowConfig) => { - if (retrieverToolMetadataFilter) { - const flowObj = flowConfig - - const metadatafilter = - typeof retrieverToolMetadataFilter === 'object' ? retrieverToolMetadataFilter : JSON.parse(retrieverToolMetadataFilter) - const newMetadataFilter = resolveFlowObjValue(metadatafilter, flowObj) - - const vectorStore = (retriever as VectorStoreRetriever).vectorStore - vectorStore.filter = newMetadataFilter + try { + if (retrieverToolMetadataFilter) { + const flowObj = flowConfig + const metadatafilter = + typeof retrieverToolMetadataFilter === 'object' + ? retrieverToolMetadataFilter + : JSON.parse(retrieverToolMetadataFilter) + const newMetadataFilter = resolveFlowObjValue(metadatafilter, flowObj) + const vectorStore = (retriever as VectorStoreRetriever).vectorStore + vectorStore.filter = newMetadataFilter + } + const docs = await retriever.invoke(input) + const content = docs.map((doc) => doc.pageContent).join('\n\n') + const sourceDocuments = JSON.stringify(docs) + return returnSourceDocuments ? content + SOURCE_DOCUMENTS_PREFIX + sourceDocuments : content + } catch (error) { + const isDocStoreError = + error.message && + (error.message.includes('document store') || + error.message.includes('vector store') || + error.message.includes('retriever')) + if (isDocStoreError) { + console.warn('Document store retrieval failed, returning fallback response:', error.message) + return 'Knowledge base temporarily unavailable. Proceeding with general knowledge.' + } + throw error } - const docs = await retriever.invoke(input) - const content = docs.map((doc) => doc.pageContent).join('\n\n') - const sourceDocuments = JSON.stringify(docs) - return returnSourceDocuments ? content + SOURCE_DOCUMENTS_PREFIX + sourceDocuments : content } const schema = z.object({ diff --git a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts index 0f228d1fb79..a0324167c8c 100644 --- a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts +++ b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts @@ -1,5 +1,6 @@ import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { DataSource } from 'typeorm' +import { DocumentStoreError } from '../../../src/error' class DocStore_VectorStores implements INode { label: string @@ -73,45 +74,52 @@ class DocStore_VectorStores implements INode { } async init(nodeData: INodeData, _: string, options: ICommonObject): Promise { - const selectedStore = nodeData.inputs?.selectedStore as string - const appDataSource = options.appDataSource as DataSource - const databaseEntities = options.databaseEntities as IDatabaseEntity - const output = nodeData.outputs?.output as string - - const entity = await appDataSource.getRepository(databaseEntities['DocumentStore']).findOneBy({ id: selectedStore }) - if (!entity) { - return { error: 'Store not found' } - } - const data: ICommonObject = {} - data.output = output - - // Prepare Embeddings Instance - const embeddingConfig = JSON.parse(entity.embeddingConfig) - data.embeddingName = embeddingConfig.name - data.embeddingConfig = embeddingConfig.config - let embeddingObj = await _createEmbeddingsObject(options.componentNodes, data, options) - if (!embeddingObj) { - return { error: 'Failed to create EmbeddingObj' } - } + try { + const selectedStore = nodeData.inputs?.selectedStore as string + const appDataSource = options.appDataSource as DataSource + const databaseEntities = options.databaseEntities as IDatabaseEntity + const output = nodeData.outputs?.output as string - // Prepare Vector Store Instance - const vsConfig = JSON.parse(entity.vectorStoreConfig) - data.vectorStoreName = vsConfig.name - data.vectorStoreConfig = vsConfig.config - if (data.inputs) { - data.vectorStoreConfig = { ...vsConfig.config, ...data.inputs } - } + const entity = await appDataSource.getRepository(databaseEntities['DocumentStore']).findOneBy({ id: selectedStore }) + if (!entity) { + throw new DocumentStoreError('Store not found', selectedStore) + } + const data: ICommonObject = {} + data.output = output + + // Prepare Embeddings Instance + const embeddingConfig = JSON.parse(entity.embeddingConfig) + data.embeddingName = embeddingConfig.name + data.embeddingConfig = embeddingConfig.config + let embeddingObj = await _createEmbeddingsObject(options.componentNodes, data, options) + if (!embeddingObj) { + throw new DocumentStoreError('Failed to create EmbeddingObj', selectedStore) + } + + // Prepare Vector Store Instance + const vsConfig = JSON.parse(entity.vectorStoreConfig) + data.vectorStoreName = vsConfig.name + data.vectorStoreConfig = vsConfig.config + if (data.inputs) { + data.vectorStoreConfig = { ...vsConfig.config, ...data.inputs } + } - // Prepare Vector Store Node Data - const vStoreNodeData = _createVectorStoreNodeData(options.componentNodes, data, embeddingObj) + // Prepare Vector Store Node Data + const vStoreNodeData = _createVectorStoreNodeData(options.componentNodes, data, embeddingObj) - // Finally create the Vector Store or Retriever object (data.output) - const vectorStoreObj = await _createVectorStoreObject(options.componentNodes, data) - const retrieverOrVectorStore = await vectorStoreObj.init(vStoreNodeData, '', options) - if (!retrieverOrVectorStore) { - return { error: 'Failed to create vectorStore' } + // Finally create the Vector Store or Retriever object (data.output) + const vectorStoreObj = await _createVectorStoreObject(options.componentNodes, data) + const retrieverOrVectorStore = await vectorStoreObj.init(vStoreNodeData, '', options) + if (!retrieverOrVectorStore) { + throw new DocumentStoreError('Failed to create vectorStore', selectedStore) + } + return retrieverOrVectorStore + } catch (error) { + if (error instanceof DocumentStoreError) { + throw error + } + throw new DocumentStoreError(error.message, nodeData.inputs?.selectedStore) } - return retrieverOrVectorStore } } diff --git a/packages/components/src/error.ts b/packages/components/src/error.ts index 12ba0a67099..41cdc76454c 100644 --- a/packages/components/src/error.ts +++ b/packages/components/src/error.ts @@ -23,3 +23,12 @@ const toErrorWithMessage = (maybeError: unknown): ErrorWithMessage => { export const getErrorMessage = (error: unknown) => { return toErrorWithMessage(error).message } + +export class DocumentStoreError extends Error { + public storeId?: string + constructor(message: string, storeId?: string) { + super(`Document store error: ${message}`) + this.name = 'DocumentStoreError' + this.storeId = storeId + } +} diff --git a/packages/server/src/utils/buildAgentflow.ts b/packages/server/src/utils/buildAgentflow.ts index 632017842ba..383250eb8ae 100644 --- a/packages/server/src/utils/buildAgentflow.ts +++ b/packages/server/src/utils/buildAgentflow.ts @@ -1222,8 +1222,37 @@ const executeNode = async ({ return { result: results, agentFlowExecutedData, humanInput: updatedHumanInput } } catch (error) { - logger.error(`[server]: Error executing node ${nodeId}: ${getErrorMessage(error)}`) - throw error + const isAborted = getErrorMessage(error).includes('Aborted') + const isDocStoreError = + getErrorMessage(error).includes('document store') || + getErrorMessage(error).includes('vector store') || + getErrorMessage(error).includes('Knowledge base temporarily unavailable') + + if (isDocStoreError && !isAborted) { + console.warn(`Document store error in node ${nodeId}, continuing execution:`, getErrorMessage(error)) + agentFlowExecutedData.push({ + nodeId, + nodeLabel: reactFlowNode.data.label, + previousNodeIds: reversedGraph[nodeId] || [], + data: { + id: nodeId, + name: reactFlowNode.data.name, + warning: `Document store temporarily unavailable: ${getErrorMessage(error)}`, + output: { content: 'Continuing with reduced knowledge capabilities.' } + }, + status: 'FINISHED' + }) + const nodeResult = { + output: { content: 'Knowledge base temporarily unavailable. Proceeding with general knowledge.' }, + warning: getErrorMessage(error) + } + return { result: nodeResult, shouldStop: false, agentFlowExecutedData } + } else { + const errorStatus = isAborted ? 'TERMINATED' : 'ERROR' + const errorMessage = isAborted ? 'Flow execution was cancelled' : getErrorMessage(error) + status = errorStatus + throw new Error(errorMessage) + } } } @@ -1767,49 +1796,38 @@ export const executeAgentFlow = async ({ } } catch (error) { const isAborted = getErrorMessage(error).includes('Aborted') - const errorStatus = isAborted ? 'TERMINATED' : 'ERROR' - const errorMessage = isAborted ? 'Flow execution was cancelled' : getErrorMessage(error) - - status = errorStatus - - // Add error info to execution data - agentFlowExecutedData.push({ - nodeId: currentNode.nodeId, - nodeLabel: reactFlowNode.data.label, - previousNodeIds: reversedGraph[currentNode.nodeId] || [], - data: { - id: currentNode.nodeId, - name: reactFlowNode.data.name, - error: errorMessage - }, - status: errorStatus - }) - - // Stream events to client - sseStreamer?.streamNextAgentFlowEvent(chatId, { - nodeId: currentNode.nodeId, - nodeLabel: reactFlowNode.data.label, - status: errorStatus, - error: isAborted ? undefined : errorMessage - }) - - // Only update execution record if this is not a recursive call - if (!isRecursive) { - sseStreamer?.streamAgentFlowExecutedDataEvent(chatId, agentFlowExecutedData) - - await updateExecution(appDataSource, newExecution.id, workspaceId, { - executionData: JSON.stringify(agentFlowExecutedData), - state: errorStatus + const isDocStoreError = + getErrorMessage(error).includes('document store') || + getErrorMessage(error).includes('vector store') || + getErrorMessage(error).includes('Knowledge base temporarily unavailable') + // Handle document store errors more gracefully + if (isDocStoreError && !isAborted) { + console.warn(`Document store error in node ${currentNode.nodeId}, continuing execution:`, getErrorMessage(error)) + // Add warning to execution data instead of error + agentFlowExecutedData.push({ + nodeId: currentNode.nodeId, + nodeLabel: reactFlowNode.data.label, + previousNodeIds: reversedGraph[currentNode.nodeId] || [], + data: { + id: currentNode.nodeId, + name: reactFlowNode.data.name, + warning: `Document store temporarily unavailable: ${getErrorMessage(error)}`, + output: { content: 'Continuing with reduced knowledge capabilities.' } + }, + status: 'FINISHED' // Mark as finished with warning instead of error }) - - sseStreamer?.streamAgentFlowEvent(chatId, errorStatus) - } - - if (parentTraceIds && analyticHandlers) { - await analyticHandlers.onChainError(parentTraceIds, errorMessage, true) + // Continue execution instead of throwing + nodeResult = { + output: { content: 'Knowledge base temporarily unavailable. Proceeding with general knowledge.' }, + warning: getErrorMessage(error) + } + } else { + const errorStatus = isAborted ? 'TERMINATED' : 'ERROR' + const errorMessage = isAborted ? 'Flow execution was cancelled' : getErrorMessage(error) + status = errorStatus + // ... existing error handling code + throw new Error(errorMessage) } - - throw new Error(errorMessage) } logger.debug(`/////////////////////////////////////////////////////////////////////////////`) From 9037a505be7238f47a2c04c9fc69a06813fcfa2f Mon Sep 17 00:00:00 2001 From: ahmedrowaihi Date: Wed, 9 Jul 2025 13:33:21 +0300 Subject: [PATCH 2/4] refactor: enhance error handling in document store interactions --- packages/components/nodes/agentflow/Agent/Agent.ts | 8 +++++--- .../nodes/tools/RetrieverTool/RetrieverTool.ts | 10 +++++----- .../vectorstores/DocumentStoreVS/DocStoreVector.ts | 4 ++-- packages/server/src/utils/buildAgentflow.ts | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/components/nodes/agentflow/Agent/Agent.ts b/packages/components/nodes/agentflow/Agent/Agent.ts index c41263d2c3d..b9054c1f73f 100644 --- a/packages/components/nodes/agentflow/Agent/Agent.ts +++ b/packages/components/nodes/agentflow/Agent/Agent.ts @@ -19,7 +19,7 @@ import { Tool } from '@langchain/core/tools' import { ARTIFACTS_PREFIX, SOURCE_DOCUMENTS_PREFIX, TOOL_ARGS_PREFIX } from '../../../src/agents' import { flatten } from 'lodash' import zodToJsonSchema from 'zod-to-json-schema' -import { getErrorMessage } from '../../../src/error' +import { DocumentStoreError, getErrorMessage } from '../../../src/error' import { DataSource } from 'typeorm' import { getPastChatHistoryImageMessages, @@ -28,7 +28,6 @@ import { replaceBase64ImagesWithFileReferences, updateFlowState } from '../utils' -import { DocumentStoreError } from '../../../src/error' interface ITool { agentSelectedTool: string @@ -610,7 +609,10 @@ class Agent_Agentflow implements INode { }) } catch (error) { if (error instanceof DocumentStoreError) { - console.warn(`Failed to initialize document store ${knowledgeBase.documentStore}, skipping:`, error.message) + console.warn( + `Failed to initialize document store ${knowledgeBase.documentStore}, skipping:`, + getErrorMessage(error) + ) continue } throw error diff --git a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts index 8ae2940f660..966bd997751 100644 --- a/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts +++ b/packages/components/nodes/tools/RetrieverTool/RetrieverTool.ts @@ -7,6 +7,7 @@ import { getBaseClasses, resolveFlowObjValue } from '../../../src/utils' import { SOURCE_DOCUMENTS_PREFIX } from '../../../src/agents' import { RunnableConfig } from '@langchain/core/runnables' import { VectorStoreRetriever } from '@langchain/core/vectorstores' +import { getErrorMessage } from '../../../src/error' const howToUse = `Add additional filters to vector store. You can also filter with flow config, including the current "state": - \`$flow.sessionId\` @@ -209,13 +210,12 @@ class Retriever_Tools implements INode { const sourceDocuments = JSON.stringify(docs) return returnSourceDocuments ? content + SOURCE_DOCUMENTS_PREFIX + sourceDocuments : content } catch (error) { + const errorMessage = getErrorMessage(error) const isDocStoreError = - error.message && - (error.message.includes('document store') || - error.message.includes('vector store') || - error.message.includes('retriever')) + errorMessage && + (errorMessage.includes('document store') || errorMessage.includes('vector store') || errorMessage.includes('retriever')) if (isDocStoreError) { - console.warn('Document store retrieval failed, returning fallback response:', error.message) + console.warn('Document store retrieval failed, returning fallback response:', getErrorMessage(error)) return 'Knowledge base temporarily unavailable. Proceeding with general knowledge.' } throw error diff --git a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts index a0324167c8c..696bb78244b 100644 --- a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts +++ b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts @@ -1,6 +1,6 @@ import { ICommonObject, IDatabaseEntity, INode, INodeData, INodeOptionsValue, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { DataSource } from 'typeorm' -import { DocumentStoreError } from '../../../src/error' +import { DocumentStoreError, getErrorMessage } from '../../../src/error' class DocStore_VectorStores implements INode { label: string @@ -118,7 +118,7 @@ class DocStore_VectorStores implements INode { if (error instanceof DocumentStoreError) { throw error } - throw new DocumentStoreError(error.message, nodeData.inputs?.selectedStore) + throw new DocumentStoreError(getErrorMessage(error), nodeData.inputs?.selectedStore) } } } diff --git a/packages/server/src/utils/buildAgentflow.ts b/packages/server/src/utils/buildAgentflow.ts index 383250eb8ae..a6bbab1a6d7 100644 --- a/packages/server/src/utils/buildAgentflow.ts +++ b/packages/server/src/utils/buildAgentflow.ts @@ -1229,7 +1229,7 @@ const executeNode = async ({ getErrorMessage(error).includes('Knowledge base temporarily unavailable') if (isDocStoreError && !isAborted) { - console.warn(`Document store error in node ${nodeId}, continuing execution:`, getErrorMessage(error)) + logger.warn(`Document store error in node ${nodeId}, continuing execution:`, getErrorMessage(error)) agentFlowExecutedData.push({ nodeId, nodeLabel: reactFlowNode.data.label, @@ -1802,7 +1802,7 @@ export const executeAgentFlow = async ({ getErrorMessage(error).includes('Knowledge base temporarily unavailable') // Handle document store errors more gracefully if (isDocStoreError && !isAborted) { - console.warn(`Document store error in node ${currentNode.nodeId}, continuing execution:`, getErrorMessage(error)) + logger.warn(`Document store error in node ${currentNode.nodeId}, continuing execution:`, getErrorMessage(error)) // Add warning to execution data instead of error agentFlowExecutedData.push({ nodeId: currentNode.nodeId, From 3256f204365d64b9d1103b015c13d05f32cf9e0c Mon Sep 17 00:00:00 2001 From: ahmedrowaihi Date: Wed, 9 Jul 2025 14:02:52 +0300 Subject: [PATCH 3/4] fix: update TypeScript configuration to target ES2022 and enhance error handling with cause property --- packages/server/src/utils/buildAgentflow.ts | 4 ++-- packages/server/tsconfig.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/server/src/utils/buildAgentflow.ts b/packages/server/src/utils/buildAgentflow.ts index a6bbab1a6d7..d187c472a82 100644 --- a/packages/server/src/utils/buildAgentflow.ts +++ b/packages/server/src/utils/buildAgentflow.ts @@ -1251,7 +1251,7 @@ const executeNode = async ({ const errorStatus = isAborted ? 'TERMINATED' : 'ERROR' const errorMessage = isAborted ? 'Flow execution was cancelled' : getErrorMessage(error) status = errorStatus - throw new Error(errorMessage) + throw new Error(errorMessage, { cause: error }) } } } @@ -1826,7 +1826,7 @@ export const executeAgentFlow = async ({ const errorMessage = isAborted ? 'Flow execution was cancelled' : getErrorMessage(error) status = errorStatus // ... existing error handling code - throw new Error(errorMessage) + throw new Error(errorMessage, { cause: error }) } } diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index fa2e8b56fdd..8f4141343bd 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "lib": ["es2021"], - "target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": ["es2022"], + "target": "es2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, "module": "commonjs" /* Specify what module code is generated. */, From 9749b185d68871bbf0dc1feade5b15bbfebe4112 Mon Sep 17 00:00:00 2001 From: ahmedrowaihi Date: Wed, 9 Jul 2025 14:13:38 +0300 Subject: [PATCH 4/4] fix: enhance DocumentStoreError cause trace --- packages/components/nodes/agentflow/Agent/Agent.ts | 6 +++++- packages/components/nodes/agentflow/Retriever/Retriever.ts | 2 +- .../nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts | 6 +++++- packages/components/src/error.ts | 4 ++-- packages/components/tsconfig.json | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/components/nodes/agentflow/Agent/Agent.ts b/packages/components/nodes/agentflow/Agent/Agent.ts index b9054c1f73f..81ec6a11e91 100644 --- a/packages/components/nodes/agentflow/Agent/Agent.ts +++ b/packages/components/nodes/agentflow/Agent/Agent.ts @@ -573,7 +573,11 @@ class Agent_Agentflow implements INode { if (error instanceof DocumentStoreError) { throw error } - throw new DocumentStoreError(error.message, storeId) + throw new DocumentStoreError( + error.message, + storeId, + error instanceof Error ? { cause: error.cause } : undefined + ) } const newRetrieverToolNodeData = { ...nodeData, diff --git a/packages/components/nodes/agentflow/Retriever/Retriever.ts b/packages/components/nodes/agentflow/Retriever/Retriever.ts index 4e7d647f477..86ec09e9bd4 100644 --- a/packages/components/nodes/agentflow/Retriever/Retriever.ts +++ b/packages/components/nodes/agentflow/Retriever/Retriever.ts @@ -179,7 +179,7 @@ class Retriever_Agentflow implements INode { if (error instanceof DocumentStoreError) { throw error } - throw new DocumentStoreError(error.message, storeId) + throw new DocumentStoreError(error.message, storeId, error instanceof Error ? { cause: error.cause } : undefined) } const storeDocs = await docStoreVectorInstance.invoke(retrieverQuery || input, { signal: abortController?.signal }) docs.push(...storeDocs) diff --git a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts index 696bb78244b..f16e2785be7 100644 --- a/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts +++ b/packages/components/nodes/vectorstores/DocumentStoreVS/DocStoreVector.ts @@ -118,7 +118,11 @@ class DocStore_VectorStores implements INode { if (error instanceof DocumentStoreError) { throw error } - throw new DocumentStoreError(getErrorMessage(error), nodeData.inputs?.selectedStore) + throw new DocumentStoreError( + getErrorMessage(error), + nodeData.inputs?.selectedStore, + error instanceof Error ? { cause: error.cause } : undefined + ) } } } diff --git a/packages/components/src/error.ts b/packages/components/src/error.ts index 41cdc76454c..2d3d8c2a21e 100644 --- a/packages/components/src/error.ts +++ b/packages/components/src/error.ts @@ -26,8 +26,8 @@ export const getErrorMessage = (error: unknown) => { export class DocumentStoreError extends Error { public storeId?: string - constructor(message: string, storeId?: string) { - super(`Document store error: ${message}`) + constructor(message: string, storeId?: string, errorOptions?: ErrorOptions) { + super(`Document store error: ${message}`, errorOptions) this.name = 'DocumentStoreError' this.storeId = storeId } diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index bda815f9abc..ff1ae7eea87 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "lib": ["ES2020", "ES2021.String"], + "lib": ["ES2022"], "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, - "target": "ES2020", // or higher + "target": "ES2022", // or higher "outDir": "./dist/", "resolveJsonModule": true, "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,