Activepieces Pieces 引擎深度解析:Piece 目录、读时可见性、公式求值与执行运行时

发布时间:2026/9/15 17:13:34
Activepieces Pieces 引擎深度解析:Piece 目录、读时可见性、公式求值与执行运行时 Activepieces Pieces 引擎深度解析Piece 目录、读时可见性、公式求值与执行运行时【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces本篇指南围绕 Activepieces 的 Pieces Engine 体系展开从 Piece 元数据目录piece_metadata 内存pieceCache、EE/Cloud 的 Piece Set 读时可见性、内置公式求值到引擎的构建/类型检查现状、沙箱文件描述符上限、CODE 步骤执行、Worker 版本门禁与 AI Agent 步骤完整梳理这些模块如何协同工作。读完你不仅能掌握 Piece 的安装、发布、过滤与调试的实操方法还能理解引擎在isolate沙箱内的真实运行约束如 64 个 fd 上限并学会用源码路径验证每个结论。Piece 目录自动化集成元数据注册表Piece是 Activepieces 中自动化集成的元数据目录条目——每一个命名集成如activepieces/piece-gmail都提供一组 actions 与 triggers。目录数据存储在piece_metadata表中并由启动时从数据库重建、通过 pub/sub 刷新的内存pieceCache对外服务。从源码看pieceCachepiece-cache.ts的核心机制如下启动初始化setup()在非测试环境下订阅PIECE_REGISTRY_INVALIDATION_CHANNEL频道收到消息后置空cachedRegistry并递增registryGeneration。惰性加载loadRegistry()合并loadPersistedRegistry()读 DB与loadDevPiecesIfEnabled()开发期本地 piece两份结果持久化注册表首次读取后缓存若读取期间 generation 发生变化并发失效则递归重读保证一致性。失效发布任何元数据写操作install/delete/sync都会调用invalidate()先本地置空缓存再向 pub/sub 频道广播让多实例 API 全部失效。实体与服务组件职责piece_metadataPieceMetadataEntity以(name, version, platformId)为唯一键platformId为 null 表示官方 piece有值表示该平台的自定义 pieceactions/triggers是 JSON 映射每个条目可携带可选的outputSchemapieceMetadataServicelist/getOrThrow/listVersions/create/delete/registry并负责缓存交互pieceInstallService.installPiece保存上传归档派发EXECUTE_METADATA引擎任务以提取元数据再落库pieceSyncService.sync从打包的注册表文件 upsert 官方 piece路由集中在/v1/pieces下list、:nameget、:name/versions、POST /options在 worker 上执行动态下拉求值、POST /platformAdmin安装自定义 piece、POST /sync、DELETE /:id。入口是pieceModule即注册于 app.ts 的 Fastify 插件它挂载了全部/v1/pieces路由。关键类型PieceTypeOFFICIAL随包分发或CUSTOM平台安装。PackageTypeREGISTRYNPM或ARCHIVE上传的 tarballarchiveId外键指向file。OutputSchema可选的 per-action/trigger 结构化渲染提示fields、itemLabel由 piece 作者设置被 Builder 的 Smart Output Viewer 与数据选择器消费opt-in 且非破坏性——定义在 output-schema.ts。目录相关的关键坑可用性分级所有版本都可用基础列表与安装属于 Community 级别。EE/Cloud 的 per-piece、per-action/trigger 可见性通过resolveVisibilitypiece-filtering-utils.ts流转CE 或platformId/projectId为空时返回null调用方将null视为不过滤。静默消失当某个 piece 的minimumSupportedRelease领先于根package.json版本时它会从列表中静默消失。fetchLatestPieces会用isSupportedRelease(apVersionUtil.getCurrentRelease(), piece)过滤每个 piecePiece 通常面向下一个版本合并因此在main上本地看不到十几个 piece 是正常现象且无任何警告日志。AP_DEV_PIECES按名称遮蔽 DB 注册表副本若某个开发 piece 未通过发布门槛会导致该 piece整体消失而不是回退到已发布版本。搜索语义pieceSearching.searchpiece-searching.ts对 piece 跑 Fuse 模糊匹配后再对每个命中跑嵌套 Fuse 得到suggestedActions——因此响应里的suggestedActions是“该查询的答案”而非 piece 的完整目录缓存该字段必须以查询词为 key。文件 URL 的 Content-Type 陷阱ctx.files.write()返回的 URL 以application/octet-stream提供签名读 URLv1/files/{id}?token不带文件扩展名传给第三方 API如 WhatsScale/make/prepareFile时必须额外显式传递mediaType不能假设 URL 自带描述性。Piece SetsEE/Cloud 的读时可见性Piece Set 是平台管理员定义一次、可复用的 piece/action/trigger 可见性配置可分配给多个项目。核心设计原则是可见性在读取时派生derived at read time——安装新 piece 或 action 时不写任何东西。该决策的完整背景见 ADR 000007。数据模型PieceSetConfig{ pieces: PieceSelection, selectedActions: Recordpiece, action[], selectedTriggers: Recordpiece, trigger[] }。PieceSelection{ mode: include_all | exclude_all, exceptions: string[] }。include_all表示除例外外全部可见未来新 piece 自动包含exclude_all表示仅例外可见隐藏未来 piece。精选组件piece key 出现在selectedActions/selectedTriggers中表示“精选模式”仅列出的组件可见新增组件保持隐藏key 缺席则表示全部可见含未来。Default Set每个平台一个isDefaultkey: default未分配的项目解析到它。不可删除项目通过重新分配而不是移除来脱离它。纯函数解析器isPieceVisible/isComponentVisible位于core/shared/.../ee/piece-set/shared 模型目录服务端与 Web 共用同一份实现保证前后端过滤逻辑一致。实体与服务piece_set实体platformIdCASCADE、name、keyembed 句柄平台内唯一自动生成kebabCase(name)-random、isDefault部分唯一索引、configjsonb项目通过project.pieceSetIdFK SET NULL引用。pieceSetServiceCRUD getOrCreateDefaultPieceSet分布式锁、duplicate、assignProject(s)/removeProjectAssignment。update走pieceSetConfig.applyUpdate声明式合并绝不触碰未引用的组件 key。路由/v1/piece-setsplatformAdminOnly。更新使用ComponentIntent{ mode: all }将 piece 重置为全部可见{ mode: selected, selected }设置允许列表空数组 全部隐藏。入口pieceSetService定义于 piece-set.service.ts由 piece-set.controller.ts 挂到路由上。关键坑仅 EE/Cloud受platform.plan.managePiecesEnabled门控。CE 或未开启时 piece set 惰性inert过滤回退到遗留的项目计划 allow/block 列表。整个/v1/piece-sets模块含GET都在这面旗子后面。没有任何安装时同步也没有onPieceCreated钩子——解析纯粹发生在读取时。Embed 鉴权v4 JWT 携带pieceSetkey claim遗留 v2/v3 token 携带piecesTags只认第一个 tag解析为key tag否则走 Default。强制逻辑applyProjectPieceAccess无条件执行不受开关门控位于 managed-authn-service.ts。usePieces({ skipProjectFilter: true })不是缓存开关——它悄悄关闭 piece-set 过滤该 flag 会从GET /v1/pieces中去掉projectId而resolveVisibility在platformId或projectId任一为 nil 时直接返回null于是响应变成未过滤的平台目录。它适用于平台管理员界面piece-set 编辑器必须能列出你尚未放行的 piece与营销式展示但在任何“此列表意味着这里能用什么”的界面上就是错的。projectId查询参数的权限语义三条GET /v1/pieces*路由实测项目成员含 VIEWER只能读自己的项目读兄弟项目返回 403平台 ADMIN/OPERATOR 可读其平台内所有项目SERVICE API key 可读本平台所有项目、拒绝其他平台WORKER、UNKNOWN 与未认证调用者被跳过、不泄露任何信息——带任意projectId得到的都是未过滤目录因为resolveVisibility因 nilplatformId直接退出ONBOARDING 根本到不了这些 handler认证即 401ENGINE 只被允许读自己的projectId含不存在的 id 也会被拒因为它直接比较 id 不做查询。迁移是三步走建表 回填1807...→CREATE INDEX CONCURRENTLY1808...非事务→ 破坏性删除遗留平台 piece-filter 列1809...。遗留tag/piece_tag表保留仅因为回填要用原生 SQL 读一次。FormulasBuilder 内联的表达式函数Formula 是面向用户的数据转换能力81 个函数可在任意 Builder 文本输入框内通过/斜杠编辑器使用保存时内联为ap-formula-v1::{expr}::ap-formula-v1标记随 flow JSON 往返不丢失。实现位置共享库packages/core/shared/src/lib/formula/。AP_FUNCTIONS注册表是唯一事实来源single source of truthformulaEvaluator.evaluate负责求值另有类型检查器。编辑器TipTap 的text-input-with-mentions。运行时挂载点引擎的 props-resolver.ts 预扫描阶段——凡文本属性值命中ap-formula-v1标记即先求值再交给属性处理。关键坑无 HTTP 端点、无 DB 表、无 worker 任务——求值是引擎内的同步计算。每个版本都无条件运行即使编辑器开关关闭已保存的 formula 依然会求值。底层用expr-eval预处理会把;归一为,归一化and/or/not并把if()重写为惰性三元表达式。版本纪律修改某个函数 升级activepieces/shared的 minor 版本绝不可硬删函数——只能标记deprecated否则存量 flow 会立即断裂。引擎的构建与类型检查为什么“nothing typechecks the engine”activepieces/engine的build使用 esbuildesbuild.config.mjs剥离类型且从不做类型检查其lint仅跑 eslint——turbo.json与任何 CI workflow 中都没有tsc --noEmit。这意味着类型错误会静默发布截至 2026-07在干净的main上执行npx tsc -p tsconfig.lib.json --noEmit会在api/engine-file-api.ts、api/engine-run-api.ts、network/dns-lookup-guard.ts、piece-context/flows.ts、variables/props-processor.ts报错。实操建议引擎改动前后自己跑 tsc 并 diff 错误文件列表而不是期待零错误——全绿从来不是基线。引擎测试只能从包目录运行cd packages/server/engine npx vitest run从仓库根目录跑会套用根配置导致每个文件都以describe is not defined收集失败。涉及activepieces/core-execution的枚举如LoopBatchMode时本地要先npx turbo run build --filteractivepieces/core-execution重建 dist否则引擎 vitest 的activepieces/shared别名会拉到旧的 dist 而在运行时报Cannot read properties of undefined。引擎只有 64 个文件描述符在AP_EXECUTION_MODESANDBOX_PROCESS/SANDBOX_CODE_AND_PROCESS下引擎运行在isolate二进制内create-sandbox-for-job.ts→isolateProcess。打包的 isolate 是 1.8.1硬编码RLIMIT_NOFILE为 64soft 和 hard 都是且没有可改的 flag。已实测沙箱内ulimit -n为 64沙箱外为 1048576上游在 1.8.1 之后才加入--open-files参数因此当前二进制会拒绝该参数。这 64 个 fd 是引擎同时做所有事的真实预算到每个 piece 的每个 HTTP socket、S3、外加每个 CODE 步骤子进程 4 个 fd。一个空闲沙箱已占用约 23 个大流程100 步骤、循环、多个 HTTP piece会直接打穿。关键结论不要去看 worker 或宿主机的限制——它们无关且看起来健康。worker 进程有 524288宿主fs.file-max近乎无上限真正受限的是sandbox-*进程而不是node .../worker/dist/src/bootstrap.js。要提高它需要把更新版本的 isolate 二进制amd64 arm放进packages/server/api/src/assets/并传入--open-files。CODE 步骤与noOpCodeSandbox每个 CODE 步骤都在一个全新的node --eval子进程中运行spawn 时使用stdio: [pipe,pipe,pipe,ipc]no-op-code-sandbox.ts。输入经 IPC 用child.send(...)传入结果作为一条消息返回。经典故障模式与排查TypeError: x.send is not a function出现在随机 CODE 步骤上几乎总是 fd 耗尽EMFILE而不是代码 bug——即上文 isolate 64-fd 上限。Node 在setupChannel()内为每个实例分配child.send在EMFILE/ENFILE时ChildProcess.prototype.spawn在 setup之前就返回于是child.send是undefined。runInChildProcess无条件调用它同步TypeError先 reject 掉 promise真正到达error事件的EMFILE在下一 tick 被丢弃。只有 EMFILE/ENFILE 会这样——EAGAIN和ENOENT时send仍被定义。修复形态typeof child.send ! function时守卫返回让errorhandler 以真实原因 reject。掩盖是彻底的worker 自身宽事件记录outcome: success全链路唯一痕迹是客户的失败告警邮件引用了伪造的堆栈。症状看起来是全场随机许多 worker、许多平台、每次不同的 CODE 步骤因为每个沙箱化引擎共享同一个 64 上限。父进程侧没有超时或child.kill()永不 resolve 的 CODE 步骤会终身占用其 4 个 fd。runWithExponentialBackoff会重试失败的 CODE 步骤因此 fd 饥饿的引擎每个步骤会重复 spawn 多次。安装/编译失败降级为抛错桩用户侧标记 FAILED而非 INTERNAL_ERROR 重试。Workers执行运行时与版本门禁Worker 是轮询应用经 Socket.IO并执行 flow 的 Node 进程。worker 本身就是沙箱——完整执行模型concurrency 1、replicas、Resolver、box 生命周期参见 Execution Runtime。这里聚焦与 piece 相关的行为版本门禁fail-closed应用与 worker 在发布版本不完全一致时拒绝交换任务一旦各集群收敛自动恢复。断连归还releaseConnectionJobs将进行中的任务归还队列避免部署后的“Job stalled”风暴。Worker 组AP_WORKER_GROUP_IDAP_PROJECT_WORKER路由专用池按项目路由受workerGroupsEnabled门控。生产部署生产用 Kamal 从 ops 机器部署~/mrsk/prod、config/worker.yml不是本仓库。探活单个 workerkamal app exec --config-fileconfig/worker.yml --hostsip --rolesshared05_n --reuse cmd。--reuse至关重要——没有它 Kamal 会启动一个开始接真实任务的新容器密集宿主机跑 28 个容器每个角色一个所以仅--hosts会扇出。含管道符的内容务必 base64否则引号会在 ssh → bash -ic → kamal → docker exec → sh 的传递链中损坏。AI Agentsrun_agent步骤受agentsEnabled门控Agent 是一种 flow 步骤类型activepieces/piece-ai的run_agentaction运行 ReAct 风格 LLM 循环最多maxSteps步可调用工具后给出最终答案。配置存在于 flow 版本的步骤设置中或存在于步骤通过externalId命名的已保存 Agent 上运行开始时解析。工具AgentTool联合类型PIECE action、FLOW子运行、MCP server、KNOWLEDGE_BASE768 维 embedding 语义搜索。配置项agentTools、structuredOutput、prompt、maxSteps、aiProviderModel、可选 web search。关键坑外部 MCP 工具在服务端通过POST /v1/projects/:projectId/agent-tools/mcp/validate验证initialize→initialized→tools/list 握手经 SSRF 过滤的apAxios发出错误全部坍缩为一条通用消息。它位于agents/目录agent 向外连接与mcp/把 AP暴露为MCP 服务器方向相反、职责不同。AgentTimeline在 Builder 中渲染步骤块。实操如何在 Builder 里强制一个 Piece 报错若你想亲眼看到客户看到的真实失败对话框而非相信单元测试可以把一个真实 piece 指向你控制的 mock 实例然后选择它返回的 HTTP 形态。该方法曾用于复现 GIT-1857TRIGGER_UPDATE_STATUS对话框。挑选载体按顺序检查第二条会淘汰大多数候选Auth 暴露用户可填的基础 URLProperty.ShortText自托管风格——无需改代码即可指向127.0.0.1。Auth 没有validate——否则 mock 不响应校验调用连接将无法保存。Trigger 没有 API 支撑的属性——动态下拉在失败模式下无法对 mock 填充props: {}能省去大量折腾。chatwoot三者皆备Chatwoot URL是纯文本、无validate、new_message是props: {}其onEnableGET{baseUrl}/api/v1/accounts/{accountId}/webhooks并重抛任何非 422 “already been taken” 的响应。若想要request.body携带凭据的错误改用baserow的Email Password (JWT)模式其onEnable→makeClientPOST{email, password}密码会进入序列化错误chatwoot 的失败调用是 GET其信封request为空。注意 baserow 有validate打同一端点所以要先在 mock 返回 200 时保存连接再切到失败形态。步骤在127.0.0.1上跑一个 mock HTTP 服务器可返回任意状态码与 body并提供/__mode/shape路由以便不重启切换形态。至少覆盖空 body 的 401、无 body 的 401、msg键的 body、Message键的 body、无 message 的数组、以及一个确实带{message}的对照组。npx turbo run build --filteractivepieces/piece-name——AP_DEV_PIECES从dist加载不是源码未构建的 piece 会静默不出现。把AP_DEV_PIECESname加入.env.dev然后npm run dev。构建 flow对http://127.0.0.1:port创建连接设置 mock 形态然后Publish或拨动 enable 开关。观察 mock 的请求日志确认调用确实到达——对话框没有对应日志行说明 piece 根本没碰到你的 mock。要点这之所以可行是因为AP_NETWORK_MODE默认UNRESTRICTED。引擎的 SSRF 守卫ssrf-guard.ts只在STRICT下安装 DNS 与 socket monkeypatch所以默认开发栈中 piece 可访问 loopback。若设了STRICTmock 不可达你看到的失败会是SSRFBlockedError——需加AP_SSRF_ALLOW_LIST127.0.0.1。该守卫是进程内 JS 补丁明确不是针对恶意代码的边界。对话框上的standardError是engineHelperResponse.error引擎将其构建为JSON.stringify(formatPieceError(error, { raw: inspect(error) }))——无论 API 返回什么对话框收到的都已是序列化的FriendlyPieceError渲染任何部分前请先参考上文“消息可能是 JSON”的陷阱。mock 是比真实第三方拒绝更强的证据而不是更弱的现实中最常见的失败形态空 401 body、无人枚举过的 key 下的消息恰恰是真实 API 只会偶然给你的刻意驱动它们才能发现友好路径对它们根本没有答案。关键文件索引目录入口与路由packages/server/api/src/app/pieces/metadata/controller、service、TypeORM entity、pub/sub 失效的piece-cache.ts、packages/server/api/src/app/pieces/community-piece-module.ts、piece-install-service.ts、piece-sync-service.ts可见性解析packages/server/api/src/app/ee/pieces/filters/piece-filtering-utils.tsresolveVisibility与VisibilityPolicy、packages/core/shared/src/lib/ee/piece-set/共享纯解析器Piece Set 模块packages/server/api/src/app/ee/pieces/piece-set/、管理 UIpackages/web/src/app/routes/platform/setup/pieces/piece-sets/、前端 apipackages/web/src/features/piece-sets/前端 piece 客户端packages/web/src/features/pieces/api/、packages/web/src/features/pieces/hooks/、packages/web/src/features/pieces/components/输出 schema 类型packages/pieces/framework/src/lib/output-schema.tsCODE 沙箱packages/server/engine/src/lib/core/code/no-op-code-sandbox.ts错误格式化packages/core/utils/src/lib/friendly-piece-error.ts、packages/pieces/common/src/lib/http/core/http-error.ts设计决策brain/decisions/000007-piece-set-visibility-is-derived-at-read-time.md所有源码路径与结论均可在本仓库直接核对路径验证于 2026-07。【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考