OH03: Permission Model OpenHarness · 对标 S03
与 S03 同题:在 Agent 能调工具的前提下,用策略 + 可选人工确认划安全边界。
OpenHarness 把判定收拢在 PermissionChecker.evaluate,配置在 PermissionSettings;交互确认通过 permission_prompt 注入(TUI 默认 ui/permission_dialog.ask_permission)。
🎯 问题(与 S03 一致)
模型可能发起删文件、跑 Shell 等高风险调用;Harness 要在自动化与可控之间折中:哪些默认放行、哪些必须问用户、哪些硬拒绝。
🔍 配置:PermissionSettings
定义于 config/settings.py:mode(见下)、allowed_tools / denied_tools 名单、path_rules(glob,可 deny 某类路径)、denied_commands(glob,匹配 Bash 等命令串)。课内 S03 的多种 PermissionMode 在 OH 里目前收敛为三个枚举值,这是产品范围差异,不是「少实现一半」的简单对比。
🔍 模式:PermissionMode
DEFAULT:只读工具直接allowed;变异工具返回allowed=False且requires_confirmation=True,等待permission_prompt。PLAN:阻断变异工具(规划态不写盘),与课内 plan 叙事接近。FULL_AUTO:策略通过后一律放行,类似高风险的「全自动」——仍受 deny 名单与 path/command 规则约束(见evaluate顺序)。
🔍 判定:PermissionChecker.evaluate
关键参数:tool_name、is_read_only(来自 OH02 的 BaseTool.is_read_only)、file_path、command(由 query._resolve_permission_file_path / _extract_permission_command 从原始 input 与 Pydantic 模型两侧抽取,避免路径规则对不上字段名)。
分支顺序(先读代码再记):denied_tools → allowed_tools → path_rules deny → denied_commands → FULL_AUTO → 只读放行 → PLAN 挡变异 → 默认模式「变异需确认」。
# permissions/checker.py — PermissionDecision 与 evaluate 核心语义(节选)
@dataclass(frozen=True)
class PermissionDecision:
allowed: bool
requires_confirmation: bool = False
reason: str = ""
# DEFAULT + 非只读 → 需确认
return PermissionDecision(
allowed=False,
requires_confirmation=True,
reason="Mutating tools require user confirmation in default mode",
)
🔗 接入循环:query._execute_tool_call
evaluate 若 not decision.allowed:若 requires_confirmation 且提供了 permission_prompt,则异步询问;用户拒绝则返回错误型 ToolResultBlock;用户同意则不再次调用 evaluate,直接进入 tool.execute。若无 prompt 且需确认、或直接硬拒绝,则返回带 reason 的错误块。读源码时注意 if/else 嵌套,避免误解为「确认后重算策略」。
💬 TUI:ask_permission
ui/permission_dialog.py 用 prompt_toolkit 打一行 [y/N],是最小可行确认;与 Claude Code 富交互相比,教学上更利于看清「prompt 是可插拔依赖」。
⚖️ 与课内叙事对照
| 维度 | 课内 S03 | OpenHarness |
|---|---|---|
| 模式数量 | 多种(acceptEdits、bypass…) | 当前 3 种枚举 + 名单 / glob 规则 |
| 确认 UI | 产品级终端 / IDE | 可注入 permission_prompt,默认简单 y/N |
| 只读快捷放行 | 课内概念 | 显式 is_read_only 分支 |
| 路径级策略 | 课内常合并讲 | path_rules + fnmatch |
🤔 思考题
- 为何
allowed_tools要在path_rules之前检查?若某路径被 deny 但工具在白名单,结果会怎样? permission_prompt为None时,默认模式下变异工具是「静默拒绝」还是抛错?对应哪段分支?FULL_AUTO仍可能拒绝的情况有哪些?
📎 延伸阅读
OH01–12 目录 · OH02 · OH04 · S03 · D03 · S10 Hooks(与 PreToolUse 顺序)