Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
82fa431a
authored
Jun 06, 2026
by
Archer
Committed by
GitHub
Jun 06, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: chatui (#7070)
* perf: chatui * fix: reuse workflow reference input check
parent
778fb386
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
157 additions
and
120 deletions
+157
-120
packages/global/core/workflow/utils.ts
+11
-1
packages/global/test/core/workflow/utils.test.ts
+10
-0
projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
+4
-8
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx
+8
-4
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/hooks/useAgentSkillSelect.ts
+10
-42
projects/app/src/pageComponents/app/detail/Edit/FormComponent/Header.tsx
+1
-1
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx
+22
-24
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeAgent/index.tsx
+13
-14
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/index.tsx
+42
-12
projects/app/src/pageComponents/app/detail/WorkflowComponents/context/workflowUtilsContext.tsx
+1
-1
projects/app/src/pageComponents/chat/ChatWindow/AppChatWindow.tsx
+9
-5
projects/app/src/pageComponents/chat/slider/ChatSliderList.tsx
+6
-2
projects/app/src/pages/chat/index.tsx
+1
-1
projects/app/src/web/core/workflow/utils.ts
+4
-4
projects/app/test/web/core/app/utils.test.ts
+15
-1
No files found.
packages/global/core/workflow/utils.ts
View file @
82fa431a
...
...
@@ -60,8 +60,18 @@ export const getHandleId = (
return
`
${
nodeId
}
-
${
type
}
-
${
key
}
`
;
};
/**
* 判断输入值是否应按工作流引用解析。
* settingDatasetQuotePrompt 内部渲染 Reference 选择器,虽然 renderType 不是 reference,
* 但它的值仍是 [nodeId, outputId],运行时必须解析成知识库检索结果。
*/
export
const
nodeInputIsReference
=
(
input
:
FlowNodeInputItemType
)
=>
{
if
(
input
.
renderTypeList
?.[
input
?.
selectedTypeIndex
||
0
]
===
FlowNodeInputTypeEnum
.
reference
)
{
const
renderType
=
input
.
renderTypeList
?.[
input
?.
selectedTypeIndex
||
0
];
if
(
renderType
===
FlowNodeInputTypeEnum
.
reference
||
renderType
===
FlowNodeInputTypeEnum
.
settingDatasetQuotePrompt
)
{
return
true
;
}
...
...
packages/global/test/core/workflow/utils.test.ts
View file @
82fa431a
...
...
@@ -120,6 +120,16 @@ describe('nodeInputIsReference', () => {
};
expect
(
nodeInputIsReference
(
input
)).
toBe
(
true
);
});
it
(
'should treat settingDatasetQuotePrompt as reference'
,
()
=>
{
const
input
:
FlowNodeInputItemType
=
{
key
:
NodeInputKeyEnum
.
aiChatDatasetQuote
,
label
:
'Dataset quote'
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
settingDatasetQuotePrompt
],
valueType
:
WorkflowIOValueTypeEnum
.
datasetQuote
};
expect
(
nodeInputIsReference
(
input
)).
toBe
(
true
);
});
});
describe
(
'getGuideModule'
,
()
=>
{
...
...
projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
View file @
82fa431a
...
...
@@ -398,7 +398,6 @@ const ChatInput = ({
</
Flex
>
);
},
[
isPc
,
InputLeftComponent
,
canUploadFile
,
selectFileLabel
,
...
...
@@ -410,13 +409,10 @@ const ChatInput = ({
isStopping
,
isChatting
,
canSendMessage
,
disableSend
,
onOpenSelectFile
,
onSelectFile
,
handleSend
,
handleStop
,
onStopChat
,
onStopSettled
handleStop
]);
const
activeStyles
:
FlexProps
=
{
...
...
@@ -430,7 +426,7 @@ const ChatInput = ({
w=
{
'100%'
}
maxW=
{
[
'100%'
,
'780px'
]
}
mx=
{
'auto'
}
pb=
{
[
'calc(12px + env(safe-area-inset-bottom))'
,
0
]
}
pb=
{
0
}
onDragOver=
{
(
e
)
=>
e
.
preventDefault
()
}
onDrop=
{
(
e
)
=>
{
e
.
preventDefault
();
...
...
@@ -462,7 +458,7 @@ const ChatInput = ({
h=
{
isDefaultInputHeight
?
ChatInputDefaultHeight
:
undefined
}
minH=
{
mobilePreSpeak
?
'48px'
:
ChatInputDefaultHeight
}
p=
{
mobilePreSpeak
?
[
0
,
4
]
:
4
}
mb=
{
4
}
mb=
{
0
}
position=
{
'relative'
}
borderRadius=
{
[
'xl'
,
'xxl'
]
}
bg=
{
'white'
}
...
...
@@ -527,7 +523,7 @@ const ChatInput = ({
{
!
mobilePreSpeak
&&
<
Box
>
{
RenderButtonGroup
}
</
Box
>
}
</
Flex
>
<
ComplianceTip
type=
{
'chat'
}
pt=
{
0
}
pb=
{
0
}
/>
<
ComplianceTip
type=
{
'chat'
}
pt=
{
4
}
pb=
{
0
}
/>
</
Box
>
);
};
...
...
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx
View file @
82fa431a
...
...
@@ -268,11 +268,15 @@ const EditForm = ({
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
</
Flex
>
{
showSandbox
&&
enableSandbox
&&
(
<
Box
mr=
{
2
}
>
<
Box
mr=
{
2
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
</
Box
>
)
}
)
:
(
<
MyTag
>
{
t
(
showSandbox
?
'app:sandbox_free_not_support'
:
'app:sandbox_not_support_tip'
)
}
</
MyTag
>
)
}
</
Box
>
<
Switch
isChecked=
{
appForm
.
aiSettings
.
useAgentSandbox
??
false
}
onChange=
{
(
e
)
=>
onChangeAgentSandbox
(
e
.
target
.
checked
)
}
...
...
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/hooks/useAgentSkillSelect.ts
View file @
82fa431a
import
{
useCallback
,
useEffect
,
useRef
,
type
Dispatch
,
type
SetStateAction
}
from
'react'
;
import
{
useCallback
,
useEffect
,
type
Dispatch
,
type
SetStateAction
}
from
'react'
;
import
{
useDisclosure
}
from
'@chakra-ui/react'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
type
{
...
...
@@ -13,8 +13,8 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
/**
* 管理 ChatAgent 表单中的 Skill 选择与 sandbox 开关联动。
*
* Skill 运行依赖 Agent sandbox:选择 Skill 时会自动打开 sandbox;
已有 Skill 时不允许手动关闭
*
sandbox;系统未配置或套餐不可用时统一给出提示,避免表单保存出无法运行的组合状态
。
* Skill 运行依赖 Agent sandbox:选择 Skill 时会自动打开 sandbox;
系统未配置或套餐不可用时
*
不允许开启 sandbox,但保留关闭入口,避免历史配置无法自助修复
。
*/
export
const
useAgentSkillSelect
=
({
appForm
,
...
...
@@ -36,7 +36,6 @@ export const useAgentSkillSelect = ({
onOpen
:
onOpenRecharge
,
onClose
:
onCloseRecharge
}
=
useDisclosure
();
const
hasShownSandboxUnavailableWarningRef
=
useRef
(
false
);
const
{
isOpen
:
isOpenSkillSelect
,
onOpen
:
onOpenSkillSelect
,
...
...
@@ -124,18 +123,14 @@ export const useAgentSkillSelect = ({
return
;
}
if
(
!
enableSandbox
)
{
openConfirm
({
title
:
t
(
'skill:sandbox_plan_not_supported_title'
),
customContent
:
t
(
'skill:sandbox_plan_not_supported_content'
),
onConfirm
:
isTeamAdmin
?
onOpenRecharge
:
undefined
,
confirmText
:
isTeamAdmin
?
t
(
'skill:sandbox_upgrade_action'
)
:
t
(
'common:Close'
),
cancelText
:
t
(
'common:Close'
),
showCancel
:
isTeamAdmin
})();
toast
({
status
:
'warning'
,
title
:
t
(
'app:sandbox_free_not_support'
)
});
return
;
}
}
if
(
!
checked
&&
hasSelectedAgentSkills
)
{
if
(
!
checked
&&
enableSandbox
&&
hasSelectedAgentSkills
)
{
toast
({
status
:
'warning'
,
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
...
...
@@ -150,39 +145,13 @@ export const useAgentSkillSelect = ({
}
}));
},
[
enableSandbox
,
hasSelectedAgentSkills
,
setAppForm
,
showSandbox
,
t
,
toast
,
openConfirm
,
isTeamAdmin
,
onOpenRecharge
]
[
enableSandbox
,
hasSelectedAgentSkills
,
setAppForm
,
showSandbox
,
t
,
toast
]
);
//
按系统/套餐能力同步修复历史 Skill 与虚拟机开关状态
。
//
套餐/系统支持时,Skill 仍自动保持 sandbox 开启;不支持时保留历史值,交给用户手动关闭
。
useEffect
(()
=>
{
const
sandboxAvailable
=
showSandbox
&&
enableSandbox
;
if
(
!
sandboxAvailable
&&
appForm
.
aiSettings
.
useAgentSandbox
)
{
setAppForm
((
state
)
=>
({
...
state
,
aiSettings
:
{
...
state
.
aiSettings
,
useAgentSandbox
:
false
}
}));
if
(
hasSelectedAgentSkills
&&
!
hasShownSandboxUnavailableWarningRef
.
current
)
{
hasShownSandboxUnavailableWarningRef
.
current
=
true
;
openSkillSelect
();
}
return
;
}
if
(
sandboxAvailable
&&
hasSelectedAgentSkills
&&
!
appForm
.
aiSettings
.
useAgentSandbox
)
{
setAppForm
((
state
)
=>
({
...
state
,
...
...
@@ -196,7 +165,6 @@ export const useAgentSkillSelect = ({
appForm
.
aiSettings
.
useAgentSandbox
,
enableSandbox
,
hasSelectedAgentSkills
,
openSkillSelect
,
setAppForm
,
showSandbox
]);
...
...
projects/app/src/pageComponents/app/detail/Edit/FormComponent/Header.tsx
View file @
82fa431a
...
...
@@ -278,7 +278,7 @@ const Header = ({
}
if
(
!
enableSandbox
)
{
toast
({
title
:
t
(
'
skill:sandbox_plan_not_supported_title
'
),
title
:
t
(
'
app:sandbox_free_not_support
'
),
status
:
'warning'
});
return
false
;
...
...
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx
View file @
82fa431a
...
...
@@ -75,6 +75,7 @@ const EditForm = ({
const
{
appDetail
}
=
useContextSelector
(
AppContext
,
(
v
)
=>
v
);
const
selectDatasets
=
useMemo
(()
=>
appForm
?.
dataset
?.
datasets
,
[
appForm
]);
const
[,
startTst
]
=
useTransition
();
const
isAgentSandboxEnabled
=
!!
appForm
.
aiSettings
.
useAgentSandbox
;
const
{
isOpen
:
isOpenDatasetSelect
,
...
...
@@ -259,31 +260,28 @@ const EditForm = ({
<
FormLabel
ml=
{
2
}
>
{
t
(
'app:use_agent_sandbox'
)
}
</
FormLabel
>
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
</
Flex
>
{
showSandbox
?
(
enableSandbox
?
(
<>
<
Box
mr=
{
2
}
>
<
SandboxTipTag
/>
</
Box
>
<
Switch
isChecked=
{
appForm
.
aiSettings
.
useAgentSandbox
??
false
}
onChange=
{
(
e
)
=>
{
setAppForm
((
state
)
=>
({
...
state
,
aiSettings
:
{
...
state
.
aiSettings
,
useAgentSandbox
:
e
.
target
.
checked
}
}));
}
}
/>
</>
<
Box
mr=
{
2
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
)
:
(
<
SandboxNotSupportTip
type=
"freeDisable"
/>
)
)
:
(
<
SandboxNotSupportTip
type=
"systemDisable"
/>
)
}
<
SandboxNotSupportTip
type=
{
showSandbox
?
'freeDisable'
:
'systemDisable'
}
/>
)
}
</
Box
>
<
Switch
isChecked=
{
isAgentSandboxEnabled
}
onChange=
{
(
e
)
=>
{
const
checked
=
e
.
target
.
checked
;
if
(
checked
&&
(
!
showSandbox
||
!
enableSandbox
))
return
;
setAppForm
((
state
)
=>
({
...
state
,
aiSettings
:
{
...
state
.
aiSettings
,
useAgentSandbox
:
checked
}
}));
}
}
/>
</
Flex
>
</
Box
>
...
...
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/NodeAgent/index.tsx
View file @
82fa431a
...
...
@@ -432,18 +432,14 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
return
;
}
if
(
!
enableSandbox
)
{
openConfirm
({
title
:
t
(
'skill:sandbox_plan_not_supported_title'
),
customContent
:
t
(
'skill:sandbox_plan_not_supported_content'
),
onConfirm
:
isTeamAdmin
?
onOpenRecharge
:
undefined
,
confirmText
:
isTeamAdmin
?
t
(
'skill:sandbox_upgrade_action'
)
:
t
(
'common:Close'
),
cancelText
:
t
(
'common:Close'
),
showCancel
:
isTeamAdmin
})();
toast
({
status
:
'warning'
,
title
:
t
(
'app:sandbox_free_not_support'
)
});
return
;
}
}
if
(
!
checked
&&
selectedAgentSkills
.
length
>
0
)
{
if
(
!
checked
&&
enableSandbox
&&
selectedAgentSkills
.
length
>
0
)
{
toast
({
status
:
'warning'
,
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
...
...
@@ -469,10 +465,7 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
selectedAgentSkills
.
length
,
showSandbox
,
t
,
toast
,
openConfirm
,
isTeamAdmin
,
onOpenRecharge
toast
]
);
const
skillsRenderType
=
useMemo
(
...
...
@@ -554,7 +547,13 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
>
<
InputLabel
nodeId=
{
nodeId
}
input=
{
sandboxInput
}
/>
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
className=
{
'nodrag'
}
>
{
showSandbox
&&
enableSandbox
&&
<
SandboxTipTag
/>
}
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
)
:
(
<
MyTag
>
{
t
(
showSandbox
?
'app:sandbox_free_not_support'
:
'app:sandbox_not_support_tip'
)
}
</
MyTag
>
)
}
<
Switch
isChecked=
{
!!
sandboxInput
.
value
}
onChange=
{
(
e
)
=>
onChangeAgentSandbox
(
e
.
target
.
checked
)
}
...
...
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/index.tsx
View file @
82fa431a
import
React
from
'react'
;
import
type
{
FlowNodeInputItemType
}
from
'@fastgpt/global/core/workflow/type/io'
;
import
{
Box
,
Flex
}
from
'@chakra-ui/react'
;
import
{
Box
,
Flex
,
Switch
}
from
'@chakra-ui/react'
;
import
{
FlowNodeInputTypeEnum
}
from
'@fastgpt/global/core/workflow/node/constant'
;
import
dynamic
from
'next/dynamic'
;
import
InputLabel
from
'./Label'
;
...
...
@@ -13,6 +13,8 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import
SandboxTipTag
from
'@/pageComponents/app/detail/components/SandboxTipTag'
;
import
SandboxNotSupportTip
from
'@/pageComponents/app/detail/components/SandboxNotSupportTip'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
MyTag
from
'@fastgpt/web/components/common/Tag/index'
;
import
{
useTranslation
}
from
'next-i18next'
;
const
RenderList
:
Record
<
FlowNodeInputTypeEnum
,
...
...
@@ -105,6 +107,7 @@ type Props = {
mb
?:
number
;
};
const
RenderInput
=
({
flowInputList
,
nodeId
,
CustomComponent
,
mb
=
5
}:
Props
)
=>
{
const
{
t
}
=
useTranslation
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
teamPlanStatus
}
=
useUserStore
();
const
enableSandbox
=
!
teamPlanStatus
?.
standard
||
!!
teamPlanStatus
?.
standard
?.
enableSandbox
;
...
...
@@ -144,14 +147,37 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
if
(
!
RenderItem
)
return
null
;
const
renderInput
=
input
.
key
===
NodeInputKeyEnum
.
useAgentSandbox
?
{
...
input
,
customRender
:
({
value
,
onChange
}:
{
value
:
boolean
;
onChange
?:
(
value
:
boolean
)
=>
void
;
})
=>
(
<
Switch
isChecked=
{
!!
value
}
onChange=
{
(
e
)
=>
{
const
checked
=
e
.
target
.
checked
;
if
(
checked
&&
(
!
showSandbox
||
!
enableSandbox
))
return
;
onChange
?.(
checked
);
}
}
/>
)
}
:
input
;
return
{
Component
:
(
<
RenderItem
.
Component
inputs=
{
filterProInputs
}
item=
{
i
nput
}
nodeId=
{
nodeId
}
/>
<
RenderItem
.
Component
inputs=
{
filterProInputs
}
item=
{
renderI
nput
}
nodeId=
{
nodeId
}
/>
),
LableRightComponent
:
RenderItem
.
LableRightComponent
?
(
<
RenderItem
.
LableRightComponent
inputs=
{
filterProInputs
}
item=
{
i
nput
}
item=
{
renderI
nput
}
nodeId=
{
nodeId
}
/>
)
:
undefined
...
...
@@ -179,17 +205,21 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
{
/* tmp */
}
{
input
.
key
===
NodeInputKeyEnum
.
useAgentSandbox
?
(
showSandbox
?
(
enableSandbox
?
(
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
>
RenderComponent
?
(
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
{
RenderComponent
!
.
Component
}
</
Flex
>
)
:
(
<
SandboxNotSupportTip
type=
"freeDisable"
/>
)
)
:
(
<
MyTag
>
{
t
(
showSandbox
?
'app:sandbox_free_not_support'
:
'app:sandbox_not_support_tip'
)
}
</
MyTag
>
)
}
{
RenderComponent
.
Component
}
</
Flex
>
)
:
(
<
SandboxNotSupportTip
type=
"systemDisable"
/>
<
SandboxNotSupportTip
type=
{
showSandbox
?
'freeDisable'
:
'systemDisable'
}
/>
)
)
:
(
<>
...
...
projects/app/src/pageComponents/app/detail/WorkflowComponents/context/workflowUtilsContext.tsx
View file @
82fa431a
...
...
@@ -216,7 +216,7 @@ export const WorkflowUtilsProvider = ({ children }: { children: ReactNode }) =>
status
:
'warning'
,
title
:
!
showSandbox
?
t
(
'skill:sandbox_system_not_configured_toast'
)
:
t
(
'
skill:sandbox_plan_not_supported_title
'
)
:
t
(
'
app:sandbox_free_not_support
'
)
});
}
return
;
...
...
projects/app/src/pageComponents/chat/ChatWindow/AppChatWindow.tsx
View file @
82fa431a
...
...
@@ -198,9 +198,7 @@ const AppChatWindow = () => {
>
<
IconButton
aria
-
label=
"Open history"
icon=
{
<
MyIcon
name=
"core/chat/sidebar/menu"
w=
"20px"
h=
"20px"
color=
"currentColor"
/>
}
icon=
{
<
MyIcon
name=
"core/chat/sidebar/menu"
w=
"20px"
h=
"20px"
color=
"currentColor"
/>
}
variant=
"unstyled"
{
...
mobileChatHeaderIconButtonStyle
}
onClick=
{
onOpenSlider
}
...
...
@@ -208,7 +206,13 @@ const AppChatWindow = () => {
<
Flex
alignItems=
"center"
minW=
{
0
}
flex=
"1"
justifyContent=
"center"
px=
{
3
}
>
<
Avatar
src=
{
chatBoxData
.
app
.
avatar
}
w=
"20px"
borderRadius=
"6px"
/>
<
Box
ml=
{
2
}
fontSize=
"16px"
fontWeight=
{
500
}
color=
"myGray.900"
className=
"textEllipsis"
>
<
Box
ml=
{
2
}
fontSize=
"16px"
fontWeight=
{
500
}
color=
"myGray.900"
className=
"textEllipsis"
>
{
chatBoxData
.
app
.
name
}
</
Box
>
</
Flex
>
...
...
@@ -219,7 +223,7 @@ const AppChatWindow = () => {
</
Flex
>
)
}
<
Box
flex=
{
'1 0 0'
}
bg=
{
'white'
}
>
<
Box
flex=
{
'1 0 0'
}
bg=
{
'white'
}
pb=
{
4
}
>
{
isPlugin
?
(
<
CustomPluginRunBox
appId=
{
appId
}
...
...
projects/app/src/pageComponents/chat/slider/ChatSliderList.tsx
View file @
82fa431a
...
...
@@ -40,6 +40,7 @@ const ChatSliderList = () => {
updateTime
:
Date
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
hasBeenRead
?:
boolean
;
isTemporary
?:
boolean
;
}[]
=
scopedHistories
.
map
((
item
)
=>
{
const
isActiveChat
=
item
.
chatId
===
activeChatId
&&
chatBoxData
.
chatId
===
item
.
chatId
;
...
...
@@ -64,6 +65,7 @@ const ChatSliderList = () => {
updateTime
:
Date
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
hasBeenRead
?:
boolean
;
isTemporary
?:
boolean
;
}
=
{
id
:
activeChatId
,
title
:
getDisplayHistoryTitle
({
...
...
@@ -71,6 +73,7 @@ const ChatSliderList = () => {
fallbackTitle
:
t
(
'common:core.chat.New Chat'
)
}),
updateTime
:
new
Date
(),
isTemporary
:
true
,
chatGenerateStatus
:
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
chatGenerateStatus
:
undefined
,
hasBeenRead
:
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
hasBeenRead
:
undefined
...
...
@@ -112,7 +115,7 @@ const ChatSliderList = () => {
overflowY=
{
'auto'
}
overflowX=
{
'hidden'
}
sx=
{
{
'& > div
:last-of-type
'
:
{
'& > div
> div:last-of-type:not(.chatHistoryItem)
'
:
{
color
:
'var(--chakra-colors-myGray-400)'
}
}
}
...
...
@@ -120,6 +123,7 @@ const ChatSliderList = () => {
{
concatHistory
.
map
((
item
,
i
)
=>
(
<
Flex
position=
{
'relative'
}
className=
"chatHistoryItem"
key=
{
item
.
id
}
alignItems=
{
'center'
}
p=
"8px"
...
...
@@ -172,7 +176,7 @@ const ChatSliderList = () => {
bg=
{
'primary.500'
}
flexShrink=
{
0
}
/>
)
:
(
)
:
item
.
isTemporary
?
null
:
(
<
Box
className=
"time"
display=
{
'block'
}
...
...
projects/app/src/pages/chat/index.tsx
View file @
82fa431a
...
...
@@ -72,7 +72,7 @@ const Chat = () => {
flex=
"1 0 0"
w=
{
0
}
position=
"relative"
pr=
{
datasetCiteData
?
0
:
undefined
}
pr=
{
datasetCiteData
?
0
:
[
0
,
'16px'
]
}
insertProps=
{
{
...
rightWindowStyle
,
...(
datasetCiteData
...
...
projects/app/src/web/core/workflow/utils.ts
View file @
82fa431a
...
...
@@ -21,7 +21,8 @@ import {
getAppChatConfig
,
getHandleId
,
isValidReferenceValue
,
isValidReferenceValueFormat
isValidReferenceValueFormat
,
nodeInputIsReference
}
from
'@fastgpt/global/core/workflow/utils'
;
import
{
type
TFunction
}
from
'next-i18next'
;
import
{
...
...
@@ -525,7 +526,7 @@ export const getNodeAllSource = ({
const
parentNode
=
getNodeById
(
parentId
);
if
(
parentNode
)
{
parentNode
.
inputs
.
forEach
((
input
)
=>
{
if
(
!
input
.
renderTypeList
?.
includes
(
FlowNodeInputTypeEnum
.
reference
))
return
;
if
(
!
nodeInputIsReference
(
input
))
return
;
const
val
=
input
.
value
as
ReferenceItemValueType
|
undefined
;
if
(
!
Array
.
isArray
(
val
)
||
val
.
length
<
2
)
return
;
const
[
refNodeId
]
=
val
;
...
...
@@ -748,8 +749,7 @@ export const checkWorkflowNodeAndConnection = ({
if
(
Array
.
isArray
(
input
.
value
)
&&
input
.
value
.
length
===
0
)
return
true
;
}
// check reference invalid
const
renderType
=
input
.
renderTypeList
[
input
.
selectedTypeIndex
||
0
];
if
(
renderType
===
FlowNodeInputTypeEnum
.
reference
)
{
if
(
nodeInputIsReference
(
input
))
{
// 无效引用时,返回 true
const
checkValueValid
=
(
value
:
ReferenceItemValueType
)
=>
{
const
nodeId
=
value
?.[
0
];
...
...
projects/app/test/web/core/app/utils.test.ts
View file @
82fa431a
...
...
@@ -6,7 +6,7 @@ import {
appWorkflow2AgentForm
}
from
'@/pageComponents/app/detail/Edit/ChatAgent/utils'
;
import
{
FlowNodeTypeEnum
}
from
'@fastgpt/global/core/workflow/node/constant'
;
import
{
NodeInputKeyEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
NodeInputKeyEnum
,
NodeOutputKeyEnum
}
from
'@fastgpt/global/core/workflow/constants'
;
import
{
getDefaultAppForm
}
from
'@fastgpt/global/core/app/utils'
;
import
type
{
AppFormEditFormType
}
from
'@fastgpt/global/core/app/formEdit/type'
;
...
...
@@ -94,6 +94,20 @@ describe('form2AppWorkflow', () => {
expect
(
result
.
nodes
).
toHaveLength
(
4
);
expect
(
result
.
edges
).
toHaveLength
(
2
);
const
datasetNode
=
result
.
nodes
.
find
(
(
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
datasetSearchNode
);
const
aiNode
=
result
.
nodes
.
find
((
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
chatNode
);
expect
(
aiNode
?.
inputs
.
find
((
input
)
=>
input
.
key
===
NodeInputKeyEnum
.
aiChatDatasetQuote
)?.
value
).
toEqual
([
datasetNode
?.
nodeId
,
NodeOutputKeyEnum
.
datasetQuoteQA
]);
expect
(
result
.
edges
.
some
(
(
edge
)
=>
edge
.
source
===
datasetNode
?.
nodeId
&&
edge
.
target
===
aiNode
?.
nodeId
)
).
toBe
(
true
);
});
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment