Skip to content

feat(approval): 审批卡片 1/2/3 快捷键、记住作用域、拒绝说明与改动预览 - #1098

Merged
AlphaCatMeow merged 1 commit into
Stack-Cairn:v2-kbrianfrom
AlphaCatMeow:feat-approval-card
Nov 1, 2026
Merged

AlphaCatMeow merged 1 commit into
Stack-Cairn:v2-kbrianfrom
AlphaCatMeow:feat-approval-card

Conversation

@AlphaCatMeow

@AlphaCatMeow AlphaCatMeow commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

LA-2a(#1094)已经把 K-brain 的记住规则、默认作用域和拒绝说明接到了客户端,但审批卡片还没有用上这些数据。本 PR 是 LA-2b,在审批卡片上把它们用起来:按键 1/2/3、选择记住的作用域、填写拒绝说明,并预览完整命令和文件改动。

Closes #1097
Depends-On: none
Stack-Root: #1098

改动

  • 按键:
    • 1 或回车:允许本次。
    • 2:允许并记住。卡片上写出要存的规则,下拉框可选本会话、本项目或所有项目,默认用后端 suggestion.default_scope。后端没有建议规则时,2 走原来的"本会话始终允许"(不带 scope)。
    • 3:展开拒绝说明输入框,回车把拒绝和说明一起发出(deny + reason)。在输入框里按 Esc 只收起输入框,在卡片上按 Esc 直接拒绝。
    • 焦点在输入框、下拉框或按钮上时,数字键不当快捷键。输入法确认候选词的回车(keyCode 229,WebKit 的事件顺序)不会提交,复用了 isImeKeyboardEvent,并把它的参数类型放宽到 KeyboardEvent<Element>。
    • "全部允许 / 全部拒绝"仍在 ▾ 菜单里。允许按钮的文案不变。
  • 命令:完整显示,自动换行,最多约 10 行,超出可滚动;不再只显示截断的一行。
  • 改动预览:Edit/Write 用 EditDiffView 显示 diff(approvalPreviewFromToolCall)。
    • 两边都不超过 4000 字:显示全文。
    • 超过时:先按行去掉两边相同的开头和结尾(各留 3 行上下文),还超就再按字符去掉(各留 200 字符,两边从同一位置截取)。这样截出来的 diff 仍然准确。
    • 只看改动的部分本身仍然超过上限时,不做 diff,分开显示"原内容 / 新内容(截断片段)"。这样不会藏住改动,也不会把没变的行显示成删除。
    • 截断点不会切在 emoji 的半个字符上。"预览已截断"提示放在滚动框外面。
  • WebUI 和桌面看到同一份:桌面算好的预览通过 __toolApprovalPreview 同步给 WebUI,只有 Edit/Write 才接受,并会校验数据格式、重新限制长度。没有这份预览时,WebUI 退回到 Gateway 截断过的参数副本;Edit 只要有一边被截断,就分开显示两块。
  • 400 提示:K-brain 存不下规则时会回 400,审批会重新弹出。turn.ts 把错误信息作为 onPermissionRequest 的第三个参数传进来,卡片显示"上次没能记住:<原因>",同时通过 __toolApprovalNotice 同步给 WebUI。
  • 防伪造:模型可以在工具参数里写入审批合成键(__toolApprovalPending 等),借此在 WebUI 上伪造审批卡片、diff 和提示。新增 TOOL_APPROVAL_SYNTHETIC_ARG_KEYS 和 withoutApprovalSyntheticArgs:同步给 Gateway 之前,先删掉模型参数里的这些键。builder 和 K-brain 回合的第一条 tool_call 事件都会经过这一步。LA-2a 加的那几个标记也一并受到保护。
  • 两种语言都加了新文案。新的合成参数已加入 DISPLAY_SYNTHETIC_ARG_KEYS,不会出现在参数展示里。

契约面

面 影响
桌面直连 审批存储新增 preview / notice;onPermissionRequest(request, signal, refusal?)
Gateway 同步 新增 __toolApprovalPreview、__toolApprovalNotice;同步前删掉模型参数里的同名合成键;chatRuntimeSnapshot 走同一个 builder
WebUI 两处收集器 都经 pendingToolApprovalFromToolCall 取得 preview/notice,用同一个卡片组件
旧 K-brain(没有 suggestion) 2 走原来的会话授权;没有 400 时不显示提示

截图(调试版真实客户端)

桌面 1280,Edit diff,拒绝说明已展开:
gui 1280

桌面 480,Edit diff 与作用域选择:
gui 480

WebUI 1280,Write 预览与拒绝说明:
webui 1280

WebUI 480:
webui 480

验证

  • 基线:upstream/v2-kbrian 021cb0f。
  • 静态检查:typecheck:ui / typecheck:gui / typecheck:webui 通过;改动文件转 LF 后 biome check --line-ending=lf 通过;node scripts/check-mirror.mjs 通过;git diff --check 通过。
  • 新增测试(先失败,改完后通过):
    • chat/tool-approval-card:真实 ToolApprovalBar,覆盖按键、作用域、拒绝说明、命令、diff、split、提示和 emoji 截断。改动前 10 条里有 9 条失败。
    • chat/tool-approval-card-wiring:真实 K-brain 回合加 HTTP/SSE fixture,覆盖 400 后提示在桌面和 WebUI 都显示、Edit 预览、WebUI 截断预览。改动前 2 条都失败。
  • 对抗复审 5 轮:前四轮一共 10 个 P2,都已修复。
    • 第 1 轮:桌面预览没有长度上限;WebKit 下输入法确认候选词的回车会提交拒绝。
    • 第 2 轮:两边各截前 4000 字后,改动看不到或出现假删除;截断提示在滚动框底部,看不到。
    • 第 3 轮:小 Edit 也被裁剪并标成已截断;差异段本身超长时两边各自截断;模型写入的合成键能伪造 WebUI 卡片。
    • 第 4 轮:K-brain 第一条 tool_call 事件没有过滤合成键。
    • 第 5 轮:没有发现阻止合并的问题。
    • 复审回归测试 review-la2b-approval-card*.test.mjs(r1–r4)都保留在 PR 里。审批相关测试共 84 条,全部通过。
  • 全量(la-full-tests.mjs,8 个批次全部跑完):共 4349 条,通过 4345,失败 3,跳过 1。3 条失败都在已知环境问题清单里:Rust 测试第一次编译超过 180 秒上限;另外两条按当前目录的相对路径读源码,在 crates/agent-gui 下重跑通过。之后只改了 capPreviewText 的 emoji 边界,改完重跑了相关测试和三项 typecheck,都通过。
  • 真机(Windows 调试版,锁定的 beta.27 sidecar,"始终询问"模式,桌面端经 MCP bridge 操作,WebUI 在浏览器里操作):
    • Write:桌面显示 diff,作用域默认"本项目"。按 3 后焦点进入输入框,填写拒绝说明后回车,模型回复里原样引用了说明,文件没有创建。WebUI 上同样的流程结果一样。
    • node -e "console.log(21*2)":按 2 选"本项目"后,规则写入项目规则文件;新开会话再运行同一条命令,不再询问,显示"按规则允许"。测试用的规则已经清理掉。
    • Edit package.json:1280 和 480 宽度下 diff 都显示 +1 −1。在拒绝说明框里按 Esc 只收起输入框,再按一次 Esc 才拒绝;文件没有改动。
    • 桌面和 WebUI 在 1280、480 两个宽度下都没有横向溢出。
    • 用户已验收。
  • 未覆盖:
    • 400 提示没有在真机上触发(真机上项目和用户作用域都能存下规则),只有带 SSE fixture 的自动化测试。
    • 没有在 macOS WKWebView 上实测输入法回车,只按 WebKit 的事件顺序模拟过。
    • Linux 和 macOS 只在 CI 上跑。
  • 另外发现:调试版从 WebUI 发起新会话时,桌面端的 Rust tokio 线程会栈溢出崩溃;本 PR 没有改动 Rust,设置 RUST_MIN_STACK=16777216 后不再出现。这个问题另行跟进。

🤖 Generated with Claude Code

- 1/回车允许本次;2 允许并记住,卡片写明规则,可选本会话/本项目/所有项目,
  默认取后端建议;3 展开拒绝说明,回车连同说明拒绝。Esc 在说明框里只收起。
  可编辑控件里的数字键与输入法上屏回车不触发快捷键。
- 命令完整显示、多行可滚动。
- Edit/Write 显示 diff:未超 4000 字显示全文;超了先按行、再按字符聚焦到改动处,
  仍超就分开显示原内容和新内容。桌面算好后经 __toolApprovalPreview 同步给 WebUI。
- K-brain 回 400 后重新弹出的审批写明原因(__toolApprovalNotice)。
- 同步给 Gateway 的工具参数先删掉模型自带的审批合成键,防止伪造 WebUI 审批卡片。

Closes Stack-Cairn#1097

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant