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
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
141 additions
and
104 deletions
+141
-104
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
+6
-2
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
+10
-12
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
+40
-10
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 = (
...
@@ -60,8 +60,18 @@ export const getHandleId = (
return
`
${
nodeId
}
-
${
type
}
-
${
key
}
`
;
return
`
${
nodeId
}
-
${
type
}
-
${
key
}
`
;
};
};
/**
* 判断输入值是否应按工作流引用解析。
* settingDatasetQuotePrompt 内部渲染 Reference 选择器,虽然 renderType 不是 reference,
* 但它的值仍是 [nodeId, outputId],运行时必须解析成知识库检索结果。
*/
export
const
nodeInputIsReference
=
(
input
:
FlowNodeInputItemType
)
=>
{
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
;
return
true
;
}
}
...
...
packages/global/test/core/workflow/utils.test.ts
View file @
82fa431a
...
@@ -120,6 +120,16 @@ describe('nodeInputIsReference', () => {
...
@@ -120,6 +120,16 @@ describe('nodeInputIsReference', () => {
};
};
expect
(
nodeInputIsReference
(
input
)).
toBe
(
true
);
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'
,
()
=>
{
describe
(
'getGuideModule'
,
()
=>
{
...
...
projects/app/src/components/core/chat/ChatContainer/ChatBox/Input/ChatInput.tsx
View file @
82fa431a
...
@@ -398,7 +398,6 @@ const ChatInput = ({
...
@@ -398,7 +398,6 @@ const ChatInput = ({
</
Flex
>
</
Flex
>
);
);
},
[
},
[
isPc
,
InputLeftComponent
,
InputLeftComponent
,
canUploadFile
,
canUploadFile
,
selectFileLabel
,
selectFileLabel
,
...
@@ -410,13 +409,10 @@ const ChatInput = ({
...
@@ -410,13 +409,10 @@ const ChatInput = ({
isStopping
,
isStopping
,
isChatting
,
isChatting
,
canSendMessage
,
canSendMessage
,
disableSend
,
onOpenSelectFile
,
onOpenSelectFile
,
onSelectFile
,
onSelectFile
,
handleSend
,
handleSend
,
handleStop
,
handleStop
onStopChat
,
onStopSettled
]);
]);
const
activeStyles
:
FlexProps
=
{
const
activeStyles
:
FlexProps
=
{
...
@@ -430,7 +426,7 @@ const ChatInput = ({
...
@@ -430,7 +426,7 @@ const ChatInput = ({
w=
{
'100%'
}
w=
{
'100%'
}
maxW=
{
[
'100%'
,
'780px'
]
}
maxW=
{
[
'100%'
,
'780px'
]
}
mx=
{
'auto'
}
mx=
{
'auto'
}
pb=
{
[
'calc(12px + env(safe-area-inset-bottom))'
,
0
]
}
pb=
{
0
}
onDragOver=
{
(
e
)
=>
e
.
preventDefault
()
}
onDragOver=
{
(
e
)
=>
e
.
preventDefault
()
}
onDrop=
{
(
e
)
=>
{
onDrop=
{
(
e
)
=>
{
e
.
preventDefault
();
e
.
preventDefault
();
...
@@ -462,7 +458,7 @@ const ChatInput = ({
...
@@ -462,7 +458,7 @@ const ChatInput = ({
h=
{
isDefaultInputHeight
?
ChatInputDefaultHeight
:
undefined
}
h=
{
isDefaultInputHeight
?
ChatInputDefaultHeight
:
undefined
}
minH=
{
mobilePreSpeak
?
'48px'
:
ChatInputDefaultHeight
}
minH=
{
mobilePreSpeak
?
'48px'
:
ChatInputDefaultHeight
}
p=
{
mobilePreSpeak
?
[
0
,
4
]
:
4
}
p=
{
mobilePreSpeak
?
[
0
,
4
]
:
4
}
mb=
{
4
}
mb=
{
0
}
position=
{
'relative'
}
position=
{
'relative'
}
borderRadius=
{
[
'xl'
,
'xxl'
]
}
borderRadius=
{
[
'xl'
,
'xxl'
]
}
bg=
{
'white'
}
bg=
{
'white'
}
...
@@ -527,7 +523,7 @@ const ChatInput = ({
...
@@ -527,7 +523,7 @@ const ChatInput = ({
{
!
mobilePreSpeak
&&
<
Box
>
{
RenderButtonGroup
}
</
Box
>
}
{
!
mobilePreSpeak
&&
<
Box
>
{
RenderButtonGroup
}
</
Box
>
}
</
Flex
>
</
Flex
>
<
ComplianceTip
type=
{
'chat'
}
pt=
{
0
}
pb=
{
0
}
/>
<
ComplianceTip
type=
{
'chat'
}
pt=
{
4
}
pb=
{
0
}
/>
</
Box
>
</
Box
>
);
);
};
};
...
...
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx
View file @
82fa431a
...
@@ -268,11 +268,15 @@ const EditForm = ({
...
@@ -268,11 +268,15 @@ const EditForm = ({
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
</
Flex
>
</
Flex
>
{
showSandbox
&&
enableSandbox
&&
(
<
Box
mr=
{
2
}
>
<
Box
mr=
{
2
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
<
SandboxTipTag
/>
</
Box
>
)
:
(
<
MyTag
>
{
t
(
showSandbox
?
'app:sandbox_free_not_support'
:
'app:sandbox_not_support_tip'
)
}
</
MyTag
>
)
}
)
}
</
Box
>
<
Switch
<
Switch
isChecked=
{
appForm
.
aiSettings
.
useAgentSandbox
??
false
}
isChecked=
{
appForm
.
aiSettings
.
useAgentSandbox
??
false
}
onChange=
{
(
e
)
=>
onChangeAgentSandbox
(
e
.
target
.
checked
)
}
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
{
useDisclosure
}
from
'@chakra-ui/react'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
type
{
import
type
{
...
@@ -13,8 +13,8 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
...
@@ -13,8 +13,8 @@ import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
/**
/**
* 管理 ChatAgent 表单中的 Skill 选择与 sandbox 开关联动。
* 管理 ChatAgent 表单中的 Skill 选择与 sandbox 开关联动。
*
*
* Skill 运行依赖 Agent sandbox:选择 Skill 时会自动打开 sandbox;
已有 Skill 时不允许手动关闭
* Skill 运行依赖 Agent sandbox:选择 Skill 时会自动打开 sandbox;
系统未配置或套餐不可用时
*
sandbox;系统未配置或套餐不可用时统一给出提示,避免表单保存出无法运行的组合状态
。
*
不允许开启 sandbox,但保留关闭入口,避免历史配置无法自助修复
。
*/
*/
export
const
useAgentSkillSelect
=
({
export
const
useAgentSkillSelect
=
({
appForm
,
appForm
,
...
@@ -36,7 +36,6 @@ export const useAgentSkillSelect = ({
...
@@ -36,7 +36,6 @@ export const useAgentSkillSelect = ({
onOpen
:
onOpenRecharge
,
onOpen
:
onOpenRecharge
,
onClose
:
onCloseRecharge
onClose
:
onCloseRecharge
}
=
useDisclosure
();
}
=
useDisclosure
();
const
hasShownSandboxUnavailableWarningRef
=
useRef
(
false
);
const
{
const
{
isOpen
:
isOpenSkillSelect
,
isOpen
:
isOpenSkillSelect
,
onOpen
:
onOpenSkillSelect
,
onOpen
:
onOpenSkillSelect
,
...
@@ -124,18 +123,14 @@ export const useAgentSkillSelect = ({
...
@@ -124,18 +123,14 @@ export const useAgentSkillSelect = ({
return
;
return
;
}
}
if
(
!
enableSandbox
)
{
if
(
!
enableSandbox
)
{
openConfirm
({
toast
({
title
:
t
(
'skill:sandbox_plan_not_supported_title'
),
status
:
'warning'
,
customContent
:
t
(
'skill:sandbox_plan_not_supported_content'
),
title
:
t
(
'app:sandbox_free_not_support'
)
onConfirm
:
isTeamAdmin
?
onOpenRecharge
:
undefined
,
});
confirmText
:
isTeamAdmin
?
t
(
'skill:sandbox_upgrade_action'
)
:
t
(
'common:Close'
),
cancelText
:
t
(
'common:Close'
),
showCancel
:
isTeamAdmin
})();
return
;
return
;
}
}
}
}
if
(
!
checked
&&
hasSelectedAgentSkills
)
{
if
(
!
checked
&&
enableSandbox
&&
hasSelectedAgentSkills
)
{
toast
({
toast
({
status
:
'warning'
,
status
:
'warning'
,
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
...
@@ -150,39 +145,13 @@ export const useAgentSkillSelect = ({
...
@@ -150,39 +145,13 @@ export const useAgentSkillSelect = ({
}
}
}));
}));
},
},
[
[
enableSandbox
,
hasSelectedAgentSkills
,
setAppForm
,
showSandbox
,
t
,
toast
]
enableSandbox
,
hasSelectedAgentSkills
,
setAppForm
,
showSandbox
,
t
,
toast
,
openConfirm
,
isTeamAdmin
,
onOpenRecharge
]
);
);
//
按系统/套餐能力同步修复历史 Skill 与虚拟机开关状态
。
//
套餐/系统支持时,Skill 仍自动保持 sandbox 开启;不支持时保留历史值,交给用户手动关闭
。
useEffect
(()
=>
{
useEffect
(()
=>
{
const
sandboxAvailable
=
showSandbox
&&
enableSandbox
;
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
)
{
if
(
sandboxAvailable
&&
hasSelectedAgentSkills
&&
!
appForm
.
aiSettings
.
useAgentSandbox
)
{
setAppForm
((
state
)
=>
({
setAppForm
((
state
)
=>
({
...
state
,
...
state
,
...
@@ -196,7 +165,6 @@ export const useAgentSkillSelect = ({
...
@@ -196,7 +165,6 @@ export const useAgentSkillSelect = ({
appForm
.
aiSettings
.
useAgentSandbox
,
appForm
.
aiSettings
.
useAgentSandbox
,
enableSandbox
,
enableSandbox
,
hasSelectedAgentSkills
,
hasSelectedAgentSkills
,
openSkillSelect
,
setAppForm
,
setAppForm
,
showSandbox
showSandbox
]);
]);
...
...
projects/app/src/pageComponents/app/detail/Edit/FormComponent/Header.tsx
View file @
82fa431a
...
@@ -278,7 +278,7 @@ const Header = ({
...
@@ -278,7 +278,7 @@ const Header = ({
}
}
if
(
!
enableSandbox
)
{
if
(
!
enableSandbox
)
{
toast
({
toast
({
title
:
t
(
'
skill:sandbox_plan_not_supported_title
'
),
title
:
t
(
'
app:sandbox_free_not_support
'
),
status
:
'warning'
status
:
'warning'
});
});
return
false
;
return
false
;
...
...
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx
View file @
82fa431a
...
@@ -75,6 +75,7 @@ const EditForm = ({
...
@@ -75,6 +75,7 @@ const EditForm = ({
const
{
appDetail
}
=
useContextSelector
(
AppContext
,
(
v
)
=>
v
);
const
{
appDetail
}
=
useContextSelector
(
AppContext
,
(
v
)
=>
v
);
const
selectDatasets
=
useMemo
(()
=>
appForm
?.
dataset
?.
datasets
,
[
appForm
]);
const
selectDatasets
=
useMemo
(()
=>
appForm
?.
dataset
?.
datasets
,
[
appForm
]);
const
[,
startTst
]
=
useTransition
();
const
[,
startTst
]
=
useTransition
();
const
isAgentSandboxEnabled
=
!!
appForm
.
aiSettings
.
useAgentSandbox
;
const
{
const
{
isOpen
:
isOpenDatasetSelect
,
isOpen
:
isOpenDatasetSelect
,
...
@@ -259,31 +260,28 @@ const EditForm = ({
...
@@ -259,31 +260,28 @@ const EditForm = ({
<
FormLabel
ml=
{
2
}
>
{
t
(
'app:use_agent_sandbox'
)
}
</
FormLabel
>
<
FormLabel
ml=
{
2
}
>
{
t
(
'app:use_agent_sandbox'
)
}
</
FormLabel
>
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
<
QuestionTip
ml=
{
1
}
label=
{
t
(
'app:use_computer_desc'
)
}
/>
</
Flex
>
</
Flex
>
{
showSandbox
?
(
enableSandbox
?
(
<>
<
Box
mr=
{
2
}
>
<
Box
mr=
{
2
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
<
SandboxTipTag
/>
)
:
(
<
SandboxNotSupportTip
type=
{
showSandbox
?
'freeDisable'
:
'systemDisable'
}
/>
)
}
</
Box
>
</
Box
>
<
Switch
<
Switch
isChecked=
{
appForm
.
aiSettings
.
useAgentSandbox
??
false
}
isChecked=
{
isAgentSandboxEnabled
}
onChange=
{
(
e
)
=>
{
onChange=
{
(
e
)
=>
{
const
checked
=
e
.
target
.
checked
;
if
(
checked
&&
(
!
showSandbox
||
!
enableSandbox
))
return
;
setAppForm
((
state
)
=>
({
setAppForm
((
state
)
=>
({
...
state
,
...
state
,
aiSettings
:
{
aiSettings
:
{
...
state
.
aiSettings
,
...
state
.
aiSettings
,
useAgentSandbox
:
e
.
target
.
checked
useAgentSandbox
:
checked
}
}
}));
}));
}
}
}
}
/>
/>
</>
)
:
(
<
SandboxNotSupportTip
type=
"freeDisable"
/>
)
)
:
(
<
SandboxNotSupportTip
type=
"systemDisable"
/>
)
}
</
Flex
>
</
Flex
>
</
Box
>
</
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>) => {
...
@@ -432,18 +432,14 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
return
;
return
;
}
}
if
(
!
enableSandbox
)
{
if
(
!
enableSandbox
)
{
openConfirm
({
toast
({
title
:
t
(
'skill:sandbox_plan_not_supported_title'
),
status
:
'warning'
,
customContent
:
t
(
'skill:sandbox_plan_not_supported_content'
),
title
:
t
(
'app:sandbox_free_not_support'
)
onConfirm
:
isTeamAdmin
?
onOpenRecharge
:
undefined
,
});
confirmText
:
isTeamAdmin
?
t
(
'skill:sandbox_upgrade_action'
)
:
t
(
'common:Close'
),
cancelText
:
t
(
'common:Close'
),
showCancel
:
isTeamAdmin
})();
return
;
return
;
}
}
}
}
if
(
!
checked
&&
selectedAgentSkills
.
length
>
0
)
{
if
(
!
checked
&&
enableSandbox
&&
selectedAgentSkills
.
length
>
0
)
{
toast
({
toast
({
status
:
'warning'
,
status
:
'warning'
,
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
title
:
t
(
'skill:sandbox_disable_blocked_toast'
)
...
@@ -469,10 +465,7 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
...
@@ -469,10 +465,7 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
selectedAgentSkills
.
length
,
selectedAgentSkills
.
length
,
showSandbox
,
showSandbox
,
t
,
t
,
toast
,
toast
openConfirm
,
isTeamAdmin
,
onOpenRecharge
]
]
);
);
const
skillsRenderType
=
useMemo
(
const
skillsRenderType
=
useMemo
(
...
@@ -554,7 +547,13 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
...
@@ -554,7 +547,13 @@ const NodeAgent = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
>
>
<
InputLabel
nodeId=
{
nodeId
}
input=
{
sandboxInput
}
/>
<
InputLabel
nodeId=
{
nodeId
}
input=
{
sandboxInput
}
/>
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
className=
{
'nodrag'
}
>
<
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
<
Switch
isChecked=
{
!!
sandboxInput
.
value
}
isChecked=
{
!!
sandboxInput
.
value
}
onChange=
{
(
e
)
=>
onChangeAgentSandbox
(
e
.
target
.
checked
)
}
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
React
from
'react'
;
import
type
{
FlowNodeInputItemType
}
from
'@fastgpt/global/core/workflow/type/io'
;
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
{
FlowNodeInputTypeEnum
}
from
'@fastgpt/global/core/workflow/node/constant'
;
import
dynamic
from
'next/dynamic'
;
import
dynamic
from
'next/dynamic'
;
import
InputLabel
from
'./Label'
;
import
InputLabel
from
'./Label'
;
...
@@ -13,6 +13,8 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
...
@@ -13,6 +13,8 @@ import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import
SandboxTipTag
from
'@/pageComponents/app/detail/components/SandboxTipTag'
;
import
SandboxTipTag
from
'@/pageComponents/app/detail/components/SandboxTipTag'
;
import
SandboxNotSupportTip
from
'@/pageComponents/app/detail/components/SandboxNotSupportTip'
;
import
SandboxNotSupportTip
from
'@/pageComponents/app/detail/components/SandboxNotSupportTip'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
MyTag
from
'@fastgpt/web/components/common/Tag/index'
;
import
{
useTranslation
}
from
'next-i18next'
;
const
RenderList
:
Record
<
const
RenderList
:
Record
<
FlowNodeInputTypeEnum
,
FlowNodeInputTypeEnum
,
...
@@ -105,6 +107,7 @@ type Props = {
...
@@ -105,6 +107,7 @@ type Props = {
mb
?:
number
;
mb
?:
number
;
};
};
const
RenderInput
=
({
flowInputList
,
nodeId
,
CustomComponent
,
mb
=
5
}:
Props
)
=>
{
const
RenderInput
=
({
flowInputList
,
nodeId
,
CustomComponent
,
mb
=
5
}:
Props
)
=>
{
const
{
t
}
=
useTranslation
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
feConfigs
}
=
useSystemStore
();
const
{
teamPlanStatus
}
=
useUserStore
();
const
{
teamPlanStatus
}
=
useUserStore
();
const
enableSandbox
=
!
teamPlanStatus
?.
standard
||
!!
teamPlanStatus
?.
standard
?.
enableSandbox
;
const
enableSandbox
=
!
teamPlanStatus
?.
standard
||
!!
teamPlanStatus
?.
standard
?.
enableSandbox
;
...
@@ -144,14 +147,37 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
...
@@ -144,14 +147,37 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
if
(
!
RenderItem
)
return
null
;
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
{
return
{
Component
:
(
Component
:
(
<
RenderItem
.
Component
inputs=
{
filterProInputs
}
item=
{
i
nput
}
nodeId=
{
nodeId
}
/>
<
RenderItem
.
Component
inputs=
{
filterProInputs
}
item=
{
renderI
nput
}
nodeId=
{
nodeId
}
/>
),
),
LableRightComponent
:
RenderItem
.
LableRightComponent
?
(
LableRightComponent
:
RenderItem
.
LableRightComponent
?
(
<
RenderItem
.
LableRightComponent
<
RenderItem
.
LableRightComponent
inputs=
{
filterProInputs
}
inputs=
{
filterProInputs
}
item=
{
i
nput
}
item=
{
renderI
nput
}
nodeId=
{
nodeId
}
nodeId=
{
nodeId
}
/>
/>
)
:
undefined
)
:
undefined
...
@@ -179,17 +205,21 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
...
@@ -179,17 +205,21 @@ const RenderInput = ({ flowInputList, nodeId, CustomComponent, mb = 5 }: Props)
{
/* tmp */
}
{
/* tmp */
}
{
input
.
key
===
NodeInputKeyEnum
.
useAgentSandbox
?
(
{
input
.
key
===
NodeInputKeyEnum
.
useAgentSandbox
?
(
showSandbox
?
(
RenderComponent
?
(
enableSandbox
?
(
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
>
<
Flex
alignItems=
{
'center'
}
gap=
{
1
}
>
{
showSandbox
&&
enableSandbox
?
(
<
SandboxTipTag
/>
<
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 }) =>
...
@@ -216,7 +216,7 @@ export const WorkflowUtilsProvider = ({ children }: { children: ReactNode }) =>
status
:
'warning'
,
status
:
'warning'
,
title
:
!
showSandbox
title
:
!
showSandbox
?
t
(
'skill:sandbox_system_not_configured_toast'
)
?
t
(
'skill:sandbox_system_not_configured_toast'
)
:
t
(
'
skill:sandbox_plan_not_supported_title
'
)
:
t
(
'
app:sandbox_free_not_support
'
)
});
});
}
}
return
;
return
;
...
...
projects/app/src/pageComponents/chat/ChatWindow/AppChatWindow.tsx
View file @
82fa431a
...
@@ -198,9 +198,7 @@ const AppChatWindow = () => {
...
@@ -198,9 +198,7 @@ const AppChatWindow = () => {
>
>
<
IconButton
<
IconButton
aria
-
label=
"Open history"
aria
-
label=
"Open history"
icon=
{
icon=
{
<
MyIcon
name=
"core/chat/sidebar/menu"
w=
"20px"
h=
"20px"
color=
"currentColor"
/>
}
<
MyIcon
name=
"core/chat/sidebar/menu"
w=
"20px"
h=
"20px"
color=
"currentColor"
/>
}
variant=
"unstyled"
variant=
"unstyled"
{
...
mobileChatHeaderIconButtonStyle
}
{
...
mobileChatHeaderIconButtonStyle
}
onClick=
{
onOpenSlider
}
onClick=
{
onOpenSlider
}
...
@@ -208,7 +206,13 @@ const AppChatWindow = () => {
...
@@ -208,7 +206,13 @@ const AppChatWindow = () => {
<
Flex
alignItems=
"center"
minW=
{
0
}
flex=
"1"
justifyContent=
"center"
px=
{
3
}
>
<
Flex
alignItems=
"center"
minW=
{
0
}
flex=
"1"
justifyContent=
"center"
px=
{
3
}
>
<
Avatar
src=
{
chatBoxData
.
app
.
avatar
}
w=
"20px"
borderRadius=
"6px"
/>
<
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
}
{
chatBoxData
.
app
.
name
}
</
Box
>
</
Box
>
</
Flex
>
</
Flex
>
...
@@ -219,7 +223,7 @@ const AppChatWindow = () => {
...
@@ -219,7 +223,7 @@ const AppChatWindow = () => {
</
Flex
>
</
Flex
>
)
}
)
}
<
Box
flex=
{
'1 0 0'
}
bg=
{
'white'
}
>
<
Box
flex=
{
'1 0 0'
}
bg=
{
'white'
}
pb=
{
4
}
>
{
isPlugin
?
(
{
isPlugin
?
(
<
CustomPluginRunBox
<
CustomPluginRunBox
appId=
{
appId
}
appId=
{
appId
}
...
...
projects/app/src/pageComponents/chat/slider/ChatSliderList.tsx
View file @
82fa431a
...
@@ -40,6 +40,7 @@ const ChatSliderList = () => {
...
@@ -40,6 +40,7 @@ const ChatSliderList = () => {
updateTime
:
Date
;
updateTime
:
Date
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
hasBeenRead
?:
boolean
;
hasBeenRead
?:
boolean
;
isTemporary
?:
boolean
;
}[]
=
scopedHistories
.
map
((
item
)
=>
{
}[]
=
scopedHistories
.
map
((
item
)
=>
{
const
isActiveChat
=
item
.
chatId
===
activeChatId
&&
chatBoxData
.
chatId
===
item
.
chatId
;
const
isActiveChat
=
item
.
chatId
===
activeChatId
&&
chatBoxData
.
chatId
===
item
.
chatId
;
...
@@ -64,6 +65,7 @@ const ChatSliderList = () => {
...
@@ -64,6 +65,7 @@ const ChatSliderList = () => {
updateTime
:
Date
;
updateTime
:
Date
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
chatGenerateStatus
?:
ChatGenerateStatusEnum
;
hasBeenRead
?:
boolean
;
hasBeenRead
?:
boolean
;
isTemporary
?:
boolean
;
}
=
{
}
=
{
id
:
activeChatId
,
id
:
activeChatId
,
title
:
getDisplayHistoryTitle
({
title
:
getDisplayHistoryTitle
({
...
@@ -71,6 +73,7 @@ const ChatSliderList = () => {
...
@@ -71,6 +73,7 @@ const ChatSliderList = () => {
fallbackTitle
:
t
(
'common:core.chat.New Chat'
)
fallbackTitle
:
t
(
'common:core.chat.New Chat'
)
}),
}),
updateTime
:
new
Date
(),
updateTime
:
new
Date
(),
isTemporary
:
true
,
chatGenerateStatus
:
chatGenerateStatus
:
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
chatGenerateStatus
:
undefined
,
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
chatGenerateStatus
:
undefined
,
hasBeenRead
:
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
hasBeenRead
:
undefined
hasBeenRead
:
chatBoxData
.
chatId
===
activeChatId
?
chatBoxData
.
hasBeenRead
:
undefined
...
@@ -112,7 +115,7 @@ const ChatSliderList = () => {
...
@@ -112,7 +115,7 @@ const ChatSliderList = () => {
overflowY=
{
'auto'
}
overflowY=
{
'auto'
}
overflowX=
{
'hidden'
}
overflowX=
{
'hidden'
}
sx=
{
{
sx=
{
{
'& > div
:last-of-type
'
:
{
'& > div
> div:last-of-type:not(.chatHistoryItem)
'
:
{
color
:
'var(--chakra-colors-myGray-400)'
color
:
'var(--chakra-colors-myGray-400)'
}
}
}
}
}
}
...
@@ -120,6 +123,7 @@ const ChatSliderList = () => {
...
@@ -120,6 +123,7 @@ const ChatSliderList = () => {
{
concatHistory
.
map
((
item
,
i
)
=>
(
{
concatHistory
.
map
((
item
,
i
)
=>
(
<
Flex
<
Flex
position=
{
'relative'
}
position=
{
'relative'
}
className=
"chatHistoryItem"
key=
{
item
.
id
}
key=
{
item
.
id
}
alignItems=
{
'center'
}
alignItems=
{
'center'
}
p=
"8px"
p=
"8px"
...
@@ -172,7 +176,7 @@ const ChatSliderList = () => {
...
@@ -172,7 +176,7 @@ const ChatSliderList = () => {
bg=
{
'primary.500'
}
bg=
{
'primary.500'
}
flexShrink=
{
0
}
flexShrink=
{
0
}
/>
/>
)
:
(
)
:
item
.
isTemporary
?
null
:
(
<
Box
<
Box
className=
"time"
className=
"time"
display=
{
'block'
}
display=
{
'block'
}
...
...
projects/app/src/pages/chat/index.tsx
View file @
82fa431a
...
@@ -72,7 +72,7 @@ const Chat = () => {
...
@@ -72,7 +72,7 @@ const Chat = () => {
flex=
"1 0 0"
flex=
"1 0 0"
w=
{
0
}
w=
{
0
}
position=
"relative"
position=
"relative"
pr=
{
datasetCiteData
?
0
:
undefined
}
pr=
{
datasetCiteData
?
0
:
[
0
,
'16px'
]
}
insertProps=
{
{
insertProps=
{
{
...
rightWindowStyle
,
...
rightWindowStyle
,
...(
datasetCiteData
...(
datasetCiteData
...
...
projects/app/src/web/core/workflow/utils.ts
View file @
82fa431a
...
@@ -21,7 +21,8 @@ import {
...
@@ -21,7 +21,8 @@ import {
getAppChatConfig
,
getAppChatConfig
,
getHandleId
,
getHandleId
,
isValidReferenceValue
,
isValidReferenceValue
,
isValidReferenceValueFormat
isValidReferenceValueFormat
,
nodeInputIsReference
}
from
'@fastgpt/global/core/workflow/utils'
;
}
from
'@fastgpt/global/core/workflow/utils'
;
import
{
type
TFunction
}
from
'next-i18next'
;
import
{
type
TFunction
}
from
'next-i18next'
;
import
{
import
{
...
@@ -525,7 +526,7 @@ export const getNodeAllSource = ({
...
@@ -525,7 +526,7 @@ export const getNodeAllSource = ({
const
parentNode
=
getNodeById
(
parentId
);
const
parentNode
=
getNodeById
(
parentId
);
if
(
parentNode
)
{
if
(
parentNode
)
{
parentNode
.
inputs
.
forEach
((
input
)
=>
{
parentNode
.
inputs
.
forEach
((
input
)
=>
{
if
(
!
input
.
renderTypeList
?.
includes
(
FlowNodeInputTypeEnum
.
reference
))
return
;
if
(
!
nodeInputIsReference
(
input
))
return
;
const
val
=
input
.
value
as
ReferenceItemValueType
|
undefined
;
const
val
=
input
.
value
as
ReferenceItemValueType
|
undefined
;
if
(
!
Array
.
isArray
(
val
)
||
val
.
length
<
2
)
return
;
if
(
!
Array
.
isArray
(
val
)
||
val
.
length
<
2
)
return
;
const
[
refNodeId
]
=
val
;
const
[
refNodeId
]
=
val
;
...
@@ -748,8 +749,7 @@ export const checkWorkflowNodeAndConnection = ({
...
@@ -748,8 +749,7 @@ export const checkWorkflowNodeAndConnection = ({
if
(
Array
.
isArray
(
input
.
value
)
&&
input
.
value
.
length
===
0
)
return
true
;
if
(
Array
.
isArray
(
input
.
value
)
&&
input
.
value
.
length
===
0
)
return
true
;
}
}
// check reference invalid
// check reference invalid
const
renderType
=
input
.
renderTypeList
[
input
.
selectedTypeIndex
||
0
];
if
(
nodeInputIsReference
(
input
))
{
if
(
renderType
===
FlowNodeInputTypeEnum
.
reference
)
{
// 无效引用时,返回 true
// 无效引用时,返回 true
const
checkValueValid
=
(
value
:
ReferenceItemValueType
)
=>
{
const
checkValueValid
=
(
value
:
ReferenceItemValueType
)
=>
{
const
nodeId
=
value
?.[
0
];
const
nodeId
=
value
?.[
0
];
...
...
projects/app/test/web/core/app/utils.test.ts
View file @
82fa431a
...
@@ -6,7 +6,7 @@ import {
...
@@ -6,7 +6,7 @@ import {
appWorkflow2AgentForm
appWorkflow2AgentForm
}
from
'@/pageComponents/app/detail/Edit/ChatAgent/utils'
;
}
from
'@/pageComponents/app/detail/Edit/ChatAgent/utils'
;
import
{
FlowNodeTypeEnum
}
from
'@fastgpt/global/core/workflow/node/constant'
;
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
{
getDefaultAppForm
}
from
'@fastgpt/global/core/app/utils'
;
import
type
{
AppFormEditFormType
}
from
'@fastgpt/global/core/app/formEdit/type'
;
import
type
{
AppFormEditFormType
}
from
'@fastgpt/global/core/app/formEdit/type'
;
...
@@ -94,6 +94,20 @@ describe('form2AppWorkflow', () => {
...
@@ -94,6 +94,20 @@ describe('form2AppWorkflow', () => {
expect
(
result
.
nodes
).
toHaveLength
(
4
);
expect
(
result
.
nodes
).
toHaveLength
(
4
);
expect
(
result
.
edges
).
toHaveLength
(
2
);
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