diff --git a/files/docker/docker-compose-milvus.yml b/files/docker/docker-compose-milvus.yml index 08410ed11a1c..e6d1ce279846 100644 --- a/files/docker/docker-compose-milvus.yml +++ b/files/docker/docker-compose-milvus.yml @@ -159,6 +159,14 @@ services: # 日志等级: debug, info, warn, error - LOG_LEVEL=info - STORE_LOG_LEVEL=warn + # 工作流最大运行次数 + - WORKFLOW_MAX_RUN_TIMES=1000 + # 批量执行节点,最大输入长度 + - WORKFLOW_MAX_LOOP_TIMES=100 + # 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割) + - ALLOWED_ORIGINS= + # 是否开启IP限制,默认不开启 + - USE_IP_LIMIT=false volumes: - ./config.json:/app/data/config.json diff --git a/files/docker/docker-compose-pgvector.yml b/files/docker/docker-compose-pgvector.yml index 787a37505069..e8da9abe82db 100644 --- a/files/docker/docker-compose-pgvector.yml +++ b/files/docker/docker-compose-pgvector.yml @@ -116,6 +116,14 @@ services: # 日志等级: debug, info, warn, error - LOG_LEVEL=info - STORE_LOG_LEVEL=warn + # 工作流最大运行次数 + - WORKFLOW_MAX_RUN_TIMES=1000 + # 批量执行节点,最大输入长度 + - WORKFLOW_MAX_LOOP_TIMES=100 + # 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割) + - ALLOWED_ORIGINS= + # 是否开启IP限制,默认不开启 + - USE_IP_LIMIT=false volumes: - ./config.json:/app/data/config.json diff --git a/files/docker/docker-compose-zilliz.yml b/files/docker/docker-compose-zilliz.yml index 2495658f17d5..6b53232e71b1 100644 --- a/files/docker/docker-compose-zilliz.yml +++ b/files/docker/docker-compose-zilliz.yml @@ -97,6 +97,14 @@ services: # 日志等级: debug, info, warn, error - LOG_LEVEL=info - STORE_LOG_LEVEL=warn + # 工作流最大运行次数 + - WORKFLOW_MAX_RUN_TIMES=1000 + # 批量执行节点,最大输入长度 + - WORKFLOW_MAX_LOOP_TIMES=100 + # 自定义跨域,不配置时,默认都允许跨域(多个域名通过逗号分割) + - ALLOWED_ORIGINS= + # 是否开启IP限制,默认不开启 + - USE_IP_LIMIT=false volumes: - ./config.json:/app/data/config.json diff --git a/packages/global/core/workflow/type/io.d.ts b/packages/global/core/workflow/type/io.d.ts index 3653e2a12e4b..7f6b46eb70b3 100644 --- a/packages/global/core/workflow/type/io.d.ts +++ b/packages/global/core/workflow/type/io.d.ts @@ -49,9 +49,10 @@ export type FlowNodeInputItemType = InputComponentPropsType & { debugLabel?: string; description?: string; // field desc required?: boolean; - toolDescription?: string; // If this field is not empty, it is entered as a tool enum?: string; + toolDescription?: string; // If this field is not empty, it is entered as a tool + // render components params canEdit?: boolean; // dynamic inputs isPro?: boolean; // Pro version field diff --git a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts index 2c20b790be50..71d5f40213f0 100644 --- a/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts +++ b/packages/service/core/workflow/dispatch/agent/runTool/toolChoice.ts @@ -210,7 +210,7 @@ export const runToolWithToolChoice = async ( properties[item.key] = { ...jsonSchema, description: item.toolDescription || '', - enum: item.enum?.split('\n').filter(Boolean) || [] + enum: item.enum?.split('\n').filter(Boolean) || undefined }; }); @@ -227,6 +227,7 @@ export const runToolWithToolChoice = async ( } }; }); + // Filter histories by maxToken const filterMessages = ( await filterGPTMessageByMaxTokens({ diff --git a/projects/app/src/web/core/app/templates.ts b/projects/app/src/web/core/app/templates.ts index 359fbe20640f..1b128e11f8ea 100644 --- a/projects/app/src/web/core/app/templates.ts +++ b/projects/app/src/web/core/app/templates.ts @@ -1,20 +1,16 @@ -// @ts-nocheck - -import { AppItemType } from '@/types/app'; import { parseCurl } from '@fastgpt/global/common/string/http'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { AppSchema } from '@fastgpt/global/core/app/type'; -import { - NodeOutputKeyEnum, - WorkflowIOValueTypeEnum -} from '@fastgpt/global/core/workflow/constants'; +import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; import { FlowNodeInputTypeEnum, FlowNodeOutputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; -import { StoreEdgeItemType } from '@fastgpt/global/core/workflow/type/edge'; -import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node'; +import { + FlowNodeInputItemType, + FlowNodeOutputItemType +} from '@fastgpt/global/core/workflow/type/io'; import { i18nT } from '@fastgpt/web/i18n/utils'; export const emptyTemplates: Record< @@ -254,7 +250,8 @@ export const emptyTemplates: Record< sourceHandle: '448745-source-right', targetHandle: 'loOvhld2ZTKa-target-left' } - ] + ], + chatConfig: {} }, [AppTypeEnum.workflow]: { avatar: 'core/app/type/workflowFill', @@ -265,7 +262,7 @@ export const emptyTemplates: Record< name: i18nT('common:core.module.template.system_config'), intro: i18nT('common:core.module.template.system_config_info'), avatar: 'core/workflow/template/systemConfig', - flowNodeType: 'userGuide', + flowNodeType: FlowNodeTypeEnum.systemConfig, position: { x: 262.2732338817093, y: -476.00241136598146 @@ -274,22 +271,22 @@ export const emptyTemplates: Record< inputs: [ { key: 'welcomeText', - renderTypeList: ['hidden'], - valueType: 'string', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.string, label: 'core.app.Welcome Text', value: '' }, { key: 'variables', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, label: 'core.app.Chat Variable', value: [] }, { key: 'questionGuide', - valueType: 'any', - renderTypeList: ['hidden'], + valueType: WorkflowIOValueTypeEnum.any, + renderTypeList: [FlowNodeInputTypeEnum.hidden], label: 'core.app.Question Guide', value: { open: false @@ -297,8 +294,8 @@ export const emptyTemplates: Record< }, { key: 'tts', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, label: '', value: { type: 'web' @@ -306,8 +303,8 @@ export const emptyTemplates: Record< }, { key: 'whisper', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, label: '', value: { open: false, @@ -317,8 +314,8 @@ export const emptyTemplates: Record< }, { key: 'scheduleTrigger', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, label: '', value: null } @@ -330,7 +327,7 @@ export const emptyTemplates: Record< name: i18nT('common:core.module.template.work_start'), intro: '', avatar: 'core/workflow/template/workflowStart', - flowNodeType: 'workflowStart', + flowNodeType: FlowNodeTypeEnum.workflowStart, position: { x: 632.368838596004, y: -347.7446492944009 @@ -339,8 +336,8 @@ export const emptyTemplates: Record< inputs: [ { key: 'userChatInput', - renderTypeList: ['reference', 'textarea'], - valueType: 'string', + renderTypeList: [FlowNodeInputTypeEnum.reference, FlowNodeInputTypeEnum.textarea], + valueType: WorkflowIOValueTypeEnum.string, label: i18nT('common:core.module.input.label.user question'), required: true, toolDescription: i18nT('common:core.module.input.label.user question') @@ -351,13 +348,14 @@ export const emptyTemplates: Record< id: 'userChatInput', key: 'userChatInput', label: 'common:core.module.input.label.user question', - type: 'static', - valueType: 'string' + type: FlowNodeOutputTypeEnum.static, + valueType: WorkflowIOValueTypeEnum.string } ] } ], - edges: [] + edges: [], + chatConfig: {} }, [AppTypeEnum.plugin]: { avatar: 'core/app/type/pluginFill', @@ -406,7 +404,8 @@ export const emptyTemplates: Record< outputs: [] } ], - edges: [] + edges: [], + chatConfig: {} } }; @@ -420,34 +419,66 @@ export const parsePluginFromCurlString = ( const { url, method, headers, body, params, bodyArray } = parseCurl(curl); const allInputs = Array.from( - new Map([...headers, ...params, ...bodyArray].map((item) => [item.key, item])).values() + new Map([...params, ...bodyArray].map((item) => [item.key, item])).values() ); - const formatInputs = allInputs.map((item) => { - const valueType = item.value === null ? 'string' : typeof item.value; - return { - renderTypeList: ['reference'], - selectedTypeIndex: 0, - valueType, - canEdit: true, - key: item.key, - label: item.key, - description: item.key, - defaultValue: '', - required: false, - toolDescription: ['string', 'number', 'boolean'].includes(valueType) ? item.key : '' - }; - }); - const formatOutputs = formatInputs.map((item) => ({ + const formatPluginStartInputs = allInputs + .map((item) => { + const valueType = item.value === null ? 'string' : typeof item.value; + const valueTypeMap = { + string: { + renderTypeList: [FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.string, + isToolType: true, + defaultValue: item.value + }, + number: { + renderTypeList: [FlowNodeInputTypeEnum.numberInput, FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.number, + isToolType: true, + defaultValue: item.value + }, + boolean: { + renderTypeList: [FlowNodeInputTypeEnum.switch, FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.boolean, + isToolType: true, + defaultValue: item.value + }, + object: { + renderTypeList: [FlowNodeInputTypeEnum.JSONEditor, FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.object, + isToolType: false, + defaultValue: '' + } + }; + + const valueTypeItem = valueTypeMap[valueType as keyof typeof valueTypeMap]; + if (!valueTypeItem) return; + + return { + renderTypeList: valueTypeItem.renderTypeList, + selectedTypeIndex: 0, + valueType: valueTypeItem.valueType, + canEdit: true, + key: item.key, + label: item.key, + description: '', + defaultValue: valueTypeItem.defaultValue, + required: false, + toolDescription: valueTypeItem.isToolType ? item.key : '' + }; + }) + .filter(Boolean) as FlowNodeInputItemType[]; + const formatPluginStartOutputs = formatPluginStartInputs.map((item) => ({ id: item.key, key: item.key, label: item.key, valueType: item.valueType, - type: 'hidden' + type: FlowNodeOutputTypeEnum.hidden })); const referenceHeaders = headers.map((item) => ({ key: item.key, - value: `{{$pluginInput.${item.key}$}}`, + value: item.value, type: item.type })); const referenceParams = params.map((item) => ({ @@ -457,14 +488,17 @@ export const parsePluginFromCurlString = ( })); const referenceBody = Object.entries(JSON.parse(body)).reduce( (acc, [key, value]) => { - acc[key] = `{{$pluginInput.${key}$}}`; + acc[key] = + typeof value === 'string' ? `###{{$pluginInput.${key}$}}###` : `{{$pluginInput.${key}$}}`; return acc; }, {} as Record ); const referenceBodyStr = JSON.stringify(referenceBody, null, 2) .replace(/"{{\$/g, '{{$') - .replace(/\$}}"/g, '$}}'); + .replace(/\$}}"/g, '$}}') + .replace(/###{{\$/g, '{{$') + .replace(/\$}}###/g, '$}}'); return { nodes: [ @@ -473,22 +507,22 @@ export const parsePluginFromCurlString = ( name: i18nT('workflow:template.plugin_start'), intro: i18nT('workflow:intro_plugin_input'), avatar: 'core/workflow/template/workflowStart', - flowNodeType: 'pluginInput', + flowNodeType: FlowNodeTypeEnum.pluginInput, showStatus: false, position: { x: 427.6554681270263, y: -291.6987155252725 }, version: '481', - inputs: formatInputs, - outputs: formatOutputs + inputs: formatPluginStartInputs, + outputs: formatPluginStartOutputs }, { nodeId: 'pluginOutput', name: i18nT('common:core.module.template.self_output'), intro: i18nT('workflow:intro_custom_plugin_output'), avatar: 'core/workflow/template/pluginOutput', - flowNodeType: 'pluginOutput', + flowNodeType: FlowNodeTypeEnum.pluginOutput, showStatus: false, position: { x: 1870.1072210870427, @@ -497,8 +531,8 @@ export const parsePluginFromCurlString = ( version: '481', inputs: [ { - renderTypeList: ['reference'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.any, canEdit: true, key: 'result', label: 'result', @@ -508,8 +542,8 @@ export const parsePluginFromCurlString = ( value: ['vumlECDQTjeC', 'httpRawResponse'] }, { - renderTypeList: ['reference'], - valueType: 'object', + renderTypeList: [FlowNodeInputTypeEnum.reference], + valueType: WorkflowIOValueTypeEnum.object, canEdit: true, key: 'error', label: 'error', @@ -526,7 +560,7 @@ export const parsePluginFromCurlString = ( name: 'HTTP 请求', intro: '可以发出一个 HTTP 请求,实现更为复杂的操作(联网搜索、数据库查询等)', avatar: 'core/workflow/template/httpRequest', - flowNodeType: 'httpRequest468', + flowNodeType: FlowNodeTypeEnum.httpRequest468, showStatus: true, position: { x: 1049.4419012643668, @@ -536,28 +570,28 @@ export const parsePluginFromCurlString = ( inputs: [ { key: 'system_addInputParam', - renderTypeList: ['addInputParam'], - valueType: 'dynamic', + renderTypeList: [FlowNodeInputTypeEnum.addInputParam], + valueType: WorkflowIOValueTypeEnum.dynamic, label: '', required: false, description: '接收前方节点的输出值作为变量,这些变量可以被 HTTP 请求参数使用。', customInputConfig: { selectValueTypeList: [ - 'string', - 'number', - 'boolean', - 'object', - 'arrayString', - 'arrayNumber', - 'arrayBoolean', - 'arrayObject', - 'arrayAny', - 'any', - 'chatHistory', - 'datasetQuote', - 'dynamic', - 'selectApp', - 'selectDataset' + WorkflowIOValueTypeEnum.string, + WorkflowIOValueTypeEnum.number, + WorkflowIOValueTypeEnum.boolean, + WorkflowIOValueTypeEnum.object, + WorkflowIOValueTypeEnum.arrayString, + WorkflowIOValueTypeEnum.arrayNumber, + WorkflowIOValueTypeEnum.arrayBoolean, + WorkflowIOValueTypeEnum.arrayObject, + WorkflowIOValueTypeEnum.arrayAny, + WorkflowIOValueTypeEnum.any, + WorkflowIOValueTypeEnum.chatHistory, + WorkflowIOValueTypeEnum.datasetQuote, + WorkflowIOValueTypeEnum.dynamic, + WorkflowIOValueTypeEnum.selectApp, + WorkflowIOValueTypeEnum.selectDataset ], showDescription: false, showDefaultValue: true @@ -568,8 +602,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpMethod', - renderTypeList: ['custom'], - valueType: 'string', + renderTypeList: [FlowNodeInputTypeEnum.custom], + valueType: WorkflowIOValueTypeEnum.string, label: '', value: method, required: true, @@ -580,8 +614,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpTimeout', - renderTypeList: ['custom'], - valueType: 'number', + renderTypeList: [FlowNodeInputTypeEnum.custom], + valueType: WorkflowIOValueTypeEnum.number, label: '', value: 30, min: 5, @@ -594,8 +628,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpReqUrl', - renderTypeList: ['hidden'], - valueType: 'string', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.string, label: '', description: '新的 HTTP 请求地址。如果出现两个"请求地址",可以删除该模块重新加入,会拉取最新的模块配置。', @@ -608,8 +642,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpHeader', - renderTypeList: ['custom'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.custom], + valueType: WorkflowIOValueTypeEnum.any, value: referenceHeaders, label: '', description: @@ -622,22 +656,21 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpParams', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, value: referenceParams, description: '新的 HTTP 请求地址。如果出现两个“请求地址”,可以删除该模块重新加入,会拉取最新的模块配置。', label: '', required: false, valueDesc: '', - description: '', debugLabel: '', toolDescription: '' }, { key: 'system_httpJsonBody', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, value: referenceBodyStr, label: '', required: false, @@ -648,8 +681,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpFormBody', - renderTypeList: ['hidden'], - valueType: 'any', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.any, value: [], label: '', required: false, @@ -660,8 +693,8 @@ export const parsePluginFromCurlString = ( }, { key: 'system_httpContentType', - renderTypeList: ['hidden'], - valueType: 'string', + renderTypeList: [FlowNodeInputTypeEnum.hidden], + valueType: WorkflowIOValueTypeEnum.string, value: 'json', label: '', required: false, @@ -675,26 +708,26 @@ export const parsePluginFromCurlString = ( { id: 'system_addOutputParam', key: 'system_addOutputParam', - type: 'dynamic', - valueType: 'dynamic', + type: FlowNodeOutputTypeEnum.dynamic, + valueType: WorkflowIOValueTypeEnum.dynamic, label: '输出字段提取', customFieldConfig: { selectValueTypeList: [ - 'string', - 'number', - 'boolean', - 'object', - 'arrayString', - 'arrayNumber', - 'arrayBoolean', - 'arrayObject', - 'arrayAny', - 'any', - 'chatHistory', - 'datasetQuote', - 'dynamic', - 'selectApp', - 'selectDataset' + WorkflowIOValueTypeEnum.string, + WorkflowIOValueTypeEnum.number, + WorkflowIOValueTypeEnum.boolean, + WorkflowIOValueTypeEnum.object, + WorkflowIOValueTypeEnum.arrayString, + WorkflowIOValueTypeEnum.arrayNumber, + WorkflowIOValueTypeEnum.arrayBoolean, + WorkflowIOValueTypeEnum.arrayObject, + WorkflowIOValueTypeEnum.arrayAny, + WorkflowIOValueTypeEnum.any, + WorkflowIOValueTypeEnum.chatHistory, + WorkflowIOValueTypeEnum.datasetQuote, + WorkflowIOValueTypeEnum.dynamic, + WorkflowIOValueTypeEnum.selectApp, + WorkflowIOValueTypeEnum.selectDataset ], showDescription: false, showDefaultValue: false @@ -707,8 +740,8 @@ export const parsePluginFromCurlString = ( key: 'error', label: '请求错误', description: 'HTTP请求错误信息,成功时返回空', - valueType: 'object', - type: 'static', + valueType: WorkflowIOValueTypeEnum.object, + type: FlowNodeOutputTypeEnum.static, valueDesc: '' }, { @@ -717,8 +750,8 @@ export const parsePluginFromCurlString = ( required: true, label: '原始响应', description: 'HTTP请求的原始响应。只能接受字符串或JSON类型响应数据。', - valueType: 'any', - type: 'static', + valueType: WorkflowIOValueTypeEnum.any, + type: FlowNodeOutputTypeEnum.static, valueDesc: '' } ] @@ -751,6 +784,7 @@ export const parsePluginFromCurlString = ( sourceHandle: 'vumlECDQTjeC-source-right', targetHandle: 'pluginOutput-target-left' } - ] + ], + chatConfig: {} }; };