Novu Tool 步骤 `enabledIntegrations` 控件移除方案:从集成标识过滤到全量投递的架构演进

发布时间:2026/9/10 19:55:01
Novu Tool 步骤 `enabledIntegrations` 控件移除方案:从集成标识过滤到全量投递的架构演进 Novu Tool 步骤enabledIntegrations控件移除方案从集成标识过滤到全量投递的架构演进【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu本指南围绕 Novu 仓库中 remove-enabled-integrations.md 这份实施计划展开系统讲解 Tool 渠道步骤中enabledIntegrations集成标识符过滤器控件的移除目标、涉及的文件与符号、兼容性策略与验证方法。读完本文你将理解 Tool 步骤从按集成标识符过滤投递演进为始终投递到环境内全部活跃 Tool 集成的完整技术路径并能结合仓库源码定位每一层改动UI、Schema、DTO、sanitize、渲染器、Worker 过滤逻辑的实际落点。一、方案背景为什么要移除enabledIntegrations在 Novu 的 Workflow 编辑器中Tool 渠道步骤Tool-channel step曾经提供一项名为enabledIntegrations的步骤级控件用于以集成标识符integration identifier为单位过滤投递目标用户可以在步骤里勾选希望消息投递到的集成Worker 在执行发送时依据该字段在环境内筛选出匹配的集成再逐个派发。该计划的核心目标是彻底移除这个控件及其全部关联逻辑——包括 UI、Schema、DTO、sanitize、渲染render以及 Worker 侧的过滤逻辑。移除之后Tool 步骤的行为回归为一种简单而明确的语义Tool 步骤始终投递到环境中所有处于活跃状态active的 Tool 集成即此前enabledIntegrations为空或未定义时的默认行为。这一决策将哪些集成参与投递的职责完全交还给环境级别的集成配置步骤本身不再持有额外的过滤状态从而消除环境里明明配置了集成、步骤却没投出去这类因步骤级过滤而产生的隐性故障源。二、范围界定明确不动什么计划文档对移除范围做了清晰的边界声明避免误伤相邻概念范围项说明enabledProviderslibs/maily-core这是邮件编辑器里建议提供者suggestion providers的配置与 Tool 步骤的集成过滤器是完全不同的概念保持不动libs/internal-sdk自动生成代码禁止手工编辑DB 迁移不需要执行数据库迁移理由见下文兼容与迁移策略这种边界划分意味着本次改动是纯代码层的收敛它只触及控制面板Dashboard的表单表现层、后端与框架的 Schema/DTO 定义层以及 Worker 的执行过滤层不触碰编辑器生态与数据存储结构。三、改动清单逐层拆解3.1 删除文件UI 控件本体计划中唯一需要整体删除的源文件是 Dashboard 侧的 Tool 步骤表单控件路径符号 / 原因apps/dashboard/src/components/workflow-editor/steps/tool/tool-enabled-providers.tsxToolEnabledProviders——该控件专属的 UI 组件仅用于渲染启用哪些集成的表单区块从当前仓库的实际状态看该文件已不存在于apps/dashboard/src/components/workflow-editor/steps/目录下tool/目录中也不再保留这一控件印证了UI 层移除这一步的落地结果。3.2 Dashboard表单接线收口apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx承担步骤表单的组装职责计划要求在此文件完成三处清理移除ToolEnabledProviders的 import 与 JSX 使用移除showToolFormMiddleSection控制中间表单区块是否展示的辅助逻辑移除registerInlineControlValues中 TOOL 分支里对enabledIntegrations默认值的写入逻辑。对照当前源码configure-step-form.tsx中的registerInlineControlValuesconfigure-step-form.tsx只保留了两条分支isInlineConfigurableStep时取getControlsDefaultValues(step)以及StepTypeEnum.HTTP_REQUEST时为continueOnFailure补充默认值TOOL 分支已不复存在——移除后的defaultValues不再为 Tool 步骤注入任何enabledIntegrations默认值表单提交的 payload 中自然也不含该键。3.3 Schema / DTO / sanitize定义层收敛这一层是移除的核心证据链涉及四个文件① Tool 控件 Zod Schema计划要求从toolControlZodSchema中删除enabledIntegrations字段。当前实现tool-control.schema.ts为export const toolControlZodSchema z .object({ skip: skipZodSchema, body: z.string(), }) .strict();注意.strict()的存在Zod 会对未知顶层键直接判失败。这意味着一旦 Schema 中不再声明enabledIntegrations任何仍携带该键的输入都会在校验阶段被拒绝——这既是移除的手段也是下文陈旧键会以 step-issue 形式浮现这一兼容性现象的直接原因。同文件生成的 JSON SchematoolControlSchema由zodToJsonSchema转换而来随之只含body与skip且被additionalProperties: false约束。② Schema 单测libs/application-generic/src/schemas/control/tool-control.schema.spec.ts需同步更新 fixtures。当前测试tool-control.schema.spec.ts已覆盖三类行为接受合法默认控件{ body: MemoryDB alert }拒绝未知顶层键unknownKey: true时success false拒绝在控件值上嵌套providerOverrides。其中拒绝未知顶层键正是验证enabledIntegrations这类残留键会被.strict()拦下的关键用例另一个用例则断言生成的 JSON Schema 属性键恰好为[body, skip]从结果上确认了字段收敛。③ Tool 控件 DTOlibs/application-generic/src/dtos/workflow/tool-control.dto.ts中的ToolControlDto计划移除enabledIntegrations字段及其校验器。当前 DTOtool-control.dto.ts仅保留export class ToolControlDto extends SkipControlDto { ApiPropertyOptional({ description: Content of the tool payload. }) IsString() IsOptional() body: string; }即继承SkipControlDto的skip外只有body一个业务字段enabledIntegrations及其IsString()等校验装饰器已不在其中。④ 控件值 sanitizelibs/application-generic/src/utils/sanitize-control-values.ts中的sanitizeTool计划停止映射enabledIntegrations。当前实现sanitize-control-values.tsfunction sanitizeTool(controlValues: WithProviderOverridesToolControlType) { const mappedValues: ToolControlType { body: sanitizeEmptyInput(controlValues.body), skip: controlValues.skip, }; return keepProviderOverrides(filterNullishValues(mappedValues) as Recordstring, unknown, controlValues); }sanitizeTool采用白名单式拷贝只从输入中复制body与skip外加透传的providerOverrides再经filterNullishValues剔除空值。因此即便持久化的步骤控件值里仍残留enabledIntegrations一旦用户重新保存save或执行 normalize该键就会被洗掉——这正是无需 DB 迁移策略的地基详见第四节。⑤ 框架层 Tool 输出 Schemapackages/framework/src/schemas/steps/channels/tool.schema.ts中的toolOutputSchema.properties计划移除该字段。当前实现tool.schema.tsconst toolOutputSchema { type: object, properties: { body: { type: string }, }, required: [body], additionalProperties: false, } as const satisfies JsonSchema;additionalProperties: false意味着任何仍携带enabledIntegrations的 in-flight bridge 输出若经过 schema 校验都会被拒绝——这是第五节中低风险评估的另一处依据。对应的packages/framework/src/schemas/steps/channels/tool.schema.test.ts期望值需同步更新。⑥ 共享 DTO预览响应packages/shared/src/dto/workflows/preview-step-response.dto.ts中的ToolRenderOutput计划移除该字段。当前定义preview-step-response.dto.tsexport class ToolRenderOutput extends RenderOutput { body: string; providerOverrides?: StepProviderOverrides; }预览preview响应体只承诺body与可选的providerOverrides不再携带任何集成过滤信息。3.4 API / Worker执行链路收敛① API 输出渲染器apps/api/src/app/environments-v1/usecases/output-renderers/tool-output-renderer.usecase.ts计划停止向输出中拷贝enabledIntegrations。当前实现tool-output-renderer.usecase.ts为仅 body 输出execute(translatedControls: Recordstring, unknown): ToolRenderOutput { return { body: (translatedControls.body as string) ?? , }; }渲染器只从已翻译的控件值中取出body其余键一概不进入输出对象。② Worker 发送用例apps/worker/src/app/workflow/usecases/send-message/send-message-tool.usecase.ts是本次改动的执行核心计划要求删除filterToolIntegrationsByEnabledIdentifiers过滤函数删除ToolStepOutputs.enabledIntegrations字段删除过滤调用删除requestedEnabledIntegrations及enabled_integrations_filter_matched_none失败明细execution details改为使用所有活跃集成简化resolveContentAndProviders使其只返回{ content }。对照当前源码SendMessageTool.execute的集成获取逻辑send-message-tool.usecase.ts为const integrations await this.getDecryptedIntegrations.execute( GetDecryptedIntegrationsCommand.create({ organizationId: command.organizationId, environmentId: command.environmentId, userId: command.userId, channelType: ChannelTypeEnum.TOOL, active: true, scopeToEnvironment: true, }) );注意active: truescopeToEnvironment: true的组合Worker 直接拉取当前环境下全部活跃 Tool 集成不再按步骤的enabledIntegrations做二次筛选。若环境内没有任何活跃 Tool 集成则创建失败明细SUBSCRIBER_NO_ACTIVE_INTEGRATIONraw 中携带reason: no_active_tool_integrations并返回失败随后遍历每个集成通过isEndpointRoutedToolProvider区分端点路由endpoint-routed与凭据路由credential-routed两类投递路径非端点路由直接sendToIntegration端点路由如 PagerDuty、Opsgenie、Grafana 及routingMode: dynamic的 Webhook经resolveEndpointsByIntegration解析出该订阅者在该集成下的 channel endpointschannelData逐端点派发无端点时以no_channel_endpoint_for_subscriber警告跳过。与此同时ToolStepOutputs类型当前仅含body?: stringsend-message-tool.usecase.tsresolveContent也只消费bridgeOutputs?.body或编译后的模板内容——过滤相关字段与失败分支已从执行链路中消失。③ Worker 单测apps/worker/src/app/workflow/usecases/send-message/send-message-tool.usecase.spec.ts计划删除enabledIntegrations filter相关的 describe 块。当前该 specsend-message-tool.usecase.spec.ts的测试焦点已完全迁移到 endpoint 路由能力上isEndpointRoutedToolProvider对 PagerDuty、Opsgenie、Grafana 恒为 true无论 credentials 如何、对 Webhook 依赖routingMode: dynamic以及 Opsgenie 端点路由发送路径的桩stub验证——过滤逻辑相关用例已无踪迹。四、兼容与迁移策略为什么可以不做 DB 迁移这是整个方案中最具工程价值的设计决策。已持久化的工作流步骤控件值MongoDB 中controls.values等字段可能仍含有enabledIntegrations但计划明确倾向不做 DB 迁移理由由三层机制共同兜底sanitize 白名单洗键sanitizeTool只拷贝已知键body、skip、providerOverrides下一次 normalize/save 就会把enabledIntegrations从持久化数据中剥离。也就是说清洗是惰性的——不需要离线脚本用户每次保存自然完成收敛。Worker 直接忽略移除过滤调用后Worker 只按active: true读取活跃集成即使旧数据里残留该键也不会影响任何一次投递行为。严格 Schema 兜底Zod 的.strict()与框架输出 Schema 的additionalProperties: false意味着如果原始校验先于 sanitize 执行陈旧键可能以 step-issue 的形式浮现直到工作流被重新保存。计划文档明确认可这一行为——它与现有未知键unknown-key的处理策略一致属于可接受的短期噪音而非功能故障。此外还需考虑在途in-flightbridge 输出框架侧运行中的 bridge 输出若仍携带该键一旦经过 schema 校验就会被拒绝additionalProperties: false但渲染器已不再产出该键因此对新流量而言风险很低。计划对此的判断是Low risk for new traffic其成立前提正是渲染器API 层与执行器Worker 层两端的同步收敛。五、验证方案如何确认移除彻底计划给出了三级验证闭环全部可在当前仓库中对应执行1. Ripgrep 全仓扫描确认 Tool 渠道相关的enabledIntegrations、ToolEnabledProviders、filterToolIntegrationsByEnabledIdentifiers不再残留libs/maily-core中与 Tool 无关的enabledProviders属于例外不应被误伤。2. 单元测试测试文件验证点apps/worker/src/app/workflow/usecases/send-message/send-message-tool.usecase.spec.tsWorker 执行路径不再包含过滤分支端点路由逻辑正常libs/application-generic/src/schemas/control/tool-control.schema.spec.tsTool 控件 Schema 属性恰为body/skip未知键被拒packages/framework/src/schemas/steps/channels/tool.schema.test.ts框架输出 Schema 期望值与body-only 结构一致3. 手动验证可选打开 Dashboard 中的任一 Tool 步骤表单中Enabled Providers区块应已消失触发发送后消息应扇出fan out到环境内所有活跃 Tool 集成。六、小结移除之后的行为模型enabledIntegrations的移除本质上是把投递目标的选择从步骤级配置迁移到环境级集成配置。移除后的完整调用链可以概括为表单层Tool 步骤表单不再渲染、不再默认写入任何集成过滤字段configure-step-form.tsx定义层toolControlZodSchema.strict()与ToolControlDto只接受body/skiptool-control.schema.ts、tool-control.dto.ts清洗层sanitizeTool以白名单方式在保存/normalize 时剥离陈旧键sanitize-control-values.ts渲染层ToolOutputRendererUsecase只输出bodytool-output-renderer.usecase.ts框架输出 Schema 以additionalProperties: false拒绝残留键tool.schema.ts执行层SendMessageTool按active: true拉取环境内全部活跃 Tool 集成并逐个派发过滤分支与相关失败明细已移除send-message-tool.usecase.ts。对于使用 Novu 的团队而言这套方案的最大收益在于语义简化一个 Tool 步骤的投递范围 该环境下全部活跃 Tool 集成排查消息为什么没发到某个集成时只需检查集成自身的 active 状态与端点路由配置而不再需要同时排查步骤里可能早已过期的过滤名单。【免费下载链接】novuThe open-source communication infrastructure for agents and products项目地址: https://gitcode.com/GitHub_Trending/no/novu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考