Dify 工具插件 `dynamic-select` 动态下拉不触发问题 Dify 工具插件dynamic-select动态下拉不触发问题排查与前端修复记录一、背景最近在自部署 Dify 的基础上接入一个数据库查询插件插件类型是Tool功能是让用户在工作流工具节点中选择一个已登记的数据源然后输入 SQL 查询语句执行查询。插件包中核心工具为SQL Query参数主要包括connection_id数据源 ID来源于 Dify 数据库中的database_connections表query_sql用户输入的 SQL 查询语句output_format输出格式支持markdown或json。其中connection_id被设计成动态下拉参数-name:connection_idtype:dynamic-selectrequired:truelabel:en_US:Data Sourcezh_Hans:数据源form:form预期效果是用户打开工具节点配置面板时页面自动调用插件的动态参数接口插件后端查询当前租户下的数据库连接列表并返回下拉选项。但实际接入后发现页面中能看到“数据源”下拉框但是点击下拉框没有任何数据。二、问题现象在工作流工具节点中添加数据库查询插件后connection_id字段展示为下拉框但没有数据。最开始观察到两个现象前端页面没有展示任何动态选项插件端的_fetch_parameter_options方法没有任何日志输出。插件代码中已经实现了动态选项方法classSqlQueryTool(Tool):def_fetch_parameter_options(self,parameter:str)-list[ParameterOption]:ifparameter!connection_id:return[]provider_credentialsdict(self.runtime.credentialsor{})tenant_idself.runtime.tenant_idwithDifyPgClient(provider_credentials)asdify:rowsdify.list_connections(tenant_id)options[ParameterOption(valuestr(r[id]),labelI18nObject(en_USf{r[name]}{r[db_type]}),)forrinrows]returnoptions这说明插件端逻辑本身是准备好的问题更可能出在 Dify 前端没有正确触发动态参数请求。三、排查思路1. 确认插件包本身是 Tool 插件先确认插件不是 Trigger 插件也不是 Model 插件。manifest.yaml中声明name:db_queryplugins:tools:-provider/db_query.yamltype:pluginprovider/db_query.yaml中声明identity:name:db_querytools:-tools/sql_query.yamltools/sql_query.yaml中声明identity:name:sql_queryparameters:-name:connection_idtype:dynamic-selectform:form所以这个插件明确是 Tool 插件动态下拉应该走 Tool 插件的参数加载逻辑。2. 在前端FormInputItem中增加日志因为页面点击下拉没有数据所以先在前端表单渲染组件中加入日志确认dynamic-select是否被识别以及是否拿到了当前工具上下文。修改文件webcustom/app/components/workflow/nodes/_base/components/form-input-item.tsx在动态选项加载逻辑前加入console.log([dynamic-select debug],{isDynamicSelect,currentTool,currentProvider,providerType,resolvedProviderType,variable,extraParams,})刷新页面后发现日志中出现{isDynamicSelect:true,currentTool:undefined,currentProvider:undefined,providerType:tool,resolvedProviderType:tool,variable:connection_id}这说明dynamic-select已经被前端识别当前字段确实是connection_idproviderType是tool但是currentTool和currentProvider没有传进来。没有currentTool和currentProvider前端就无法拼出完整的动态参数请求也就不会正确调用插件的_fetch_parameter_options。四、修改点一给providerType增加默认值修改文件webcustom/app/components/workflow/nodes/_base/components/form-input-item.tsx修改前原逻辑直接使用providerTypeconst{mutateAsync:fetchDynamicOptions}useFetchDynamicOptions(currentProvider?.plugin_id||,currentProvider?.name||,currentTool?.name||,variable||,providerType,extraParams,)如果上层没有传providerType动态下拉请求可能无法正确判断插件类型。修改后在varInput后增加统一处理后的插件类型constvarInputvalue[variable]constresolvedProviderTypeproviderType||PluginCategoryEnum.tool然后统一使用resolvedProviderTypeconst{mutateAsync:fetchDynamicOptions}useFetchDynamicOptions(currentProvider?.plugin_id||,currentProvider?.name||,currentTool?.name||,variable||,resolvedProviderType,extraParams,)动态选项来源判断也同步改成constdynamicOptionsresolvedProviderTypePluginCategoryEnum.trigger?triggerOptions??toolsOptions:toolsOptionsconstisLoadingOptionsresolvedProviderTypePluginCategoryEnum.trigger?(isTriggerOptionsLoading||isLoadingToolsOptions):isLoadingToolsOptions动态选项请求判断也改为if(isDynamicSelectcurrentToolcurrentProvider(resolvedProviderTypePluginCategoryEnum.tool||resolvedProviderTypePluginCategoryEnum.trigger)){setIsLoadingToolsOptions(true)try{constdataawaitfetchDynamicOptions()setToolsOptions(data?.options||[])}catch(error){console.error(Failed to fetch dynamic options:,error)setToolsOptions([])}finally{setIsLoadingToolsOptions(false)}}修改目的这一步主要解决两个问题当上层没有传providerType时默认按tool处理避免 Tool 插件的动态下拉因为providerType为空而不触发请求。五、修改点二给toolSettingSchema区域补充工具上下文问题定位继续排查调用链tool/panel.tsx → tool-form/index.tsx → tool-form/item.tsx → form-input-item.tsx发现tool/panel.tsx中有两个ToolForm。第一个是输入参数区ToolForm readOnly{readOnly} nodeId{id} schema{toolInputVarSchema as any} value{inputs.tool_parameters} onChange{setInputVar} currentProvider{currCollection} currentTool{currTool} /这里已经传了currentProvider和currentTool。但是第二个是配置参数区ToolForm readOnly{readOnly} nodeId{id} schema{toolSettingSchema as any} value{toolSettingValue} onChange{setToolSettingValue} /这里没有传currentProvider和currentTool。而插件中的connection_id参数是type:dynamic-selectform:formform: form类型的参数会进入toolSettingSchema区域渲染而不是toolInputVarSchema区域。因此connection_id渲染时拿不到当前工具和当前插件信息。修改文件webcustom/app/components/workflow/nodes/tool/panel.tsx修改前ToolForm readOnly{readOnly} nodeId{id} schema{toolSettingSchema as any} value{toolSettingValue} onChange{setToolSettingValue} /修改后ToolForm readOnly{readOnly} nodeId{id} schema{toolSettingSchema as any} value{toolSettingValue} onChange{setToolSettingValue} currentProvider{currCollection} currentTool{currTool} /修改目的让form: form的动态下拉参数在渲染时也能拿到currentProvider currentTool这样FormInputItem才能拼出正确的动态参数请求plugin_idxxx providerdb_query actionsql_query parameterconnection_id provider_typetool六、修改后的调用链修改后connection_id的动态下拉加载链路变为SQL Query 工具节点 ↓ tool/panel.tsx ↓ toolSettingSchema 区域 ToolForm ↓ tool-form/index.tsx ↓ tool-form/item.tsx ↓ FormInputItem ↓ useFetchDynamicOptions ↓ GET /console/api/workspaces/current/plugin/parameters/dynamic-options ↓ 插件端 _fetch_parameter_options(connection_id)前端请求参数类似plugin_idxxx providerdb_query actionsql_query parameterconnection_id provider_typetool这说明前端已经能正确触发 Tool 插件的动态参数请求。七、验证结果修改后刷新页面浏览器控制台能看到[dynamic-select debug]{isDynamicSelect:true,currentTool:{...},currentProvider:{...},providerType:tool,resolvedProviderType:tool,variable:connection_id}并且 Network 中可以看到请求GET /console/api/workspaces/current/plugin/parameters/dynamic-options请求参数中包含providerdb_query actionsql_query parameterconnection_id provider_typetool这说明前端已经修复完成动态下拉请求已经能够正常发起。八、后续发现的问题前端请求发出后后端返回了{code:plugin_error,message:{\args\:{},\error_type\:\ValueError\,\message\:\Trigger provider db_query not found\}}这说明当前问题已经从“前端不触发动态下拉请求”变成了“后端处理动态参数请求时错误地按 Trigger provider 查找了db_query”。因为db_query插件本身是 Tool 插件所以这个错误不属于本次前端修改范围后续需要继续排查后端接口/workspaces/current/plugin/parameters/dynamic-options重点检查后端是否正确根据provider_typetool进入 Tool 插件动态参数分支。九、最终改动清单本次前端只需要保留webcustom下的修改。1.form-input-item.tsx文件路径webcustom/app/components/workflow/nodes/_base/components/form-input-item.tsx改动内容新增resolvedProviderTypeuseFetchDynamicOptions使用resolvedProviderType动态选项判断统一使用resolvedProviderType增加动态下拉调试日志。2.panel.tsx文件路径webcustom/app/components/workflow/nodes/tool/panel.tsx改动内容在toolSettingSchema对应的ToolForm中补充currentProvider{currCollection} currentTool{currTool}十、恢复误改文件因为当前实际运行的是webcustom如果之前误改了web目录可以恢复web目录只保留webcustom修改gitrestore web检查修改状态gitstatus--short理想情况下只保留M webcustom/app/components/workflow/nodes/_base/components/form-input-item.tsx M webcustom/app/components/workflow/nodes/tool/panel.tsx十一、总结这次问题的核心不是插件包没有实现动态下拉而是 Dify 前端在渲染form: form的 Tool 插件参数时没有把当前工具和插件 Provider 信息传递到表单组件。对于dynamic-select类型参数来说仅识别出isDynamicSelect true还不够还必须拿到currentTool currentProvider providerType否则前端无法正确请求动态选项。最终通过两处修改解决了前端触发问题在FormInputItem中统一补齐providerType默认值在工具节点toolSettingSchema表单区域补传currentTool和currentProvider。修改后前端已经可以正常发起动态下拉请求。后续如果仍然出现Trigger provider not found则应继续排查 Dify 后端动态参数接口的 provider 类型分支处理逻辑。