octopus-rpa-app-runner 技能升级需求 v2
原始文件:wecom_e588f9e2_octopus-rpa-app-runner_技能升级需求_v2.md
octopus-rpa-app-runner 技能升级需求 v2
基于《octopus-rpa-app-runner 技能升级 PRD》v1.0、当前 SKILL.md、Python/PowerShell 脚本、临时脚本与静态测试形成的可实施需求基线。
---
1. 文档信息
| 项目 | 内容 |
|---|---|
| 文档名称 | octopus-rpa-app-runner 技能升级需求 v2 |
| 版本 | v2.0-draft |
| 日期 | 2026-08-06(Asia/Shanghai) |
| 上游需求 | octopus-rpa-app-runner_技能升级PRD_20260806.md v1.0 |
| 目标版本 | 技能下一次向后兼容的小版本升级 |
| 目标 | 将“参数弹窗直接运行”和“关闭运行浮窗”从临时脚本收敛为安全、可观测、可测试的正式能力,并补齐契约与验收标准 |
| 实施边界 | 增量升级现有技能,不重构 Octopus RPA Studio,不重写整个 runner,不引入远程调度平台 |
1.1 规范用语
- “必须”:P0/P1 交付不可缺少,未满足即不通过验收。
- “应”:原则上实现;若不实现,必须在发布说明中记录原因和替代方案。
- “可以”:增强项,不阻塞本次发布。
- “直接运行”:仅指参数对话框已经存在时,不修改任何输入框,点击该对话框的“运行应用”按钮;不等同于从应用列表首次点击
running。 - “关闭浮窗”:先尝试通过 UI 停止当前运行,再关闭“八爪鱼RPA运行窗口”以恢复 Studio;关闭窗口本身不等同于已证明业务任务停止。
- “只读命令”:不得启动 Studio、点击运行/停止、关闭窗口、创建目录、写配置或清理进程的命令。
---
2. 背景、现状与差距
2.1 已有能力
当前技能以 scripts/run_pywinauto.cmd + OctopusRpaAppRunner.py 为默认实现,以 OctopusRpaAppRunner.ps1 为兼容回退,已经具备:
- 列出应用、精确名称运行、按关键词/前缀选最高版本、互动选择。
--current-running/--check-run-list只读查询,输出RUN_LIST_STATE=empty|active|unknown。- 运行确认与恢复已有运行浮窗确认分离:
--yes-run、--yes-restore-existing-run。 - 单个高置信度 Edit 输入框的目录填写,以及默认目录记忆。
--stop-run-window、进程快照、显式清理重启。- 浮窗快照二次校验,避免确认后窗口对象发生变化仍继续操作。
- 临时
click_run_app_direct.py与close_run_window_direct.py已验证两个真实边界场景。
2.2 原 PRD 的主要价值
原 PRD 正确识别了两个 P0 缺口:参数弹窗多输入框时需要受控“直接运行”;停止按钮不存在时需要显式“关闭浮窗恢复 Studio”。本 v2 保留这两个核心目标,不改变原 PRD 的业务方向。
2.3 现状差距
| 编号 | 现状/歧义 | 风险 | v2 处理方向 |
|---|---|---|---|
| GAP-01 | --click-run-app-direct 尚无正式 CLI;临时脚本无内建确认 | 误触真实生产运行 | 正式命令、专用确认、弹窗快照复核 |
| GAP-02 | close_run_window_if_present 存在但无正式 CLI;临时脚本无内建确认 | 未授权停止/关闭;将“关闭”误报为“停止成功” | 正式命令、专用确认、分阶段结果与后置验证 |
| GAP-03 | “直接运行”是独立接管现有弹窗,还是运行命令的一种参数策略,原 PRD 未定 | 参数组合和确认范围不清 | 同时定义集成策略与独立恢复命令,语义互斥且可验收 |
| GAP-04 | 多输入框只按数量拒绝,缺少标签到输入框的稳定映射契约 | 填错字段或无法运行 | 显式参数映射优先;自动映射仅限高置信度唯一匹配 |
| GAP-05 | --skip-run-parameter-dialog 容易被理解为“跳过弹窗并继续运行”,实际是不等待/不处理 | 把“首击成功”误当完整启动 | 保留兼容但弃用,改名为明确的 leave 策略并输出未完成状态 |
| GAP-06 | --yes-run 当前同时跳过首次运行确认和参数弹窗继续确认 | 一次确认覆盖的动作范围不够清晰 | 输出确认计划;直接运行必须被计划明确包含,独立接管使用专用确认 |
| GAP-07 | --stop-run-window Python 找不到按钮返回 1,PowerShell 回退仍返回 0 | 调用方无法一致判断失败 | 统一动作结果、退出码和降级规则 |
| GAP-08 | RUN_LIST_STATE 只有局部输出契约,其他动作多为自由文本 | Agent 难以可靠判断结果 | 定义稳定的 key-value/JSON 结果契约和事件字段 |
| GAP-09 | 运行成功只输出 Clicked run / Done,缺少“请求、首击、弹窗、二次点击、已观测运行”的层级 | 误报业务成功 | 明确阶段状态;禁止把 UI 点击成功表述为业务完成 |
| GAP-10 | 没有统一错误码,异常大多聚合为退出码 1 | 无法自动恢复或决定是否重试 | 稳定错误码 + 退出码分类 |
| GAP-11 | 无完整幂等约束;重复直接运行可能重复点击,重复关闭结果被当失败 | 重复执行产生副作用或噪声 | 每个写操作定义幂等键、重复调用结果与禁止重试点 |
| GAP-12 | argparse/PowerShell 未定义动作参数互斥;可同时传入多个主动作 | 执行优先级隐式、调用结果意外 | 主动作互斥校验,冲突直接失败且不触碰 UI |
| GAP-13 | 互动选择支持 1,3 后顺序运行,但 Octopus 同时只能运行一个应用 | 首个应用启动后第二个动作不可控 | 本次限制单选;批量运行不在范围内 |
| GAP-14 | “latest by prefix”实现包含关键词匹配,名称与实际语义不完全一致;同版本平局规则未写明 | 选错生产应用 | 明确兼容语义、候选输出和歧义阻断 |
| GAP-15 | 当前 tests_static.py 主要是 assert 与源码字符串检查;缺少 UI 适配层 mock、CLI 契约、错误码、状态转换测试 | 改动易回归,静态通过不代表行为正确 | 建立分层测试矩阵和生产动作门禁 |
| GAP-16 | Python 与 PowerShell 能力、参数和返回语义已出现漂移 | 回退路径行为不同 | P0 核心安全语义双实现一致;非核心差异显式声明 |
| GAP-17 | config.json 写入无原子性/模式版本要求,路径合法性和敏感信息约束未定义 | 配置损坏、泄露或误写 | 最小配置 schema、原子写入、目录校验、日志脱敏 |
| GAP-18 | SKILL.md 未明确内部主类和临时脚本复用边界 | 再次误用类名或绕过安全门 | 明确 OctopusPywinautoRunner;禁止以临时脚本绕过正式确认 |
---
3. 目标与成功指标
3.1 产品目标
- 多输入框弹窗出现时,技能能安全地:显式映射参数后运行、经用户确认后不填直接运行,或保持弹窗等待人工处理。
- 浮窗残留时,技能能经独立确认执行“尝试停止 -> 关闭浮窗 -> 验证 Studio”,并如实报告每一步,而不把关闭视为停止证明。
- 所有动作具有稳定命令语义、结果字段、错误码、退出码和最小可回归测试。
- 保持现有默认 Python 路径和 PowerShell 回退,不扩大为系统级架构重构。
3.2 成功指标
- P0/P1 验收用例通过率 100%。
- 所有危险动作在无对应确认时,UI 点击数为 0,目录/配置写入数为 0。
- Python 与 PowerShell 在 P0 安全用例中的退出类别和错误码一致率 100%。
- 对直接运行和关闭浮窗,输出可区分
confirmed、clicked、verified、partial、cancelled。 - 静态/单元/CLI mock 测试可在无 Octopus、无生产动作的环境运行。
---
4. 范围与非范围
4.1 本次范围
- 正式提供参数弹窗“直接运行”能力。
- 正式提供“关闭运行浮窗恢复 Studio”能力。
- 参数对话框策略、单输入框和多输入框映射规则。
- 用户确认机制、状态机、幂等规则、安全边界。
- CLI 参数、结构化输出、日志、错误码和退出码契约。
- Python 默认实现与 PowerShell 回退的关键安全行为对齐。
- SKILL.md、自动测试、受控现场验收和版本迁移说明。
4.2 非范围
- 不重构 Octopus RPA Studio、BrowserBridge 或 Bot。
- 不实现跨机器调度、队列、定时任务、账号管理或远程凭据管理。
- 不判断 RPA 内部业务逻辑是否最终成功;仅观测 UI/进程/运行列表等启动证据。
- 不实现多个应用串行/并行批量运行。
- 不通过 OCR/视觉模型猜测未知字段;本次仅使用 UI Automation 可验证属性。
- 不自动杀死所有 Edge、Bot 或未知进程。
- 不为所有 Octopus 应用建立业务参数模板;仅提供通用映射和可选配置基础。
- 不取消 PowerShell 回退,也不要求将两套实现重写为同一代码库。
---
5. 角色与场景
5.1 角色
| 角色 | 诉求 | 权限边界 |
|---|---|---|
| 业务用户 | 选择并运行指定 RPA,恢复 Studio | 必须确认真实运行、直接运行、停止/关闭等副作用动作 |
| Agent | 将自然语言转换为安全 CLI 计划并解释结果 | 不得自行补充确认;不得将点击成功说成业务成功 |
| 运维/开发 | 排障、查看进程、维护配置和回退实现 | 清理/重启仍需显式授权 |
| 测试人员 | 无生产副作用验证状态机和契约 | 默认使用 mock/静态/只读;现场动作使用白名单应用与单独确认 |
5.2 核心场景
- SCN-01:用户只读列出应用或查询运行状态。
- SCN-02:用户确认运行指定应用,无参数弹窗。
- SCN-03:用户确认运行,出现唯一目录输入框,填值后二次点击。
- SCN-04:出现多个输入框,用户提供明确字段映射后运行。
- SCN-05:出现多个输入框,用户明确说“不填,直接点运行应用”。
- SCN-06:第一次运行流程失败后,参数弹窗仍在;用户独立授权接管该弹窗直接运行。
- SCN-07:浮窗存在,用户只要求停止;找不到停止按钮时不得自动关闭。
- SCN-08:浮窗存在,用户明确要求恢复 Studio;确认后尝试停止并关闭浮窗。
- SCN-09:有现存运行时用户要运行新应用;分别确认恢复现有运行和启动新应用。
- SCN-10:重复提交同一命令,技能避免重复点击或如实返回“已处于目标状态”。
---
6. 功能需求
6.1 动作与命令语义
| ID | 优先级 | 需求 |
|---|---|---|
| FR-001 | P0 | 新增正式主动作 --click-run-app-direct:仅在已检测到合法 Octopus 参数弹窗时,不修改输入框,点击唯一可用的“运行应用”按钮。 |
| FR-002 | P0 | --click-run-app-direct 不得从应用列表选择应用、不得点击列表 running、不得创建默认目录、不得保存配置;弹窗不存在时返回 PARAM_DIALOG_NOT_FOUND,不得启动 Studio。 |
| FR-003 | P0 | 独立直接运行动作必须获得专用授权 --yes-direct-run,或在交互模式展示弹窗快照、未填写字段数量和“不填任何输入”的风险后得到肯定答复。仅有 --yes-run 不得授权独立接管一个既有弹窗。 |
| FR-004 | P0 | 集成运行命令允许通过 --parameter-dialog-policy direct 声明多输入框时直接运行;该策略必须在首次运行确认文本中明确展示。此时 --yes-run 可授权完整计划,但输出必须记录 CONFIRM_SCOPE=initial_run,direct_parameter_continue。 |
| FR-005 | P0 | 新增正式主动作 --close-run-window:检测浮窗 -> 获取快照 -> 确认 -> 再次校验同一浮窗 -> 尝试停止 -> 等待 -> 必要时关闭浮窗 -> 验证 Studio/浮窗状态。 |
| FR-006 | P0 | 独立关闭浮窗必须使用 --yes-close-run-window 或交互确认;--yes-run、--yes-restore-existing-run、--yes-direct-run 均不得替代。 |
| FR-007 | P0 | --stop-run-window 语义保持为“只尝试停止,不关闭”;找不到停止按钮或无法确认点击时返回非成功结果,绝不隐式升级为 close。 |
| FR-008 | P0 | 运行新应用前发现已有浮窗时,继续使用 --yes-restore-existing-run 独立授权恢复旧运行;该授权只对确认时的窗口快照有效,不授权新应用运行。 |
| FR-009 | P0 | 所有主动作必须互斥。主动作包括 list、run exact、run latest、current/check、process snapshot、stop、close、restart clean、direct parameter continue、set-default-only。冲突时返回参数错误且不得访问 UI。 |
| FR-010 | P1 | 互动选择本次只允许选择一个应用;输入多个编号时提示“不支持批量运行”并要求重新选择,不得顺序点击多个生产应用。 |
6.2 参数对话框
| ID | 优先级 | 需求 |
|---|---|---|
| FR-011 | P0 | 将参数弹窗处理定义为策略:auto(默认)、map、direct、leave。不得因检测失败自动从 auto 降级到 direct。 |
| FR-012 | P0 | auto 仅在恰有一个可写 Edit,且满足高置信度规则时填写目录并点击;零个、多个或只读输入均阻断二次点击并返回可操作错误。 |
| FR-013 | P0 | direct 必须枚举并输出 PARAM_INPUT_COUNT、非空/空值状态(不得输出敏感值)和 PARAM_DIALOG_FINGERPRINT,然后执行专用确认机制;确认前不得改值或点击。 |
| FR-014 | P1 | map 支持重复参数 --parameter <key>=<value>。key 匹配优先级为 AutomationId 精确匹配 > 关联 Label 精确匹配 > 可访问名称精确匹配;同层级多匹配、零匹配或一个控件被多个 key 命中均失败。 |
| FR-015 | P1 | 多输入框映射不得仅凭控件顺序自动填写。若要按索引映射,必须使用显式 index:<1-based> key,并输出控件摘要供用户确认;默认禁用索引猜测。 |
| FR-016 | P1 | 参数值写入后必须回读验证;不支持 ValuePattern 时可使用现有键盘回退,但仍需回读或返回 PARAM_VALUE_UNVERIFIED,不得直接点击“运行应用”。 |
| FR-017 | P1 | 对目录型参数,在写入前规范化路径;是否自动创建目录必须由 --create-missing-directories 明确授权,或在交互确认计划中列明。不得因 direct 策略创建目录。 |
| FR-018 | P1 | leave 表示完成应用列表首击后不等待/不处理参数弹窗,结果必须是 RUN_STAGE=initial_clicked、START_VERIFIED=false;原 --skip-run-parameter-dialog 保留为该策略的弃用别名。 |
| FR-019 | P1 | 参数弹窗识别必须同时满足:窗口属于 OctopusRPA.Studio 进程、存在唯一“运行应用”按钮、存在参数区域标识;多个候选弹窗时返回歧义错误,不得取第一个。 |
| FR-020 | P1 | 点击“运行应用”前必须按窗口 handle、pid、按钮标识和输入控件摘要复核指纹;指纹变化则取消本次授权并要求重新确认。 |
6.3 应用选择与启动验证
| ID | 优先级 | 需求 |
|---|---|---|
| FR-021 | P1 | --run-exact-name 必须严格全名匹配,零匹配/多匹配均不点击。 |
| FR-022 | P1 | --run-latest-by-prefix 为兼容旧名称可保留,但必须文档化实际为 token/前缀候选匹配;候选属于多个明显不同业务前缀或最高版本平局时,输出候选并阻断,除非精确前缀可唯一消歧。 |
| FR-023 | P0 | 运行阶段至少区分:selected、initial_clicked、parameter_waiting、parameter_submitted、start_observed、start_unverified、cancelled、failed。 |
| FR-024 | P0 | Done 只能表示命令流程结束,不得表示 RPA 业务完成。成功点击参数弹窗按钮后,应尝试观测浮窗、运行列表或受控进程证据;无证据时返回 start_unverified,并可使用警告类退出码。 |
| FR-025 | P1 | 验证优先级为:运行列表显示目标应用 > 新的合法运行浮窗 > Octopus BrowserBridge/受控 Edge 进程变化。仅进程证据不得证明具体应用名称。 |
| FR-026 | P1 | 验证应使用动作前后的快照差异,避免把早已存在的浮窗/进程误认为本次启动结果。 |
6.4 浮窗停止与关闭
| ID | 优先级 | 需求 |
|---|---|---|
| FR-027 | P0 | --close-run-window 输出 STOP_ATTEMPTED、STOP_CLICKED、WINDOW_CLOSE_ATTEMPTED、WINDOW_CLOSED、STUDIO_RESTORED、RUN_STOP_VERIFIED 六个独立字段。 |
| FR-028 | P0 | 找不到停止按钮时,交互确认必须明确:“将关闭浮窗以恢复 Studio,但无法证明任务已经停止”;只有专用关闭确认覆盖该风险后才能关闭。非交互命令若已给 --yes-close-run-window,确认计划中应预先声明此降级。 |
| FR-029 | P0 | 关闭浮窗后必须重新枚举窗口。Studio 可访问但运行列表为 unknown 时结果为 partial;运行列表仍为 active 时结果为失败/不安全,不得输出“停止成功”。 |
| FR-030 | P1 | 浮窗不存在且 Studio 可用时,重复 --close-run-window 返回 already_restored,退出成功,不触发任何点击。浮窗和 Studio 均不可识别时返回状态未知,不启动 Studio。 |
| FR-031 | P1 | 若停止点击后浮窗自行消失,禁止继续向旧 handle 发送 close;直接进入后置验证。 |
| FR-032 | P1 | close 操作不得杀进程。只有独立 --restart-studio-clean 能执行受限进程清理,且继续遵守现有显式授权和 Edge 进程树边界。 |
6.5 配置、兼容与文档
| ID | 优先级 | 需求 |
|---|---|---|
| FR-033 | P1 | config.json 增加 schema_version,保留现有 DataDirectory 读取兼容;写入采用临时文件 + 原子替换,失败不得破坏旧配置。 |
| FR-034 | P1 | 默认不持久化 --parameter 值;本次仅允许继续记忆非敏感目录。日志不得输出令牌、密码或疑似敏感字段的值。 |
| FR-035 | P1 | SKILL.md 必须明确主类名 OctopusPywinautoRunner,但将内部方法标记为非稳定 API;不得再推荐通过临时脚本绕过正式确认。 |
| FR-036 | P1 | Python 是默认实现;PowerShell 为回退。两者对 P0 命令、确认边界、错误码和退出类别必须一致;暂不支持的增强参数必须明确返回 UNSUPPORTED_IN_FALLBACK,不得静默改变语义。 |
| FR-037 | P1 | 临时脚本可保留一个迁移版本,但调用时必须打印弃用提示并转发正式 CLI;不得继续保留无确认的独立实现。后续小版本可移除。 |
---
7. 非功能需求
| ID | 优先级 | 需求 |
|---|---|---|
| NFR-001 | P0 | 安全默认:不确定即阻断;unknown 不得解释为空闲或成功。 |
| NFR-002 | P0 | 可审计:每次命令生成 OPERATION_ID,确认、快照、动作和验证事件均关联该 ID。 |
| NFR-003 | P1 | 性能:在桌面会话正常时,弹窗检测默认 12 秒内结束;关闭浮窗后置验证默认 15 秒内结束;超时可配置但必须有上限。 |
| NFR-004 | P1 | 可靠性:UI 控件引用在关键点击前重新查询;不得长时间持有虚拟化列表行或已变化弹窗控件。 |
| NFR-005 | P1 | 可测试性:业务决策逻辑与 pywinauto/PowerShell UI 调用应可通过适配器或 mock 隔离测试;不要求整体重构。 |
| NFR-006 | P1 | 可维护性:Python 与 PowerShell 共享同一份文档化错误码/输出契约;测试检查行为而非大量源码字符串。 |
| NFR-007 | P1 | 兼容性:Windows 10/11、PowerShell 5.1+、现有技能本地 .venv;不得要求全局 Python 包。 |
| NFR-008 | P1 | 日志编码统一为 UTF-8;机器输出字段使用 ASCII key,值按 UTF-8 输出。 |
| NFR-009 | P2 | 可诊断性:--output json 时提供控件摘要和阶段耗时,但不得包含输入框原始敏感值。 |
---
8. 安全约束与确认机制
8.1 动作授权矩阵
| 动作 | 默认行为 | 所需非交互确认 | 不可替代的确认 |
|---|---|---|---|
| 列应用/查状态/进程快照 | 只读执行 | 无 | 不得产生任何副作用 |
| 首次点击应用列表运行按钮 | 阻断并询问 | --yes-run | 不授权恢复旧浮窗或独立接管弹窗 |
| 集成流程采用 direct 参数策略 | 在首次确认中明确展示后执行 | --yes-run + --parameter-dialog-policy direct | 输出确认范围必须含 direct continue |
| 独立接管既有参数弹窗并直接运行 | 阻断并询问 | --click-run-app-direct --yes-direct-run | --yes-run 不可替代 |
| 仅停止浮窗 | 显式命令执行 | --stop-run-window 本身代表请求;若产品要求二次确认则使用专用确认 | 找不到按钮不得自动 close |
| 独立关闭浮窗恢复 Studio | 阻断并询问 | --close-run-window --yes-close-run-window | 其他 yes 标志不可替代 |
| 为新应用恢复旧运行 | 阻断并询问 | --yes-restore-existing-run | 不授权新应用运行 |
| 清理进程并重启 Studio | 保持现有显式维护动作门禁 | 独立维护确认 | 不得由 close/stop 自动触发 |
8.2 交互确认内容
直接运行确认必须展示:
- 动作名称:“不填写参数,点击参数弹窗中的运行应用”。
- 弹窗所属进程、窗口标题/handle 摘要和指纹。
- 检测到的输入框数量、空/非空数量;不展示实际敏感值。
- 风险:“现有默认值或空值将原样提交,可能导致任务失败或使用应用内默认配置”。
- 可接受肯定词;其他输入一律取消。
关闭浮窗确认必须展示:
- 当前浮窗 title、pid、handle、检测时间。
- 计划:“先尝试停止;若停止按钮不存在或浮窗仍在,则关闭浮窗恢复 Studio”。
- 风险:“关闭浮窗不必然证明任务已停止;技能会在关闭后再次验证”。
- 是否正在为启动另一应用恢复旧运行;若是,仍需另行确认新应用运行。
8.3 确认有效期和竞态保护
- 确认仅对当前进程内、当前
OPERATION_ID、当前 UI 快照有效,不持久化。 - 确认后、点击前必须再次比较窗口 pid/handle/指纹;变化则返回
STALE_CONFIRMATION。 - 非交互 yes 标志仅授权命令行中明确声明的动作,不授权运行中动态升级出来的新副作用。
- 用户取消返回
cancelled,不得创建目录、写配置或点击后续按钮。
---
9. CLI 与输出契约
9.1 推荐 CLI
run_pywinauto.cmd --click-run-app-direct [--yes-direct-run]
run_pywinauto.cmd --close-run-window [--yes-close-run-window]
run_pywinauto.cmd --run-exact-name NAME --parameter-dialog-policy auto|map|direct|leave [--parameter KEY=VALUE ...] [--yes-run]
run_pywinauto.cmd --run-latest-by-prefix KEY --parameter-dialog-policy auto|map|direct|leave [--yes-run]
run_pywinauto.cmd --output text|json
约束:
--parameter仅可与policy=map一起使用。--yes-direct-run仅可与--click-run-app-direct一起使用。--yes-close-run-window仅可与--close-run-window一起使用。--skip-run-parameter-dialog等价于--parameter-dialog-policy leave,打印弃用警告。--yes保留为--yes-run弃用别名,不扩展权限。- 参数冲突在初始化 pywinauto 之前失败。
9.2 文本输出
机器可依赖的最终结果块必须每行一个 KEY=VALUE,至少包含:
CONTRACT_VERSION=2
OPERATION_ID=<uuid>
ACTION=<action>
RESULT=success|partial|cancelled|failed|already_satisfied
STAGE=<state>
CHANGED=true|false
VERIFIED=true|false
ERROR_CODE=<code-or-empty>
MESSAGE=<single-line-human-readable-message>
动作可增加字段,例如:
PARAM_DIALOG_FOUND=true
PARAM_INPUT_COUNT=3
DIRECT_RUN_CLICKED=true
STOP_ATTEMPTED=true
STOP_CLICKED=false
WINDOW_CLOSED=true
STUDIO_RESTORED=true
RUN_STOP_VERIFIED=false
RUN_LIST_STATE=unknown
要求:
- 自由文本日志可保留,但最终结果块字段名和值域稳定。
RUN_LIST_SAFE=true仅在可信empty时输出;active和unknown均为 false。VERIFIED=true必须有对应后置条件证据,不能仅因为 InvokePattern 未抛异常。MESSAGE不得包含换行或敏感参数值。
9.3 JSON 输出
--output json 必须只向 stdout 输出一个合法 JSON 对象;诊断日志写 stderr。最小 schema:
{
"contract_version": 2,
"operation_id": "...",
"action": "close_run_window",
"result": "partial",
"stage": "studio_restored",
"changed": true,
"verified": false,
"error": {"code": "RUN_STOP_UNVERIFIED", "message": "..."},
"evidence": {
"stop_attempted": true,
"stop_clicked": false,
"window_closed": true,
"studio_restored": true,
"run_list_state": "unknown"
}
}
9.4 退出码
| 退出码 | 类别 | 示例 |
|---|---|---|
| 0 | 成功、已满足或用户主动取消 | verified success、already restored、cancelled |
| 2 | 状态未知/部分完成,调用方不得当作安全 | run list unknown、窗口已关但停止未验证、启动未验证 |
| 3 | 参数/用法错误 | 主动作冲突、缺少配套参数、非法 policy |
| 4 | 未授权 | 非交互环境缺少对应 yes 标志 |
| 5 | 目标不存在或歧义 | 弹窗不存在、应用零/多匹配、多个候选弹窗 |
| 6 | UI 动作失败或竞态 | 控件消失、指纹变化、点击失败、回读失败 |
| 7 | 环境/依赖失败 | 无 pywinauto、本地 venv 缺失、非活动桌面会话 |
| 1 | 未分类内部错误(兜底) | 编程错误或未映射异常 |
用户取消虽返回 0,但 RESULT=cancelled、CHANGED=false,调用方不得将其当作动作成功。
9.5 错误码
至少提供以下稳定错误码:
ARG_CONFLICT、ARG_REQUIRED、UNSUPPORTED_IN_FALLBACKCONFIRMATION_REQUIRED、STALE_CONFIRMATION、USER_CANCELLEDAPP_NOT_FOUND、APP_MATCH_AMBIGUOUS、BATCH_RUN_UNSUPPORTEDPARAM_DIALOG_NOT_FOUND、PARAM_DIALOG_AMBIGUOUS、PARAM_INPUT_NOT_FOUNDPARAM_INPUT_AMBIGUOUS、PARAM_MAPPING_FAILED、PARAM_VALUE_UNVERIFIEDRUN_APP_BUTTON_NOT_FOUND、DIRECT_RUN_CLICK_FAILEDRUN_WINDOW_NOT_FOUND、STOP_BUTTON_NOT_FOUND、STOP_CLICK_FAILEDRUN_WINDOW_CLOSE_FAILED、STUDIO_RESTORE_FAILED、RUN_STOP_UNVERIFIEDRUN_LIST_UNKNOWN、RUN_START_UNVERIFIEDCONFIG_INVALID、CONFIG_WRITE_FAILED、DEPENDENCY_MISSING、UI_SESSION_UNAVAILABLE
---
10. 状态机
10.1 运行状态机
IDLE/STUDIO_READY
-> APP_SELECTED
-> RUN_CONFIRMED
-> INITIAL_RUN_CLICKED
-> START_OBSERVED (无参数弹窗)
-> PARAMETER_WAITING (检测到弹窗)
-> PARAM_AUTO_MAPPED -> PARAM_SUBMITTED
-> PARAM_EXPLICITLY_MAPPED -> PARAM_SUBMITTED
-> DIRECT_RUN_CONFIRMED -> PARAM_SUBMITTED
-> LEFT_FOR_MANUAL -> START_UNVERIFIED
-> CANCELLED
-> START_UNVERIFIED (超时无明确证据)
-> FAILED
转换约束:
PARAMETER_WAITING -> DIRECT_RUN_CONFIRMED必须具备匹配当前快照的授权。PARAM_SUBMITTED -> START_OBSERVED需要后置证据;点击成功本身不足。- 任意竞态、目标歧义或未知状态进入
FAILED/START_UNVERIFIED,不得自动重试点击。 - 有现存运行浮窗时,在进入
APP_SELECTED前先执行独立恢复子状态机。
10.2 浮窗恢复状态机
RUN_WINDOW_DETECTED
-> CLOSE_CONFIRMED
-> SNAPSHOT_REVALIDATED
-> STOP_ATTEMPTED
-> STOP_CLICKED -> WAIT_FOR_DISAPPEAR
-> STOP_NOT_AVAILABLE
-> WINDOW_ALREADY_GONE -> VERIFY_STUDIO
-> WINDOW_CLOSE_ATTEMPTED -> WINDOW_CLOSED
-> VERIFY_STUDIO
-> RESTORED_AND_STOP_VERIFIED
-> RESTORED_BUT_STOP_UNVERIFIED
-> STILL_ACTIVE
-> RESTORE_FAILED
STOP_NOT_AVAILABLE只有在 close 专用确认覆盖降级风险时才能转入WINDOW_CLOSE_ATTEMPTED。RESTORED_BUT_STOP_UNVERIFIED是 partial,不是 success。- 浮窗初始不存在且 Studio 可用,直接进入
ALREADY_RESTORED。
10.3 可观测状态与业务状态
技能仅声明:
- UI 点击是否发出。
- 参数是否写入并回读。
- 浮窗是否出现/消失。
- Studio 是否恢复。
- 运行列表和受控进程证据。
技能不得声明:
- 简历是否下载完成、招呼是否发送成功等业务结果。
- 仅凭浮窗关闭即声明 RPA 已停止。
- 仅凭 Edge/Bridge 存在即声明目标应用已运行。
---
11. 幂等性与重试
| 动作 | 重复调用规则 | 自动重试边界 |
|---|---|---|
| list/current/process snapshot | 天然只读,可重试 | 可对读取超时做有限重试,不产生 UI 副作用 |
| direct parameter run | 非幂等;点击后不得自动重复点击 | 仅可在点击前重新查找/复核;点击结果未知时返回 partial,不重试 |
| initial run click | 非幂等 | Invoke 调用后即使验证超时也不得再次点击 |
| parameter value write | 在同一弹窗、同一目标值下可幂等写入 | 回读失败可重查一次;不可切换到其他输入框 |
| stop run window | 条件幂等 | 点击后可轮询状态,不自动第二次点击未知按钮 |
| close run window | 目标状态幂等 | 已恢复返回 already_satisfied;旧 handle 消失后不发送 close |
| set default directory | 同值幂等 | 原子写失败可保留旧配置,不循环覆盖 |
建议以 OPERATION_ID + action + target fingerprint 记录进程内动作账本;本次不要求跨进程持久化幂等键。
---
12. 异常处理
12.1 通用原则
- 参数校验失败:不初始化 UI、不写配置。
- 目标歧义:输出候选摘要,等待用户选择,不猜测。
- 确认后对象变化:作废确认,不自动套用到新对象。
- 点击结果未知:停止副作用动作,返回 partial/unknown,不盲目重试。
- 只读命令遇到浮窗:报告受限,不关闭、不停止、不启动 Studio。
- Python 默认实现失败时,不得在已执行副作用后自动切换 PowerShell 重做;只允许在任何点击前、安全可判定时回退。
12.2 关键异常表
| 场景 | 处理 | 结果 |
|---|---|---|
| 参数弹窗不存在,执行 direct | 不启动 Studio,不点击其他按钮 | PARAM_DIALOG_NOT_FOUND, exit 5 |
| 两个合法参数弹窗 | 输出候选数量/摘要,不选第一个 | PARAM_DIALOG_AMBIGUOUS, exit 5 |
| 多输入框且 auto | 保留弹窗,不填不点 | PARAM_INPUT_AMBIGUOUS, exit 5 |
| map 缺字段或一对多 | 不写任何字段;映射计划应先整体校验 | PARAM_MAPPING_FAILED, exit 5/6 |
| 写入后无法回读 | 不点击运行应用 | PARAM_VALUE_UNVERIFIED, exit 6 |
| direct 确认后弹窗变化 | 不点击 | STALE_CONFIRMATION, exit 6 |
| stop 找不到按钮 | stop 命令失败;close 命令按已确认降级继续 | STOP_BUTTON_NOT_FOUND |
| close 后 Studio 恢复、状态 unknown | 如实报告 partial | RUN_STOP_UNVERIFIED, exit 2 |
| close 后运行列表 active | 报仍有运行,不执行进程清理 | RUN_STOP_UNVERIFIED, exit 2/6 |
| 无活动桌面/锁屏 | 不尝试坐标点击 | UI_SESSION_UNAVAILABLE, exit 7 |
| 配置损坏 | 忽略为默认值前先警告;不覆盖损坏文件,除非显式修复 | CONFIG_INVALID |
---
13. 验收标准
13.1 P0 验收
| AC | 对应需求 | Given / When / Then |
|---|---|---|
| AC-001 | FR-001~003 | Given 一个合法、多输入框参数弹窗;When 执行 direct 且未确认;Then 不修改输入、不点击,返回 confirmation required。 |
| AC-002 | FR-001~004 | Given 同一弹窗;When 用户确认“不填直接运行”;Then 复核指纹,仅点击唯一“运行应用”,输出输入框数量和点击结果。 |
| AC-003 | FR-002 | Given 无参数弹窗;When 执行 direct;Then 不启动 Studio、不创建目录、不点击其他控件,返回 PARAM_DIALOG_NOT_FOUND。 |
| AC-004 | FR-005~006 | Given 浮窗存在;When close 未确认;Then stop/close 点击均为 0。 |
| AC-005 | FR-005, FR-027~029 | Given 浮窗有停止按钮;When 已确认 close;Then 先 stop,若浮窗消失不再 close,并输出六个阶段字段与后置验证。 |
| AC-006 | FR-028~029 | Given 浮窗无停止按钮;When 已确认 close;Then 输出 stop 未点击,再关闭浮窗;若状态未知则 result=partial、exit 2,不宣称停止成功。 |
| AC-007 | FR-007 | Given 浮窗无停止按钮;When 仅执行 stop;Then 不关闭浮窗,返回非成功错误码。 |
| AC-008 | FR-008 | Given 有旧浮窗且要运行新应用;When 只有 --yes-run;Then 不恢复旧浮窗、不运行新应用,要求 restore 确认。 |
| AC-009 | FR-009 | Given 同时传 list 与 run;When CLI 解析;Then exit 3,UI 访问和配置写入均为 0。 |
| AC-010 | FR-011~013 | Given 多输入框、policy=auto;When 运行;Then 不填不点,保持 parameter_waiting 并返回歧义。 |
| AC-011 | FR-023~026 | Given按钮点击成功但无后置证据;When 验证超时;Then start_unverified/exit 2,不输出业务成功。 |
| AC-012 | NFR-001 | Given run list unknown;When 查询或后置验证;Then RUN_LIST_SAFE=false,不可进入安全空闲状态。 |
13.2 P1 验收
| AC | 对应需求 | Given / When / Then |
|---|---|---|
| AC-013 | FR-014~016 | Given 两个带唯一 AutomationId/Label 的 Edit;When 提供完整 map;Then 整体校验后逐项写入并回读,再点击。 |
| AC-014 | FR-015 | Given 两个无标识 Edit;When 未提供 index 映射;Then 不按顺序猜测。 |
| AC-015 | FR-018 | Given policy=leave;When 首击后出现弹窗;Then 不处理弹窗,结果为 initial_clicked/start_unverified。 |
| AC-016 | FR-019~020 | Given确认后窗口 handle 或控件摘要变化;When 准备点击;Then 返回 stale confirmation,点击数为 0。 |
| AC-017 | FR-010 | Given互动输入 1,3;When 解析;Then 提示不支持批量,不点击任何应用。 |
| AC-018 | FR-030 | Given无浮窗且 Studio 已可用;When close;Then already_satisfied、changed=false、exit 0。 |
| AC-019 | FR-033 | Given旧版仅含 DataDirectory 的 config;When 读取并更新;Then 值兼容,原子写出 schema_version,失败时旧文件完整。 |
| AC-020 | FR-036 | Given同一 mock 场景;When Python 与 PowerShell 执行 P0 动作;Then动作边界、错误码和退出类别一致。 |
| AC-021 | FR-037 | Given运行旧临时脚本;When 调用;Then展示弃用提示并进入正式 CLI 确认门,不可直接点击。 |
| AC-022 | NFR-002 | Given任意动作;When查看输出;Then所有阶段事件和最终结果具有同一 operation_id。 |
13.3 发布门槛
- 所有 P0、P1 自动化验收通过。
- 代码评审确认没有扩大 Edge/Bot 清理范围。
- SKILL.md 与
--help对新命令、确认和退出码一致。 - 完成一次受控现场 smoke:只读查询必测;直接运行和关闭浮窗仅在用户明确授权、白名单应用和可恢复环境下测试。
- 现场测试产生的运行/停止不作为自动 CI 的组成部分。
---
14. 测试矩阵
| 层级 | 用例 | Python | PowerShell | 是否允许生产副作用 |
|---|---|---|---|---|
| 静态 | 语法、help、参数互斥、弃用别名 | 必测 | 必测 | 否 |
| 单元 | 参数策略、确认范围、状态转换、错误码、退出码 | 必测 | 可通过函数级脚本测试 | 否 |
| 单元 | 多输入框 label/AutomationId/index 映射与歧义 | 必测 | 必测 P1 核心 | 否 |
| 单元 | 窗口/弹窗 fingerprint 比较和 stale confirmation | 必测 | 必测 | 否 |
| 单元 | latest 匹配、平局、批量选择拒绝 | 必测 | 必测 | 否 |
| 单元 | config 旧 schema、原子写失败、敏感字段脱敏 | 必测 | 必测 | 否 |
| Mock UI | direct:无弹窗/单弹窗/多弹窗/按钮消失/点击异常 | 必测 | 必测 P0 | 否 |
| Mock UI | close:有 stop/无 stop/stop 后消失/close 失败/状态 unknown | 必测 | 必测 P0 | 否 |
| 契约 | text 与 JSON schema、stdout/stderr、operation_id | 必测 | 必测 | 否 |
| 回归 | list/current 保持只读,浮窗存在时不恢复 | 必测 | 必测 | 否 |
| 回归 | stop 不自动 close,restart clean 不扩大进程树 | 必测 | 必测 | 否 |
| 集成只读 | --list-only、--current-running、--process-snapshot | 必测 | 回退抽测 | 否 |
| 现场受控 | 参数弹窗直接运行 | 用户确认后 | 默认实现通过后再抽测 | 是,需白名单 |
| 现场受控 | 无 stop 按钮时 close 恢复 | 用户确认后 | 默认实现通过后再抽测 | 是,需维护窗口 |
测试实现要求:
- 保留当前纯函数断言的有效部分,但拆分为可报告用例;失败必须指出用例名。
- 降低“源码必须包含某字符串”式测试比例,改为调用函数/CLI 并断言行为。
- Mock 必须记录 UI 调用序列,能断言“确认前零点击”“stop 先于 close”“旧 handle 不再操作”。
- 测试不得把历史真实运行记录当作当前回归证明。
---
15. 版本迁移与兼容策略
15.1 CLI 迁移
| 旧能力 | v2 行为 | 兼容计划 |
|---|---|---|
--yes | 仍仅等价 --yes-run | 保留一个小版本并警告,不扩大权限 |
--skip-run-parameter-dialog | 等价 policy=leave | 保留一个小版本并打印弃用提示 |
--stop-run-window | 继续只 stop | 修正 PowerShell 失败仍 exit 0 的不一致;发布说明标记行为收紧 |
临时 click_run_app_direct.py | 转发正式 direct CLI | 一个小版本后移除 |
临时 close_run_window_direct.py | 转发正式 close CLI | 一个小版本后移除 |
config.json 无 schema | 按 schema v1 兼容读取 | 下次写入迁移到 schema v2,原子替换 |
--run-latest-by-prefix | 保留旧名与 token/前缀匹配 | 增加歧义阻断,不静默选跨业务候选 |
15.2 行为变化说明
- 过去“用户已确认运行”可能被用于参数弹窗继续;v2 只有当 direct 策略在首次计划中明确声明时,
--yes-run才覆盖该二次点击。 - 独立接管已有参数弹窗必须使用专用 direct 确认。
- 过去关闭临时脚本以方法返回 true 代表成功;v2 将“窗口已关闭”和“任务停止已验证”分开,可能返回 partial。
- 过去互动选择可多选;v2 因单实例安全约束改为单选。
- 旧调用方若只判断 exit 0/1,必须升级为理解 exit 2~7 或至少把所有非 0 视为未成功。
15.3 发布步骤
- 先落地错误码、结果对象、参数互斥和 mock 测试。
- 实现 Python direct/close 正式入口及确认。
- 对齐 PowerShell P0 安全语义,或对未支持能力明确阻断。
- 更新 SKILL.md、help、临时脚本转发和迁移说明。
- 运行静态、单元、mock、只读集成测试。
- 获得用户单独确认后进行受控现场验收。
---
16. 待确认项
| ID | 优先级 | 待确认问题 | 建议默认决策 |
|---|---|---|---|
| TBD-01 | 阻塞 P0 | 独立 --stop-run-window 是否也必须增加二次 yes 标志?当前命令本身已是显式动作。 | 本次保持命令即授权;Agent 自然语言层仍需用户明确说“停止”。 |
| TBD-02 | 阻塞 P0 | close 在找不到 stop 时,是否允许非交互 --yes-close-run-window 直接覆盖“仍关闭”的降级风险? | 允许,但 help/结果必须明确该标志包含此降级。 |
| TBD-03 | 阻塞 P1 | 多输入框 --parameter key=value 的首批 key 是否以 AutomationId/Label 为主,是否需要维护应用级别名配置? | 本次只做通用精确映射;应用级模板不在范围内。 |
| TBD-04 | 非阻塞 | start_observed 是否要求浮窗出现即可,还是必须运行列表出现目标名称? | 浮窗可作为启动观测成功,但仅运行列表可验证具体应用;输出 evidence_level 区分。 |
| TBD-05 | 非阻塞 | PowerShell 回退是否必须在同一版本支持 map,还是只保证 P0 direct/close? | P0 direct/close 同版;map 可返回明确 unsupported,不得静默 direct。 |
| TBD-06 | 非阻塞 | 用户取消是否沿用 exit 0,还是使用单独退出码? | 保持 exit 0 兼容,以 RESULT=cancelled 区分。 |
| TBD-07 | 非阻塞 | 现场验收使用哪个无敏感副作用的白名单应用,以及由谁确认业务影响? | 发布前由业务负责人指定,未指定则只做 mock 和只读验收。 |
| TBD-08 | 非阻塞 | 参数对话框中的已有非空值是否允许日志输出摘要长度/哈希? | 默认只输出 empty/non-empty,不输出长度和哈希。 |
| TBD-09 | 非阻塞 | --output json 是否纳入本次 P1,还是先稳定文本 key-value? | 建议 P1 同版实现,若排期不足至少保留结果对象并锁定 schema。 |
---
17. 需求追溯
| 原 PRD 需求 | v2 对应 |
|---|---|
REQ-01 --click-run-app-direct | FR-001~004、FR-011~013、FR-019~020、AC-001~003 |
REQ-02 --close-run-window | FR-005~008、FR-027~032、AC-004~008、AC-018 |
| REQ-03 参数对话框交互升级 | FR-011~020、参数映射与确认机制、AC-010、AC-013~016 |
| REQ-04 SKILL.md 类名/复用说明 | FR-035、FR-037;保留类名说明但禁止绕过正式安全门 |
| REQ-05 用例回归与验证 | 第 13、14 节完整验收与测试矩阵 |
---
18. 最终交付物
- 更新后的
SKILL.md与--help。 - Python 默认实现的正式 direct/close 命令、参数策略和输出契约。
- PowerShell 回退的 P0 安全语义对齐或显式不支持提示。
- 单元、mock、CLI 契约、静态和只读集成测试。
- 临时脚本弃用转发与版本迁移说明。
- 一份现场验收记录,清晰区分“点击成功、启动已观测、业务结果未知”。
---
*本需求尊重原 PRD 的增量升级范围,核心聚焦参数弹窗直接运行与关闭浮窗恢复,不扩展为整个 RPA 系统重构。*