From 81ce4bc9b85d57543ed23e26a14e4850bbb11e92 Mon Sep 17 00:00:00 2001 From: yu <1919727607@qq.com> Date: Fri, 6 Nov 2026 15:29:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(engine):=20RunEvent=20=E5=A2=9E=20executor?= =?UTF-8?q?=20=E9=A9=BB=E5=9C=B0=E5=AD=97=E6=AE=B5=EF=BC=88ADR-R6=20?= =?UTF-8?q?=E8=A1=A5=E8=AE=B0=EF=BC=9A=E5=8F=8C=E7=AB=AF=E9=80=8F=E6=98=8E?= =?UTF-8?q?=E8=B0=83=E5=BA=A6=E8=AE=BE=E8=AE=A1=E2=80=94=E2=80=94=E4=B8=89?= =?UTF-8?q?=E6=9D=A1=E7=BA=AA=E5=BE=8B+=E7=A1=AE=E5=AE=9A=E6=80=A7?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E8=A1=A8+=E6=95=B0=E6=8D=AE=E4=B8=8D?= =?UTF-8?q?=E5=8A=A8=E5=8E=9F=E5=88=99=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/rpa-core-migration-guide-v2.md | 25 ++++++++++++++++++- .../src/engine/checkpoint-events.test.ts | 2 ++ packages/rpa-core/src/engine/runtime.ts | 1 + packages/rpa-core/src/types.ts | 2 ++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/rpa-core-migration-guide-v2.md b/docs/rpa-core-migration-guide-v2.md index 90d290a..8d6f1b8 100644 --- a/docs/rpa-core-migration-guide-v2.md +++ b/docs/rpa-core-migration-guide-v2.md @@ -342,7 +342,7 @@ | R3 | 桌面执行安全模型:RPA PowerShell 驱动 vs 对面"受信 C# 原生进程"红线 | **C# 扩展 actuate**:把 RPA 五域执行逻辑移植进 windows-runner 原生进程;PowerShell 通道仅限本 demo,不进宿主。**原型已产出并编译验证(2026-11-06)**:`contrib/windows-runner-actuate/` 补丁包(协议扩展 + NativeInput + ActuateService + 逐原语移植对照表 + 合入指引含门禁合规清单);对面 csproj 原样合编 0 警告 0 错误(.NET 10.0.403),协议冒烟 5 例通过(安全门错误码/双路分发/observe 无回归);对面 README Windows 行"click/type 或随本轮交付"与该路线吻合 | | R4 | 浏览器双路径 | **按场景分工**:RPA 场景走咱们的 CDP 接管路线(复用用户登录态/真实页面——RPA 核心价值);对面 PlaywrightBrowserRunner 留给 AI 智能体场景(无头自管浏览器)。约束:①咱们 CDP 路线必须接对面 BrowserContextPolicy 白名单与证据体系,不自建;②迁移前修完 transport 超时与定位器不统一两缺陷;③需对面在插件清单给咱们的 runner 备案(rpa.browser) | | R5 | 包消费方式 | **源码并入 + 锁版本**:git subtree 进对面仓库统一编译,Bun 锁 1.4.3(与对面全家 workspace:* 源码消费现状一致) | -| R6 | 部署拓扑:rpa-core 各域跑在哪 | **按能力域拆分部署**:纯 Node 域→backend plugin-worker;桌面/视觉/弹窗域→用户电脑 Electron 宿主;同一包按 PLATFORM_GROUPS 分组加载,不维护两份代码 | +| R6 | 部署拓扑:rpa-core 各域跑在哪 | **按能力域拆分部署**:纯 Node 域→backend plugin-worker;桌面/视觉/弹窗域→用户电脑 Electron 宿主;同一包按 PLATFORM_GROUPS 分组加载,不维护两份代码。**补记(2026-11-06 用户拍板:双端并存+透明调度)**——同一能力本地/后端两驻地并存,SaaS 与本地部署两形态通用,用户无感知;防乱设计见下方专条 | | R2 | 集成形态:RPA 流程=单个 capability(方案 A)还是节点=step 映射(方案 B) | **方案 A + 两补丁**:RPA 流程=`rpa.flow.execute` 单能力,对面一个 step 一次租约一次结算;节点级事件走 event-bus 旁路(保透明、不进权威账本);人审/高危节点照常升级对面审批。**不用 B 的理由**(记录在案):双账本一致性(崩溃窗口两边分歧、破坏对面 recovery 的单账本假设)、控制流节点无副作用无法映射 CapabilityRef、审批/重试粒度与业务语义错位。**B 的触发条件**:对面产品确认需要"逐步控制 RPA"(单步执行/任意步回退)时局部启用,事件流已备好数据不返工。**A++ 补记(2026-11-06 二次拍板)**:方案 A 骨架不变,节点事件流从"透明度日志"升级为**检查点协议**(nodeId+状态+幂等键+可恢复标记),崩溃后 `rpa.flow.execute` 带 resumeToken 重入、从最近检查点续跑,权威账本仍为单 step、无双账本;B 的隐藏触发条件(长流程断点续跑,RPA 桌面场景高发)由此覆盖而无需节点=step。业界对照:UiPath Orchestrator=Job 黑盒+日志旁路(≈A);Camunda/Zeebe External Task 的"单引擎假设"不适用于双引擎集成;AWS Step Functions callback≈补丁 2。两侧改动清单与落地节奏见 §7-A5 | ### 待对面对确认(仅剩小问题,不猜测) @@ -354,6 +354,29 @@ > 已回答:Q3(human-dialog 弹窗落点)已由 R6 回答——用户电脑 Electron 宿主窗口;仅样式/交互细节与对面 UI 对齐。 +### R6 补记:双端透明调度设计(2026-11-06 用户拍板:前端留、后端也留) + +同一能力允许本地(用户电脑宿主)与后端(plugin-worker)两驻地并存,调度对用户无感知,SaaS 与本地部署两形态通用(本地部署时"后端"即客户自有机房,规则不变)。防乱靠三条纪律与一张确定性路由表: + +**三条纪律:** + +1. **一个脑决策**:路由只在宿主侧 Resolver 一处发生(本质是 A1 注入机制的扩展——registry 条目的 handler 绑定二选一:本地实现 or 自动生成的远端代理,远端代理走对面 gateway 授权/租约/审计,不绕行)。能力代码与流程定义里**禁止**出现任何驻地 if-else,规则全部来自 catalog 元数据。 +2. **一份契约两处实现**:能力签名/参数/返回/错误码同一套(catalog 单一源已保证);本地与远端实现跑同一套契约测试;远端代理自动生成而非手写第二份逻辑,杜绝漂移。 +3. **数据不动原则**:能力在哪个驻地执行由"数据已经在哪里"决定(代码就数据,不搬数据)。需要搬数据时必须是流程中的显式节点(上传/下载),**路由器不得隐式搬运用户本地文件到后端**——用户无感知的是"在哪算",不是"数据去哪"(隐私红线)。 + +**路由规则表(按序匹配,确定性,不留裁量空间):** + +| 序 | 条件 | 执行驻地 | +|---|---|---| +| 1 | platformTag 限宿主平台 / 需要桌面会话 / 弹窗人审 | 仅本地(无远端选项) | +| 2 | 输入数据在本地(本地文件路径) | 本地 | +| 3 | 输入数据在云端(对面 tenant-files 等) | 后端 | +| 4 | 数据两驻地均有副本 | 默认本地(隐私+省带宽);流程可显式声明 `prefer: backend`(如夜间批量) | +| 5 | 本地不可用(宿主离线)且能力无本地数据依赖且标可远端 | 后端兜底 | +| 6 | 均不可用 | 节点失败,错误码 `location_unavailable` | + +**用户无感知 ≠ 审计无感知**:`node.finished` 事件携带 `executor: "local" | "backend"` 字段(已定稿进 RunEvent 并有契约测试,当前恒为 `local`,远端代理落地后由代理覆盖)——用户界面不展示,审计与排障必须可分辨。该字段同时是对面 event-bus 入审计链的取用点。 + --- ## 11. 本指南边界 diff --git a/packages/rpa-core/src/engine/checkpoint-events.test.ts b/packages/rpa-core/src/engine/checkpoint-events.test.ts index eedc1a3..a6c85ac 100644 --- a/packages/rpa-core/src/engine/checkpoint-events.test.ts +++ b/packages/rpa-core/src/engine/checkpoint-events.test.ts @@ -87,6 +87,8 @@ describe("A++ 检查点事件负载", () => { expect(first.checkpointId).toBe("first"); expect(first.resumable).toBe(true); expect(first.idempotencyKey).toBe("run_cp:first"); + // 双端透明调度(ADR-R6 补记):本地执行驻地必须随事件上报,供审计区分 + expect(first.executor).toBe("local"); const second = finished.find((e) => e.nodeId === "second")!; expect(second.checkpointId).toBe("second"); diff --git a/packages/rpa-core/src/engine/runtime.ts b/packages/rpa-core/src/engine/runtime.ts index 4e2ca49..b3dfd5d 100644 --- a/packages/rpa-core/src/engine/runtime.ts +++ b/packages/rpa-core/src/engine/runtime.ts @@ -370,6 +370,7 @@ async function executeNode(node: FlowNode, ctx: RunContext, states: Map