Feature/sse (#3125)

* Base changes for ServerSide Events (instead of socket.io)

* lint fixes

* adding of interface and separate methods for streaming events

* lint

* first draft, handles both internal and external prediction end points.

* lint fixes

* additional internal end point for streaming and associated changes

* return streamresponse as true to build agent flow

* 1) JSON formatting for internal events
2) other fixes

* 1) convert internal event to metadata to maintain consistency with external response

* fix action and metadata streaming

* fix for error when agent flow is aborted

* prevent subflows from streaming and other code cleanup

* prevent streaming from enclosed tools

* add fix for preventing chaintool streaming

* update lock file

* add open when hidden to sse

* Streaming errors

* Streaming errors

* add fix for showing error message

---------

Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
Vinod Kiran
2024-09-17 12:31:25 +05:30
committed by GitHub
parent 7a4c7efcab
commit 26444ac3ae
47 changed files with 1021 additions and 327 deletions
+32 -25
View File
@@ -5,7 +5,8 @@ import {
ICommonObject,
addSingleFileToStorage,
addArrayFilesToStorage,
mapMimeTypeToInputField
mapMimeTypeToInputField,
IServerSideEventStreamer
} from 'flowise-components'
import { StatusCodes } from 'http-status-codes'
import {
@@ -22,7 +23,6 @@ import {
} from '../Interface'
import { InternalFlowiseError } from '../errors/internalFlowiseError'
import { ChatFlow } from '../database/entities/ChatFlow'
import { Server } from 'socket.io'
import { getRunningExpressApp } from '../utils/getRunningExpressApp'
import {
isFlowValidForStream,
@@ -56,10 +56,9 @@ import { IAction } from 'flowise-components'
/**
* Build Chatflow
* @param {Request} req
* @param {Server} socketIO
* @param {boolean} isInternal
*/
export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInternal: boolean = false): Promise<any> => {
export const utilBuildChatflow = async (req: Request, isInternal: boolean = false): Promise<any> => {
try {
const appServer = getRunningExpressApp()
const chatflowid = req.params.id
@@ -78,7 +77,6 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
const chatId = incomingInput.chatId ?? incomingInput.overrideConfig?.sessionId ?? uuidv4()
const userMessageDateTime = new Date()
if (!isInternal) {
const isKeyValidated = await validateChatflowAPIKey(req, chatflow)
if (!isKeyValidated) {
@@ -161,8 +159,7 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
}
incomingInput = {
question: req.body.question ?? 'hello',
overrideConfig,
socketIOClientId: req.body.socketIOClientId
overrideConfig
}
}
@@ -181,7 +178,6 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
const { graph, nodeDependencies } = constructGraphs(nodes, edges)
const directedGraph = graph
const endingNodes = getEndingNodes(nodeDependencies, directedGraph, nodes)
/*** If the graph is an agent graph, build the agent response ***/
if (endingNodes.filter((node) => node.data.category === 'Multi Agents' || node.data.category === 'Sequential Agents').length) {
return await utilBuildAgentResponse(
@@ -195,8 +191,9 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
incomingInput,
nodes,
edges,
socketIO,
baseURL
baseURL,
appServer.sseStreamer,
true
)
}
@@ -320,9 +317,7 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
cachePool: appServer.cachePool,
isUpsert: false,
uploads: incomingInput.uploads,
baseURL,
socketIO,
socketIOClientId: incomingInput.socketIOClientId
baseURL
})
const nodeToExecute =
@@ -373,9 +368,9 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
databaseEntities,
analytic: chatflow.analytic,
uploads: incomingInput.uploads,
socketIO,
socketIOClientId: incomingInput.socketIOClientId,
prependMessages
prependMessages,
sseStreamer: appServer.sseStreamer,
shouldStreamResponse: isStreamValid
})
: await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId,
@@ -442,6 +437,8 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
result.question = incomingInput.question
result.chatId = chatId
result.chatMessageId = chatMessage?.id
result.isStreamValid = isStreamValid
if (sessionId) result.sessionId = sessionId
if (memoryType) result.memoryType = memoryType
@@ -467,12 +464,22 @@ const utilBuildAgentResponse = async (
incomingInput: IncomingInput,
nodes: IReactFlowNode[],
edges: IReactFlowEdge[],
socketIO?: Server,
baseURL?: string
baseURL?: string,
sseStreamer?: IServerSideEventStreamer,
shouldStreamResponse?: boolean
) => {
try {
const appServer = getRunningExpressApp()
const streamResults = await buildAgentGraph(agentflow, chatId, sessionId, incomingInput, isInternal, baseURL, socketIO)
const streamResults = await buildAgentGraph(
agentflow,
chatId,
sessionId,
incomingInput,
isInternal,
baseURL,
sseStreamer,
shouldStreamResponse
)
if (streamResults) {
const { finalResult, finalAction, sourceDocuments, usedTools, agentReasoning } = streamResults
const userMessage: Omit<IChatMessage, 'id'> = {
@@ -498,10 +505,10 @@ const utilBuildAgentResponse = async (
memoryType,
sessionId
}
if (sourceDocuments.length) apiMessage.sourceDocuments = JSON.stringify(sourceDocuments)
if (usedTools.length) apiMessage.usedTools = JSON.stringify(usedTools)
if (agentReasoning.length) apiMessage.agentReasoning = JSON.stringify(agentReasoning)
if (Object.keys(finalAction).length) apiMessage.action = JSON.stringify(finalAction)
if (sourceDocuments?.length) apiMessage.sourceDocuments = JSON.stringify(sourceDocuments)
if (usedTools?.length) apiMessage.usedTools = JSON.stringify(usedTools)
if (agentReasoning?.length) apiMessage.agentReasoning = JSON.stringify(agentReasoning)
if (finalAction && Object.keys(finalAction).length) apiMessage.action = JSON.stringify(finalAction)
const chatMessage = await utilAddChatMessage(apiMessage)
await appServer.telemetry.sendTelemetry('agentflow_prediction_sent', {
@@ -548,8 +555,8 @@ const utilBuildAgentResponse = async (
result.chatMessageId = chatMessage?.id
if (sessionId) result.sessionId = sessionId
if (memoryType) result.memoryType = memoryType
if (agentReasoning.length) result.agentReasoning = agentReasoning
if (Object.keys(finalAction).length) result.action = finalAction
if (agentReasoning?.length) result.agentReasoning = agentReasoning
if (finalAction && Object.keys(finalAction).length) result.action = finalAction
return result
}