workspace 抽象 · 工具怎么触达文件、又怎么被放行
进 Part 3。一次工具调用从主循环出来,经过 WorkspaceOps 派发、AsyncFileSystem 触达文件,中间还要过权限管理器那道「判定瀑布」。这一章拆 workspace 的三件事:派发缝、文件系统抽象、以及决定放行/询问/拒绝的顺序。
workspace 抽象 · 工具怎么触达文件、又怎么被放行
Part 1、2 看了循环和工具本身。这一部分看它们脚下的地基——工作区(xai-grok-workspace):一次工具调用怎么真正落到文件上,以及落之前怎么被「放行/询问/拒绝」。
什么是 workspace
WorkspaceHandle 是「一个工作目录」的宿主级抽象,把文件系统、VCS、工具执行、权限、hunk 追踪、代码库图谱、文件监听全都拴在一起。每个 agent 会话对应一个 WorkspaceSession,持有该会话的 FinalizedToolset、hunk tracker、AsyncFsWrapper 等。
WorkspaceOps:工具派发缝
主循环执行工具时调的 WorkspaceOps::call_tool,就在这里。它是个二选一的枚举:
Local(进程内):handle.session(sid).toolset().call(name, args, ...)——直接走会话的 FinalizedToolset 派发。Proxy(远程):通过 hub WebSocket RPC 调远端 workspace 服务器,再把流式结果收回来。
这层抽象的价值:同一套上层逻辑,工具既能在本地进程跑,也能跑在远端 workspace(云端/容器)——和工具协议那章「一套契约两种传输」一脉相承。
它的 RPC 契约值得学:WorkspaceRpc trait 带 const METHOD + type Response,客户端和服务端共用同一个请求结构体——改名字编译期就报错,不会一端漏改。六十多个 WorkspaceOp(git、hunk、code-nav、worktree、fs……)都这么定。
AsyncFileSystem:工具眼里的文件系统
工具不直接碰 std::fs,而是拿一个 Arc<dyn AsyncFileSystem>(file_system/fs.rs):read_file/write_file/try_read_file……实现有 LocalFs(本地 tokio::fs)、MockFs(测试)、AcpFsAdapter(远程客户端 fs)。有界读是硬约束:MAX_READ_BYTES = 4 MiB(压在 8 MiB 服务器帧上限之下)、MAX_LIST_COLLECT = 50000,还能把 walk 限制在规范根内防符号链接逃逸。把文件系统抽象成 trait,才能让同一个工具在本地、远程、测试三种后端下都跑。
权限判定瀑布
工具要动文件之前,得先过权限管理器(permission/manager/mod.rs,已从单文件拆成一个模块目录)。它是个 actor(mpsc 命令 + oneshot 回复),一次 request(PermissionRequest) 最终落到一个 Decision(Allow/Ask/Reject/PolicyDeny/Cancelled……)。判定是一条顺序敏感的瀑布——顺序本身就是安全设计:
几个关键设计:
- Policy Deny 排在 YOLO 之前:哪怕你开了「全部放行(YOLO)」,受管策略的拒绝仍然拦得住——企业管控不被用户开关绕过。
- bash 用 tree-sitter 拆解再判:
evaluate_bash把命令按&&/;/管道拆段,优先级 禁止 > 危险 > 安全白名单 > 询问;危险命令(is_dangerous_command_words)即使在白名单里也强制询问。 - sandbox_auto(沙箱那章埋的线,需打开
[sandbox] auto_allow_bash):沙箱激活时,只读或只写「安全 sink」的 bash 自动放行,但写真实文件、设危险环境变量仍要问——OS 硬隔离 + 命令下限,双保险。 - 只读默认放:
Read/Grep/WebSearch走pre_decision自动允许(除非策略明确要问);但MCPTool不在此列——没有会话授权的 MCP 工具一律要问,用户拒过的直接驳回。 - 受管策略成了独立引擎:
permission/managed_policy/把managed-settings.json与各层managed_config.toml/requirements.toml按「最严者胜」合成 MCP/插件市场白名单;每次请求先由gate_preflight.rs一次算好策略规则和两道 bash 安全闸的结论,瀑布各处只读这一个结果。
和《从 LLM 到 Coding Agent》对照
对照 permissions:最小实现里权限就是「危险操作前问一句 y/n」。grok 的增量是一整套分层判定:受管策略、YOLO、会话授权、LLM 分类器 auto 模式、沙箱自动、只读快放——按精心设计的顺序层层过。这是「玩具靠一个 if,产品靠一条瀑布」的典型。下一章看工作区怎么感知文件被改。
上一篇:与别家 agent 互通 · 下一篇:文件监听 · fsnotify