Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum VariableUpdateOperatorEnum {
set = 'set',
add = 'add',
sub = 'sub',
mul = 'mul',
div = 'div',
negate = 'negate',
push = 'push',
clear = 'clear'
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
value: [
{
variable: ['', ''],
value: ['', ''],
updateType: 'set',
inputValue: '',
valueType: WorkflowIOValueTypeEnum.string,
renderType: FlowNodeInputTypeEnum.input
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { z } from 'zod';
import { FlowNodeInputTypeEnum } from '../../../node/constant';
import { WorkflowIOValueTypeEnum } from '../../../constants';
import { VariableUpdateOperatorEnum } from './constants';

const ReferenceItemValueSchema = z.tuple([z.string(), z.union([z.string(), z.undefined()])]);

export const UpdateListItemSchema = z.object({
variable: ReferenceItemValueSchema.optional(),
valueType: z.enum(WorkflowIOValueTypeEnum).optional(),
renderType: z.union([
z.literal(FlowNodeInputTypeEnum.input),
z.literal(FlowNodeInputTypeEnum.reference)
]),

updateType: z.enum(VariableUpdateOperatorEnum).optional(),
referenceValue: ReferenceItemValueSchema.optional(),
inputValue: z.any().optional(),

/** @deprecated 旧格式字段,运行时由 normalizeUpdateItem 转换为 updateType + inputValue/referenceValue */
value: z.any().optional()
});

export type TUpdateListItem = z.infer<typeof UpdateListItemSchema>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { TUpdateListItem } from './type';
import { VariableUpdateOperatorEnum } from './constants';

export const normalizeUpdateItem = (item: TUpdateListItem): TUpdateListItem => {
// 新格式:已有 updateType,直接返回
if (item.updateType !== undefined) return item;

// 旧格式:value 是数组
const raw = item.value;
if (Array.isArray(raw)) {
const [first, second] = raw as [string, string | undefined];
const isRef = !!first;
return {
variable: item.variable,
valueType: item.valueType,
renderType: item.renderType,
updateType: VariableUpdateOperatorEnum.set,
referenceValue: isRef ? [first, second] : undefined,
inputValue: isRef ? undefined : second
};
}

return {
...item,
updateType: VariableUpdateOperatorEnum.set,
inputValue: ''
};
};
28 changes: 22 additions & 6 deletions packages/global/core/workflow/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,29 @@ export const toolSetData2FlowNodeIO = ({ nodes }: { nodes: StoreNodeItemType[] }
};
};

export const formatEditorVariablePickerIcon = (
variables: { key: string; label: string; type?: `${VariableInputEnum}`; required?: boolean }[]
export const formatEditorVariable = (
variables: {
key: string;
label: string;
type?: `${VariableInputEnum}`;
required?: boolean;
valueType?: WorkflowIOValueTypeEnum;
}[]
): EditorVariablePickerType[] => {
return variables.map((item) => ({
...item,
icon: item.type ? variableMap[item.type]?.icon : variableMap['input'].icon
}));
return variables.map((item) => {
const config = item.type ? variableMap[item.type] : variableMap['input'];

return {
...item,
icon: config?.icon,
valueType:
([VariableInputEnum.custom, VariableInputEnum.internal].includes(
item.type as VariableInputEnum
) &&
item.valueType) ||
config?.defaultValueType
};
});
};

// Check the value is a valid reference value format: [variableId, outputId]
Expand Down
84 changes: 61 additions & 23 deletions packages/service/core/workflow/dispatch/tools/runUpdateVar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { VARIABLE_NODE_ID } from '@fastgpt/global/core/workflow/constants';
import { VARIABLE_NODE_ID, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import {
DispatchNodeResponseKeyEnum,
SseResponseEventEnum
Expand All @@ -10,10 +10,30 @@ import {
replaceEditorVariable
} from '@fastgpt/global/core/workflow/runtime/utils';
import { type TUpdateListItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/type';
import type { ReferenceValueType } from '@fastgpt/global/core/workflow/type/io';
import { type ModuleDispatchProps } from '@fastgpt/global/core/workflow/runtime/type';
import { runtimeSystemVar2StoreType } from '../utils';
import { isValidReferenceValue } from '@fastgpt/global/core/workflow/utils';
import { valueTypeFormat } from '@fastgpt/global/core/workflow/runtime/utils';
import { VariableUpdateOperatorEnum } from '@fastgpt/global/core/workflow/template/system/variableUpdate/constants';
import { normalizeUpdateItem } from '@fastgpt/global/core/workflow/template/system/variableUpdate/utils';
import { FlowNodeInputTypeEnum } from '@fastgpt/global/core/workflow/node/constant';

const operatorHandlerMap: Record<string, (cur: any, operand: any) => any> = {
[VariableUpdateOperatorEnum.set]: (_cur, operand) => operand,
[VariableUpdateOperatorEnum.add]: (cur, operand) => Number(cur) + Number(operand),
[VariableUpdateOperatorEnum.sub]: (cur, operand) => Number(cur) - Number(operand),
[VariableUpdateOperatorEnum.mul]: (cur, operand) => Number(cur) * Number(operand),
[VariableUpdateOperatorEnum.div]: (cur, operand) =>
Number(operand) !== 0 ? Number(cur) / Number(operand) : cur,
[VariableUpdateOperatorEnum.negate]: (cur) =>
!(typeof cur === 'string' ? cur.toLowerCase() === 'true' : cur),
[VariableUpdateOperatorEnum.push]: (cur, operand) => [
...(Array.isArray(cur) ? cur : []),
operand
],
[VariableUpdateOperatorEnum.clear]: () => []
};

type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.updateList]: TUpdateListItem[];
Expand All @@ -34,7 +54,8 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
const { updateList } = params;
const nodeIds = runtimeNodes.map((node) => node.nodeId);

const result = updateList.map((item) => {
const result = updateList.map((rawItem) => {
const item = normalizeUpdateItem(rawItem);
const variable = item.variable;

if (!isValidReferenceValue(variable, nodeIds)) {
Expand All @@ -49,33 +70,50 @@ export const dispatchUpdateVariable = async (props: Props): Promise<Response> =>
}

const value = (() => {
// If first item is empty, it means it is a input value
if (!item.value?.[0]) {
const val =
typeof item.value?.[1] === 'string'
? replaceEditorVariable({
text: item.value?.[1],
nodes: runtimeNodes,
variables
})
: item.value?.[1];

return valueTypeFormat(val, item.valueType);
} else {
return getReferenceVariableValue({
value: item.value,
variables,
nodes: runtimeNodes
});
const operator = item.updateType ?? VariableUpdateOperatorEnum.set;
const operand =
item.renderType === FlowNodeInputTypeEnum.reference
? getReferenceVariableValue({
value: item.referenceValue as ReferenceValueType,
variables,
nodes: runtimeNodes
})
: replaceEditorVariable({ text: item.inputValue, nodes: runtimeNodes, variables });

const handler = operatorHandlerMap[operator];
if (!handler) return operand ?? null;

if (operator === VariableUpdateOperatorEnum.set) {
return valueTypeFormat(operand, item.valueType);
}

const currentValue = getReferenceVariableValue({
value: variable,
variables,
nodes: runtimeNodes
});
const typedCurrentValue = valueTypeFormat(currentValue, item.valueType) ?? currentValue;

const processedOperand =
operator === VariableUpdateOperatorEnum.push &&
typeof operand === 'string' &&
(item.valueType === WorkflowIOValueTypeEnum.arrayObject ||
item.valueType === WorkflowIOValueTypeEnum.arrayAny)
? (() => {
try {
return JSON.parse(operand);
} catch {
return operand;
}
})()
: operand;

return handler(typedCurrentValue, processedOperand);
})();

// Update node output
// Global variable
if (varNodeId === VARIABLE_NODE_ID) {
variables[varKey] = value;
} else {
// Other nodes
runtimeNodes
.find((node) => node.nodeId === varNodeId)
?.outputs?.find((output) => {
Expand Down
9 changes: 9 additions & 0 deletions packages/web/i18n/en/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@
"variable_description": "Variable description",
"variable_picker_tips": "Type node name or variable name to search",
"variable_update": "Variable Update",
"variable_update_operator_set": "Set",
"variable_update_operator_add": "Add",
"variable_update_operator_sub": "Subtract",
"variable_update_operator_mul": "Multiply",
"variable_update_operator_div": "Divide",
"variable_update_number_placeholder": "Enter value",
"variable_update_boolean_negate": "Negate",
"variable_update_operator_push": "Push",
"variable_update_operator_clear": "Clear",
"workflow.My edit": "My Edit",
"workflow.Switch_success": "Switch Successful",
"workflow.Team cloud": "Team Cloud",
Expand Down
9 changes: 9 additions & 0 deletions packages/web/i18n/zh-CN/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@
"variable_description": "变量描述",
"variable_picker_tips": "可输入节点名或变量名搜索",
"variable_update": "变量更新",
"variable_update_operator_set": "等于",
"variable_update_operator_add": "加",
"variable_update_operator_sub": "减",
"variable_update_operator_mul": "乘",
"variable_update_operator_div": "除",
"variable_update_number_placeholder": "输入值",
"variable_update_boolean_negate": "取反",
"variable_update_operator_push": "追加",
"variable_update_operator_clear": "清空",
"workflow.My edit": "我的编辑",
"workflow.Switch_success": "切换成功",
"workflow.Team cloud": "团队云端",
Expand Down
9 changes: 9 additions & 0 deletions packages/web/i18n/zh-Hant/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@
"variable_description": "變數描述",
"variable_picker_tips": "可以輸入節點名稱或變數名稱搜尋",
"variable_update": "變數更新",
"variable_update_operator_set": "等於",
"variable_update_operator_add": "加",
"variable_update_operator_sub": "減",
"variable_update_operator_mul": "乘",
"variable_update_operator_div": "除",
"variable_update_number_placeholder": "輸入值",
"variable_update_boolean_negate": "取反",
"variable_update_operator_push": "追加",
"variable_update_operator_clear": "清空",
"workflow.My edit": "我的編輯",
"workflow.Switch_success": "切換成功",
"workflow.Team cloud": "團隊雲端",
Expand Down
4 changes: 2 additions & 2 deletions projects/app/src/components/core/app/VariableEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import type { VariableItemType } from '@fastgpt/global/core/app/type.d';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next';
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
import { formatEditorVariable } from '@fastgpt/global/core/workflow/utils';
import ChatFunctionTip from './Tip';
import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
import MyIconButton from '@fastgpt/web/components/common/Icon/button';
Expand Down Expand Up @@ -77,7 +77,7 @@ const VariableEdit = ({
const [editingVariable, setEditingVariable] = useState<VariableItemType | null>(null);

const formatVariables = useMemo(() => {
const results = formatEditorVariablePickerIcon(variables);
const results = formatEditorVariable(variables);
return results.map<VariableItemType & { icon?: string }>((item) => {
const variable = variables.find((variable) => variable.key === item.key)!;
return {
Expand Down
4 changes: 2 additions & 2 deletions projects/app/src/components/core/app/formRender/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const InputRender = (props: InputRenderProps) => {
variableLabels={props.variableLabels}
title={props.title}
maxLength={props.maxLength}
minH={40}
minH={Number(props.minH) || 40}
maxH={120}
isRichText={props.isRichText}
/>
Expand All @@ -85,7 +85,7 @@ const InputRender = (props: InputRenderProps) => {
variableLabels={props.variableLabels}
title={props.title}
maxLength={props.maxLength}
minH={100}
minH={Number(props.minH) || 100}
maxH={300}
ExtensionPopover={props.ExtensionPopover}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Avatar from '@fastgpt/web/components/common/Avatar';
import MyIcon from '@fastgpt/web/components/common/Icon';
import VariableEdit from '@/components/core/app/VariableEdit';
import PromptEditor from '@fastgpt/web/components/common/Textarea/PromptEditor';
import { formatEditorVariablePickerIcon } from '@fastgpt/global/core/workflow/utils';
import { formatEditorVariable } from '@fastgpt/global/core/workflow/utils';
import SearchParamsTip from '@/components/core/dataset/SearchParamsTip';
import SettingLLMModel from '@/components/core/ai/SettingLLMModel';
import { TTSTypeEnum } from '@/web/core/app/constants';
Expand Down Expand Up @@ -86,7 +86,7 @@ const EditForm = ({

const formatVariables = useMemo(
() =>
formatEditorVariablePickerIcon([
formatEditorVariable([
...workflowSystemVariables.filter(
(variable) =>
!['appId', 'chatId', 'responseChatItemId', 'histories'].includes(variable.key)
Expand Down
Loading
Loading