feat: add history parameter to PostWorkflowDebugProps and update related components
This commit is contained in:
@@ -65,6 +65,7 @@ export type ModuleDispatchProps<T> = ChatDispatchProps & {
|
|||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
params: T;
|
params: T;
|
||||||
|
realmode: 'chat' | 'debug' | 'test';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SystemVariablesType = {
|
export type SystemVariablesType = {
|
||||||
|
|||||||
@@ -581,7 +581,8 @@ export async function dispatchWorkFlow(data: Props): Promise<DispatchFlowRespons
|
|||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
params,
|
params,
|
||||||
mode: props.mode === 'debug' ? 'test' : props.mode
|
mode: props.mode === 'debug' ? 'test' : props.mode,
|
||||||
|
realmode: props.mode
|
||||||
};
|
};
|
||||||
|
|
||||||
// run module
|
// run module
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ import {
|
|||||||
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
} from '@fastgpt/global/core/workflow/template/system/interactive/type';
|
||||||
import { useContextSelector } from 'use-context-selector';
|
import { useContextSelector } from 'use-context-selector';
|
||||||
import { WorkflowContext } from '@/pageComponents/app/detail/WorkflowComponents/context';
|
import { WorkflowContext } from '@/pageComponents/app/detail/WorkflowComponents/context';
|
||||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
||||||
import { UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import {
|
||||||
|
AIChatItemValueItemType,
|
||||||
|
ChatItemType,
|
||||||
|
UserChatItemValueItemType
|
||||||
|
} from '@fastgpt/global/core/chat/type';
|
||||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||||
|
import { StoreEdgeItemType, RuntimeEdgeItemType } from '@fastgpt/global/core/workflow/type/edge';
|
||||||
|
import { initWorkflowEdgeStatus } from '@fastgpt/global/core/workflow/runtime/utils';
|
||||||
|
|
||||||
export const RenderUserSelectInteractive = React.memo(function RenderInteractive({
|
export const RenderUserSelectInteractive = React.memo(function RenderInteractive({
|
||||||
interactive,
|
interactive,
|
||||||
@@ -29,42 +35,78 @@ export const RenderUserSelectInteractive = React.memo(function RenderInteractive
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedValue, setSelectedValue] = useState<string | undefined>(undefined);
|
const [selectedValue, setSelectedValue] = useState<string | undefined>(undefined);
|
||||||
const { onChangeNode, onNextNodeDebug, workflowDebugData, setWorkflowDebugData } =
|
// 在两个组件中更新上下文选择器,添加 onStartNodeDebug
|
||||||
useContextSelector(WorkflowContext, (v) => ({
|
const { onChangeNode, onStartNodeDebug, workflowDebugData } = useContextSelector(
|
||||||
|
WorkflowContext,
|
||||||
|
(v) => ({
|
||||||
onChangeNode: v.onChangeNode,
|
onChangeNode: v.onChangeNode,
|
||||||
onNextNodeDebug: v.onNextNodeDebug,
|
onStartNodeDebug: v.onStartNodeDebug,
|
||||||
workflowDebugData: v.workflowDebugData,
|
// onNextNodeDebug: v.onNextNodeDebug, // 不再使用
|
||||||
setWorkflowDebugData: v.setWorkflowDebugData
|
workflowDebugData: v.workflowDebugData
|
||||||
|
})
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* 创建交互数据结构
|
||||||
|
* @param nodeId 交互节点ID
|
||||||
|
* @param interactive 交互组件数据
|
||||||
|
* @param edges 当前的边数组
|
||||||
|
* @returns 交互数据结构
|
||||||
|
*/
|
||||||
|
const createInteractiveData = (
|
||||||
|
nodeId: string,
|
||||||
|
interactive: UserSelectInteractive | UserInputInteractive,
|
||||||
|
edges: StoreEdgeItemType[]
|
||||||
|
) => {
|
||||||
|
// 创建 memoryEdges - 指向交互节点的边设为 active
|
||||||
|
const memoryEdges: RuntimeEdgeItemType[] = edges.map((edge) => ({
|
||||||
|
...edge,
|
||||||
|
status: edge.target === nodeId ? ('active' as const) : ('waiting' as const)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...interactive,
|
||||||
|
entryNodeIds: [nodeId],
|
||||||
|
memoryEdges,
|
||||||
|
nodeOutputs: [] // 如果有需要可以填充节点输出数据
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建模拟的历史记录
|
||||||
|
* @param nodeId 交互节点ID
|
||||||
|
* @param interactive 交互组件数据
|
||||||
|
* @param edges 当前的边数组
|
||||||
|
* @returns 模拟的历史记录
|
||||||
|
*/
|
||||||
|
const createMockHistory = (
|
||||||
|
nodeId: string,
|
||||||
|
interactive: UserSelectInteractive | UserInputInteractive,
|
||||||
|
edges: StoreEdgeItemType[]
|
||||||
|
): ChatItemType[] => {
|
||||||
|
const interactiveData = createInteractiveData(nodeId, interactive, edges);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.interactive,
|
||||||
|
interactive: interactiveData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
const handleSelect = useCallback(
|
const handleSelect = useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
if (!nodeId || !workflowDebugData) return;
|
if (!nodeId || !workflowDebugData) return;
|
||||||
|
|
||||||
// 保存选中的值到本地状态
|
// 保存选中的值到本地状态
|
||||||
setSelectedValue(value);
|
setSelectedValue(value);
|
||||||
|
|
||||||
// 更新查询以包含用户的选择
|
|
||||||
const updatedQuery: UserChatItemValueItemType[] = [
|
|
||||||
...(workflowDebugData.query || []),
|
|
||||||
{
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: value
|
|
||||||
}
|
|
||||||
} as UserChatItemValueItemType
|
|
||||||
];
|
|
||||||
|
|
||||||
// 更新工作流调试数据
|
|
||||||
setWorkflowDebugData({
|
|
||||||
...workflowDebugData,
|
|
||||||
query: updatedQuery
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[nodeId, onChangeNode, workflowDebugData, setWorkflowDebugData]
|
[nodeId, workflowDebugData]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 处理下一步调试的逻辑
|
|
||||||
const handleStartDebug = useCallback(() => {
|
const handleStartDebug = useCallback(() => {
|
||||||
if (!nodeId || !workflowDebugData) return;
|
if (!nodeId || !workflowDebugData) return;
|
||||||
|
|
||||||
@@ -76,10 +118,67 @@ export const RenderUserSelectInteractive = React.memo(function RenderInteractive
|
|||||||
value: true
|
value: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// 然后调用onNextNodeDebug函数
|
// 更新此节点的值(将用户选择保存到节点)
|
||||||
onNextNodeDebug();
|
if (selectedValue) {
|
||||||
}, [nodeId, workflowDebugData, onNextNodeDebug, onChangeNode]);
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'attr',
|
||||||
|
key: 'userSelectedVal',
|
||||||
|
value: selectedValue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建包含用户选择的查询数据
|
||||||
|
const updatedQuery: UserChatItemValueItemType[] = [
|
||||||
|
...(workflowDebugData.query || []),
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.text,
|
||||||
|
text: {
|
||||||
|
content: selectedValue || ''
|
||||||
|
}
|
||||||
|
} as UserChatItemValueItemType
|
||||||
|
];
|
||||||
|
// 创建模拟的历史记录
|
||||||
|
const mockHistory = createMockHistory(nodeId, interactive, workflowDebugData.runtimeEdges);
|
||||||
|
|
||||||
|
// 使用模拟的历史记录初始化边状态
|
||||||
|
const updatedRuntimeEdges = initWorkflowEdgeStatus(workflowDebugData.runtimeEdges, mockHistory);
|
||||||
|
|
||||||
|
// 更新 runtimeNodes 以反映用户的选择
|
||||||
|
const updatedRuntimeNodes = workflowDebugData.runtimeNodes.map((node) => {
|
||||||
|
if (node.nodeId === nodeId) {
|
||||||
|
// 找到我们需要的输入字段并更新它
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
inputs: node.inputs.map((input) => {
|
||||||
|
// 根据您的实际字段结构,这里可能需要调整
|
||||||
|
if (input.key === 'userSelect' || input.key === 'selectedOption') {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: selectedValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}),
|
||||||
|
// 添加或更新任何需要的节点属性
|
||||||
|
userSelectedVal: selectedValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新 runtimeEdges 状态
|
||||||
|
|
||||||
|
// 使用 onStartNodeDebug 替代 onNextNodeDebug,带上更新后的 nodes 和 edges
|
||||||
|
onStartNodeDebug({
|
||||||
|
entryNodeId: nodeId,
|
||||||
|
runtimeNodes: updatedRuntimeNodes,
|
||||||
|
runtimeEdges: updatedRuntimeEdges,
|
||||||
|
variables: workflowDebugData.variables,
|
||||||
|
query: updatedQuery,
|
||||||
|
history: mockHistory
|
||||||
|
});
|
||||||
|
}, [nodeId, workflowDebugData, onStartNodeDebug, onChangeNode, selectedValue, interactive]);
|
||||||
return (
|
return (
|
||||||
<Box px={4} py={3}>
|
<Box px={4} py={3}>
|
||||||
{interactive?.params?.description && (
|
{interactive?.params?.description && (
|
||||||
@@ -155,7 +254,6 @@ export const RenderUserSelectInteractive = React.memo(function RenderInteractive
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
export const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
||||||
interactive,
|
interactive,
|
||||||
nodeId
|
nodeId
|
||||||
@@ -164,61 +262,167 @@ export const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
|||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { register, setValue, handleSubmit: handleSubmitChat, control, reset } = useForm();
|
const {
|
||||||
|
register,
|
||||||
|
setValue,
|
||||||
|
handleSubmit: handleSubmitChat,
|
||||||
|
control,
|
||||||
|
reset,
|
||||||
|
getValues
|
||||||
|
} = useForm();
|
||||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||||
const { onChangeNode, onNextNodeDebug, workflowDebugData, setWorkflowDebugData } =
|
// 在两个组件中更新上下文选择器,添加 onStartNodeDebug
|
||||||
useContextSelector(WorkflowContext, (v) => ({
|
const { onChangeNode, onStartNodeDebug, workflowDebugData } = useContextSelector(
|
||||||
|
WorkflowContext,
|
||||||
|
(v) => ({
|
||||||
onChangeNode: v.onChangeNode,
|
onChangeNode: v.onChangeNode,
|
||||||
onNextNodeDebug: v.onNextNodeDebug,
|
onStartNodeDebug: v.onStartNodeDebug,
|
||||||
workflowDebugData: v.workflowDebugData,
|
workflowDebugData: v.workflowDebugData
|
||||||
setWorkflowDebugData: v.setWorkflowDebugData
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建交互数据结构
|
||||||
|
* @param nodeId 交互节点ID
|
||||||
|
* @param interactive 交互组件数据
|
||||||
|
* @param edges 当前的边数组
|
||||||
|
* @returns 交互数据结构
|
||||||
|
*/
|
||||||
|
const createInteractiveData = (
|
||||||
|
nodeId: string,
|
||||||
|
interactive: UserInputInteractive,
|
||||||
|
edges: StoreEdgeItemType[]
|
||||||
|
) => {
|
||||||
|
// 创建 memoryEdges - 指向交互节点的边设为 active
|
||||||
|
const memoryEdges: RuntimeEdgeItemType[] = edges.map((edge) => ({
|
||||||
|
...edge,
|
||||||
|
status: edge.target === nodeId ? ('active' as const) : ('waiting' as const)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...interactive,
|
||||||
|
entryNodeIds: [nodeId],
|
||||||
|
memoryEdges,
|
||||||
|
nodeOutputs: [] // 如果有需要可以填充节点输出数据
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建模拟的历史记录
|
||||||
|
* @param nodeId 交互节点ID
|
||||||
|
* @param interactive 交互组件数据
|
||||||
|
* @param edges 当前的边数组
|
||||||
|
* @returns 模拟的历史记录
|
||||||
|
*/
|
||||||
|
const createMockHistory = (
|
||||||
|
nodeId: string,
|
||||||
|
interactive: UserInputInteractive,
|
||||||
|
edges: StoreEdgeItemType[]
|
||||||
|
): ChatItemType[] => {
|
||||||
|
// 创建一个新的 interactive 对象,确保 submitted 为 false
|
||||||
|
const adjustedInteractive = {
|
||||||
|
...interactive,
|
||||||
|
params: {
|
||||||
|
...interactive.params,
|
||||||
|
submitted: false // 关键修改点:确保 submitted 为 false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const interactiveData = createInteractiveData(nodeId, adjustedInteractive, edges);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
obj: ChatRoleEnum.AI,
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
type: ChatItemValueTypeEnum.interactive,
|
||||||
|
interactive: interactiveData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
(data: any) => {
|
(data: any) => {
|
||||||
if (!nodeId || !workflowDebugData) return;
|
if (!nodeId || !workflowDebugData) return;
|
||||||
|
|
||||||
// 标记表单已提交
|
|
||||||
setIsSubmitted(true);
|
setIsSubmitted(true);
|
||||||
|
|
||||||
const jsonData = JSON.stringify(data);
|
// 直接调用 handleStartDebug,合并提交和下一步操作
|
||||||
|
const formData = getValues();
|
||||||
|
|
||||||
|
onChangeNode({
|
||||||
|
nodeId,
|
||||||
|
type: 'attr',
|
||||||
|
key: 'isEntry',
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
// 更新查询以包含用户的表单数据
|
|
||||||
const updatedQuery: UserChatItemValueItemType[] = [
|
const updatedQuery: UserChatItemValueItemType[] = [
|
||||||
...(workflowDebugData.query || []),
|
...(workflowDebugData.query || []),
|
||||||
{
|
{
|
||||||
type: ChatItemValueTypeEnum.text,
|
type: ChatItemValueTypeEnum.text,
|
||||||
text: {
|
text: {
|
||||||
content: jsonData
|
content: JSON.stringify(formData)
|
||||||
}
|
}
|
||||||
} as UserChatItemValueItemType
|
} as UserChatItemValueItemType
|
||||||
];
|
];
|
||||||
|
|
||||||
// 更新工作流调试数据
|
const updatedInteractive = {
|
||||||
setWorkflowDebugData({
|
...interactive,
|
||||||
...workflowDebugData,
|
params: {
|
||||||
query: updatedQuery
|
...interactive.params,
|
||||||
|
submitted: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockHistory = createMockHistory(
|
||||||
|
nodeId,
|
||||||
|
updatedInteractive,
|
||||||
|
workflowDebugData.runtimeEdges
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedRuntimeEdges = initWorkflowEdgeStatus(
|
||||||
|
workflowDebugData.runtimeEdges,
|
||||||
|
mockHistory
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedRuntimeNodes = workflowDebugData.runtimeNodes.map((node) => {
|
||||||
|
if (node.nodeId === nodeId) {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
inputs: node.inputs.map((input) => {
|
||||||
|
const formField = interactive.params.inputForm?.find(
|
||||||
|
(field) => field.label === input.key || field.key === input.key
|
||||||
|
);
|
||||||
|
|
||||||
|
if (formField) {
|
||||||
|
return {
|
||||||
|
...input,
|
||||||
|
value: formData[formField.label]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}),
|
||||||
|
formSubmitted: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
});
|
||||||
|
|
||||||
|
onStartNodeDebug({
|
||||||
|
entryNodeId: nodeId,
|
||||||
|
runtimeNodes: updatedRuntimeNodes,
|
||||||
|
runtimeEdges: updatedRuntimeEdges,
|
||||||
|
variables: workflowDebugData.variables,
|
||||||
|
query: updatedQuery,
|
||||||
|
history: mockHistory
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[nodeId, onChangeNode, workflowDebugData, setWorkflowDebugData]
|
[nodeId, workflowDebugData, onStartNodeDebug, onChangeNode, getValues, interactive]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 处理下一步调试的逻辑
|
|
||||||
const handleStartDebug = useCallback(() => {
|
|
||||||
if (!nodeId || !workflowDebugData) return;
|
|
||||||
|
|
||||||
// 先将当前节点设置为入口节点
|
|
||||||
onChangeNode({
|
|
||||||
nodeId,
|
|
||||||
type: 'attr',
|
|
||||||
key: 'isEntry',
|
|
||||||
value: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// 然后调用onNextNodeDebug函数
|
|
||||||
onNextNodeDebug();
|
|
||||||
}, [nodeId, workflowDebugData, onNextNodeDebug, onChangeNode]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (interactive.type === 'userInput') {
|
if (interactive.type === 'userInput') {
|
||||||
const defaultValues = interactive.params.inputForm?.reduce(
|
const defaultValues = interactive.params.inputForm?.reduce(
|
||||||
@@ -375,37 +579,15 @@ export const RenderUserFormInteractive = React.memo(function RenderFormInput({
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
<Flex w={'full'} justifyContent={'flex-end'} mt={3} gap={2}>
|
<Flex w={'full'} justifyContent={'flex-end'} mt={3} gap={2}>
|
||||||
{!isSubmitted && !interactive.params.submitted && (
|
<Button
|
||||||
<Button
|
type="submit"
|
||||||
type="submit"
|
size="sm"
|
||||||
colorScheme="blue"
|
leftIcon={<MyIcon name={'core/workflow/debugNext'} w={'16px'} />}
|
||||||
size="md"
|
colorScheme="blue"
|
||||||
height="44px"
|
variant="solid"
|
||||||
px={8}
|
>
|
||||||
fontWeight="medium"
|
{t('common:Submit')}
|
||||||
borderRadius="md"
|
</Button>
|
||||||
boxShadow="sm"
|
|
||||||
_hover={{ transform: 'translateY(-1px)', boxShadow: 'md' }}
|
|
||||||
_active={{ transform: 'translateY(0)' }}
|
|
||||||
transition="all 0.2s"
|
|
||||||
>
|
|
||||||
{t('common:Submit')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 提交完成后显示下一步按钮 */}
|
|
||||||
{(isSubmitted || interactive.params.submitted) && (
|
|
||||||
<Button
|
|
||||||
size="md"
|
|
||||||
height="44px"
|
|
||||||
leftIcon={<MyIcon name={'core/workflow/debugNext'} w={'16px'} />}
|
|
||||||
colorScheme="blue"
|
|
||||||
variant="solid"
|
|
||||||
onClick={handleStartDebug}
|
|
||||||
>
|
|
||||||
{t('common:common.Next Step')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export type PostWorkflowDebugProps = {
|
|||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
appId: string;
|
appId: string;
|
||||||
query?: UserChatItemValueItemType[];
|
query?: UserChatItemValueItemType[];
|
||||||
|
history?: ChatItemType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PostWorkflowDebugResponse = {
|
export type PostWorkflowDebugResponse = {
|
||||||
|
|||||||
@@ -830,6 +830,7 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{(debugResult.status === 'success' || debugResult.status === 'skipped') &&
|
{(debugResult.status === 'success' || debugResult.status === 'skipped') &&
|
||||||
|
!firstInteractive &&
|
||||||
!debugResult.isExpired &&
|
!debugResult.isExpired &&
|
||||||
workflowDebugData?.nextRunNodes &&
|
workflowDebugData?.nextRunNodes &&
|
||||||
workflowDebugData.nextRunNodes.length > 0 && (
|
workflowDebugData.nextRunNodes.length > 0 && (
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import WorkflowEventContextProvider from './workflowEventContext';
|
|||||||
import { getAppConfigByDiff } from '@/web/core/app/diff';
|
import { getAppConfigByDiff } from '@/web/core/app/diff';
|
||||||
import WorkflowStatusContextProvider from './workflowStatusContext';
|
import WorkflowStatusContextProvider from './workflowStatusContext';
|
||||||
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { ChatRoleEnum, ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Context
|
Context
|
||||||
@@ -163,35 +162,35 @@ type WorkflowContextType = {
|
|||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
nextRunNodes: RuntimeNodeItemType[];
|
||||||
query?: UserChatItemValueItemType[];
|
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
|
query?: UserChatItemValueItemType[];
|
||||||
|
history?: ChatItemType[];
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
setWorkflowDebugData: React.Dispatch<
|
onNextNodeDebug: (
|
||||||
React.SetStateAction<
|
history?: ChatItemType[],
|
||||||
| {
|
query?: UserChatItemValueItemType[],
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
debugData?: {
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
query?: UserChatItemValueItemType[];
|
nextRunNodes: RuntimeNodeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
}
|
}
|
||||||
| undefined
|
) => Promise<void>;
|
||||||
>
|
|
||||||
>;
|
|
||||||
onNextNodeDebug: () => Promise<void>;
|
|
||||||
onStartNodeDebug: ({
|
onStartNodeDebug: ({
|
||||||
entryNodeId,
|
entryNodeId,
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
|
variables,
|
||||||
query,
|
query,
|
||||||
variables
|
history
|
||||||
}: {
|
}: {
|
||||||
entryNodeId: string;
|
entryNodeId: string;
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
query?: UserChatItemValueItemType[];
|
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
|
query?: UserChatItemValueItemType[];
|
||||||
|
history?: ChatItemType[];
|
||||||
}) => Promise<void>;
|
}) => Promise<void>;
|
||||||
onStopNodeDebug: () => void;
|
onStopNodeDebug: () => void;
|
||||||
|
|
||||||
@@ -212,7 +211,6 @@ type DebugDataType = {
|
|||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
nextRunNodes: RuntimeNodeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
query?: UserChatItemValueItemType[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkflowContext = createContext<WorkflowContextType>({
|
export const WorkflowContext = createContext<WorkflowContextType>({
|
||||||
@@ -255,31 +253,25 @@ export const WorkflowContext = createContext<WorkflowContextType>({
|
|||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
workflowDebugData: undefined,
|
workflowDebugData: undefined,
|
||||||
setWorkflowDebugData: function (
|
onNextNodeDebug: function (
|
||||||
value: React.SetStateAction<
|
history?: ChatItemType[],
|
||||||
| {
|
query?: UserChatItemValueItemType[],
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
debugData?: any
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
): Promise<void> {
|
||||||
nextRunNodes: RuntimeNodeItemType[];
|
|
||||||
query?: UserChatItemValueItemType[];
|
|
||||||
variables: Record<string, any>;
|
|
||||||
}
|
|
||||||
| undefined
|
|
||||||
>
|
|
||||||
): void {
|
|
||||||
throw new Error('Function not implemented.');
|
|
||||||
},
|
|
||||||
onNextNodeDebug: function (): Promise<void> {
|
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
onStartNodeDebug: function ({
|
onStartNodeDebug: function ({
|
||||||
entryNodeId,
|
entryNodeId,
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges
|
runtimeEdges,
|
||||||
|
query,
|
||||||
|
history
|
||||||
}: {
|
}: {
|
||||||
entryNodeId: string;
|
entryNodeId: string;
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
|
query?: UserChatItemValueItemType[];
|
||||||
|
history?: ChatItemType[];
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
throw new Error('Function not implemented.');
|
throw new Error('Function not implemented.');
|
||||||
},
|
},
|
||||||
@@ -582,39 +574,13 @@ const WorkflowContextProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* debug */
|
/* debug */
|
||||||
const [workflowDebugData, setWorkflowDebugData] = useState<
|
const [workflowDebugData, setWorkflowDebugData] = useState<DebugDataType>();
|
||||||
DebugDataType & {
|
|
||||||
query?: UserChatItemValueItemType[];
|
|
||||||
}
|
|
||||||
>();
|
|
||||||
// 添加这个函数用于捕获入口节点的输入值
|
|
||||||
const captureEntryInputValues = (entryNodeId: string, nodes: RuntimeNodeItemType[]) => {
|
|
||||||
const entryNode = nodes.find((node) => node.nodeId === entryNodeId);
|
|
||||||
if (!entryNode || !entryNode.inputs) return null;
|
|
||||||
|
|
||||||
// 提取用户输入值
|
|
||||||
const userInput = entryNode.inputs.find((input) => input.key === 'userChatInput')?.value || '';
|
|
||||||
return userInput;
|
|
||||||
};
|
|
||||||
// 添加函数用于准备调试数据
|
|
||||||
const prepareDebugData = (entryNodeId: string, nodes: RuntimeNodeItemType[]) => {
|
|
||||||
const userInput = captureEntryInputValues(entryNodeId, nodes);
|
|
||||||
if (!userInput) return null;
|
|
||||||
|
|
||||||
// 构建查询项
|
|
||||||
const queryItem: UserChatItemValueItemType = {
|
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: userInput
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
query: [queryItem]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const onNextNodeDebug = useCallback(
|
const onNextNodeDebug = useCallback(
|
||||||
async (debugData = workflowDebugData) => {
|
async (
|
||||||
|
history?: ChatItemType[],
|
||||||
|
query?: UserChatItemValueItemType[],
|
||||||
|
debugData = workflowDebugData
|
||||||
|
) => {
|
||||||
if (!debugData) return;
|
if (!debugData) return;
|
||||||
// 1. Cancel node selected status and debugResult.showStatus
|
// 1. Cancel node selected status and debugResult.showStatus
|
||||||
setNodes((state) =>
|
setNodes((state) =>
|
||||||
@@ -674,7 +640,7 @@ const WorkflowContextProvider = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 4. Run one step - 添加历史记录和查询到请求中
|
// 4. Run one step
|
||||||
const { finishedEdges, finishedNodes, nextStepRunNodes, flowResponses, newVariables } =
|
const { finishedEdges, finishedNodes, nextStepRunNodes, flowResponses, newVariables } =
|
||||||
await postWorkflowDebug({
|
await postWorkflowDebug({
|
||||||
nodes: runtimeNodes,
|
nodes: runtimeNodes,
|
||||||
@@ -684,7 +650,8 @@ const WorkflowContextProvider = ({
|
|||||||
cTime: formatTime2YMDHMW(),
|
cTime: formatTime2YMDHMW(),
|
||||||
...debugData.variables
|
...debugData.variables
|
||||||
},
|
},
|
||||||
query: debugData.query || [],
|
query, // 添加 query 参数
|
||||||
|
history,
|
||||||
appId
|
appId
|
||||||
});
|
});
|
||||||
// 5. Store debug result
|
// 5. Store debug result
|
||||||
@@ -694,7 +661,8 @@ const WorkflowContextProvider = ({
|
|||||||
runtimeEdges: finishedEdges,
|
runtimeEdges: finishedEdges,
|
||||||
nextRunNodes: nextStepRunNodes,
|
nextRunNodes: nextStepRunNodes,
|
||||||
variables: newVariables,
|
variables: newVariables,
|
||||||
query: debugData.query // 保留查询
|
query,
|
||||||
|
history
|
||||||
};
|
};
|
||||||
setWorkflowDebugData(newStoreDebugData);
|
setWorkflowDebugData(newStoreDebugData);
|
||||||
|
|
||||||
@@ -739,7 +707,7 @@ const WorkflowContextProvider = ({
|
|||||||
|
|
||||||
// Check for an empty response
|
// Check for an empty response
|
||||||
if (flowResponses.length === 0 && nextStepRunNodes.length > 0) {
|
if (flowResponses.length === 0 && nextStepRunNodes.length > 0) {
|
||||||
onNextNodeDebug(newStoreDebugData);
|
onNextNodeDebug(history, query, newStoreDebugData);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
entryNodes.forEach((node) => {
|
entryNodes.forEach((node) => {
|
||||||
@@ -777,25 +745,29 @@ const WorkflowContextProvider = ({
|
|||||||
entryNodeId,
|
entryNodeId,
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
variables
|
variables,
|
||||||
|
query,
|
||||||
|
history
|
||||||
}: {
|
}: {
|
||||||
entryNodeId: string;
|
entryNodeId: string;
|
||||||
runtimeNodes: RuntimeNodeItemType[];
|
runtimeNodes: RuntimeNodeItemType[];
|
||||||
runtimeEdges: RuntimeEdgeItemType[];
|
runtimeEdges: RuntimeEdgeItemType[];
|
||||||
variables: Record<string, any>;
|
variables: Record<string, any>;
|
||||||
|
query?: UserChatItemValueItemType[];
|
||||||
|
history?: ChatItemType[];
|
||||||
}) => {
|
}) => {
|
||||||
const debugHistoryData = prepareDebugData(entryNodeId, runtimeNodes);
|
|
||||||
const data = {
|
const data = {
|
||||||
runtimeNodes,
|
runtimeNodes,
|
||||||
runtimeEdges,
|
runtimeEdges,
|
||||||
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId),
|
nextRunNodes: runtimeNodes.filter((node) => node.nodeId === entryNodeId),
|
||||||
query: debugHistoryData?.query || [],
|
variables,
|
||||||
variables
|
query,
|
||||||
|
history
|
||||||
};
|
};
|
||||||
onStopNodeDebug();
|
onStopNodeDebug();
|
||||||
setWorkflowDebugData(data);
|
setWorkflowDebugData(data);
|
||||||
|
|
||||||
onNextNodeDebug(data);
|
onNextNodeDebug(history, query, data);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1059,7 +1031,6 @@ const WorkflowContextProvider = ({
|
|||||||
flowData2StoreData,
|
flowData2StoreData,
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
setWorkflowDebugData,
|
|
||||||
workflowDebugData,
|
workflowDebugData,
|
||||||
onNextNodeDebug,
|
onNextNodeDebug,
|
||||||
onStartNodeDebug,
|
onStartNodeDebug,
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import { NextAPI } from '@/service/middleware/entry';
|
|||||||
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
|
||||||
import { defaultApp } from '@/web/core/app/constants';
|
import { defaultApp } from '@/web/core/app/constants';
|
||||||
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
|
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
|
||||||
import { ChatItemValueTypeEnum, ChatRoleEnum } from '@fastgpt/global/core/chat/constants';
|
|
||||||
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
import { ChatItemType, UserChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||||
import { NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
|
|
||||||
|
|
||||||
async function handler(
|
async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
@@ -24,10 +22,10 @@ async function handler(
|
|||||||
variables = {},
|
variables = {},
|
||||||
appId,
|
appId,
|
||||||
query: requestQuery,
|
query: requestQuery,
|
||||||
histories: requestHistories
|
history: requestHistories
|
||||||
} = req.body as PostWorkflowDebugProps & {
|
} = req.body as PostWorkflowDebugProps & {
|
||||||
query?: UserChatItemValueItemType[];
|
query?: UserChatItemValueItemType[];
|
||||||
histories?: ChatItemType[];
|
history?: ChatItemType[];
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!nodes) {
|
if (!nodes) {
|
||||||
@@ -39,26 +37,16 @@ async function handler(
|
|||||||
if (!Array.isArray(edges)) {
|
if (!Array.isArray(edges)) {
|
||||||
throw new Error('Edges is not array');
|
throw new Error('Edges is not array');
|
||||||
}
|
}
|
||||||
|
const entryNode = nodes.find((node) => node.isEntry === true);
|
||||||
|
if (!entryNode) {
|
||||||
|
throw new Error('No entry node found');
|
||||||
|
}
|
||||||
|
|
||||||
const query_form_input: UserChatItemValueItemType[] = requestQuery || [
|
const isEntryNodeInteractive =
|
||||||
{
|
entryNode.flowNodeType === 'formInput' || entryNode.flowNodeType === 'userSelect';
|
||||||
type: ChatItemValueTypeEnum.text,
|
|
||||||
text: {
|
|
||||||
content: '{"未知":"未知","数字":2}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const query: UserChatItemValueItemType[] =
|
const histories: ChatItemType[] = isEntryNodeInteractive ? requestHistories || [] : [];
|
||||||
requestQuery ||
|
const query: UserChatItemValueItemType[] = requestQuery || [];
|
||||||
[
|
|
||||||
// {
|
|
||||||
// type: ChatItemValueTypeEnum.text,
|
|
||||||
// text: {
|
|
||||||
// content: 'Cancel'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
/* user auth */
|
/* user auth */
|
||||||
const [{ teamId, tmbId }, { app }] = await Promise.all([
|
const [{ teamId, tmbId }, { app }] = await Promise.all([
|
||||||
@@ -96,7 +84,7 @@ async function handler(
|
|||||||
variables,
|
variables,
|
||||||
query: query,
|
query: query,
|
||||||
chatConfig: defaultApp.chatConfig,
|
chatConfig: defaultApp.chatConfig,
|
||||||
histories: [],
|
histories: histories,
|
||||||
stream: false,
|
stream: false,
|
||||||
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user