fix: workflow result generation render

This commit is contained in:
zxhlyh
2026-01-28 21:00:57 +08:00
parent 0c1e812d21
commit 3af927556e
5 changed files with 124 additions and 4 deletions

View File

@ -1,13 +1,25 @@
import type { TextChunkResponse } from '@/types/workflow'
import { produce } from 'immer'
import { useCallback } from 'react'
import { useCallback, useRef } from 'react'
import { v4 as uuidV4 } from 'uuid'
import { useWorkflowStore } from '@/app/components/workflow/store'
export const useWorkflowTextChunk = () => {
const workflowStore = useWorkflowStore()
const toolCallIdRef = useRef<string | null>(null)
const handleWorkflowTextChunk = useCallback((params: TextChunkResponse) => {
const { data: { text } } = params
const { data: {
text,
chunk_type,
tool_name,
tool_arguments,
tool_icon,
tool_icon_dark,
tool_error,
tool_elapsed_time,
tool_files,
} } = params
const {
workflowRunningData,
setWorkflowRunningData,
@ -15,7 +27,87 @@ export const useWorkflowTextChunk = () => {
setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
draft.resultTabActive = true
draft.resultText += text
if (chunk_type === 'text') {
draft.resultText += text
if (!draft.resultLLMGenerationItems)
draft.resultLLMGenerationItems = []
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
if (isNotCompletedTextItemIndex > -1) {
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].text += text
}
else {
draft.resultLLMGenerationItems?.push({
id: uuidV4(),
type: 'text',
text,
})
}
}
if (chunk_type === 'tool_call') {
if (!draft.resultLLMGenerationItems)
draft.resultLLMGenerationItems = []
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
if (isNotCompletedTextItemIndex > -1) {
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].textCompleted = true
}
toolCallIdRef.current = uuidV4()
draft.resultLLMGenerationItems?.push({
id: toolCallIdRef.current,
type: 'tool',
toolName: tool_name,
toolArguments: tool_arguments,
toolIcon: tool_icon,
toolIconDark: tool_icon_dark,
})
}
if (chunk_type === 'tool_result') {
const currentToolCallIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
if (currentToolCallIndex > -1) {
draft.resultLLMGenerationItems![currentToolCallIndex].toolError = tool_error
draft.resultLLMGenerationItems![currentToolCallIndex].toolDuration = tool_elapsed_time
draft.resultLLMGenerationItems![currentToolCallIndex].toolFiles = tool_files
draft.resultLLMGenerationItems![currentToolCallIndex].toolOutput = text
}
}
if (chunk_type === 'thought_start') {
if (!draft.resultLLMGenerationItems)
draft.resultLLMGenerationItems = []
const isNotCompletedTextItemIndex = draft.resultLLMGenerationItems?.findIndex(item => item.type === 'text' && !item.textCompleted)
if (isNotCompletedTextItemIndex > -1) {
draft.resultLLMGenerationItems![isNotCompletedTextItemIndex].textCompleted = true
}
toolCallIdRef.current = uuidV4()
draft.resultLLMGenerationItems?.push({
id: toolCallIdRef.current,
type: 'thought',
thoughtOutput: '',
})
}
if (chunk_type === 'thought') {
const currentThoughtIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
if (currentThoughtIndex > -1) {
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtOutput += text
}
}
if (chunk_type === 'thought_end') {
const currentThoughtIndex = draft.resultLLMGenerationItems?.findIndex(item => item.id === toolCallIdRef.current) ?? -1
if (currentThoughtIndex > -1) {
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtOutput += text
draft.resultLLMGenerationItems![currentThoughtIndex].thoughtCompleted = true
}
}
}))
}, [workflowStore])

View File

@ -178,6 +178,7 @@ const WorkflowPreview = () => {
<ResultText
isRunning={workflowRunningData?.result?.status === WorkflowRunningStatus.Running || !workflowRunningData?.result}
outputs={workflowRunningData?.resultText}
llmGenerationItems={workflowRunningData?.resultLLMGenerationItems}
allFiles={workflowRunningData?.result?.files}
error={workflowRunningData?.result?.error}
onClick={() => switchTab('DETAIL')}

View File

@ -1,6 +1,8 @@
'use client'
import type { FC } from 'react'
import type { LLMGenerationItem } from '@/types/workflow'
import { useTranslation } from 'react-i18next'
import GenerationContent from '@/app/components/base/chat/chat/answer/generation-content'
import LoadingAnim from '@/app/components/base/chat/chat/loading-anim'
import { FileList } from '@/app/components/base/file-uploader'
import { ImageIndentLeft } from '@/app/components/base/icons/src/vender/line/editor'
@ -10,6 +12,7 @@ import StatusContainer from '@/app/components/workflow/run/status-container'
type ResultTextProps = {
isRunning?: boolean
outputs?: any
llmGenerationItems?: LLMGenerationItem[]
error?: string
onClick?: () => void
allFiles?: any[]
@ -18,11 +21,16 @@ type ResultTextProps = {
const ResultText: FC<ResultTextProps> = ({
isRunning,
outputs,
llmGenerationItems,
error,
onClick,
allFiles,
}) => {
const { t } = useTranslation()
const generationContentRenderIsUsed = llmGenerationItems?.length && llmGenerationItems.some((item) => {
return item.type === 'tool' || item.type === 'thought'
})
return (
<div className="bg-background-section-burn">
{isRunning && !outputs && (
@ -50,11 +58,18 @@ const ResultText: FC<ResultTextProps> = ({
)}
{(outputs || !!allFiles?.length) && (
<>
{outputs && (
{outputs && !generationContentRenderIsUsed && (
<div className="px-4 py-2">
<Markdown content={outputs} />
</div>
)}
{
generationContentRenderIsUsed && (
<div className="px-2 py-1">
<GenerationContent llmGenerationItems={llmGenerationItems} />
</div>
)
}
{!!allFiles?.length && allFiles.map(item => (
<div key={item.varName} className="system-xs-regular flex flex-col gap-1 px-4 py-2">
<div className="py-1 text-text-tertiary ">{item.varName}</div>

View File

@ -5,10 +5,12 @@ import type {
WorkflowRunningData,
} from '@/app/components/workflow/types'
import type { FileUploadConfigResponse } from '@/models/common'
import type { LLMGenerationItem } from '@/types/workflow'
type PreviewRunningData = WorkflowRunningData & {
resultTabActive?: boolean
resultText?: string
resultLLMGenerationItems?: LLMGenerationItem[]
}
type MousePosition = {

View File

@ -369,6 +369,16 @@ export type TextChunkResponse = {
event: string
data: {
text: string
chunk_type?: 'text' | 'tool_call' | 'tool_result' | 'thought' | 'thought_start' | 'thought_end'
tool_call_id?: string
tool_name?: string
tool_arguments?: string
tool_icon?: string | IconObject
tool_icon_dark?: string | IconObject
tool_files?: string[]
tool_error?: string
tool_elapsed_time?: number
}
}