• v0.3.9 64af91bde9

    thzxx released this 2026-07-21 11:46:15 +08:00 | 6 commits to master since this release

    本次版本聚焦并行工具审批体验安全频率限制两大方向。共 1 次提交,修改 11 个文件,+608 / -177。

    一、工具批量审批(核心特性)

    问题现象

    • Agent 并行调用多个需要确认的工具(如 5 个 read_file)时,后端 pendingConfirmations Map 本身支持并发,但前端 ConfirmationDialog 用单值 state,多个 tool:confirmationRequest IPC 事件几乎同时到达会互相覆盖
    • 最终 UI 只显示最后一个请求,前 4 个 request 在 120 秒超时后全部 reject,导致 4 个工具自动失败
    • 同一工具多次调用场景下,rememberedDecisions 缓存按 toolName 写入,但并发场景下 5 个调用同时进入 beforeExecute 时缓存还没写入,5 个全部触发 IPC 请求

    修复方案

    后端(confirmation-hook.ts)

    • 扩展 pendingConfirmations Map 类型,缓存 args/riskLevel/reason 完整请求信息
    • 新增 resolveConfirmationsBatch(toolCallIds, approved, remember, autoExecute) 批量处理
    • 新增 getPendingConfirmations() 供前端主动拉取已积压的请求
    • remember/autoExecute 按 toolName 去重写入,避免 Map 重复赋值

    IPC 层(handlers.ts / preload.ts)

    • 新增 tool:confirmationResponseBatch IPC 通道(ipcMain.on)
    • 新增 tool:getPendingConfirmations IPC 通道(ipcMain.handle)
    • 严格参数校验(toolCallIds 必须是非空字符串数组,approved 必须是 boolean)
    • preload 暴露 sendConfirmationResponseBatchgetPendingConfirmations API

    前端(ConfirmationDialog.tsx)

    • state 从单值 request 改为数组 requests: ConfirmationRequest[]
    • 弹框打开时主动调用 getPendingConfirmations 拉取已积压请求,解决 state 覆盖丢失
    • 同工具多次调用按 toolName 分组展示(如 read_file (×5)
    • 支持批量勾选 / 批量批准 / 批量拒绝
    • 三种操作按钮:拒绝全部 / 批准全部 / 批准选中(动态文案)
    • 倒计时取最早过期的,进度条按最早过期算
    • 全部使用 MUI 组件(Dialog/List/ListItem/Accordion/Checkbox/Chip/Button)

    二、审批弹框健壮性增强

    超时 toast 防风暴

    问题:5 个并行工具全部超时会触发 5 个 toast:show 事件,用户看到 5 条几乎相同的警告。

    修复:加 lastTimeoutToastAt 时间戳,3 秒节流。消息改为汇总形式:工具确认超时(120秒),N 个工具未执行

    agent 状态同步

    问题:abort 场景下后端 clearPending() 清空 Map,但前端 requests state 不会自动同步,弹框会停留在已失效的请求上。

    修复:监听 agent:stateChange,收到 INIT(新 run 开始)或 TERMINATED(run 结束/abort/超时)时清空前端 state。

    批准选中保留未选中项

    问题:用户点击"批准选中",只有选中的 toolCallId 被处理,未选中的仍 pending。但原代码 setRequests([]) 会清空所有,导致 Dialog 关闭,用户看不到未选中的 pending,120 秒后超时失败。

    修复onlySelected=true 时只从 requests 中移除已处理的 toolCallId,保留未选中的。若保留后 requests 为空,setTimeout 主动拉取后端最新 pending。

    Dialog onClose 一致性

    问题:isExpired 时"拒绝全部"按钮 disabled,但 Dialog 的 onClose 仍会触发拒绝全部,与按钮状态不一致。

    修复:isExpired 时 onClose 直接 return,禁止关闭。正常情况下只在 backdropClick/escapeKeyDown 时触发拒绝全部。

    ErrorBoundary 防白屏

    ErrorBoundary 包裹 ConfirmationDialog,即使弹框内部抛异常也不会白屏整个应用,显示"工具确认弹框渲染失败"降级 UI + 错误消息 + 重试按钮。

    三、run_command 频率限制优化

    问题

    run_commandmaxFrequency 配置为 3(每分钟最多调用 3 次),正常开发场景 Agent 经常需要连续跑命令,第 4 次调用被拦截返回 Rate limit exceeded for run_command: max 3 calls per minute (current: 3)

    修复

    maxFrequency 从 3 调整为 10,与 file_editor/git_commit 同档。

    工具 maxFrequency 风险等级
    run_command 3 → 10 EXTERNAL_ACTION
    write_file 5 WRITE
    file_editor 10 WRITE
    git_commit 10 WRITE
    web_browser 20 EXTERNAL_ACTION
    delete_file 30 WRITE

    run_command 已有 requireConfirmation: true 作为主要安全防线,10 次/分钟仍能防止失控循环。

    四、开发规范补充

    新增 3.2 Toast 通知铁律

    所有 Toast 通知必须使用项目封装的 MeToast 组件,禁止自写 Toast 组件、禁止直接使用第三方 Toast 库(notistack、react-hot-toast、react-toastify 等)。

    场景 规范
    前端主动显示 Toast 使用 MeToast 组件(通过 showToast() 或对应 hook 调用)
    后端通过 IPC 触发 Toast 主进程发送 toast:show IPC 事件,参数 { type, message },前端 MeToast 监听并统一渲染
    type 枚举 success / info / warning / error 四种
    并行事件防风暴 同一来源的并行事件需在后端节流

    本次 toast 防风暴实现(lastTimeoutToastAt 3 秒节流)符合新规范。

    五、改动文件清单

    文件 改动
    electron/harness/hooks/confirmation-hook.ts 接口加 expiresAt 字段;新增 resolveConfirmationsBatch / getPendingConfirmations;toast 防风暴
    electron/harness/sandbox/permissions.ts run_command maxFrequency: 3 → 10
    electron/ipc/handlers.ts 新增 tool:confirmationResponseBatch / tool:getPendingConfirmations IPC
    electron/preload.ts 暴露 sendConfirmationResponseBatch / getPendingConfirmations
    src/App.tsx 用 ErrorBoundary 包裹 ConfirmationDialog
    src/components/ConfirmationDialog.tsx 完全重写为批量列表 UI
    src/types/global.d.ts MetonaConfirmationRequest 加 expiresAt;MetonaToolAPI 加两个新方法
    standard/开发规范.md 新增 3.2 Toast 通知铁律
    package.json / package-lock.json / README.md 版本号 0.3.8 → 0.3.9

    六、升级说明

    • 直接拉取 master 分支或 v0.3.9 tag
    • npm installnpm run dev 启动
    • 无数据库 schema 变更,无需迁移
    • 与 v0.3.8 完全兼容
    Downloads