UNPKG

dtamind-components

Version:

Apps integration for Dtamind. Contain Nodes and Credentials.

260 lines 10.8 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); const utils_1 = require("../../../src/utils"); const utils_2 = require("../utils"); class ExecuteFlow_Agentflow { constructor() { //@ts-ignore this.loadMethods = { async listFlows(_, options) { const returnData = []; const appDataSource = options.appDataSource; const databaseEntities = options.databaseEntities; if (appDataSource === undefined || !appDataSource) { return returnData; } const searchOptions = options.searchOptions || {}; const chatflows = await appDataSource.getRepository(databaseEntities['ChatFlow']).findBy(searchOptions); for (let i = 0; i < chatflows.length; i += 1) { let cfType = 'Chatflow'; if (chatflows[i].type === 'AGENTFLOW') { cfType = 'Agentflow V2'; } else if (chatflows[i].type === 'MULTIAGENT') { cfType = 'Agentflow V1'; } const data = { label: chatflows[i].name, name: chatflows[i].id, description: cfType }; returnData.push(data); } // order by label return returnData.sort((a, b) => a.label.localeCompare(b.label)); }, async listRuntimeStateKeys(_, options) { const previousNodes = options.previousNodes; const startAgentflowNode = previousNodes.find((node) => node.name === 'startAgentflow'); const state = startAgentflowNode?.inputs?.startState; return state.map((item) => ({ label: item.key, name: item.key })); } }; this.label = 'Execute Flow'; this.name = 'executeFlowAgentflow'; this.version = 1.0; this.type = 'ExecuteFlow'; this.category = 'Agent Flows'; this.description = 'Execute another flow'; this.baseClasses = [this.type]; this.color = '#a3b18a'; this.credential = { label: 'Connect Credential', name: 'credential', type: 'credential', credentialNames: ['chatflowApi'], optional: true }; this.inputs = [ { label: 'Select Flow', name: 'executeFlowSelectedFlow', type: 'asyncOptions', loadMethod: 'listFlows' }, { label: 'Input', name: 'executeFlowInput', type: 'string', rows: 4, acceptVariable: true }, { label: 'Override Config', name: 'executeFlowOverrideConfig', description: 'Override the config passed to the flow', type: 'json', optional: true }, { label: 'Base URL', name: 'executeFlowBaseURL', type: 'string', description: 'Base URL to Dtamind. By default, it is the URL of the incoming request. Useful when you need to execute flow through an alternative route.', placeholder: 'http://localhost:3000', optional: true }, { label: 'Return Response As', name: 'executeFlowReturnResponseAs', type: 'options', options: [ { label: 'User Message', name: 'userMessage' }, { label: 'Assistant Message', name: 'assistantMessage' } ], default: 'userMessage' }, { label: 'Update Flow State', name: 'executeFlowUpdateState', description: 'Update runtime state during the execution of the workflow', type: 'array', optional: true, acceptVariable: true, array: [ { label: 'Key', name: 'key', type: 'asyncOptions', loadMethod: 'listRuntimeStateKeys', freeSolo: true }, { label: 'Value', name: 'value', type: 'string', acceptVariable: true, acceptNodeOutputAsVariable: true } ] } ]; } async run(nodeData, _, options) { const baseURL = nodeData.inputs?.executeFlowBaseURL || options.baseURL; const selectedFlowId = nodeData.inputs?.executeFlowSelectedFlow; const flowInput = nodeData.inputs?.executeFlowInput; const returnResponseAs = nodeData.inputs?.executeFlowReturnResponseAs; const _executeFlowUpdateState = nodeData.inputs?.executeFlowUpdateState; const overrideConfig = typeof nodeData.inputs?.executeFlowOverrideConfig === 'string' && nodeData.inputs.executeFlowOverrideConfig.startsWith('{') && nodeData.inputs.executeFlowOverrideConfig.endsWith('}') ? JSON.parse(nodeData.inputs.executeFlowOverrideConfig) : nodeData.inputs?.executeFlowOverrideConfig; const state = options.agentflowRuntime?.state; const runtimeChatHistory = options.agentflowRuntime?.chatHistory ?? []; const isLastNode = options.isLastNode; const sseStreamer = options.sseStreamer; try { const credentialData = await (0, utils_1.getCredentialData)(nodeData.credential ?? '', options); const chatflowApiKey = (0, utils_1.getCredentialParam)('chatflowApiKey', credentialData, nodeData); if (selectedFlowId === options.chatflowid) throw new Error('Cannot call the same agentflow!'); let headers = { 'Content-Type': 'application/json' }; if (chatflowApiKey) headers = { ...headers, Authorization: `Bearer ${chatflowApiKey}` }; const finalUrl = `${baseURL}/api/v1/prediction/${selectedFlowId}`; const requestConfig = { method: 'POST', url: finalUrl, headers, data: { question: flowInput, chatId: options.chatId, overrideConfig } }; const response = await (0, axios_1.default)(requestConfig); let resultText = ''; if (response.data.text) resultText = response.data.text; else if (response.data.json) resultText = '```json\n' + JSON.stringify(response.data.json, null, 2); else resultText = JSON.stringify(response.data, null, 2); if (isLastNode && sseStreamer) { sseStreamer.streamTokenEvent(options.chatId, resultText); } // Update flow state if needed let newState = { ...state }; if (_executeFlowUpdateState && Array.isArray(_executeFlowUpdateState) && _executeFlowUpdateState.length > 0) { newState = (0, utils_2.updateFlowState)(state, _executeFlowUpdateState); } // Process template variables in state if (newState && Object.keys(newState).length > 0) { for (const key in newState) { if (newState[key].toString().includes('{{ output }}')) { newState[key] = resultText; } } } // Only add to runtime chat history if this is the first node const inputMessages = []; if (!runtimeChatHistory.length) { inputMessages.push({ role: 'user', content: flowInput }); } let returnRole = 'user'; if (returnResponseAs === 'assistantMessage') { returnRole = 'assistant'; } const returnOutput = { id: nodeData.id, name: this.name, input: { messages: [ { role: 'user', content: flowInput } ] }, output: { content: resultText }, state: newState, chatHistory: [ ...inputMessages, { role: returnRole, content: resultText, name: nodeData?.label ? nodeData?.label.toLowerCase().replace(/\s/g, '_').trim() : nodeData?.id } ] }; return returnOutput; } catch (error) { console.error('ExecuteFlow Error:', error); // Format error response const errorResponse = { id: nodeData.id, name: this.name, input: { messages: [ { role: 'user', content: flowInput } ] }, error: { name: error.name || 'Error', message: error.message || 'An error occurred during the execution of the flow' }, state }; // Add more error details if available if (error.response) { errorResponse.error.status = error.response.status; errorResponse.error.statusText = error.response.statusText; errorResponse.error.data = error.response.data; errorResponse.error.headers = error.response.headers; } throw new Error(error); } } } module.exports = { nodeClass: ExecuteFlow_Agentflow }; //# sourceMappingURL=ExecuteFlow.js.map