HarmonyOS 7 小艺智能体确认流程:确认后参数被改了,怎样防止执行另一个动作

HarmonyOS 7 小艺智能体确认流程:确认后参数被改了,怎样防止执行另一个动作
弹出确认框并不代表确认流程安全。确认框展示“删除文件 A”,等待点击期间,页面把共享对象里的文件名改成 B,最后执行 B,这就是确认内容和执行内容脱节。需要把待确认参数冻结为独立快照,同时让确认凭据只使用一次。
版本与适用范围
HarmonyOS 7 官方新能力页面列出 Agent 系统能力及 A2A 接入。这不意味着每一种应用动作都能直接执行。下面验证应用侧的确认快照;系统意图声明、身份验证和授权能力必须按具体 SDK 文档接入。
官方参考文档,核对日期:2026-09-14。下面的 JavaScript 实验可以直接用 Node.js 运行;它验证应用侧算法与状态边界,不是已经在 HarmonyOS SDK 或真机上跑通的完整应用。应用接入时,SDK 调用、事件订阅和资源释放应分别验证。
问题是怎样发生的
准备删除 A 后把原对象改成 B,确认返回的快照仍是 A。UI 必须展示同一快照的 summary,而不是再次读取原对象。
复现不依赖随机等待。测试用固定输入、显式完成的异步结果或明确的状态变化,让错误条件可以重复出现。先保留失败信号,再检查修复后的状态,避免只看“没有抛异常”就认为问题解决。
案例一:确认期间参数改变
准备删除 A 后把原对象改成 B,确认返回的快照仍是 A。UI 必须展示同一快照的 summary,而不是再次读取原对象。
案例二:凭据过期或重复确认
在截止时间确认应失败,成功使用后重复确认也应失败。删除 Map 项放在返回之前,避免同步重入再次消费。
实现代码
export class ConfirmedAction {
serial = 0;
pending = new Map();
prepare(action, fileId, expiresAt) {
if (action !== 'delete' || typeof fileId !== 'string' || !fileId || !Number.isFinite(expiresAt)) throw Error('invalid_action');
const ticket = String(++this.serial);
const snapshot = Object.freeze({action, fileId, expiresAt});
this.pending.set(ticket, snapshot);
return {ticket, summary: action + ':' + fileId};
}
confirm(ticket, now) {
const snapshot = this.pending.get(ticket);
this.pending.delete(ticket);
if (!snapshot) throw Error('ticket_missing');
if (now >= snapshot.expiresAt) throw Error('ticket_expired');
return snapshot;
}
cancel(ticket) { this.pending.delete(ticket); }
}
运行验证
把上面的实现和下面的测试按顺序放进同一个 example.mjs 文件,使用 Node.js 执行 node example.mjs。测试采用 Node 内置的 assert,不需要第三方依赖。断言失败时进程报错,全部通过时正常退出。
import assert from 'node:assert/strict';
const flow = new ConfirmedAction();
const shared = {fileId:'A'};
const prepared = flow.prepare('delete', shared.fileId, 100);
shared.fileId = 'B';
assert.equal(flow.confirm(prepared.ticket, 90).fileId, 'A');
assert.throws(() => flow.confirm(prepared.ticket, 90));
const expired = flow.prepare('delete', 'C', 100);
assert.throws(() => flow.confirm(expired.ticket, 100), /ticket_expired/);
assert.throws(() => flow.prepare('unknown', 'A', 100));
核对时不要把输入样本当作性能数据。上述测试已经在 Node.js 环境逐项执行通过,验证的是代码中写出的条件。涉及窗口、材质、音频或系统入口的真实表现,需要另外在适配设备验证。
为什么选择这个方案
复制少量白名单字段比冻结整个业务对象更容易审查。Object.freeze 是浅冻结,示例只存字符串和数字;如果有嵌套参数,应显式复制和验证,不能以为浅冻结保护了整棵对象。
| 检查项 | 实验中的做法 | 接入应用时要补的验证 |
|---|---|---|
| 输入边界 | 拒绝非法输入或区分失效请求 | SDK 返回类型与错误码 |
| 状态变化 | 显式记录每次操作的输入和结果 | 页面切换、窗口销毁与后台恢复 |
| 失败路径 | 断言旧状态不被错误结果覆盖 | 弱网、权限拒绝与设备能力缺失 |
| 成功路径 | 检查最终状态,而非只检查无异常 | 目标设备界面与真实资源行为 |
封装与复用
把上面的纯逻辑保留为独立模块,界面层只提交输入和消费结果。系统事件适配层负责取得当前窗口、设备或入口的实际数据,不要把测试常量直接搬到正式应用。这样单元测试仍可在没有设备时运行,SDK 接入问题也能和算法问题分开排查。
复用之前先检查实例的作用域:窗口、播放器或请求协调器是否属于同一个会话。复用函数不等于共享所有状态。对于异步回调,需要同时考虑结果失效与底层任务取消;对于同步计算,需要确认单位、取样范围和输入上限。
边界与后续检查
serial 只是进程内标识,不能当作安全随机令牌或跨端授权凭证。真正的执行仍需要会话身份和权限检查;多进程或服务端确认要使用持久化、原子消费和可靠时间源。
回归测试应保留两个案例,再增加空输入、重复入口和生命周期结束后的操作。日志记录输入身份、状态修订与失败原因,不记录敏感内容。升级 SDK 后先检查官方接口签名、支持设备与版本说明,再运行同一组实验和设备回归,避免把旧版本假设带入新环境。
更多推荐



所有评论(0)