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
6591565e
authored
Aug 06, 2026
by
Finley Ge
Committed by
GitHub
Aug 06, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(workflow): restore legacy HTTP tool input defaults (#7462)
parent
0591a4f5
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
205 additions
and
6 deletions
+205
-6
packages/global/core/app/formEdit/utils.ts
+25
-0
packages/global/test/core/app/formEdit/utils.test.ts
+52
-0
packages/service/core/app/utils.ts
+4
-0
packages/service/core/workflow/dispatch/utils/index.ts
+10
-4
packages/service/test/core/workflow/dispatch/utils.test.ts
+56
-0
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderToolInput/EditFieldModal.tsx
+3
-2
projects/app/test/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderToolInput/EditFieldModal.test.ts
+8
-0
projects/app/test/service/core/app/rewriteAppWorkflowToDetail.test.ts
+47
-0
No files found.
packages/global/core/app/formEdit/utils.ts
View file @
6591565e
...
@@ -111,6 +111,31 @@ export const canInputBeAgentGenerated = (
...
@@ -111,6 +111,31 @@ export const canInputBeAgentGenerated = (
};
};
/**
/**
* 恢复旧版工作流 HTTP 节点动态工具参数的默认来源。
*
* 旧编辑器只保存 canEdit 和 toolDescription;显式来源配置始终优先,避免覆盖用户手动选择。
*/
export
const
normalizeLegacyWorkflowHttpToolInputsDefaultMode
=
<
T
extends
FlowNodeInputItemType
>
(
inputs
:
T
[]
):
T
[]
=>
inputs
.
map
((
input
)
=>
{
if
(
input
.
canEdit
!==
true
||
!
input
.
toolDescription
||
input
.
isToolParam
!==
undefined
||
input
.
selectedType
!==
undefined
||
!
canInputBeAgentGenerated
(
input
)
)
{
return
input
;
}
return
{
...
input
,
isToolParam
:
true
};
});
/**
* 将节点输入升级为 selectedType 协议。
* 将节点输入升级为 selectedType 协议。
*
*
* 显式 selectedType 优先;旧 selectedTypeIndex 仅在没有新字段时用于恢复选择。
* 显式 selectedType 优先;旧 selectedTypeIndex 仅在没有新字段时用于恢复选择。
...
...
packages/global/test/core/app/formEdit/utils.test.ts
View file @
6591565e
...
@@ -13,6 +13,7 @@ import {
...
@@ -13,6 +13,7 @@ import {
getToolConfigStatus
,
getToolConfigStatus
,
initToolInputTypeByDefaultMode
,
initToolInputTypeByDefaultMode
,
isAgentGeneratedToolInput
,
isAgentGeneratedToolInput
,
normalizeLegacyWorkflowHttpToolInputsDefaultMode
,
normalizeFlowNodeInputType
,
normalizeFlowNodeInputType
,
stripToolInputDefaultMode
stripToolInputDefaultMode
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
...
@@ -903,6 +904,57 @@ describe('getToolConfigStatus', () => {
...
@@ -903,6 +904,57 @@ describe('getToolConfigStatus', () => {
});
});
describe
(
'agent generated tool input helpers'
,
()
=>
{
describe
(
'agent generated tool input helpers'
,
()
=>
{
it
(
'should restore only legacy editable HTTP tool params'
,
()
=>
{
const
legacyInput
=
createMockInput
({
canEdit
:
true
,
toolDescription
:
'Generated query'
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
]
});
const
explicitManualInput
=
createMockInput
({
key
:
'manual'
,
canEdit
:
true
,
toolDescription
:
'Manual query'
,
isToolParam
:
false
});
const
selectedManualInput
=
createMockInput
({
key
:
'selected-manual'
,
canEdit
:
true
,
toolDescription
:
'Selected manual query'
,
selectedType
:
FlowNodeInputTypeEnum
.
reference
});
const
staticInput
=
createMockInput
({
key
:
'static'
,
toolDescription
:
'Static input'
});
const
emptyDescriptionInput
=
createMockInput
({
key
:
'empty-description'
,
canEdit
:
true
,
toolDescription
:
''
});
const
unsafeInput
=
createMockInput
({
key
:
'unsafe'
,
canEdit
:
true
,
toolDescription
:
'Secret input'
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
password
]
});
const
result
=
normalizeLegacyWorkflowHttpToolInputsDefaultMode
([
legacyInput
,
explicitManualInput
,
selectedManualInput
,
staticInput
,
emptyDescriptionInput
,
unsafeInput
]);
expect
(
result
[
0
]).
toMatchObject
({
isToolParam
:
true
});
expect
(
result
[
1
]).
toBe
(
explicitManualInput
);
expect
(
result
[
2
]).
toBe
(
selectedManualInput
);
expect
(
result
[
3
]).
toBe
(
staticInput
);
expect
(
result
[
4
]).
toBe
(
emptyDescriptionInput
);
expect
(
result
[
5
]).
toBe
(
unsafeInput
);
});
it
.
each
([
it
.
each
([
FlowNodeInputTypeEnum
.
hidden
,
FlowNodeInputTypeEnum
.
hidden
,
FlowNodeInputTypeEnum
.
fileSelect
,
FlowNodeInputTypeEnum
.
fileSelect
,
...
...
packages/service/core/app/utils.ts
View file @
6591565e
...
@@ -7,6 +7,7 @@ import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node'
...
@@ -7,6 +7,7 @@ import type { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node'
import
{
nodeInputIsReference
}
from
'@fastgpt/global/core/workflow/utils'
;
import
{
nodeInputIsReference
}
from
'@fastgpt/global/core/workflow/utils'
;
import
{
import
{
initAgentToolInputType
,
initAgentToolInputType
,
normalizeLegacyWorkflowHttpToolInputsDefaultMode
,
normalizeFlowNodeInputType
normalizeFlowNodeInputType
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
import
{
getClientToolPreviewNode
}
from
'./tool/utils/client'
;
import
{
getClientToolPreviewNode
}
from
'./tool/utils/client'
;
...
@@ -221,6 +222,9 @@ export async function rewriteAppWorkflowToDetail({
...
@@ -221,6 +222,9 @@ export async function rewriteAppWorkflowToDetail({
if
(
allowLegacyFallback
)
{
if
(
allowLegacyFallback
)
{
node
.
inputs
=
normalizeWorkflowToolInputsDefaultMode
(
node
.
inputs
);
node
.
inputs
=
normalizeWorkflowToolInputsDefaultMode
(
node
.
inputs
);
}
}
if
(
node
.
flowNodeType
===
FlowNodeTypeEnum
.
httpRequest468
)
{
node
.
inputs
=
normalizeLegacyWorkflowHttpToolInputsDefaultMode
(
node
.
inputs
);
}
if
(
node
.
flowNodeType
!==
FlowNodeTypeEnum
.
pluginInput
)
{
if
(
node
.
flowNodeType
!==
FlowNodeTypeEnum
.
pluginInput
)
{
node
.
inputs
=
node
.
inputs
.
map
((
input
)
=>
node
.
inputs
=
node
.
inputs
.
map
((
input
)
=>
normalizeFlowNodeInputType
(
input
,
{
deferDefaultSelection
:
true
})
normalizeFlowNodeInputType
(
input
,
{
deferDefaultSelection
:
true
})
...
...
packages/service/core/workflow/dispatch/utils/index.ts
View file @
6591565e
...
@@ -39,6 +39,7 @@ import { getLastInteractiveValue } from '@fastgpt/global/core/workflow/runtime/u
...
@@ -39,6 +39,7 @@ import { getLastInteractiveValue } from '@fastgpt/global/core/workflow/runtime/u
import
{
import
{
getSavedToolInputSelectedType
,
getSavedToolInputSelectedType
,
initToolInputsTypeByDefaultMode
,
initToolInputsTypeByDefaultMode
,
normalizeLegacyWorkflowHttpToolInputsDefaultMode
,
normalizeFlowNodeInputType
normalizeFlowNodeInputType
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
}
from
'@fastgpt/global/core/app/formEdit/utils'
;
import
{
jsonSchema2NodeInput
}
from
'@fastgpt/global/core/app/jsonschema'
;
import
{
jsonSchema2NodeInput
}
from
'@fastgpt/global/core/app/jsonschema'
;
...
@@ -772,10 +773,15 @@ export const rewriteRuntimeWorkFlow = async ({
...
@@ -772,10 +773,15 @@ export const rewriteRuntimeWorkFlow = async ({
node
.
pluginId
?.
startsWith
(
'systemTool-'
)
||
node
.
pluginId
?.
startsWith
(
'systemTool-'
)
||
node
.
pluginId
?.
startsWith
(
'commercial-'
)
node
.
pluginId
?.
startsWith
(
'commercial-'
)
);
);
const
inputsWithLegacyDefaults
=
const
inputsWithLegacyDefaults
=
(()
=>
{
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginModule
&&
isTool
if
(
node
.
flowNodeType
===
FlowNodeTypeEnum
.
pluginModule
&&
isTool
)
{
?
normalizeWorkflowToolInputsDefaultMode
(
node
.
inputs
)
return
normalizeWorkflowToolInputsDefaultMode
(
node
.
inputs
);
:
node
.
inputs
;
}
if
(
node
.
flowNodeType
===
FlowNodeTypeEnum
.
httpRequest468
&&
isTool
)
{
return
normalizeLegacyWorkflowHttpToolInputsDefaultMode
(
node
.
inputs
);
}
return
node
.
inputs
;
})();
node
.
inputs
=
inputsWithLegacyDefaults
.
map
((
input
)
=>
node
.
inputs
=
inputsWithLegacyDefaults
.
map
((
input
)
=>
normalizeFlowNodeInputType
(
input
,
{
normalizeFlowNodeInputType
(
input
,
{
...
...
packages/service/test/core/workflow/dispatch/utils.test.ts
View file @
6591565e
...
@@ -1025,6 +1025,62 @@ describe('rewriteRuntimeWorkFlow', () => {
...
@@ -1025,6 +1025,62 @@ describe('rewriteRuntimeWorkFlow', () => {
expect
(
runtimeInputs
.
find
((
input
)
=>
input
.
key
===
'text2'
)?.
value
).
toBe
(
''
);
expect
(
runtimeInputs
.
find
((
input
)
=>
input
.
key
===
'text2'
)?.
value
).
toBe
(
''
);
});
});
it
(
'should restore legacy HTTP workflow tool params at runtime'
,
async
()
=>
{
const
toolCallNode
=
makeNode
(
'tool-call'
,
FlowNodeTypeEnum
.
toolCall
);
const
httpToolNode
=
makeNode
(
'http-tool'
,
FlowNodeTypeEnum
.
httpRequest468
,
{
inputs
:
[
{
key
:
'query'
,
label
:
'query'
,
valueType
:
'string'
,
required
:
true
,
canEdit
:
true
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
toolDescription
:
'Search query'
},
{
key
:
'manual'
,
label
:
'manual'
,
valueType
:
'string'
,
required
:
false
,
canEdit
:
true
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
toolDescription
:
'Manual value'
,
isToolParam
:
false
}
]
});
const
nodes
=
[
toolCallNode
,
httpToolNode
];
const
edges
=
[
makeEdge
(
'tool-call'
,
'http-tool'
,
{
sourceHandle
:
NodeOutputKeyEnum
.
selectedTools
,
targetHandle
:
NodeOutputKeyEnum
.
selectedTools
})
];
await
rewriteRuntimeWorkFlow
({
teamId
:
'team1'
,
nodes
,
edges
});
expect
(
httpToolNode
.
inputs
[
0
]).
toMatchObject
({
selectedType
:
FlowNodeInputTypeEnum
.
agentGenerated
,
isToolParam
:
true
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
agentGenerated
,
FlowNodeInputTypeEnum
.
reference
]
});
expect
(
httpToolNode
.
inputs
[
1
]).
toMatchObject
({
selectedType
:
FlowNodeInputTypeEnum
.
reference
,
isToolParam
:
false
});
const
runtimeInputs
=
updateAgentLoopCoreWorkflowToolInputValue
({
params
:
{
query
:
'generated query'
,
manual
:
'ignored model value'
},
inputs
:
httpToolNode
.
inputs
});
expect
(
runtimeInputs
[
0
].
value
).
toBe
(
'generated query'
);
expect
(
runtimeInputs
[
1
].
value
).
toBeUndefined
();
});
it
(
'should normalize legacy system tool inputs at the runtime boundary'
,
async
()
=>
{
it
(
'should normalize legacy system tool inputs at the runtime boundary'
,
async
()
=>
{
const
toolCallNode
=
makeNode
(
'tool-call'
,
FlowNodeTypeEnum
.
toolCall
);
const
toolCallNode
=
makeNode
(
'tool-call'
,
FlowNodeTypeEnum
.
toolCall
);
const
systemToolNode
=
makeNode
(
'system-tool'
,
FlowNodeTypeEnum
.
tool
,
{
const
systemToolNode
=
makeNode
(
'system-tool'
,
FlowNodeTypeEnum
.
tool
,
{
...
...
projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderToolInput/EditFieldModal.tsx
View file @
6591565e
import
React
,
{
useCallback
,
useRef
}
from
'react'
;
import
React
,
{
useCallback
}
from
'react'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
MyModal
from
'@fastgpt/web/components/common/MyModal'
;
import
type
{
EditFieldModalProps
}
from
'./type'
;
import
type
{
EditFieldModalProps
}
from
'./type'
;
import
{
useTranslation
}
from
'next-i18next'
;
import
{
useTranslation
}
from
'next-i18next'
;
...
@@ -69,7 +69,7 @@ const EditFieldModal = ({
...
@@ -69,7 +69,7 @@ const EditFieldModal = ({
});
});
const
onclickSubmitError
=
useCallback
(
const
onclickSubmitError
=
useCallback
(
(
e
:
O
bject
)
=>
{
(
e
:
o
bject
)
=>
{
for
(
const
item
of
Object
.
values
(
e
))
{
for
(
const
item
of
Object
.
values
(
e
))
{
if
(
item
.
message
)
{
if
(
item
.
message
)
{
toast
({
toast
({
...
@@ -143,6 +143,7 @@ export default React.memo(EditFieldModal);
...
@@ -143,6 +143,7 @@ export default React.memo(EditFieldModal);
export
const
defaultEditFormData
:
FlowNodeInputItemType
=
{
export
const
defaultEditFormData
:
FlowNodeInputItemType
=
{
valueType
:
WorkflowIOValueTypeEnum
.
string
,
valueType
:
WorkflowIOValueTypeEnum
.
string
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
isToolParam
:
true
,
key
:
''
,
key
:
''
,
label
:
''
,
label
:
''
,
toolDescription
:
''
,
toolDescription
:
''
,
...
...
projects/app/test/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderToolInput/EditFieldModal.test.ts
0 → 100644
View file @
6591565e
import
{
describe
,
expect
,
it
}
from
'vitest'
;
import
{
defaultEditFormData
}
from
'@/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderToolInput/EditFieldModal'
;
describe
(
'RenderToolInput EditFieldModal'
,
()
=>
{
it
(
'creates new dynamic tool params with the Agent-generated default'
,
()
=>
{
expect
(
defaultEditFormData
.
isToolParam
).
toBe
(
true
);
});
});
projects/app/test/service/core/app/rewriteAppWorkflowToDetail.test.ts
View file @
6591565e
...
@@ -41,6 +41,53 @@ vi.mock('@fastgpt/service/support/permission/app/auth', async (importOriginal) =
...
@@ -41,6 +41,53 @@ vi.mock('@fastgpt/service/support/permission/app/auth', async (importOriginal) =
const
{
rewriteAppWorkflowToDetail
}
=
await
import
(
'@fastgpt/service/core/app/utils'
);
const
{
rewriteAppWorkflowToDetail
}
=
await
import
(
'@fastgpt/service/core/app/utils'
);
describe
(
'rewriteAppWorkflowToDetail - legacy HTTP workflow tool inputs'
,
()
=>
{
it
(
'恢复旧版 HTTP 动态工具参数并保留显式手动配置'
,
async
()
=>
{
const
nodes
=
[
{
nodeId
:
'http-tool'
,
flowNodeType
:
FlowNodeTypeEnum
.
httpRequest468
,
inputs
:
[
{
key
:
'query'
,
label
:
'query'
,
valueType
:
WorkflowIOValueTypeEnum
.
string
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
toolDescription
:
'Search query'
,
canEdit
:
true
},
{
key
:
'manual'
,
label
:
'manual'
,
valueType
:
WorkflowIOValueTypeEnum
.
string
,
renderTypeList
:
[
FlowNodeInputTypeEnum
.
reference
],
toolDescription
:
'Manual value'
,
canEdit
:
true
,
isToolParam
:
false
}
],
outputs
:
[]
}
as
StoreNodeItemType
];
await
rewriteAppWorkflowToDetail
({
nodes
,
teamId
:
'team-1'
,
ownerTmbId
:
'tmb-1'
,
isRoot
:
false
});
expect
(
nodes
[
0
].
inputs
[
0
]).
toMatchObject
({
isToolParam
:
true
,
selectedType
:
undefined
});
expect
(
nodes
[
0
].
inputs
[
1
]).
toMatchObject
({
isToolParam
:
false
,
selectedType
:
FlowNodeInputTypeEnum
.
reference
});
});
});
describe
(
'rewriteAppWorkflowToDetail - legacy workflow tool inputs'
,
()
=>
{
describe
(
'rewriteAppWorkflowToDetail - legacy workflow tool inputs'
,
()
=>
{
it
(
'回显旧版工作流工具输入的默认 AI 生成配置并保留显式关闭'
,
async
()
=>
{
it
(
'回显旧版工作流工具输入的默认 AI 生成配置并保留显式关闭'
,
async
()
=>
{
const
legacyInput
=
{
const
legacyInput
=
{
...
...
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