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
f05c0fff
authored
Aug 05, 2026
by
YeYuheng
Committed by
GitHub
Aug 05, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(agent): decouple file upload settings from model capabilities (#7459)
parent
fc70c504
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
81 additions
and
84 deletions
+81
-84
projects/app/src/components/core/app/FileSelect.tsx
+0
-13
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx
+1
-22
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/utils.ts
+1
-14
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx
+0
-21
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/utils.ts
+1
-14
projects/app/test/web/core/app/utils.test.ts
+78
-0
No files found.
projects/app/src/components/core/app/FileSelect.tsx
View file @
f05c0fff
...
@@ -18,7 +18,6 @@ import type { AppFileSelectConfigType } from '@fastgpt/global/core/app/type/conf
...
@@ -18,7 +18,6 @@ import type { AppFileSelectConfigType } from '@fastgpt/global/core/app/type/conf
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
ChatFunctionTip
from
'./Tip'
;
import
ChatFunctionTip
from
'./Tip'
;
import
FormLabel
from
'@fastgpt/web/components/common/MyBox/FormLabel'
;
import
FormLabel
from
'@fastgpt/web/components/common/MyBox/FormLabel'
;
import
{
useMount
}
from
'ahooks'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useSystemStore
}
from
'@/web/common/system/useSystemStore'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
{
useUserStore
}
from
'@/web/support/user/useUserStore'
;
import
QuestionTip
from
'@fastgpt/web/components/common/MyTooltip/QuestionTip'
;
import
QuestionTip
from
'@fastgpt/web/components/common/MyTooltip/QuestionTip'
;
...
@@ -29,12 +28,10 @@ import { FileTypeSelectorPanel } from '@fastgpt/web/components/core/app/FileType
...
@@ -29,12 +28,10 @@ import { FileTypeSelectorPanel } from '@fastgpt/web/components/core/app/FileType
import
{
getUserFileAmountLimit
}
from
'@fastgpt/global/core/workflow/fileLimit'
;
import
{
getUserFileAmountLimit
}
from
'@fastgpt/global/core/workflow/fileLimit'
;
const
FileSelect
=
({
const
FileSelect
=
({
forbidVision
=
false
,
value
=
defaultAppSelectFileConfig
,
value
=
defaultAppSelectFileConfig
,
onChange
,
onChange
,
...
labelStyle
...
labelStyle
}:
Omit
<
BoxProps
,
'onChange'
>
&
{
}:
Omit
<
BoxProps
,
'onChange'
>
&
{
forbidVision
?:
boolean
;
value
?:
AppFileSelectConfigType
;
value
?:
AppFileSelectConfigType
;
onChange
:
(
e
:
AppFileSelectConfigType
)
=>
void
;
onChange
:
(
e
:
AppFileSelectConfigType
)
=>
void
;
})
=>
{
})
=>
{
...
@@ -61,16 +58,6 @@ const FileSelect = ({
...
@@ -61,16 +58,6 @@ const FileSelect = ({
?
t
(
'common:core.app.whisper.Open'
)
?
t
(
'common:core.app.whisper.Open'
)
:
t
(
'common:core.app.whisper.Close'
);
:
t
(
'common:core.app.whisper.Close'
);
// Close select img switch when vision is forbidden
useMount
(()
=>
{
if
(
forbidVision
)
{
onChange
({
...
value
,
canSelectImg
:
false
});
}
});
return
(
return
(
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
MyIcon
name=
{
'core/app/simpleMode/file'
}
mr=
{
2
}
w=
{
'20px'
}
/>
<
MyIcon
name=
{
'core/app/simpleMode/file'
}
mr=
{
2
}
w=
{
'20px'
}
/>
...
...
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx
View file @
f05c0fff
import
React
,
{
use
Effect
,
use
Memo
}
from
'react'
;
import
React
,
{
useMemo
}
from
'react'
;
import
{
import
{
Box
,
Box
,
Flex
,
Flex
,
...
@@ -165,26 +165,6 @@ const EditForm = ({
...
@@ -165,26 +165,6 @@ const EditForm = ({
return
selectedModel
.
quoteMaxToken
||
3000
;
return
selectedModel
.
quoteMaxToken
||
3000
;
},
[
selectedModel
.
quoteMaxToken
]);
},
[
selectedModel
.
quoteMaxToken
]);
// 简易 Agent 不暴露多模态开关,文件选择能力直接跟随模型能力。
useEffect
(()
=>
{
setAppForm
((
state
)
=>
({
...
state
,
chatConfig
:
{
...
state
.
chatConfig
,
...(
state
.
chatConfig
.
fileSelectConfig
?
{
fileSelectConfig
:
{
...
state
.
chatConfig
.
fileSelectConfig
,
canSelectImg
:
!!
selectedModel
.
vision
,
canSelectAudio
:
!!
selectedModel
.
audio
,
canSelectVideo
:
!!
selectedModel
.
video
}
}
:
{})
}
}));
},
[
selectedModel
,
setAppForm
]);
return
(
return
(
<>
<>
<
Box
mt=
{
4
}
{
...
cardStyles
}
boxShadow=
{
'3.5'
}
>
<
Box
mt=
{
4
}
{
...
cardStyles
}
boxShadow=
{
'3.5'
}
>
...
@@ -521,7 +501,6 @@ const EditForm = ({
...
@@ -521,7 +501,6 @@ const EditForm = ({
{
/* File select */
}
{
/* File select */
}
<
Box
{
...
BoxStyles
}
>
<
Box
{
...
BoxStyles
}
>
<
FileSelectConfig
<
FileSelectConfig
forbidVision=
{
!
selectedModel
?.
vision
}
value=
{
appForm
.
chatConfig
.
fileSelectConfig
}
value=
{
appForm
.
chatConfig
.
fileSelectConfig
}
onChange=
{
(
e
)
=>
{
onChange=
{
(
e
)
=>
{
setAppForm
((
state
)
=>
({
setAppForm
((
state
)
=>
({
...
...
projects/app/src/pageComponents/app/detail/Edit/ChatAgent/utils.ts
View file @
f05c0fff
...
@@ -159,19 +159,6 @@ export function agentForm2AppWorkflow(
...
@@ -159,19 +159,6 @@ export function agentForm2AppWorkflow(
video
:
!!
modelData
?.
video
,
video
:
!!
modelData
?.
video
,
extractFiles
:
!!
(
modelData
?.
vision
||
modelData
?.
audio
||
modelData
?.
video
)
extractFiles
:
!!
(
modelData
?.
vision
||
modelData
?.
audio
||
modelData
?.
video
)
};
};
const
chatConfig
:
AppChatConfigType
=
{
...
data
.
chatConfig
,
...(
data
.
chatConfig
.
fileSelectConfig
?
{
fileSelectConfig
:
{
...
data
.
chatConfig
.
fileSelectConfig
,
canSelectImg
:
modelMultimodal
.
vision
,
canSelectAudio
:
modelMultimodal
.
audio
,
canSelectVideo
:
modelMultimodal
.
video
}
}
:
{})
};
function
systemConfigTemplate
():
StoreNodeItemType
{
function
systemConfigTemplate
():
StoreNodeItemType
{
return
{
return
{
...
@@ -412,7 +399,7 @@ export function agentForm2AppWorkflow(
...
@@ -412,7 +399,7 @@ export function agentForm2AppWorkflow(
return
{
return
{
nodes
:
[
systemConfigTemplate
(),
workflowStartTemplate
(),
...
workflow
.
nodes
],
nodes
:
[
systemConfigTemplate
(),
workflowStartTemplate
(),
...
workflow
.
nodes
],
edges
:
workflow
.
edges
,
edges
:
workflow
.
edges
,
chatConfig
chatConfig
:
data
.
chatConfig
};
};
}
}
...
...
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx
View file @
f05c0fff
...
@@ -112,26 +112,6 @@ const EditForm = ({
...
@@ -112,26 +112,6 @@ const EditForm = ({
return
selectedModel
.
quoteMaxToken
||
3000
;
return
selectedModel
.
quoteMaxToken
||
3000
;
},
[
selectedModel
.
quoteMaxToken
]);
},
[
selectedModel
.
quoteMaxToken
]);
// 简易应用不暴露多模态开关,文件选择能力直接跟随模型能力。
useEffect
(()
=>
{
setAppForm
((
state
)
=>
({
...
state
,
chatConfig
:
{
...
state
.
chatConfig
,
...(
state
.
chatConfig
.
fileSelectConfig
?
{
fileSelectConfig
:
{
...
state
.
chatConfig
.
fileSelectConfig
,
canSelectImg
:
!!
selectedModel
.
vision
,
canSelectAudio
:
!!
selectedModel
.
audio
,
canSelectVideo
:
!!
selectedModel
.
video
}
}
:
{})
}
}));
},
[
selectedModel
,
setAppForm
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
if
(
appForm
.
dataset
.
datasetSearchUsingExtensionQuery
&&
appForm
.
dataset
.
datasetSearchUsingExtensionQuery
&&
...
@@ -402,7 +382,6 @@ const EditForm = ({
...
@@ -402,7 +382,6 @@ const EditForm = ({
{
/* File select */
}
{
/* File select */
}
<
Box
{
...
BoxStyles
}
>
<
Box
{
...
BoxStyles
}
>
<
FileSelectConfig
<
FileSelectConfig
forbidVision=
{
!
selectedModel
?.
vision
}
value=
{
appForm
.
chatConfig
.
fileSelectConfig
}
value=
{
appForm
.
chatConfig
.
fileSelectConfig
}
onChange=
{
(
e
)
=>
{
onChange=
{
(
e
)
=>
{
setAppForm
((
state
)
=>
({
setAppForm
((
state
)
=>
({
...
...
projects/app/src/pageComponents/app/detail/Edit/SimpleApp/utils.ts
View file @
f05c0fff
...
@@ -226,19 +226,6 @@ export function form2AppWorkflow(
...
@@ -226,19 +226,6 @@ export function form2AppWorkflow(
video
:
!!
modelData
?.
video
,
video
:
!!
modelData
?.
video
,
extractFiles
:
!!
(
modelData
?.
vision
||
modelData
?.
audio
||
modelData
?.
video
)
extractFiles
:
!!
(
modelData
?.
vision
||
modelData
?.
audio
||
modelData
?.
video
)
};
};
const
chatConfig
:
AppChatConfigType
=
{
...
data
.
chatConfig
,
...(
data
.
chatConfig
.
fileSelectConfig
?
{
fileSelectConfig
:
{
...
data
.
chatConfig
.
fileSelectConfig
,
canSelectImg
:
modelMultimodal
.
vision
,
canSelectAudio
:
modelMultimodal
.
audio
,
canSelectVideo
:
modelMultimodal
.
video
}
}
:
{})
};
function
systemConfigTemplate
():
StoreNodeItemType
{
function
systemConfigTemplate
():
StoreNodeItemType
{
return
{
return
{
...
@@ -860,6 +847,6 @@ export function form2AppWorkflow(
...
@@ -860,6 +847,6 @@ export function form2AppWorkflow(
return
{
return
{
nodes
:
[
systemConfigTemplate
(),
workflowStartTemplate
(),
...
workflow
.
nodes
],
nodes
:
[
systemConfigTemplate
(),
workflowStartTemplate
(),
...
workflow
.
nodes
],
edges
:
workflow
.
edges
,
edges
:
workflow
.
edges
,
chatConfig
chatConfig
:
data
.
chatConfig
};
};
}
}
projects/app/test/web/core/app/utils.test.ts
View file @
f05c0fff
...
@@ -57,6 +57,45 @@ describe('form2AppWorkflow', () => {
...
@@ -57,6 +57,45 @@ describe('form2AppWorkflow', () => {
expect
(
result
.
edges
).
toHaveLength
(
1
);
expect
(
result
.
edges
).
toHaveLength
(
1
);
});
});
it
(
'should preserve file upload settings independently from model capabilities'
,
()
=>
{
const
fileSelectConfigs
=
[
{
canSelectFile
:
true
,
canSelectImg
:
true
,
canSelectAudio
:
true
,
canSelectVideo
:
true
},
{
canSelectFile
:
false
,
canSelectImg
:
false
,
canSelectAudio
:
false
,
canSelectVideo
:
false
}
];
const
workflows
=
fileSelectConfigs
.
map
((
fileSelectConfig
)
=>
{
const
form
=
getDefaultAppForm
();
form
.
chatConfig
.
fileSelectConfig
=
fileSelectConfig
;
return
form2AppWorkflow
(
form
,
mockT
);
});
expect
(
workflows
.
map
((
workflow
)
=>
workflow
.
chatConfig
.
fileSelectConfig
)).
toEqual
(
fileSelectConfigs
);
const
getMultimodalInputs
=
(
workflow
:
(
typeof
workflows
)[
number
])
=>
{
const
aiNode
=
workflow
.
nodes
.
find
((
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
chatNode
);
return
[
NodeInputKeyEnum
.
aiChatVision
,
NodeInputKeyEnum
.
aiChatAudio
,
NodeInputKeyEnum
.
aiChatVideo
].
map
((
key
)
=>
aiNode
?.
inputs
.
find
((
input
)
=>
input
.
key
===
key
)?.
value
);
};
expect
(
getMultimodalInputs
(
workflows
[
0
])).
toEqual
(
getMultimodalInputs
(
workflows
[
1
]));
});
it
(
'roundtrips simple app sandbox entrypoint through the tool call node'
,
()
=>
{
it
(
'roundtrips simple app sandbox entrypoint through the tool call node'
,
()
=>
{
const
form
:
AppFormEditFormType
=
{
const
form
:
AppFormEditFormType
=
{
aiSettings
:
{
aiSettings
:
{
...
@@ -395,6 +434,45 @@ describe('getAppQGuideCustomURL', () => {
...
@@ -395,6 +434,45 @@ describe('getAppQGuideCustomURL', () => {
describe
(
'appWorkflow2AgentForm'
,
()
=>
{
describe
(
'appWorkflow2AgentForm'
,
()
=>
{
const
mockT
=
(
str
:
string
)
=>
str
;
const
mockT
=
(
str
:
string
)
=>
str
;
it
(
'should preserve agent file upload settings independently from model capabilities'
,
()
=>
{
const
fileSelectConfigs
=
[
{
canSelectFile
:
true
,
canSelectImg
:
true
,
canSelectAudio
:
true
,
canSelectVideo
:
true
},
{
canSelectFile
:
false
,
canSelectImg
:
false
,
canSelectAudio
:
false
,
canSelectVideo
:
false
}
];
const
workflows
=
fileSelectConfigs
.
map
((
fileSelectConfig
)
=>
{
const
form
=
getDefaultAppForm
();
form
.
chatConfig
.
fileSelectConfig
=
fileSelectConfig
;
return
agentForm2AppWorkflow
(
form
,
mockT
);
});
expect
(
workflows
.
map
((
workflow
)
=>
workflow
.
chatConfig
.
fileSelectConfig
)).
toEqual
(
fileSelectConfigs
);
const
getMultimodalInputs
=
(
workflow
:
(
typeof
workflows
)[
number
])
=>
{
const
agentNode
=
workflow
.
nodes
.
find
((
node
)
=>
node
.
flowNodeType
===
FlowNodeTypeEnum
.
agent
);
return
[
NodeInputKeyEnum
.
aiChatVision
,
NodeInputKeyEnum
.
aiChatAudio
,
NodeInputKeyEnum
.
aiChatVideo
].
map
((
key
)
=>
agentNode
?.
inputs
.
find
((
input
)
=>
input
.
key
===
key
)?.
value
);
};
expect
(
getMultimodalInputs
(
workflows
[
0
])).
toEqual
(
getMultimodalInputs
(
workflows
[
1
]));
});
it
(
'should normalize dataset rerank fields from partial datasetParams'
,
()
=>
{
it
(
'should normalize dataset rerank fields from partial datasetParams'
,
()
=>
{
const
result
=
appWorkflow2AgentForm
({
const
result
=
appWorkflow2AgentForm
({
nodes
:
[
nodes
:
[
...
...
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