Tolaria 的 Gemini CLI Agent 适配器设计(ADR 0097):无头调用、瞬态 MCP 配置与安全/权限双模式 Tolaria 的 Gemini CLI Agent 适配器设计ADR 0097无头调用、瞬态 MCP 配置与安全/权限双模式【免费下载链接】tolariaDesktop app to manage markdown knowledge bases项目地址: https://gitcode.com/GitHub_Trending/to/tolaria本文基于 Tolaria 仓库中的架构决策记录 ADR 0097完整还原其设计背景、桌面端 Gemini CLI 适配器的六项核心行为可执行发现、无头 JSON 调用、瞬态 MCP 注入、Safe/Power User 权限映射、流事件归一化与被否决的备选方案。读完本文你可以理解 Tolaria 如何在不篡改用户全局配置的前提下把一个第三方 CLI Agent 接入应用内 AI 面板并能在当前源码中验证这些设计决策的落地痕迹与后续演化。1. 背景Gemini CLI 为什么必须成为“一等公民” AgentADR 0097 的 Context 部分指出了一个具体的能力断层ADR 00910091-gemini-cli-external-ai-setup.md已经允许 Tolaria 为用户显式生成 Gemini CLI 的外部 MCP 配置但 Gemini 仍然缺席于 Tolaria 可选择的 App 托管 AI Agent 列表。结果是AI 面板能够生成 Gemini 兼容的 MCP 配置但实际的 Agent 选择器、可用性探测、安装链接、流式分发却没有把 Gemini 当作 Claude Code、Codex、OpenCode 或 Pi 那样的平级 Agent 对待。Gemini CLI 本身具备被 Tolaria 程序化驱动所需的全部能力无头--prompt执行并支持 JSON 输出可配置的 approval审批模式工具排除tool exclusion通过环境变量GEMINI_CLI_SYSTEM_SETTINGS_PATH覆盖 settings 文件加载路径。ADR 原文的判断是这些能力“足够 Tolaria 在 App 托管会话中启动 Gemini同时不篡改用户持久的~/.gemini/settings.json”。这一句同时定下了整个适配器的两条设计基线——无头一次性调用与瞬态配置注入。2. 核心决策Gemini 成为一等AiAgentIdADR 0097 的决策分前端与桌面后端两层。2.1 前端Agent 身份贯穿所有用户可见表面决策第一条Tolaria 将 Gemini CLI 提升为一等AiAgentId。具体覆盖的前端表面包括Agent 定义表、onboarding 提示、安装链接、默认 Agent 归一化、状态徽章status badge、命令注册表、设置持久化以及 mock Tauri 状态载荷——全部纳入gemini。当前仓库中这一层代码的骨架仍然清晰可见。aiAgents.ts 维护了AI_AGENT_DEFINITIONS常量表id、label、shortLabel、installUrl并提供normalizeStoredAiAgent与normalizeAiAgentsStatus两个归一化入口。值得注意的一个实现细节是normalizeAiAgentsStatus对旧版状态载荷做了兼容取值// src/lib/aiAgents.ts L119 return agent antigravity ? payload?.antigravity ?? payload?.gemini : payload?.[agent]这行“antigravity优先、回退gemini”的取值逻辑正是 ADR 0097 把gemini写入 mock Tauri 状态载荷这一设计的直接遗产——后续 Agent 被替换后前端仍需消费旧载荷形态否则老版本设置与旧 IPC 载荷会被静默丢弃。2.2 桌面端AiAgentId枚举与权限模式Tolaria 桌面端的 Agent 身份定义在 ai_agents.rspub enum AiAgentId { ClaudeCode, Codex, Copilot, Opencode, Pi, #[serde(alias gemini)] Antigravity, Kiro, Hermes, }从源码结构看Antigravity变体上保留的#[serde(alias gemini)]就是 ADR 0097 时代gemini身份在序列化层的残留兼容旧设置里存储的gemini字面量仍能被正确反序列化而不会被当成未知值。ADR 0097 引入的权限语义也由同文件的AiAgentPermissionMode承载ai_agents.rs#L21-L27pub enum AiAgentPermissionMode { #[default] Safe, PowerUser, }Safe 作为默认值、permission_mode()方法对None回退到Safeai_agents.rs#L135-L139与 ADR 0097 中“Safe/Power User 双模式”的设定一脉相承后续 ADR 0103 进一步细化了“同一权限语义在不同适配器上的映射差异”而这正是 ADR 0097 在 Consequences 中预先声明的风险点见第 5 节。3. 桌面端 Gemini 适配器六项行为的实现级解读ADR 0097 对后端适配器的要求列出了六条逐条对照仓库现状展开。3.1 可执行文件发现PATH、登录 Shell、常见安装目录适配器需通过进程 PATH、登录 Shell、以及常见本地/工具链安装位置三路探测gemini可执行文件。这一“三路探测”模式在 Tolaria 中是所有 CLI Agent 的通用范式——Pi 适配器的 ADR 00900090-pi-cli-agent-adapter.md用几乎相同的措辞描述过。当前实现可见于 ai_agents.rs 的get_ai_agents_status每个 Agent 的同步check_cli()探测被spawn_blocking分发到 Tokio 阻塞线程池并行执行单项超时 5 秒超时或 panic 一律降级为installed: false保证 IPC 永远返回结构完整的AiAgentsStatus前端渲染不中断。源码注释还解释了并行化的动机登录 Shell 回退如/bin/zsh -lc command -v agent会完整执行 Shell 启动流程串行探测会在冷启动时叠加数秒延迟。3.2 无头调用从活动 Vault 目录发起适配器以如下命令形态从活动 Vault 目录运行 Geminigemini --output-format json --approval-mode mode --prompt prompt三个关键参数各司其职--output-format json让输出可被程序解析并映射为流事件--approval-mode mode承载 Safe/Power User 的权限差异mode的取值见 3.4 节工作目录锁定为活动 Vault 使 Gemini 的上下文天然限定在该知识库内。这一“从 vault cwd 发起一次性调用”的形态与 Pi 适配器pi --mode json --no-session从活动 Vault cwd 运行的设计同构。3.3 瞬态 MCP 注入GEMINI_CLI_SYSTEM_SETTINGS_PATH的妙用这是 ADR 0097 最核心的设计。适配器通过GEMINI_CLI_SYSTEM_SETTINGS_PATH指向一个临时 settings 文件来提供 Tolaria MCP Server从而在 App 托管会话中让 Gemini 获得 Vault 工具能力同时完全不改写用户的全局~/.gemini/settings.json。对比仓库中“持久化外部 MCP 设置”路径可以看清这条边界的两侧mcp.rs 中legacy_gemini_mcp_config_paths指向的正是~/.gemini/settings.json及~/.gemini/config/mcp_config.json——那是用户显式执行外部 MCP 设置/移除时才会触碰的持久路径。ADR 0097 的 Consequences 明确保留了这条边界“持久的 MCP 设置路径与可选的GEMINI.mdshim 继续服务于 Tolaria AI 面板之外的外部 Gemini 使用。”也就是说同一个~/.gemini目录在 Tolaria 眼里有两个角色显式设置时的持久写入点App 托管会话时绝不触碰的红线。3.4 权限模式映射Safe 与 Power User 的 Gemini 语义ADR 0097 将 Tolaria 的两种权限模式映射到 Gemini 自身的 approval/信任语义Tolaria 权限模式Gemini CLI 侧映射设计意图Safe默认--approval-mode auto_editTolaria MCP 条目为未信任untrusted且tools.exclude[run_shell_command]允许编辑类操作但排除 Shell 执行工具MCP 工具处于未信任状态最小化自主权限Power User--approval-mode yoloTolaria MCP 条目为已信任trusted放开审批以换取完整工具链能力用户显式选择该模式即视为承担相应风险注意排除项的具体性被禁用的不是泛化的“危险工具”而是 Gemini 的具体工具名run_shell_command。这也解释了 Consequences 中的一条风险声明——Safe 与 Power User 的行为上限受限于 Gemini 自身的审批/工具语义如果 Gemini 改名这些 flag适配器测试与文档必须同步更新而不是静默回退到更宽松的配置。这个立场在继任者 ADR 0147 中被继承并强化为“绝不回退到--dangerously-skip-permissions这类危险旁路 flag”。3.5 流事件归一化Gemini JSON → Tolaria 流事件适配器最后一项行为是把 Gemini 的 JSON 响应映射进 Tolaria 既有的 AI 面板流事件协议。该协议统一定义在 ai_agents.rs#L94-L119pub enum AiAgentStreamEvent { Init { session_id: String }, TextDelta { text: String }, ThinkingDelta { text: String }, ToolStart { tool_name: String, tool_id: String, input: OptionString }, ToolDone { tool_id: String, output: OptionString }, Error { message: String }, Done, }从源码结构看各 Agent 的私有事件类型如 Claude 的ClaudeStreamEvent经map_*_event函数归一到这套协议后再经emit回调上行分派入口shared_agent_runnerai_agents.rs#L229-L243将非 Claude 的 Agent 路由到 cli_agent_runtime 共享运行时——这正是 ADR 0093 建立的共享适配器运行时。Gemini 适配器当时的价值在于验证了该协议的跨供应商扩展性一个全新的供应商 CLI 只需实现“发现 调用 事件映射”三件事即可接入。4. 备选方案与取舍ADR 0097 的 Options Considered 给出了四个选项及否决理由完整继承如下作为一等 App 托管 Agent 接入选中匹配既有的 Agent 选择器与 onboarding UI使用 Gemini 的无头 JSON 模式MCP 设置保持 Vault 作用域。保持 Gemini 仅为外部 MCP 设置省掉一个适配器但界面不一致——其他 Agent 都能在面板内完成的流程Gemini 用户必须离开 Tolaria。把 App 托管 Gemini 配置写入~/.gemini/settings.json复用了外部设置路径但会模糊“显式设置”与“正常使用”之间的同意边界正常用 AI 面板就有覆盖用户偏好的风险。使用交互式 Gemini 会话能保留更丰富的 CLI 状态但不契合 Tolaria 当前“一次请求一个流”的生命周期且会显著复杂化清理、鉴权与错误处理。这组取舍浓缩了 Tolaria CLI Agent 接入的通用工程原则无头一次性调用优先于持久会话、瞬态配置优先于全局写入、面板内体验一致性优先于省一个适配器。ADR 0090Pi与 ADR 0147Antigravity在各自语境下重复了相同的权衡结构。5. 后果Consequences与仓库中的后续演化ADR 0097 声明的四条后果及其在仓库中的对应证据Gemini 出现在所有可选择、安装、切换本地 AI Agent 的位置。对应前端定义表、状态徽章AiAgentsBadge 相关测试与 mock Tauri 状态载荷mock-tauri/mock-handlers.ts。端到端原生 Gemini QA 需要 Gemini CLI 已安装并认证但缺失/认证失败现在会给出 Agent 专属指引。即错误文案不是通用的“Agent 不可用”而是针对 Gemini 安装/认证流程的恢复建议。Safe 与 Power User 行为受限于 Gemini 自身的审批/工具语义若 Gemini 改名适配器测试与文档需更新。见 3.4 节讨论。持久 MCP 设置路径与可选GEMINI.mdshim 继续服务 AI 面板之外的外部 Gemini 使用。仓库根目录的 GEMINI.md 即该 shim 形态vault/config_seed.rs 实现了 shim 的状态分类Missing/Managed与“用户已自定义则不覆盖”的恢复逻辑测试test_restore_ai_guidance_files_preserves_custom_gemini明确验证了自定义内容不会被 Tolaria 重写。5.1 当前仓库状态0097 已被 ADR 0147 取代但遗产完整保留需要向读者说明的关键事实仓库中的 ADR 0147Antigravity CLI agent adapter 在 frontmatter 中声明supersedes: [0091, 0097]将 App 托管的 Gemini CLI Agent 替换为 Google 维护的继任者 Antigravity CLIagy -p prompt --cwd vault瞬态 MCP 配置改写到工作区.agents/mcp_config.json。当前src-tauri/src下已不存在独立的 Gemini 适配器模块取而代之的是 antigravity_cli.rs 等模块。ADR 0097 的设计遗产却完整保留在代码里且都以“兼容旧身份”的形式存在后端AiAgentId中#[serde(alias gemini)]ai_agents.rs#L15-L16使旧序列化值仍可解析设置归一化normalize_default_ai_agent将存储值gemini显式迁移为antigravitysettings.rs#L153-L159并有配套测试test_legacy_gemini_default_ai_agent_migrates_to_antigravitysettings_normalization_tests.rs前端LegacyAiAgentId gemini与状态载荷回退取值aiAgents.ts#L2、aiAgents.ts#L97-L119外部路径~/.gemini/settings.json等 legacy 路径仍被mcp.rs的 MCP 移除逻辑识别以清理旧设置残留mcp.rs#L237-L250、mcp.rs#L482-L491。6. 小结从 ADR 0097 可以提炼的三条 CLI Agent 接入经验用供应商原生的“配置路径覆盖”机制注入瞬态配置此处为GEMINI_CLI_SYSTEM_SETTINGS_PATH而不是改写用户全局文件——App 托管会话与用户显式设置之间保持清晰的同意边界权限模式必须映射到供应商自身的审批语义且在映射表中显式列出被排除的具体工具名tools.exclude[run_shell_command]把“改名即需同步更新测试与文档”写进 ADR 后果而非留作隐性依赖Agent 身份变更时用别名/归一化层承接迁移serde alias、normalize_default_ai_agent、前端gemini → antigravity映射保证旧版本设置与旧 IPC 载荷在升级后依然有效。ADR 0097 虽已被 ADR 0147 取代但它确立的这三条原则仍是 Tolaria 当前所有 CLI Agent 适配器见 ADR 0093 共享运行时共同的工程底座。【免费下载链接】tolariaDesktop app to manage markdown knowledge bases项目地址: https://gitcode.com/GitHub_Trending/to/tolaria创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考