From 64308c3d0debd86606f55fafb9e83c94078157a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yanli=20=E7=9B=90=E7=B2=92?= Date: Tue, 17 Mar 2026 19:18:39 +0800 Subject: [PATCH] fix: address workflow tracing review feedback --- web/app/components/base/chat/chat/hooks.ts | 4 +-- .../workflow-stream-handlers.spec.ts | 26 ++++++++++++++++ .../result/workflow-stream-handlers.ts | 7 ++--- .../use-workflow-run-event-store-only.spec.ts | 30 +++++++++++++++---- ...e-workflow-run-event-with-viewport.spec.ts | 4 +-- .../use-workflow-agent-log.ts | 10 +++---- .../workflow/panel/debug-and-preview/hooks.ts | 7 +++-- 7 files changed, 65 insertions(+), 23 deletions(-) diff --git a/web/app/components/base/chat/chat/hooks.ts b/web/app/components/base/chat/chat/hooks.ts index 51e6ad7560..1da6b58bac 100644 --- a/web/app/components/base/chat/chat/hooks.ts +++ b/web/app/components/base/chat/chat/hooks.ts @@ -452,7 +452,7 @@ export const useChat = ( upsertTopLevelTracingNodeOnStart(responseItem.workflowProcess.tracing, { ...nodeStartedData, - status: WorkflowRunningStatus.Running, + status: NodeRunningStatus.Running, }) }) }, @@ -1005,7 +1005,7 @@ export const useChat = ( upsertTopLevelTracingNodeOnStart(responseItem.workflowProcess.tracing, { ...nodeStartedData, - status: WorkflowRunningStatus.Running, + status: NodeRunningStatus.Running, }) updateCurrentQAOnTree({ placeholderQuestionId, diff --git a/web/app/components/share/text-generation/result/__tests__/workflow-stream-handlers.spec.ts b/web/app/components/share/text-generation/result/__tests__/workflow-stream-handlers.spec.ts index 45d5ded302..4b61a8ffd9 100644 --- a/web/app/components/share/text-generation/result/__tests__/workflow-stream-handlers.spec.ts +++ b/web/app/components/share/text-generation/result/__tests__/workflow-stream-handlers.spec.ts @@ -101,6 +101,7 @@ const createHumanInput = (overrides: Partial = {}): HumanInp describe('workflow-stream-handlers helpers', () => { it('should update tracing, result text, and human input state', () => { const parallelTrace = createTrace({ + id: 'parallel-trace-1', node_id: 'parallel-node', execution_metadata: { parallel_id: 'parallel-1' }, details: [[]], @@ -109,11 +110,13 @@ describe('workflow-stream-handlers helpers', () => { let workflowProcessData = appendParallelStart(undefined, parallelTrace) workflowProcessData = appendParallelNext(workflowProcessData, parallelTrace) workflowProcessData = finishParallelTrace(workflowProcessData, createTrace({ + id: 'parallel-trace-1', node_id: 'parallel-node', execution_metadata: { parallel_id: 'parallel-1' }, error: 'failed', })) workflowProcessData = upsertWorkflowNode(workflowProcessData, createTrace({ + id: 'node-trace-1', node_id: 'node-1', execution_metadata: { parallel_id: 'parallel-2' }, }))! @@ -160,6 +163,29 @@ describe('workflow-stream-handlers helpers', () => { expect(nextProcess.tracing[0]?.details).toEqual([[], []]) }) + it('should append a new top-level trace when the same node starts with a different execution id', () => { + const process = createWorkflowProcess() + process.tracing = [ + createTrace({ + id: 'trace-1', + node_id: 'node-1', + status: NodeRunningStatus.Succeeded, + }), + ] + + const updatedProcess = upsertWorkflowNode(process, createTrace({ + id: 'trace-2', + node_id: 'node-1', + }))! + + expect(updatedProcess.tracing).toHaveLength(2) + expect(updatedProcess.tracing[1]).toEqual(expect.objectContaining({ + id: 'trace-2', + node_id: 'node-1', + status: NodeRunningStatus.Running, + })) + }) + it('should leave tracing unchanged when a parallel next event has no matching trace', () => { const process = createWorkflowProcess() process.tracing = [ diff --git a/web/app/components/share/text-generation/result/workflow-stream-handlers.ts b/web/app/components/share/text-generation/result/workflow-stream-handlers.ts index 48b132587e..7b50faba27 100644 --- a/web/app/components/share/text-generation/result/workflow-stream-handlers.ts +++ b/web/app/components/share/text-generation/result/workflow-stream-handlers.ts @@ -5,6 +5,7 @@ import type { HumanInputFormTimeoutData, NodeTracing, WorkflowFinishedResponse } import { produce } from 'immer' import { getFilesInLogs } from '@/app/components/base/file-uploader/utils' import { NodeRunningStatus, WorkflowRunningStatus } from '@/app/components/workflow/types' +import { upsertTopLevelTracingNodeOnStart } from '@/app/components/workflow/utils/top-level-tracing' import { sseGet } from '@/service/base' type Notify = (payload: { type: 'error' | 'warning', message: string }) => void @@ -96,17 +97,13 @@ const upsertWorkflowNode = (current: WorkflowProcess | undefined, data: NodeTrac return updateWorkflowProcess(current, (draft) => { draft.expand = true - const currentIndex = draft.tracing.findIndex(item => item.node_id === data.node_id) const nextTrace = { ...data, status: NodeRunningStatus.Running, expand: true, } - if (currentIndex > -1) - draft.tracing[currentIndex] = nextTrace - else - draft.tracing.push(nextTrace) + upsertTopLevelTracingNodeOnStart(draft.tracing, nextTrace) }) } diff --git a/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-store-only.spec.ts b/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-store-only.spec.ts index 6a3347f77a..57f7298e68 100644 --- a/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-store-only.spec.ts +++ b/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-store-only.spec.ts @@ -109,13 +109,13 @@ describe('useWorkflowAgentLog', () => { const { result, store } = renderWorkflowHook(() => useWorkflowAgentLog(), { initialStoreState: { workflowRunningData: baseRunningData({ - tracing: [{ node_id: 'n1', execution_metadata: {} }], + tracing: [{ id: 'trace-1', node_id: 'n1', execution_metadata: {} }], }), }, }) result.current.handleWorkflowAgentLog({ - data: { node_id: 'n1', message_id: 'm1' }, + data: { node_id: 'n1', node_execution_id: 'trace-1', message_id: 'm1' }, } as AgentLogResponse) const trace = store.getState().workflowRunningData!.tracing![0] @@ -128,6 +128,7 @@ describe('useWorkflowAgentLog', () => { initialStoreState: { workflowRunningData: baseRunningData({ tracing: [{ + id: 'trace-1', node_id: 'n1', execution_metadata: { agent_log: [{ message_id: 'm1', text: 'log1' }] }, }], @@ -136,7 +137,7 @@ describe('useWorkflowAgentLog', () => { }) result.current.handleWorkflowAgentLog({ - data: { node_id: 'n1', message_id: 'm2' }, + data: { node_id: 'n1', node_execution_id: 'trace-1', message_id: 'm2' }, } as AgentLogResponse) expect(store.getState().workflowRunningData!.tracing![0].execution_metadata!.agent_log).toHaveLength(2) @@ -147,6 +148,7 @@ describe('useWorkflowAgentLog', () => { initialStoreState: { workflowRunningData: baseRunningData({ tracing: [{ + id: 'trace-1', node_id: 'n1', execution_metadata: { agent_log: [{ message_id: 'm1', text: 'old' }] }, }], @@ -155,7 +157,7 @@ describe('useWorkflowAgentLog', () => { }) result.current.handleWorkflowAgentLog({ - data: { node_id: 'n1', message_id: 'm1', text: 'new' }, + data: { node_id: 'n1', node_execution_id: 'trace-1', message_id: 'm1', text: 'new' }, } as unknown as AgentLogResponse) const log = store.getState().workflowRunningData!.tracing![0].execution_metadata!.agent_log! @@ -167,13 +169,13 @@ describe('useWorkflowAgentLog', () => { const { result, store } = renderWorkflowHook(() => useWorkflowAgentLog(), { initialStoreState: { workflowRunningData: baseRunningData({ - tracing: [{ node_id: 'n1' }], + tracing: [{ id: 'trace-1', node_id: 'n1' }], }), }, }) result.current.handleWorkflowAgentLog({ - data: { node_id: 'n1', message_id: 'm1' }, + data: { node_id: 'n1', node_execution_id: 'trace-1', message_id: 'm1' }, } as AgentLogResponse) expect(store.getState().workflowRunningData!.tracing![0].execution_metadata!.agent_log).toHaveLength(1) @@ -200,6 +202,22 @@ describe('useWorkflowAgentLog', () => { expect(tracing[1].execution_metadata!.agent_log).toHaveLength(1) expect(tracing[1].execution_metadata!.agent_log![0].message_id).toBe('m2') }) + + it('should ignore agent logs when node_execution_id is missing', () => { + const { result, store } = renderWorkflowHook(() => useWorkflowAgentLog(), { + initialStoreState: { + workflowRunningData: baseRunningData({ + tracing: [{ id: 'trace-1', node_id: 'n1', execution_metadata: {} }], + }), + }, + }) + + result.current.handleWorkflowAgentLog({ + data: { node_id: 'n1', message_id: 'm1' }, + } as AgentLogResponse) + + expect(store.getState().workflowRunningData!.tracing![0].execution_metadata!.agent_log).toBeUndefined() + }) }) describe('useWorkflowNodeHumanInputFormFilled', () => { diff --git a/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-with-viewport.spec.ts b/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-with-viewport.spec.ts index 1495c1b2b8..7074aba148 100644 --- a/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-with-viewport.spec.ts +++ b/web/app/components/workflow/hooks/__tests__/use-workflow-run-event-with-viewport.spec.ts @@ -41,7 +41,7 @@ describe('useWorkflowNodeStarted', () => { }) result.current.handleWorkflowNodeStarted( - { data: { node_id: 'n1' } } as NodeStartedResponse, + { data: { id: 'trace-n1', node_id: 'n1' } } as NodeStartedResponse, containerParams, ) @@ -65,7 +65,7 @@ describe('useWorkflowNodeStarted', () => { }) result.current.handleWorkflowNodeStarted( - { data: { node_id: 'n2' } } as NodeStartedResponse, + { data: { id: 'trace-n2', node_id: 'n2' } } as NodeStartedResponse, containerParams, ) diff --git a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-agent-log.ts b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-agent-log.ts index 31f82ffdc8..0f88572a0b 100644 --- a/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-agent-log.ts +++ b/web/app/components/workflow/hooks/use-workflow-run-event/use-workflow-agent-log.ts @@ -13,13 +13,11 @@ export const useWorkflowAgentLog = () => { setWorkflowRunningData, } = workflowStore.getState() - setWorkflowRunningData(produce(workflowRunningData!, (draft) => { - const currentIndex = draft.tracing!.findIndex((item) => { - if (data.node_execution_id) - return item.id === data.node_execution_id + if (!data.node_execution_id) + return - return item.node_id === data.node_id - }) + setWorkflowRunningData(produce(workflowRunningData!, (draft) => { + const currentIndex = draft.tracing!.findIndex(item => item.id === data.node_execution_id) if (currentIndex > -1) { const current = draft.tracing![currentIndex] diff --git a/web/app/components/workflow/panel/debug-and-preview/hooks.ts b/web/app/components/workflow/panel/debug-and-preview/hooks.ts index 2807976bad..f7c182867f 100644 --- a/web/app/components/workflow/panel/debug-and-preview/hooks.ts +++ b/web/app/components/workflow/panel/debug-and-preview/hooks.ts @@ -530,7 +530,10 @@ export const useChat = ( } }, onAgentLog: ({ data }) => { - const currentNodeIndex = responseItem.workflowProcess!.tracing!.findIndex(item => item.node_id === data.node_id) + if (!data.node_execution_id) + return + + const currentNodeIndex = responseItem.workflowProcess!.tracing!.findIndex(item => item.id === data.node_execution_id) if (currentNodeIndex > -1) { const current = responseItem.workflowProcess!.tracing![currentNodeIndex] @@ -775,7 +778,7 @@ export const useChat = ( upsertTopLevelTracingNodeOnStart(responseItem.workflowProcess.tracing, { ...nodeStartedData, - status: WorkflowRunningStatus.Running, + status: NodeRunningStatus.Running, }) }) },