Qwen Code Approval Mode 跨语言契约设计:core 单一事实来源与 SDK 派生校验
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
Approval Mode(审批模式)是 Qwen Code 终端 AI 编程代理中控制 AI 对文件编辑与 Shell 命令权限的核心机制。本文基于仓库设计文档 2026-08-23-approval-mode-contract.md,完整讲解五种权限模式的取值语义,并从源码层面剖析"以 core 为运行时单一事实来源、TypeScript/Python/Java SDK 各自派生本地类型、用统一 JSON fixture 做跨语言契约校验"这一架构决策,帮助你在使用、集成或二次开发 Qwen Code 时准确理解和复用 Approval Mode 契约。
一、契约决策总览:为什么需要跨语言契约
Qwen Code 是一个多语言 SDK 生态的终端 AI 编程代理,Approval Mode 的取值域被以下多个层共同使用:
- core:
ApprovalMode枚举与APPROVAL_MODES数组,是运行时的事实来源; - CLI 与 TypeScript SDK:系统消息中的
permission_mode字段需要类型化; - Python SDK 与 Java SDK:分别维护原生公共类型(
PermissionMode别名 / 枚举)。
如果没有统一契约,各包自行定义字符串字面量,极易出现拼写漂移、漏加新模式、校验逻辑不一致等问题。设计文档给出的核心决策是:
Keep
ApprovalModeandAPPROVAL_MODESin core as the runtime source of truth.TypeScript packages derive their local types and validators from either that core contract or the TypeScript SDK's checked tuple. Python and Java keep native public types, with their accepted values checked against a small JSON fixture that is also checked against core.
即:core 持有权威枚举;TypeScript 侧从 core 或 SDK 的受检元组派生本地类型与校验器;Python/Java 保留原生公共类型,但通过一份同时与 core 对照的 JSON fixture 校验取值。这样既避免了已发布 SDK 对 core 引入运行时依赖,也为一个仅有五个取值的领域避免了引入代码生成。
二、core 侧的事实来源:枚举、字符串联合与 JSON fixture
2.1 枚举定义
core 中 Approval Mode 的权威定义位于 packages/core/src/config/approval-mode.ts:
export enum ApprovalMode { PLAN = 'plan', DEFAULT = 'default', AUTO_EDIT = 'auto-edit', AUTO = 'auto', YOLO = 'yolo', } export type ApprovalModeValue = `${ApprovalMode}`; export const APPROVAL_MODES = Object.values(ApprovalMode);ApprovalMode枚举定义了五个取值:plan、default、auto-edit、auto、yolo;ApprovalModeValue通过模板字面量类型把枚举投影为字符串联合类型(string-union form),这正是设计文档中"Export the string-union form of core'sApprovalMode"所指的改动;APPROVAL_MODES是取值数组,供各消费方做包含性校验与遍历。
2.2 JSON fixture:跨语言契约的锚点
packages/core/src/config/approval-modes.json 是全文唯一的跨语言契约文件:
["plan", "default", "auto-edit", "auto", "yolo"]设计文档中"Check core, TypeScript, Python, and Java accepted values against one fixture in their existing test suites"与"Trigger the Python and Java SDK workflows when the fixture changes"两条改动,均以这份 JSON 为锚点。它不参与运行时逻辑,只作为测试期的一致性参照物。
2.3 相邻取值域为何不并入本契约
设计文档明确划定了边界:channel modes、hook permission decisions、desktop cycling preferences 等相邻取值域保持独立,因为它们的支持取值与语义有意不同。这提示我们在集成时不要把 Approval Mode 契约泛化到其他权限相关字段,以免破坏各自领域的独立演化。
三、TypeScript 侧派生:core / SDK 双路径
设计文档要求"Replace repeated TypeScript unions and validation arrays with the core or SDK contract",并"Type the CLI and TypeScript SDK system-messagepermission_modefields with the shared union"。
- CLI 非交互层:
permission_mode出现在控制协议中,例如 packages/cli/src/nonInteractive/types.ts 定义的permission_mode?: PermissionMode,以及set_permission_mode控制请求(同文件 L410 附近),由 permissionController.ts 在运行时处理set_permission_mode。 - TypeScript SDK:
PermissionMode、DAEMON_APPROVAL_MODES等在 packages/sdk-typescript/src/index.ts 导出,查询选项层面对其做 schema 校验(见 queryOptionsSchema.ts)。
SDK 侧的校验器与 core 的对照由漂移检测测试保证: packages/sdk-typescript/test/unit/approval-mode-drift.test.ts 读取 core 的approval-modes.json,断言:
- core 的
APPROVAL_MODES、SDK 的PERMISSION_MODES、acp-bridge 的KNOWN_APPROVAL_MODES三者与 fixture 完全一致; DAEMON_APPROVAL_MODES与PERMISSION_MODES指向同一对象。
expect([...APPROVAL_MODES]).toEqual(crossLanguageContract); expect([...PERMISSION_MODES]).toEqual(crossLanguageContract); expect([...KNOWN_APPROVAL_MODES]).toEqual(crossLanguageContract); expect(DAEMON_APPROVAL_MODES).toBe(PERMISSION_MODES);这段测试正是"TypeScript SDK drift and query-option tests"验证项的落地实现:一旦任一层级漏加或错写取值,测试立即失败。
四、Python 侧:原生别名 + fixture 校验
Python SDK 在 packages/sdk-python/src/qwen_code_sdk/types.py 用Literal类型别名声明公共类型:
PermissionMode: TypeAlias = Literal["default", "plan", "auto-edit", "auto", "yolo"]该别名被用于会话选项permission_mode字段(types.py L112、L153),在传输层映射为 CLI 的--approval-mode参数(packages/sdk-python/src/qwen_code_sdk/transport.py):
if options.permission_mode: args.extend(["--approval-mode", options.permission_mode])运行时切换则由set_permission_mode控制请求完成(query.py):
async def set_permission_mode(self, mode: str) -> None: await self._send_control_request("set_permission_mode", {"mode": mode})设计文档中"Python validation tests"指的就是对该Literal取值域与 JSON fixture 的一致性校验。
五、Java 侧:原生枚举 + fixture 校验
Java SDK 在 PermissionMode.java 中维护五个常量,与 core 取值一一对应:
public enum PermissionMode { DEFAULT("default"), PLAN("plan"), AUTO_EDIT("auto-edit"), AUTO("auto"), YOLO("yolo"); // getValue() / fromValue(String) }- 会话层通过
Session.setPermissionMode(PermissionMode)下发控制请求,底层将枚举值写入cliControlSetPermissionModeRequest.setMode(...)(Session.java); - 系统消息中的
permissionMode字段同样使用该字符串取值(SDKSystemMessage.java); - 守护进程(daemon)侧另有 DaemonApprovalMode.java 维护相同取值集。
设计文档中"Java permission-mode tests"即针对该枚举的取值与 fixture 的一致性、fromValue对未知取值的异常行为进行验证。
六、五种模式的取值语义与使用场景
以 core 契约为准,五种approvalMode取值及其对文件编辑与 Shell 命令的权限差异如下表(对应 Approval Mode 用户指南):
| 取值(契约值) | 文件编辑 | Shell 命令 | 典型场景 | 风险等级 |
|---|---|---|---|---|
plan | ❌ 只读分析 | ❌ 不执行 | 代码探索、复杂变更规划、安全代码评审 | 最低 |
default(Ask Permissions) | ✅ 需人工批准 | ✅ 需人工批准 | 新/不熟悉代码库、关键系统、团队协作、教学 | 低 |
auto-edit | ✅ 自动批准 | ❌ 需人工批准 | 日常开发、重构与代码改进、安全自动化 | 中 |
auto | ✅ 分类器评估 | ✅ 分类器评估 | 长时自主会话、介于 Auto-Edit 与 YOLO 之间 | 中 |
yolo | ✅ 自动批准 | ✅ 自动批准 | 可信个人项目、CI/CD 自动化脚本、批处理 | 最高 |
几点值得注意的语义细节:
- 用户文档中曾被称为Default的模式已改名为Ask Permissions,但底层配置值
tools.approvalMode: "default"与/approval-mode default命令保持不变,用于向后兼容——这正是契约值default需要稳定存在的原因之一; - 循环切换顺序为
plan → default → auto-edit → auto → yolo → plan → ...,可通过Shift+Tab(Windows 上为Tab)快速切换,终端状态栏会显示当前模式; auto模式由 LLM 分类器评估 Shell 命令、网络调用与工作区外编辑,偏向"不确定即拦截";同时保留硬性规则(permissions.deny优先于分类器)、失败关闭(classifier API 不可达时拦截,连续两次不可达后回退人工批准)与循环护栏(连续三次策略拦截后回退人工批准)等安全机制。
七、配置与命令实操
7.1 会话内切换
/approval-mode plan # 进入计划模式(只读) /approval-mode default # 回到 Ask Permissions(默认) /approval-mode auto-edit # 自动批准文件编辑 /approval-mode auto # 分类器驱动的自动审批 /approval-mode yolo # 全自动(谨慎使用)也可用/plan快捷进出只读规划模式(/plan exit会恢复进入前的模式),或在无头模式下用qwen --prompt "..."直接以当前默认模式运行。
7.2 持久化配置
在项目级.qwen/settings.json或用户级~/.qwen/settings.json中写入:
{ "tools": { "approvalMode": "auto-edit" // 可选 "plan" | "default" | "auto-edit" | "auto" | "yolo" } }auto模式还支持在permissions.autoMode下配置自然语言 hints、环境描述与可选开关:
{ "tools": { "approvalMode": "auto" }, "permissions": { "autoMode": { "hints": { "allow": ["Running pytest, mypy, and ruff on this Python repo"], "deny": ["Any network call to intranet.example.com"] }, "environment": ["Open-source monorepo; commits are signed"] // "classifyAllShell": true, // 可选:所有 Shell 命令都过分类器 // "mcp": { "forwardArguments": false } // 可选:仅按名称发送 MCP 工具调用 } } }八、验证矩阵与落地检查
设计文档的 Verification 一节给出了完整的验证清单,映射到仓库中的具体位置如下:
| 验证项 | 仓库落点 |
|---|---|
| Core approval-mode tests | packages/core/src/config/config.test.ts 等 core 配置相关测试 |
| CLI ACP 与非交互类型检查 + 聚焦测试 | packages/cli/src/nonInteractive/control/controllers/permissionController.test.ts、packages/cli/src/acp-integration/acpAgent.test.ts |
| TypeScript SDK drift 与 query-option 测试 | packages/sdk-typescript/test/unit/approval-mode-drift.test.ts、packages/sdk-typescript/test/unit/queryOptionsSchema.test.ts |
| Python validation tests | packages/sdk-python/src/qwen_code_sdk/types.py 的PermissionMode别名及对应校验测试 |
| Java permission-mode tests | PermissionMode.java 及fromValue相关测试 |
| lint / typecheck / build | 仓库根目录 package.json 定义的脚本 |
从源码结构看,CI 侧还会在approval-modes.json变更时触发 Python 与 Java SDK 的工作流,确保跨语言取值域始终与 core 对齐。
九、小结
Approval Mode 契约设计的核心价值在于:
- 单一事实来源:
plan/default/auto-edit/auto/yolo五个取值以 core 的枚举与数组为权威,杜绝多包各自定义导致的漂移; - 零运行时耦合:已发布的 SDK 不依赖 core,而是各自维护原生类型(TS 字符串联合、Python
Literal、Java 枚举),把一致性检查收敛到测试期; - 轻量不引入代码生成:对一个五取值领域而言,一份 approval-modes.json 加各语言的 drift/validation 测试,是性价比最高的方案。
无论你是终端用户(通过/approval-mode与 settings.json 使用五种模式)、SDK 集成方(在 Python/Java/TypeScript 中传入permission_mode),还是平台扩展开发者(新增或校验取值),理解这一契约的"core 锚定 + 派生校验"结构,都能帮助你避免取值不一致的坑,并快速定位校验失败的原因。
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考