From f03427f36f2d98774cfc424ceddfc574e8f15b46 Mon Sep 17 00:00:00 2001 From: sheny Date: Wed, 12 Aug 2026 18:08:52 +0800 Subject: [PATCH 1/5] fix(sdk-python): support "auto" permission mode --- packages/sdk-python/README.md | 5 +++-- packages/sdk-python/src/qwen_code_sdk/types.py | 2 +- packages/sdk-python/src/qwen_code_sdk/validation.py | 4 ++-- packages/sdk-python/tests/unit/test_validation.py | 8 ++++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/sdk-python/README.md b/packages/sdk-python/README.md index 6deca2011f4..664e634188e 100644 --- a/packages/sdk-python/README.md +++ b/packages/sdk-python/README.md @@ -141,8 +141,9 @@ Common fields: - `path_to_qwen_executable`: `qwen`, an absolute binary path, or a `.js` CLI bundle - `model`: model override for this session -- `permission_mode`: one of `default`, `plan`, `auto-edit`, or `yolo`; `yolo` - auto-approves all tools, so use it only in trusted or sandboxed environments +- `permission_mode`: one of `default`, `plan`, `auto-edit`, `auto`, or `yolo`; + `auto` lets an LLM classifier approve tool calls; `yolo` auto-approves all + tools, so use it only in trusted or sandboxed environments - `env`: extra environment variables passed to the CLI process - `system_prompt` / `append_system_prompt`: override or extend the system prompt diff --git a/packages/sdk-python/src/qwen_code_sdk/types.py b/packages/sdk-python/src/qwen_code_sdk/types.py index 615ff1d460e..425b844e9ba 100644 --- a/packages/sdk-python/src/qwen_code_sdk/types.py +++ b/packages/sdk-python/src/qwen_code_sdk/types.py @@ -15,7 +15,7 @@ from typing_extensions import NotRequired -PermissionMode: TypeAlias = Literal["default", "plan", "auto-edit", "yolo"] +PermissionMode: TypeAlias = Literal["default", "plan", "auto-edit", "auto", "yolo"] AuthType: TypeAlias = Literal[ "openai", "anthropic", diff --git a/packages/sdk-python/src/qwen_code_sdk/validation.py b/packages/sdk-python/src/qwen_code_sdk/validation.py index 61ced1976c0..8c1a6822086 100644 --- a/packages/sdk-python/src/qwen_code_sdk/validation.py +++ b/packages/sdk-python/src/qwen_code_sdk/validation.py @@ -12,7 +12,7 @@ _validate_stderr_callable, ) -_VALID_PERMISSION_MODES = {"default", "plan", "auto-edit", "yolo"} +_VALID_PERMISSION_MODES = {"default", "plan", "auto-edit", "auto", "yolo"} _VALID_AUTH_TYPES = {"openai", "anthropic", "qwen-oauth", "gemini", "vertex-ai"} _VALID_EFFORTS = {"low", "medium", "high", "xhigh", "max"} @@ -87,7 +87,7 @@ def validate_query_options(options: QueryOptions) -> None: ): raise ValidationError( f"Invalid permission_mode: {options.permission_mode!r}. " - "Expected one of: default, plan, auto-edit, yolo." + "Expected one of: default, plan, auto-edit, auto, yolo." ) if options.auth_type and options.auth_type not in _VALID_AUTH_TYPES: diff --git a/packages/sdk-python/tests/unit/test_validation.py b/packages/sdk-python/tests/unit/test_validation.py index 783e8e1bee9..45277424ac1 100644 --- a/packages/sdk-python/tests/unit/test_validation.py +++ b/packages/sdk-python/tests/unit/test_validation.py @@ -74,6 +74,14 @@ def test_accepts_canonical_session_id_in_either_case() -> None: validate_query_options(QueryOptions(session_id=VALID_UUID.upper())) +@pytest.mark.parametrize( + "mode", + ["default", "plan", "auto-edit", "auto", "yolo"], +) +def test_accepts_valid_permission_modes(mode: str) -> None: + validate_query_options(QueryOptions.from_mapping({"permission_mode": mode})) + + def test_rejects_invalid_permission_mode() -> None: with pytest.raises(ValidationError, match="Invalid permission_mode"): validate_query_options( From 89bc3612327b5bbd3b3cd653f232a75d4799e09e Mon Sep 17 00:00:00 2001 From: sheny Date: Wed, 12 Aug 2026 19:26:55 +0800 Subject: [PATCH 2/5] refactor(sdk-python): derive permission-mode validation from PermissionMode type --- docs/developers/sdk-python.md | 44 +++++++++---------- .../src/qwen_code_sdk/validation.py | 6 ++- .../sdk-python/tests/unit/test_validation.py | 9 +++- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/docs/developers/sdk-python.md b/docs/developers/sdk-python.md index c39f5a9d23e..9a21083da95 100644 --- a/docs/developers/sdk-python.md +++ b/docs/developers/sdk-python.md @@ -139,28 +139,28 @@ with query_sync( ### `QueryOptions` -| Option | Type / values | Description | -| -------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -| `cwd` | `str` | Working directory for the CLI process. | -| `model` | `str` | Model override for this SDK session. | -| `path_to_qwen_executable` | `str` | `qwen`, an explicit binary path, or a `.js` CLI bundle. | -| `permission_mode` | `default`, `plan`, `auto-edit`, `yolo` | Tool execution approval mode. `yolo` auto-approves all tools; use it only in trusted or sandboxed environments. | -| `can_use_tool` | async callback | Custom permission callback for tool requests. | -| `env` | `dict[str, str]` | Extra environment variables passed to the CLI process. | -| `system_prompt` | `str` | Override the system prompt. | -| `append_system_prompt` | `str` | Append extra instructions to the system prompt. | -| `debug` | `bool` | Forward CLI stderr to stderr when no `stderr` hook exists. | -| `max_session_turns` | `int` | Maximum turns before the CLI ends the session. | -| `core_tools` | `list[str]` | Restrict the available tool set. | -| `exclude_tools` | `list[str]` | Exclude matching tools. | -| `allowed_tools` | `list[str]` | Allow matching tools without callback approval. | -| `auth_type` | `openai`, `anthropic`, `qwen-oauth`, `gemini`, `vertex-ai` | Authentication mode passed to the CLI. | -| `include_partial_messages` | `bool` | Emit partial assistant stream events. | -| `resume` | UUID string | Resume a known session id. | -| `continue_session` | `bool` | Continue the latest CLI session. | -| `session_id` | UUID string | Start or correlate a session with a known id. | -| `timeout` | mapping | Timeouts in seconds. | -| `stderr` | callable | Receives CLI stderr lines. | +| Option | Type / values | Description | +| -------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cwd` | `str` | Working directory for the CLI process. | +| `model` | `str` | Model override for this SDK session. | +| `path_to_qwen_executable` | `str` | `qwen`, an explicit binary path, or a `.js` CLI bundle. | +| `permission_mode` | `default`, `plan`, `auto-edit`, `auto`, `yolo` | Tool execution approval mode. `auto` lets an LLM classifier approve tool calls; `yolo` auto-approves all tools; use it only in trusted or sandboxed environments. | +| `can_use_tool` | async callback | Custom permission callback for tool requests. | +| `env` | `dict[str, str]` | Extra environment variables passed to the CLI process. | +| `system_prompt` | `str` | Override the system prompt. | +| `append_system_prompt` | `str` | Append extra instructions to the system prompt. | +| `debug` | `bool` | Forward CLI stderr to stderr when no `stderr` hook exists. | +| `max_session_turns` | `int` | Maximum turns before the CLI ends the session. | +| `core_tools` | `list[str]` | Restrict the available tool set. | +| `exclude_tools` | `list[str]` | Exclude matching tools. | +| `allowed_tools` | `list[str]` | Allow matching tools without callback approval. | +| `auth_type` | `openai`, `anthropic`, `qwen-oauth`, `gemini`, `vertex-ai` | Authentication mode passed to the CLI. | +| `include_partial_messages` | `bool` | Emit partial assistant stream events. | +| `resume` | UUID string | Resume a known session id. | +| `continue_session` | `bool` | Continue the latest CLI session. | +| `session_id` | UUID string | Start or correlate a session with a known id. | +| `timeout` | mapping | Timeouts in seconds. | +| `stderr` | callable | Receives CLI stderr lines. | Use only one of `resume`, `continue_session`, or `session_id` in a request. The SDK raises `ValidationError` if these session options are combined. diff --git a/packages/sdk-python/src/qwen_code_sdk/validation.py b/packages/sdk-python/src/qwen_code_sdk/validation.py index 8c1a6822086..0eb175af140 100644 --- a/packages/sdk-python/src/qwen_code_sdk/validation.py +++ b/packages/sdk-python/src/qwen_code_sdk/validation.py @@ -3,16 +3,18 @@ from __future__ import annotations from collections.abc import Callable +from typing import get_args from uuid import RFC_4122, UUID from .errors import ValidationError from .types import ( + PermissionMode, QueryOptions, _validate_can_use_tool_callable, _validate_stderr_callable, ) -_VALID_PERMISSION_MODES = {"default", "plan", "auto-edit", "auto", "yolo"} +_VALID_PERMISSION_MODES = set(get_args(PermissionMode)) _VALID_AUTH_TYPES = {"openai", "anthropic", "qwen-oauth", "gemini", "vertex-ai"} _VALID_EFFORTS = {"low", "medium", "high", "xhigh", "max"} @@ -87,7 +89,7 @@ def validate_query_options(options: QueryOptions) -> None: ): raise ValidationError( f"Invalid permission_mode: {options.permission_mode!r}. " - "Expected one of: default, plan, auto-edit, auto, yolo." + f"Expected one of: {', '.join(get_args(PermissionMode))}." ) if options.auth_type and options.auth_type not in _VALID_AUTH_TYPES: diff --git a/packages/sdk-python/tests/unit/test_validation.py b/packages/sdk-python/tests/unit/test_validation.py index 45277424ac1..4e6168b9b44 100644 --- a/packages/sdk-python/tests/unit/test_validation.py +++ b/packages/sdk-python/tests/unit/test_validation.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re from typing import Any, cast import pytest @@ -83,7 +84,13 @@ def test_accepts_valid_permission_modes(mode: str) -> None: def test_rejects_invalid_permission_mode() -> None: - with pytest.raises(ValidationError, match="Invalid permission_mode"): + with pytest.raises( + ValidationError, + match=re.escape( + "Invalid permission_mode: 'unsafe-mode'. " + "Expected one of: default, plan, auto-edit, auto, yolo." + ), + ): validate_query_options( QueryOptions.from_mapping({"permission_mode": "unsafe-mode"}) ) From 0b7306f7349e09cfd22a6f9205ad37ea747a99eb Mon Sep 17 00:00:00 2001 From: sheny Date: Thu, 13 Aug 2026 08:28:10 +0800 Subject: [PATCH 3/5] fix(sdk-java): support "auto" permission mode --- packages/sdk-java/qwencode/README.md | 1 + .../alibaba/qwen/code/cli/protocol/data/PermissionMode.java | 4 ++++ .../main/java/com/alibaba/qwen/code/cli/protocol/protocol.ts | 2 +- .../alibaba/qwen/code/cli/transport/PermissionModeTest.java | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/sdk-java/qwencode/README.md b/packages/sdk-java/qwencode/README.md index c72825bdee7..6fed89427ef 100644 --- a/packages/sdk-java/qwencode/README.md +++ b/packages/sdk-java/qwencode/README.md @@ -220,6 +220,7 @@ The SDK supports different permission modes for controlling tool execution: - **`default`**: Write tools are denied unless approved via `canUseTool` callback or in `allowedTools`. Read-only tools execute without confirmation. - **`plan`**: Blocks all write tools, instructing AI to present a plan first. - **`auto-edit`**: Auto-approve edit tools (`edit`, `write_file`, `notebook_edit`) while other tools require confirmation. +- **`auto`**: An LLM classifier approves tool calls. - **`yolo`**: All tools execute automatically without confirmation. ### Session Event Consumers and Assistant Content Consumers diff --git a/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/data/PermissionMode.java b/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/data/PermissionMode.java index 420dd760d4c..18d709c3371 100644 --- a/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/data/PermissionMode.java +++ b/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/data/PermissionMode.java @@ -19,6 +19,10 @@ public enum PermissionMode { * Auto-edit permission mode. */ AUTO_EDIT("auto-edit"), + /** + * Auto permission mode. + */ + AUTO("auto"), /** * YOLO permission mode. */ diff --git a/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/protocol.ts b/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/protocol.ts index 07d54a1c7c5..59901395eae 100644 --- a/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/protocol.ts +++ b/packages/sdk-java/qwencode/src/main/java/com/alibaba/qwen/code/cli/protocol/protocol.ts @@ -230,7 +230,7 @@ export interface SDKPartialAssistantMessage { parent_tool_use_id: string | null; } -export type PermissionMode = 'default' | 'plan' | 'auto-edit' | 'yolo'; +export type PermissionMode = 'default' | 'plan' | 'auto-edit' | 'auto' | 'yolo'; /** * TODO: Align with `ToolCallConfirmationDetails` diff --git a/packages/sdk-java/qwencode/src/test/java/com/alibaba/qwen/code/cli/transport/PermissionModeTest.java b/packages/sdk-java/qwencode/src/test/java/com/alibaba/qwen/code/cli/transport/PermissionModeTest.java index 97e6fe0d19f..b74f42854de 100644 --- a/packages/sdk-java/qwencode/src/test/java/com/alibaba/qwen/code/cli/transport/PermissionModeTest.java +++ b/packages/sdk-java/qwencode/src/test/java/com/alibaba/qwen/code/cli/transport/PermissionModeTest.java @@ -13,6 +13,7 @@ public void shouldBeReturnQwenPermissionModeValue() { assertEquals("default", PermissionMode.DEFAULT.getValue()); assertEquals("plan", PermissionMode.PLAN.getValue()); assertEquals("auto-edit", PermissionMode.AUTO_EDIT.getValue()); + assertEquals("auto", PermissionMode.AUTO.getValue()); assertEquals("yolo", PermissionMode.YOLO.getValue()); } From 8e4de233d3be1f094cf48e5cac42db392050054a Mon Sep 17 00:00:00 2001 From: sheny Date: Fri, 14 Aug 2026 12:39:48 +0800 Subject: [PATCH 4/5] refactor(sdk-python): derive auth-type and effort validation from type aliases --- packages/sdk-python/src/qwen_code_sdk/validation.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/sdk-python/src/qwen_code_sdk/validation.py b/packages/sdk-python/src/qwen_code_sdk/validation.py index 0eb175af140..7153b088833 100644 --- a/packages/sdk-python/src/qwen_code_sdk/validation.py +++ b/packages/sdk-python/src/qwen_code_sdk/validation.py @@ -8,6 +8,8 @@ from .errors import ValidationError from .types import ( + AuthType, + Effort, PermissionMode, QueryOptions, _validate_can_use_tool_callable, @@ -15,8 +17,8 @@ ) _VALID_PERMISSION_MODES = set(get_args(PermissionMode)) -_VALID_AUTH_TYPES = {"openai", "anthropic", "qwen-oauth", "gemini", "vertex-ai"} -_VALID_EFFORTS = {"low", "medium", "high", "xhigh", "max"} +_VALID_AUTH_TYPES = set(get_args(AuthType)) +_VALID_EFFORTS = set(get_args(Effort)) _RESERVED_CLI_FLAGS = frozenset( @@ -95,13 +97,13 @@ def validate_query_options(options: QueryOptions) -> None: if options.auth_type and options.auth_type not in _VALID_AUTH_TYPES: raise ValidationError( f"Invalid auth_type: {options.auth_type!r}. " - "Expected one of: openai, anthropic, qwen-oauth, gemini, vertex-ai." + f"Expected one of: {', '.join(get_args(AuthType))}." ) if options.effort and options.effort not in _VALID_EFFORTS: raise ValidationError( f"Invalid effort: {options.effort!r}. " - "Expected one of: low, medium, high, xhigh, max." + f"Expected one of: {', '.join(get_args(Effort))}." ) _validate_optional_callable(options.can_use_tool, _validate_can_use_tool_callable) From 9e82d4f8811fa3de18015e380327a44228207e39 Mon Sep 17 00:00:00 2001 From: sheny Date: Tue, 18 Aug 2026 23:30:30 +0800 Subject: [PATCH 5/5] chore: rerun CI