mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 17:01:00 +03:00
Feature/Code Interpreter (#3183)
* 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 * add code interpreter * add artifacts to view message dialog * Update pnpm-lock.yaml --------- Co-authored-by: Vinod Paidimarry <vinodkiran@outlook.in>
This commit is contained in:
@@ -8,6 +8,7 @@ import rehypeRaw from 'rehype-raw'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkMath from 'remark-math'
|
||||
import axios from 'axios'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
// material-ui
|
||||
import {
|
||||
@@ -207,7 +208,16 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
if (chatmsg.fileAnnotations) msg.fileAnnotations = chatmsg.fileAnnotations
|
||||
if (chatmsg.feedback) msg.feedback = chatmsg.feedback?.content
|
||||
if (chatmsg.agentReasoning) msg.agentReasoning = chatmsg.agentReasoning
|
||||
|
||||
if (chatmsg.artifacts) {
|
||||
obj.artifacts = chatmsg.artifacts
|
||||
obj.artifacts.forEach((artifact) => {
|
||||
if (artifact.type === 'png' || artifact.type === 'jpeg') {
|
||||
artifact.data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatmsg.chatflowid}&chatId=${
|
||||
chatmsg.chatId
|
||||
}&fileName=${artifact.data.replace('FILE-STORAGE::', '')}`
|
||||
}
|
||||
})
|
||||
}
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, chatPK)) {
|
||||
obj[chatPK] = {
|
||||
id: chatmsg.chatId,
|
||||
@@ -341,7 +351,16 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
if (chatmsg.usedTools) obj.usedTools = chatmsg.usedTools
|
||||
if (chatmsg.fileAnnotations) obj.fileAnnotations = chatmsg.fileAnnotations
|
||||
if (chatmsg.agentReasoning) obj.agentReasoning = chatmsg.agentReasoning
|
||||
|
||||
if (chatmsg.artifacts) {
|
||||
obj.artifacts = chatmsg.artifacts
|
||||
obj.artifacts.forEach((artifact) => {
|
||||
if (artifact.type === 'png' || artifact.type === 'jpeg') {
|
||||
artifact.data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatmsg.chatflowid}&chatId=${
|
||||
chatmsg.chatId
|
||||
}&fileName=${artifact.data.replace('FILE-STORAGE::', '')}`
|
||||
}
|
||||
})
|
||||
}
|
||||
loadedMessages.push(obj)
|
||||
}
|
||||
setChatMessages(loadedMessages)
|
||||
@@ -574,6 +593,83 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [feedbackTypeFilter])
|
||||
|
||||
const agentReasoningArtifacts = (artifacts) => {
|
||||
const newArtifacts = cloneDeep(artifacts)
|
||||
for (let i = 0; i < newArtifacts.length; i++) {
|
||||
const artifact = newArtifacts[i]
|
||||
if (artifact && (artifact.type === 'png' || artifact.type === 'jpeg')) {
|
||||
const data = artifact.data
|
||||
newArtifacts[i].data = `${baseURL}/api/v1/get-upload-file?chatflowId=${
|
||||
dialogProps.chatflow.id
|
||||
}&chatId=${selectedChatId}&fileName=${data.replace('FILE-STORAGE::', '')}`
|
||||
}
|
||||
}
|
||||
return newArtifacts
|
||||
}
|
||||
|
||||
const renderArtifacts = (item, index, isAgentReasoning) => {
|
||||
if (item.type === 'png' || item.type === 'jpeg') {
|
||||
return (
|
||||
<Card
|
||||
key={index}
|
||||
sx={{
|
||||
p: 0,
|
||||
m: 0,
|
||||
mt: 2,
|
||||
mb: 2,
|
||||
flex: '0 0 auto'
|
||||
}}
|
||||
>
|
||||
<CardMedia
|
||||
component='img'
|
||||
image={item.data}
|
||||
sx={{ height: 'auto' }}
|
||||
alt={'artifact'}
|
||||
style={{
|
||||
width: isAgentReasoning ? '200px' : '100%',
|
||||
height: isAgentReasoning ? '200px' : 'auto',
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
)
|
||||
} else if (item.type === 'html') {
|
||||
return (
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<div dangerouslySetInnerHTML={{ __html: item.data }}></div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<MemoizedReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeMathjax, rehypeRaw]}
|
||||
components={{
|
||||
code({ inline, className, children, ...props }) {
|
||||
const match = /language-(\w+)/.exec(className || '')
|
||||
return !inline ? (
|
||||
<CodeBlock
|
||||
key={Math.random()}
|
||||
chatflowid={dialogProps.chatflow.id}
|
||||
isDialog={true}
|
||||
language={(match && match[1]) || ''}
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.data}
|
||||
</MemoizedReactMarkdown>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const component = show ? (
|
||||
<Dialog
|
||||
onClose={onCancel}
|
||||
@@ -879,24 +975,6 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
{message.usedTools && (
|
||||
<div style={{ display: 'block', flexDirection: 'row', width: '100%' }}>
|
||||
{message.usedTools.map((tool, index) => {
|
||||
return (
|
||||
<Chip
|
||||
size='small'
|
||||
key={index}
|
||||
label={tool.tool}
|
||||
component='a'
|
||||
sx={{ mr: 1, mt: 1 }}
|
||||
variant='outlined'
|
||||
clickable
|
||||
onClick={() => onSourceDialogClick(tool, 'Used Tools')}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{message.fileUploads && message.fileUploads.length > 0 && (
|
||||
<div
|
||||
style={{
|
||||
@@ -1008,6 +1086,31 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{agent.artifacts && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
gap: '8px'
|
||||
}}
|
||||
>
|
||||
{agentReasoningArtifacts(
|
||||
agent.artifacts
|
||||
).map((item, index) => {
|
||||
return item !== null ? (
|
||||
<>
|
||||
{renderArtifacts(
|
||||
item,
|
||||
index,
|
||||
true
|
||||
)}
|
||||
</>
|
||||
) : null
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{agent.messages.length > 0 && (
|
||||
<MemoizedReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
@@ -1025,8 +1128,10 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
return !inline ? (
|
||||
<CodeBlock
|
||||
key={Math.random()}
|
||||
chatflowid={chatflowid}
|
||||
isDialog={isDialog}
|
||||
chatflowid={
|
||||
dialogProps.chatflow.id
|
||||
}
|
||||
isDialog={true}
|
||||
language={
|
||||
(match && match[1]) ||
|
||||
''
|
||||
@@ -1122,6 +1227,40 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{message.usedTools && (
|
||||
<div style={{ display: 'block', flexDirection: 'row', width: '100%' }}>
|
||||
{message.usedTools.map((tool, index) => {
|
||||
return (
|
||||
<Chip
|
||||
size='small'
|
||||
key={index}
|
||||
label={tool.tool}
|
||||
component='a'
|
||||
sx={{ mr: 1, mt: 1 }}
|
||||
variant='outlined'
|
||||
clickable
|
||||
onClick={() => onSourceDialogClick(tool, 'Used Tools')}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{message.artifacts && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
{message.artifacts.map((item, index) => {
|
||||
return item !== null ? (
|
||||
<>{renderArtifacts(item, index)}</>
|
||||
) : null
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className='markdownanswer'>
|
||||
{/* Messages are being rendered in Markdown format */}
|
||||
<MemoizedReactMarkdown
|
||||
|
||||
@@ -534,6 +534,23 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
})
|
||||
}
|
||||
|
||||
const updateLastMessageArtifacts = (artifacts) => {
|
||||
artifacts.forEach((artifact) => {
|
||||
if (artifact.type === 'png' || artifact.type === 'jpeg') {
|
||||
artifact.data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&chatId=${chatId}&fileName=${artifact.data.replace(
|
||||
'FILE-STORAGE::',
|
||||
''
|
||||
)}`
|
||||
}
|
||||
})
|
||||
setMessages((prevMessages) => {
|
||||
let allMessages = [...cloneDeep(prevMessages)]
|
||||
if (allMessages[allMessages.length - 1].type === 'userMessage') return allMessages
|
||||
allMessages[allMessages.length - 1].artifacts = artifacts
|
||||
return allMessages
|
||||
})
|
||||
}
|
||||
|
||||
const updateLastMessageNextAgent = (nextAgent) => {
|
||||
setMessages((prevMessages) => {
|
||||
let allMessages = [...cloneDeep(prevMessages)]
|
||||
@@ -730,6 +747,7 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
fileAnnotations: data?.fileAnnotations,
|
||||
agentReasoning: data?.agentReasoning,
|
||||
action: data?.action,
|
||||
artifacts: data?.artifacts,
|
||||
type: 'apiMessage',
|
||||
feedback: null
|
||||
}
|
||||
@@ -792,6 +810,9 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
case 'agentReasoning':
|
||||
updateLastMessageAgentReasoning(payload.data)
|
||||
break
|
||||
case 'artifacts':
|
||||
updateLastMessageArtifacts(payload.data)
|
||||
break
|
||||
case 'action':
|
||||
updateLastMessageAction(payload.data)
|
||||
break
|
||||
@@ -913,6 +934,17 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
if (message.fileAnnotations) obj.fileAnnotations = message.fileAnnotations
|
||||
if (message.agentReasoning) obj.agentReasoning = message.agentReasoning
|
||||
if (message.action) obj.action = message.action
|
||||
if (message.artifacts) {
|
||||
obj.artifacts = message.artifacts
|
||||
obj.artifacts.forEach((artifact) => {
|
||||
if (artifact.type === 'png' || artifact.type === 'jpeg') {
|
||||
artifact.data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&chatId=${chatId}&fileName=${artifact.data.replace(
|
||||
'FILE-STORAGE::',
|
||||
''
|
||||
)}`
|
||||
}
|
||||
})
|
||||
}
|
||||
if (message.fileUploads) {
|
||||
obj.fileUploads = message.fileUploads
|
||||
obj.fileUploads.forEach((file) => {
|
||||
@@ -1260,6 +1292,84 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
}
|
||||
}
|
||||
|
||||
const agentReasoningArtifacts = (artifacts) => {
|
||||
const newArtifacts = cloneDeep(artifacts)
|
||||
for (let i = 0; i < newArtifacts.length; i++) {
|
||||
const artifact = newArtifacts[i]
|
||||
if (artifact && (artifact.type === 'png' || artifact.type === 'jpeg')) {
|
||||
const data = artifact.data
|
||||
newArtifacts[i].data = `${baseURL}/api/v1/get-upload-file?chatflowId=${chatflowid}&chatId=${chatId}&fileName=${data.replace(
|
||||
'FILE-STORAGE::',
|
||||
''
|
||||
)}`
|
||||
}
|
||||
}
|
||||
return newArtifacts
|
||||
}
|
||||
|
||||
const renderArtifacts = (item, index, isAgentReasoning) => {
|
||||
if (item.type === 'png' || item.type === 'jpeg') {
|
||||
return (
|
||||
<Card
|
||||
key={index}
|
||||
sx={{
|
||||
p: 0,
|
||||
m: 0,
|
||||
mt: 2,
|
||||
mb: 2,
|
||||
flex: '0 0 auto'
|
||||
}}
|
||||
>
|
||||
<CardMedia
|
||||
component='img'
|
||||
image={item.data}
|
||||
sx={{ height: 'auto' }}
|
||||
alt={'artifact'}
|
||||
style={{
|
||||
width: isAgentReasoning ? '200px' : '100%',
|
||||
height: isAgentReasoning ? '200px' : 'auto',
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
)
|
||||
} else if (item.type === 'html') {
|
||||
return (
|
||||
<div style={{ marginTop: '20px' }}>
|
||||
<div dangerouslySetInnerHTML={{ __html: item.data }}></div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<MemoizedReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeMathjax, rehypeRaw]}
|
||||
components={{
|
||||
code({ inline, className, children, ...props }) {
|
||||
const match = /language-(\w+)/.exec(className || '')
|
||||
return !inline ? (
|
||||
<CodeBlock
|
||||
key={Math.random()}
|
||||
chatflowid={chatflowid}
|
||||
isDialog={isDialog}
|
||||
language={(match && match[1]) || ''}
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.data}
|
||||
</MemoizedReactMarkdown>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div onDragEnter={handleDrag}>
|
||||
{isDragActive && (
|
||||
@@ -1459,6 +1569,23 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{agent.artifacts && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'row',
|
||||
width: '100%',
|
||||
gap: '8px'
|
||||
}}
|
||||
>
|
||||
{agentReasoningArtifacts(agent.artifacts).map((item, index) => {
|
||||
return item !== null ? (
|
||||
<>{renderArtifacts(item, index, true)}</>
|
||||
) : null
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{agent.messages.length > 0 && (
|
||||
<MemoizedReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
@@ -1553,6 +1680,20 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{message.artifacts && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'column',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
{message.artifacts.map((item, index) => {
|
||||
return item !== null ? <>{renderArtifacts(item, index)}</> : null
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className='markdownanswer'>
|
||||
{message.type === 'leadCaptureMessage' &&
|
||||
!getLocalStorageChatflow(chatflowid)?.lead &&
|
||||
|
||||
Reference in New Issue
Block a user