Fix workflow (#5592)

* fix: fileselector default

* fix: workflow run process
This commit is contained in:
Archer
2025-09-04 20:22:35 +08:00
committed by GitHub
parent 9be1e591d3
commit 85ea117481
13 changed files with 230 additions and 192 deletions

View File

@@ -17,7 +17,6 @@ import { useTranslation } from 'next-i18next';
import type { AppFileSelectConfigType } from '@fastgpt/global/core/app/type.d';
import MyModal from '@fastgpt/web/components/common/MyModal';
import MySlider from '@/components/Slider';
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
import ChatFunctionTip from './Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import { useMount } from 'ahooks';
@@ -25,6 +24,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import MyTag from '@fastgpt/web/components/common/Tag/index';
import MyDivider from '@fastgpt/web/components/common/MyDivider';
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
const FileSelect = ({
forbidVision = false,

View File

@@ -5,21 +5,18 @@ import type { WorkflowInteractiveResponseType } from '@fastgpt/global/core/workf
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type';
import type { RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
import type { WorkflowDebugResponse } from '@fastgpt/service/core/workflow/dispatch/type';
export type PostWorkflowDebugProps = {
nodes: RuntimeNodeItemType[];
edges: RuntimeEdgeItemType[];
skipNodeQueue?: WorkflowDebugResponse['skipNodeQueue'];
variables: Record<string, any>;
appId: string;
query?: UserChatItemValueItemType[];
history?: ChatItemType[];
};
export type PostWorkflowDebugResponse = {
finishedNodes: RuntimeNodeItemType[];
finishedEdges: RuntimeEdgeItemType[];
nextStepRunNodes: RuntimeNodeItemType[];
flowResponses: ChatHistoryItemResType[];
workflowInteractiveResponse?: WorkflowInteractiveResponseType;
export type PostWorkflowDebugResponse = WorkflowDebugResponse & {
newVariables: Record<string, any>;
};

View File

@@ -31,7 +31,6 @@ import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import VariableTip from '@/components/common/Textarea/MyTextarea/VariableTip';
import { getWebLLMModel } from '@/web/common/system/utils';
import ToolSelect from './components/ToolSelect';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import OptimizerPopover from '@/components/common/PromptEditor/OptimizerPopover';
const DatasetSelectModal = dynamic(() => import('@/components/core/app/DatasetSelectModal'));
@@ -148,7 +147,7 @@ const EditForm = ({
},
[appForm.aiSettings.systemPrompt, setAppForm]
);
console.log(appForm.chatConfig.fileSelectConfig);
return (
<>
<Box>

View File

@@ -11,6 +11,7 @@ import { type SimpleAppSnapshotType, useSimpleAppSnapshots } from './useSnapshot
import { useDebounceEffect, useMount } from 'ahooks';
import { v1Workflow2V2 } from '@/web/core/workflow/adapt';
import { getAppConfigByDiff } from '@/web/core/app/diff';
import { defaultAppSelectFileConfig } from '@fastgpt/global/core/app/constants';
const Edit = dynamic(() => import('./Edit'));
const Logs = dynamic(() => import('../Logs/index'));
@@ -79,7 +80,13 @@ const SimpleEdit = () => {
if (past.length === 0) {
const appForm = appWorkflow2Form({
nodes: appDetail.modules,
chatConfig: appDetail.chatConfig
chatConfig: {
...appDetail.chatConfig,
fileSelectConfig: appDetail.chatConfig.fileSelectConfig || {
...defaultAppSelectFileConfig,
canSelectFile: true
}
}
});
saveSnapshot({
appForm,

View File

@@ -127,11 +127,9 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
}
];
const lastInteractive = getLastInteractiveValue(mockHistory);
onNextNodeDebug({
...workflowDebugData,
// Rewrite runtimeEdges
runtimeEdges: storeEdges2RuntimeEdges(workflowDebugData.runtimeEdges, lastInteractive),
runtimeEdges: workflowDebugData.runtimeEdges,
query: updatedQuery,
history: mockHistory
});
@@ -189,7 +187,7 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
<Box fontWeight={'bold'} flex={'1'}>
{t('common:core.workflow.debug.Run result')}
</Box>
{workflowDebugData?.nextRunNodes.length !== 0 && (
{workflowDebugData?.entryNodeIds.length !== 0 && (
<PopoverConfirm
Trigger={
<Button
@@ -209,8 +207,8 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
<>
{(debugResult.status === 'success' || debugResult.status === 'skipped') &&
!debugResult.isExpired &&
workflowDebugData?.nextRunNodes &&
workflowDebugData.nextRunNodes.length > 0 && (
workflowDebugData?.entryNodeIds &&
workflowDebugData.entryNodeIds.length > 0 && (
<Button
ml={2}
size={'sm'}
@@ -221,8 +219,8 @@ const NodeDebugResponse = ({ nodeId, debugResult }: NodeDebugResponseProps) => {
{t('common:next_step')}
</Button>
)}
{workflowDebugData?.nextRunNodes &&
workflowDebugData?.nextRunNodes.length === 0 && (
{workflowDebugData?.entryNodeIds &&
workflowDebugData?.entryNodeIds.length === 0 && (
<Button ml={2} size={'sm'} variant={'primary'} onClick={onStopNodeDebug}>
{t('common:core.workflow.debug.Done')}
</Button>

View File

@@ -54,12 +54,12 @@ import { cloneDeep } from 'lodash';
import { type AppVersionSchemaType } from '@fastgpt/global/core/app/version';
import WorkflowInitContextProvider, { WorkflowNodeEdgeContext } from './workflowInitContext';
import WorkflowEventContextProvider from './workflowEventContext';
import { getAppConfigByDiff } from '@/web/core/app/diff';
import WorkflowStatusContextProvider from './workflowStatusContext';
import { type ChatItemType, type UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
import { type WorkflowInteractiveResponseType } from '@fastgpt/global/core/workflow/template/system/interactive/type';
import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import { useChatStore } from '@/web/core/chat/context/useChatStore';
import type { WorkflowDebugResponse } from '@fastgpt/service/core/workflow/dispatch/type';
/*
Context
@@ -266,7 +266,9 @@ type WorkflowContextType = {
export type DebugDataType = {
runtimeNodes: RuntimeNodeItemType[];
runtimeEdges: RuntimeEdgeItemType[];
nextRunNodes: RuntimeNodeItemType[];
entryNodeIds: string[];
skipNodeQueue?: WorkflowDebugResponse['skipNodeQueue'];
variables: Record<string, any>;
history?: ChatItemType[];
query?: UserChatItemValueItemType[];
@@ -686,112 +688,67 @@ const WorkflowContextProvider = ({
}))
);
// 2. Set isEntry field and get entryNodes
// 2. Set isEntry field and get entryNodes, and set running status
const runtimeNodes = debugData.runtimeNodes.map((item) => ({
...item,
isEntry: debugData.nextRunNodes.some((node) => node.nodeId === item.nodeId)
isEntry: debugData.entryNodeIds.some((id) => id === item.nodeId)
}));
const entryNodes = runtimeNodes.filter((item) => item.isEntry);
const runtimeNodeStatus: Record<string, string> = entryNodes
.map((node) => {
const status = checkNodeRunStatus({
node,
nodesMap: new Map(runtimeNodes.map((item) => [item.nodeId, item])),
runtimeEdges: debugData?.runtimeEdges || []
});
return {
nodeId: node.nodeId,
status
};
})
.reduce(
(acc, cur) => ({
...acc,
[cur.nodeId]: cur.status
}),
{}
);
// 3. Set entry node status to running
entryNodes.forEach((node) => {
if (runtimeNodeStatus[node.nodeId] !== 'wait') {
const entryNodes = runtimeNodes.filter((item) => {
if (item.isEntry) {
onChangeNode({
nodeId: node.nodeId,
nodeId: item.nodeId,
type: 'attr',
key: 'debugResult',
value: defaultRunningStatus
});
return true;
}
});
try {
// 4. Run one step
const {
finishedEdges,
finishedNodes,
nextStepRunNodes,
flowResponses,
newVariables,
workflowInteractiveResponse
} = await postWorkflowDebug({
nodes: runtimeNodes,
edges: debugData.runtimeEdges,
variables: {
appId,
cTime: formatTime2YMDHMW(),
...debugData.variables
},
query: debugData.query, // 添加 query 参数
history: debugData.history,
appId
});
// 3. Run one step
const { memoryEdges, entryNodeIds, skipNodeQueue, nodeResponses, newVariables } =
await postWorkflowDebug({
nodes: runtimeNodes,
edges: debugData.runtimeEdges,
skipNodeQueue: debugData.skipNodeQueue,
variables: {
appId,
cTime: formatTime2YMDHMW(),
...debugData.variables
},
query: debugData.query, // 添加 query 参数
history: debugData.history,
appId
});
// 5. Store debug result
// 4. Store debug result
setWorkflowDebugData({
runtimeNodes: finishedNodes,
// edges need to save status
runtimeEdges: finishedEdges,
nextRunNodes: nextStepRunNodes,
variables: newVariables,
workflowInteractiveResponse: workflowInteractiveResponse
runtimeNodes: debugData.runtimeNodes,
runtimeEdges: memoryEdges,
entryNodeIds,
skipNodeQueue,
variables: newVariables
});
// 6. selected entry node and Update entry node debug result
// 5. selected entry node and Update entry node debug result
setNodes((state) =>
state.map((node) => {
const isEntryNode = entryNodes.some((item) => item.nodeId === node.data.nodeId);
if (!isEntryNode || runtimeNodeStatus[node.data.nodeId] === 'wait') return node;
const result = flowResponses.find((item) => item.nodeId === node.data.nodeId);
if (runtimeNodeStatus[node.data.nodeId] === 'skip') {
return {
...node,
selected: isEntryNode,
data: {
...node.data,
debugResult: {
status: 'skipped',
showResult: true,
isExpired: false
}
}
};
}
const result = nodeResponses[node.data.nodeId];
if (!result) return node;
return {
...node,
selected: isEntryNode,
selected: result.type === 'run' && isEntryNode,
data: {
...node.data,
debugResult: {
status: 'success',
response: result,
status: result.type === 'run' ? 'success' : 'skipped',
response: result.response,
showResult: true,
isExpired: false,
workflowInteractiveResponse: workflowInteractiveResponse
workflowInteractiveResponse: result.interactiveResponse
}
}
};
@@ -799,13 +756,9 @@ const WorkflowContextProvider = ({
);
// Check for an empty response(Skip node)
if (
!workflowInteractiveResponse &&
flowResponses.length === 0 &&
nextStepRunNodes.length > 0
) {
onNextNodeDebug(debugData);
}
// if (!workflowInteractiveResponse && flowResponses.length === 0 && entryNodeIds.length > 0) {
// onNextNodeDebug(debugData);
// }
} catch (error) {
entryNodes.forEach((node) => {
onChangeNode({
@@ -856,7 +809,10 @@ const WorkflowContextProvider = ({
const data: DebugDataType = {
runtimeNodes,
runtimeEdges,
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId),
entryNodeIds: runtimeNodes
.filter((node) => node.nodeId === entryNodeId)
.map((node) => node.nodeId),
skipNodeQueue: [],
variables,
query,
history

View File

@@ -21,6 +21,7 @@ async function handler(
const {
nodes = [],
edges = [],
skipNodeQueue,
variables = {},
appId,
query = [],
@@ -47,34 +48,34 @@ async function handler(
// auth balance
const { timezone, externalProvider } = await getUserChatInfoAndAuthTeamPoints(tmbId);
const lastInteractive = getLastInteractiveValue(history);
const interactive = getLastInteractiveValue(history);
/* start process */
const { flowUsages, flowResponses, debugResponse, newVariables, workflowInteractiveResponse } =
await dispatchWorkFlow({
res,
lang: getLocale(req),
requestOrigin: req.headers.origin,
mode: 'debug',
timezone,
externalProvider,
uid: tmbId,
runningAppInfo: {
id: app._id,
teamId: app.teamId,
tmbId: app.tmbId
},
runningUserInfo: await getRunningUserInfoByTmbId(tmbId),
runtimeNodes: nodes,
runtimeEdges: edges,
lastInteractive,
variables,
query: query,
chatConfig: defaultApp.chatConfig,
histories: history,
stream: false,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
});
const { flowUsages, debugResponse, newVariables } = await dispatchWorkFlow({
res,
lang: getLocale(req),
requestOrigin: req.headers.origin,
mode: 'debug',
timezone,
externalProvider,
uid: tmbId,
runningAppInfo: {
id: app._id,
teamId: app.teamId,
tmbId: app.tmbId
},
runningUserInfo: await getRunningUserInfoByTmbId(tmbId),
runtimeNodes: nodes,
runtimeEdges: edges,
defaultSkipNodeQueue: skipNodeQueue,
lastInteractive: interactive,
variables,
query: query,
chatConfig: defaultApp.chatConfig,
histories: history,
stream: false,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
});
createChatUsage({
appName: `${app.name}-Debug`,
@@ -86,10 +87,8 @@ async function handler(
});
return {
...debugResponse,
newVariables,
flowResponses,
workflowInteractiveResponse
...debugResponse!,
newVariables
};
}