Commit 8751665d by Finley Ge Committed by GitHub

fix(workflow): preserve explicit tool input render types (#7437)

* fix(workflow): preserve explicit tool input render types

* fix(tool-runtime): exclude referenced inputs from model schema
parent b60be546
......@@ -163,15 +163,12 @@ export const normalizeFlowNodeInputType = <T extends FlowNodeInputItemType>(
: isLegacyDefaultSelection
? undefined
: legacySelectedType;
const mustUseAgentGenerated =
canUseAgentGenerated && shouldUseAgentGeneratedOnly({ ...input, renderTypeList });
const shouldDefaultToAgentGenerated = canUseAgentGenerated && recommendsAgentGenerated;
const defaultManualType = renderTypeList.find(
(type) => type !== FlowNodeInputTypeEnum.agentGenerated
);
const selectedType = mustUseAgentGenerated
? FlowNodeInputTypeEnum.agentGenerated
: deferDefaultSelection && recommendsAgentGenerated && !savedSelectedType
const selectedType =
deferDefaultSelection && recommendsAgentGenerated && !savedSelectedType
? undefined
: savedSelectedType &&
renderTypeList.includes(savedSelectedType) &&
......@@ -307,12 +304,11 @@ export const getToolInputDisplayRenderTypeList = ({
}
const manualRenderType = getToolInputManualRenderType(input);
if (!manualRenderType) return [FlowNodeInputTypeEnum.agentGenerated];
return Array.from(
new Set([
FlowNodeInputTypeEnum.agentGenerated,
manualRenderType,
...(manualRenderType ? [manualRenderType] : []),
...input.renderTypeList.filter(
(type) => type !== FlowNodeInputTypeEnum.agentGenerated && !manualInputRenderTypes.has(type)
)
......@@ -527,8 +523,17 @@ export const initToolInputTypeByDefaultMode = <T extends FlowNodeInputItemType>(
}: ToolInputDefaultModeOptions = {}
): T => {
const isTool = allowUserChatInputAgentGenerated || input.key !== NodeInputKeyEnum.userChatInput;
const normalizedInput = normalizeFlowNodeInputType(input, { isTool, forceDefaultMode });
// Agent 配置不展示 reference 等工作流专用类型;没有手动控件时只能由 Agent 生成。
if (isTool && shouldUseAgentGeneratedOnly(normalizedInput)) {
return {
...normalizedInput,
selectedType: FlowNodeInputTypeEnum.agentGenerated
};
}
return normalizeFlowNodeInputType(input, { isTool, forceDefaultMode });
return normalizedInput;
};
export const initToolInputsTypeByDefaultMode = <T extends FlowNodeInputItemType>(
......
......@@ -2,6 +2,7 @@ import Ajv, { type ErrorObject, type ValidateFunction } from 'ajv';
import Ajv2019 from 'ajv/dist/2019';
import Ajv2020 from 'ajv/dist/2020';
import type { ChatCompletionTool } from '../../ai/llm/type';
import { FlowNodeInputTypeEnum } from '../../workflow/node/constant';
import type { FlowNodeInputItemType } from '../../workflow/type/io';
import { AgentToolInputModeEnum } from './constants';
import {
......@@ -9,6 +10,7 @@ import {
canInputBeManuallyConfigured,
isAgentGeneratedToolInput
} from '../formEdit/utils';
import { getSelectedInputRenderType } from '../../workflow/utils';
import {
buildModelVisibleToolJsonSchema,
type JSONSchemaInputType,
......@@ -47,8 +49,10 @@ const createToolInputDefinitions = ({
}): ToolInputDefinition[] =>
inputs.map((input) => {
const canAgentGenerate = canInputBeAgentGenerated(input);
const canConfigureManually =
// reference 在工作流执行前已解析为固定值,不受 Agent 配置页手动控件范围限制。
const canUseFixedBinding =
canInputBeManuallyConfigured({ renderTypeList: input.renderTypeList ?? [] }) ||
getSelectedInputRenderType(input) === FlowNodeInputTypeEnum.reference ||
!canAgentGenerate;
return {
......@@ -57,7 +61,7 @@ const createToolInputDefinitions = ({
nodeInput: input,
allowedModes: [
...(canAgentGenerate ? [AgentToolInputModeEnum.agentGenerated] : []),
...(canConfigureManually ? [AgentToolInputModeEnum.manual] : [])
...(canUseFixedBinding ? [AgentToolInputModeEnum.manual] : [])
]
};
});
......
......@@ -1017,6 +1017,22 @@ describe('agent generated tool input helpers', () => {
expect(getToolInputManualRenderType(input)).toBeUndefined();
});
it('should preserve an explicit reference-only selection in workflow tool context', () => {
const input = normalizeFlowNodeInputType(
createMockInput({
renderTypeList: [FlowNodeInputTypeEnum.reference],
selectedType: FlowNodeInputTypeEnum.reference
}),
{ isTool: true }
);
expect(input.renderTypeList).toEqual([
FlowNodeInputTypeEnum.agentGenerated,
FlowNodeInputTypeEnum.reference
]);
expect(input.selectedType).toBe(FlowNodeInputTypeEnum.reference);
});
it('should normalize reference-only inputs to agent generated mode', () => {
const input = initToolInputTypeByDefaultMode(
createMockInput({
......@@ -1485,6 +1501,20 @@ describe('agent generated tool input helpers', () => {
]);
});
it('should keep reference available for reference-only workflow tool inputs', () => {
const renderTypeList = getToolInputDisplayRenderTypeList({
input: createMockInput({
renderTypeList: [FlowNodeInputTypeEnum.agentGenerated, FlowNodeInputTypeEnum.reference]
}),
showAgentGenerated: true
});
expect(renderTypeList).toEqual([
FlowNodeInputTypeEnum.agentGenerated,
FlowNodeInputTypeEnum.reference
]);
});
it.each([
{
valueType: WorkflowIOValueTypeEnum.number,
......
......@@ -65,6 +65,41 @@ describe('compileToolRuntime', () => {
});
});
it('keeps a selected workflow reference out of the model schema', () => {
const compiled = compileToolRuntime({
toolId: 'workflow-tool',
name: 'Workflow tool',
inputs: [
{
key: 'var_ref',
label: 'var_ref',
valueType: WorkflowIOValueTypeEnum.string,
renderTypeList: [FlowNodeInputTypeEnum.agentGenerated, FlowNodeInputTypeEnum.reference],
selectedType: FlowNodeInputTypeEnum.reference,
value: ['workflowStart', 'userChatInput']
},
{
key: 'var_ref2',
label: 'var_ref2',
valueType: WorkflowIOValueTypeEnum.string,
renderTypeList: [FlowNodeInputTypeEnum.agentGenerated, FlowNodeInputTypeEnum.reference],
selectedType: FlowNodeInputTypeEnum.agentGenerated
}
]
});
expect(compiled.modelTool.function.parameters).toEqual({
type: 'object',
properties: {
var_ref2: { type: 'string', description: '' }
}
});
expect(compiled.agentGeneratedKeys).toEqual(['var_ref2']);
expect(compiled.fixedInputBindings).toEqual({
var_ref: ['workflowStart', 'userChatInput']
});
});
it('normalizes persisted modes to each input allowed modes', () => {
const compiled = compileToolRuntime({
toolId: 'guarded-tool',
......
......@@ -14,11 +14,7 @@ import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyIcon from '@fastgpt/web/components/common/Icon';
import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { WorkflowActionsContext } from '../../../../context/workflowActionsContext';
import {
canInputBeAgentGenerated,
canInputBeManuallyConfigured,
getToolInputDisplayRenderTypeList
} from '@fastgpt/global/core/app/formEdit/utils';
import { getToolInputDisplayRenderTypeList } from '@fastgpt/global/core/app/formEdit/utils';
import { getSelectedInputRenderType } from '@fastgpt/global/core/workflow/utils';
type Props = {
......@@ -34,11 +30,8 @@ const InputLabel = ({ nodeId, input, RightComponent, isTool }: Props) => {
const onChangeNode = useContextSelector(WorkflowActionsContext, (v) => v.onChangeNode);
const { description, required, label, renderTypeList, valueType, valueDesc } = input;
const canManuallyConfigure = canInputBeManuallyConfigured(input);
const renderType =
isTool && canInputBeAgentGenerated(input) && !canManuallyConfigure
? FlowNodeInputTypeEnum.agentGenerated
: (getSelectedInputRenderType(input) ?? renderTypeList?.[0] ?? FlowNodeInputTypeEnum.input);
getSelectedInputRenderType(input) ?? renderTypeList?.[0] ?? FlowNodeInputTypeEnum.input;
const displayRenderTypeList = useMemo(
() =>
getToolInputDisplayRenderTypeList({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment