diff --git a/api/controllers/console/workspace/workspace.py b/api/controllers/console/workspace/workspace.py
index 34af80bca7..03dd4f6eb8 100644
--- a/api/controllers/console/workspace/workspace.py
+++ b/api/controllers/console/workspace/workspace.py
@@ -48,6 +48,7 @@ tenant_fields = {
"in_trial": fields.Boolean,
"trial_end_reason": fields.String,
"custom_config": fields.Raw(attribute="custom_config"),
+ "beta_config": fields.Raw(attribute="beta_config"),
}
tenants_fields = {
@@ -177,6 +178,31 @@ class CustomConfigWorkspaceApi(Resource):
return {"result": "success", "tenant": marshal(WorkspaceService.get_tenant_info(tenant), tenant_fields)}
+class BetaConfigWorkspaceApi(Resource):
+ @setup_required
+ @login_required
+ @account_initialization_required
+ def post(self):
+ parser = reqparse.RequestParser()
+ parser.add_argument("beta_config", type=dict, location="json")
+ args = parser.parse_args()
+
+ tenant = db.get_or_404(Tenant, current_user.current_tenant_id)
+
+ db_config = tenant.beta_config_dict
+ param_config = args["beta_config"] or {}
+
+ if not db_config:
+ tenant.beta_config_dict = param_config
+ else:
+ merged_config = {**db_config, **param_config}
+ tenant.beta_config_dict = merged_config
+
+ db.session.commit()
+
+ return {"result": "success", "tenant": marshal(WorkspaceService.get_tenant_info(tenant), tenant_fields)}
+
+
class WebappLogoWorkspaceApi(Resource):
@setup_required
@login_required
@@ -239,5 +265,6 @@ api.add_resource(TenantApi, "/workspaces/current", endpoint="workspaces_current"
api.add_resource(TenantApi, "/info", endpoint="info") # Deprecated
api.add_resource(SwitchWorkspaceApi, "/workspaces/switch") # POST for switching tenant
api.add_resource(CustomConfigWorkspaceApi, "/workspaces/custom-config")
+api.add_resource(BetaConfigWorkspaceApi, "/workspaces/beta-config")
api.add_resource(WebappLogoWorkspaceApi, "/workspaces/custom-config/webapp-logo/upload")
api.add_resource(WorkspaceInfoApi, "/workspaces/info") # POST for changing workspace info
diff --git a/api/models/account.py b/api/models/account.py
index bb6a2a4735..4e81b7cc5d 100644
--- a/api/models/account.py
+++ b/api/models/account.py
@@ -199,6 +199,7 @@ class Tenant(Base):
plan = db.Column(db.String(255), nullable=False, server_default=db.text("'basic'::character varying"))
status = db.Column(db.String(255), nullable=False, server_default=db.text("'normal'::character varying"))
custom_config = db.Column(db.Text)
+ beta_config = db.Column(db.Text)
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
@@ -217,6 +218,14 @@ class Tenant(Base):
def custom_config_dict(self, value: dict):
self.custom_config = json.dumps(value)
+ @property
+ def beta_config_dict(self) -> dict:
+ return json.loads(self.beta_config) if self.beta_config else {}
+
+ @beta_config_dict.setter
+ def beta_config_dict(self, value: dict):
+ self.beta_config = json.dumps(value)
+
class TenantAccountJoin(Base):
__tablename__ = "tenant_account_joins"
diff --git a/api/services/workspace_service.py b/api/services/workspace_service.py
index 125e0c1b1e..034c6ad4fc 100644
--- a/api/services/workspace_service.py
+++ b/api/services/workspace_service.py
@@ -20,6 +20,7 @@ class WorkspaceService:
"created_at": tenant.created_at,
"trial_end_reason": None,
"role": "normal",
+ "beta_config": tenant.beta_config_dict,
}
# Get role of user
diff --git a/web/app/components/header/account-setting/beta-page/index.tsx b/web/app/components/header/account-setting/beta-page/index.tsx
new file mode 100644
index 0000000000..8283e6ab71
--- /dev/null
+++ b/web/app/components/header/account-setting/beta-page/index.tsx
@@ -0,0 +1,45 @@
+import { useTranslation } from 'react-i18next'
+import Switch from '@/app/components/base/switch'
+import {
+ updateCurrentWorkspace,
+} from '@/service/common'
+import { useAppContext } from '@/context/app-context'
+
+const BetaPage = () => {
+ const { t } = useTranslation()
+ const {
+ currentWorkspace,
+ mutateCurrentWorkspace,
+ } = useAppContext()
+ const workflowVarCheck = currentWorkspace.beta_config?.workflow_var_check
+
+ const handleSwitch = async (checked: boolean) => {
+ await updateCurrentWorkspace({
+ url: '/workspaces/beta-config',
+ body: {
+ beta_config: {
+ workflow_var_check: checked,
+ },
+ },
+ })
+ mutateCurrentWorkspace()
+ }
+
+ return (
+
+
+
+
{t('common.beta.workflowVarCheck')}
+
{t('common.beta.workflowVarCheckTip')}
+
+
+
+
+ )
+}
+
+export default BetaPage
diff --git a/web/app/components/header/account-setting/index.tsx b/web/app/components/header/account-setting/index.tsx
index b2a3c8245b..83098f6698 100644
--- a/web/app/components/header/account-setting/index.tsx
+++ b/web/app/components/header/account-setting/index.tsx
@@ -15,6 +15,8 @@ import {
RiMoneyDollarCircleLine,
RiPuzzle2Fill,
RiPuzzle2Line,
+ RiTestTubeFill,
+ RiTestTubeLine,
RiTranslate2,
} from '@remixicon/react'
import Button from '../../base/button'
@@ -31,6 +33,7 @@ import { useProviderContext } from '@/context/provider-context'
import { useAppContext } from '@/context/app-context'
import MenuDialog from '@/app/components/header/account-setting/menu-dialog'
import Input from '@/app/components/base/input'
+import BatePage from './beta-page'
const iconClassName = `
w-5 h-5 mr-2
@@ -56,8 +59,7 @@ export default function AccountSetting({
const [activeMenu, setActiveMenu] = useState(activeTab)
const { t } = useTranslation()
const { enableBilling, enableReplaceWebAppLogo } = useProviderContext()
- const { isCurrentWorkspaceDatasetOperator } = useAppContext()
-
+ const { isCurrentWorkspaceDatasetOperator, currentWorkspace } = useAppContext()
const workplaceGroupItems = (() => {
if (isCurrentWorkspaceDatasetOperator)
return []
@@ -100,6 +102,12 @@ export default function AccountSetting({
icon: ,
activeIcon: ,
},
+ {
+ key: currentWorkspace.role === 'owner' ? 'beta' : false,
+ name: t('common.beta.beta'),
+ icon: ,
+ activeIcon: ,
+ },
].filter(item => !!item.key) as GroupItem[]
})()
@@ -220,6 +228,7 @@ export default function AccountSetting({
{activeMenu === 'api-based-extension' && }
{activeMenu === 'custom' && }
{activeMenu === 'language' && }
+ {activeMenu === 'beta' && }
diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts
index ebef0e0c2c..13a6c53250 100644
--- a/web/app/components/workflow/hooks/use-checklist.ts
+++ b/web/app/components/workflow/hooks/use-checklist.ts
@@ -34,6 +34,7 @@ import { useDatasetsDetailStore } from '../datasets-detail-store/store'
import type { KnowledgeRetrievalNodeType } from '../nodes/knowledge-retrieval/types'
import type { DataSet } from '@/models/datasets'
import { fetchDatasets } from '@/service/datasets'
+import { useAppContext } from '@/context/app-context'
export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const { t } = useTranslation()
@@ -45,6 +46,9 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const workflowTools = useStore(s => s.workflowTools)
const { data: strategyProviders } = useStrategyProviders()
const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail)
+ const {
+ currentWorkspace,
+ } = useAppContext()
const chatVarList = useStore(s => s.conversationVariables)
const environmentVariables = useStore(s => s.environmentVariables)
@@ -72,6 +76,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
const allVariablesMap = transformStartNodeVariables(chatVarList, environmentVariables)
const errMessageMap = new Map()
+ const workflowVarCheck = currentWorkspace.beta_config?.workflow_var_check
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
@@ -120,7 +125,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
varErrorMessage: [],
})
}
- if (nodesExtraData[node.data.type as BlockEnum].checkVarValid) {
+ if (workflowVarCheck && nodesExtraData[node.data.type as BlockEnum].checkVarValid) {
const { errorMessage: varErrorMessages } = nodesExtraData[node.data.type as BlockEnum].checkVarValid(node.data, { ...allVariablesMap, ...node._parentOutputVarMap }, t)
if (varErrorMessages?.length) {
diff --git a/web/app/components/workflow/nodes/http/default.ts b/web/app/components/workflow/nodes/http/default.ts
index 1c027a3fec..1b89ac1961 100644
--- a/web/app/components/workflow/nodes/http/default.ts
+++ b/web/app/components/workflow/nodes/http/default.ts
@@ -7,6 +7,7 @@ import {
ALL_CHAT_AVAILABLE_BLOCKS,
ALL_COMPLETION_AVAILABLE_BLOCKS,
} from '@/app/components/workflow/blocks'
+import { transformToBodyPayload } from './utils'
const nodeDefault: NodeDefault = {
defaultValue: {
@@ -78,7 +79,9 @@ const nodeDefault: NodeDefault = {
const body_warnings: string[] = []
if ([BodyType.binary].includes(payload.body.type)) {
- const body_data = payload.body.data as BodyPayload
+ let body_data = payload.body.data
+ if (typeof body_data === 'string')
+ body_data = transformToBodyPayload(body_data, false)
body_data.forEach((item) => {
const key_warnings = getNotExistVariablesByText(item.key || '', varMap)
if (key_warnings.length)
@@ -89,7 +92,9 @@ const nodeDefault: NodeDefault = {
})
}
else {
- const body_data = payload.body.data as BodyPayload
+ let body_data = payload.body.data
+ if (typeof body_data === 'string')
+ body_data = transformToBodyPayload(body_data, [BodyType.formData, BodyType.xWwwFormUrlencoded].includes(payload.body.type))
body_data.forEach((item) => {
const key_warnings = getNotExistVariablesByText(item.key || '', varMap)
if (key_warnings.length)
diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts
index f3a7e09ab7..f7f008a854 100644
--- a/web/i18n/zh-Hans/common.ts
+++ b/web/i18n/zh-Hans/common.ts
@@ -273,6 +273,11 @@ const translation = {
setBuilder: 'Set as builder (设置为构建器)',
builder: '构建器',
},
+ beta: {
+ beta: 'Beta 功能',
+ workflowVarCheck: '严格模式-变量可用性检查',
+ workflowVarCheckTip: '启用后,cahflow/workflow 将会检查节点中变量是否可用。',
+ },
integrations: {
connected: '登录方式',
google: 'Google',
diff --git a/web/models/common.ts b/web/models/common.ts
index cb8fb7f2bf..705e66e56c 100644
--- a/web/models/common.ts
+++ b/web/models/common.ts
@@ -134,6 +134,9 @@ export type ICurrentWorkspace = Omit & {
custom_config?: {
remove_webapp_brand?: boolean
replace_webapp_logo?: string
+ },
+ beta_config?: {
+ workflow_var_check?: boolean
}
}