Skip to content

fix(types): add missing dontAsk permission mode#719

Merged
qing-ant merged 4 commits intomainfrom
fix/add-missing-permission-modes
Mar 26, 2026
Merged

fix(types): add missing dontAsk permission mode#719
qing-ant merged 4 commits intomainfrom
fix/add-missing-permission-modes

Conversation

@qing-ant
Copy link
Copy Markdown
Contributor

@qing-ant qing-ant commented Mar 24, 2026

Summary

The PermissionMode type was missing dontAsk, which the CLI supports and is documented at https://platform.claude.com/docs/en/agent-sdk/permissions#available-modes. This caused type errors when users tried to use it via ClaudeAgentOptions.

Fixes #483

Changes

  • Add dontAsk to PermissionMode Literal type — now matches the TS SDK's ExternalPermissionMode exactly (default, acceptEdits, plan, bypassPermissions, dontAsk)
  • Type set_permission_mode(mode) as PermissionMode instead of bare str in both client.py and _internal/query.py (resolves inline TODO on SDKControlSetPermissionModeRequest.mode)
  • Add plan and dontAsk to the docstrings in client.py and query.py (plan was already in the type but missing from docs)
  • Add tests for dontAsk in types and transport

Note: auto and bubble were considered but intentionally excluded — they are internal-only modes in the TS SDK (InternalPermissionMode), not part of the public ExternalPermissionMode surface.

Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — straightforward addition of missing permission mode literals with tests.

Extended reasoning...

Overview

This PR adds three missing permission modes (dontAsk, auto, bubble) to the PermissionMode Literal type in types.py, updates the SDKControlSetPermissionModeRequest.mode field from bare str to PermissionMode (resolving an existing TODO), and adds corresponding tests in test_types.py and test_transport.py. Three files changed with ~25 lines added.

Security risks

None. This is a type annotation change only — no runtime behavior is modified. Permission mode validation still happens in the CLI itself.

Level of scrutiny

Low scrutiny warranted. This is a mechanical type definition expansion adding well-known CLI modes that were simply missing from the SDK type. The changes follow established patterns exactly.

Other factors

The inline bug comment about set_permission_mode method signatures in client.py and query.py still accepting str is a valid consistency nit, but does not affect correctness — Python does not enforce type annotations at runtime, and the CLI validates the mode string server-side. The PR accomplishes its stated goal cleanly. No CODEOWNERS file exists. Tests cover the new modes adequately.

Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — previous feedback addressed, straightforward type annotation fix with tests.

Extended reasoning...

Overview

This PR adds three missing permission modes (dontAsk, auto, bubble) to the PermissionMode Literal type, tightens SDKControlSetPermissionModeRequest.mode from str to PermissionMode, and updates the set_permission_mode method signatures in both client.py and _internal/query.py to use PermissionMode. Tests are added for the new modes in both test_types.py and test_transport.py.

Security risks

None. This is a type annotation change with no runtime behavior impact. Permission modes are validated by the CLI itself, and no new code paths are introduced.

Level of scrutiny

Low scrutiny appropriate. This is a mechanical type definition update — adding literal values to an existing union type and propagating the type annotation to method signatures. The diff is small (under 50 lines of non-test code) and follows established patterns.

Other factors

My previous review flagged that the set_permission_mode signatures still accepted bare str and the docstring was incomplete. Both issues have been fully addressed in this revision. The remaining inline nit about query.py's docstring is a pre-existing documentation gap (not introduced by this PR) and is minor enough not to block approval.

Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — all prior feedback addressed, straightforward type annotation fix with tests.

Extended reasoning...

Overview

This PR adds three missing permission modes (dontAsk, auto, bubble) to the PermissionMode Literal type, updates SDKControlSetPermissionModeRequest.mode from bare str to PermissionMode, updates the set_permission_mode method signatures in both client.py and _internal/query.py to use PermissionMode, and updates docstrings in client.py and query.py to list all 7 valid modes. Tests are added for the new modes in both test_types.py and test_transport.py.

Security risks

None. This is a type annotation change with no runtime behavioral impact. Permission mode validation still happens in the CLI.

Level of scrutiny

Low scrutiny is appropriate. The changes are mechanical: expanding a Literal type, updating type annotations and docstrings for consistency, and adding simple assertion-based tests. No logic changes, no new code paths.

Other factors

Both issues I raised in prior reviews (signature consistency and docstring completeness) have been fully addressed in the current diff. The first inline comment is marked resolved. The PR includes test coverage for all three new modes. No CODEOWNERS concerns for these files.

Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — previous feedback addressed, type annotations and docstrings are consistent.

Extended reasoning...

Overview

This PR adds dontAsk to the PermissionMode Literal type, tightens SDKControlSetPermissionModeRequest.mode from bare str to PermissionMode (resolving an inline TODO), updates method signatures in client.py and _internal/query.py to use PermissionMode, updates docstrings in both client.py and query.py, and adds corresponding tests.

Security risks

None. This is a type annotation change only — Python does not enforce type annotations at runtime, and the CLI validates mode strings server-side. No auth, crypto, or permission logic is altered.

Level of scrutiny

Low scrutiny is appropriate. The changes are mechanical: adding a literal value to a type union, updating function signatures to use that type, and updating docstrings. The pattern follows existing code exactly. Both my prior review comments have been addressed and resolved.

Other factors

Tests have been added for the new permission mode (test_build_command_with_dont_ask_permission_mode, test_claude_code_options_with_permission_mode extended). A human reviewer (qing-ant) confirmed E2E testing passes. All 328 unit tests pass. No CODEOWNERS concerns. The bug hunting system found no issues.

claude and others added 4 commits March 26, 2026 03:12
The PermissionMode type was missing three modes that the CLI supports:
dontAsk, auto, and bubble. This caused type errors when users tried to
use these modes via ClaudeAgentOptions.

- Add dontAsk, auto, bubble to PermissionMode Literal type
- Fix SDKControlSetPermissionModeRequest.mode to use PermissionMode
  instead of bare str (resolves TODO)
- Add tests for new permission modes in types and transport

Fixes #483
Update ClaudeSDKClient.set_permission_mode() and
InternalQuery.set_permission_mode() to accept PermissionMode instead
of bare str, enabling static type checkers to catch invalid mode
strings at call sites.

Also update the client docstring to document all seven valid
permission modes including the three new ones (dontAsk, auto, bubble).
Only expose permission modes that are in the public CLI SDK schema:
default, acceptEdits, plan, bypassPermissions, dontAsk.

auto and bubble are internal-only modes used by the coordinator
system and should not be exposed to external SDK users.

:house: Remote-Dev: homespace
@qing-ant qing-ant force-pushed the fix/add-missing-permission-modes branch 2 times, most recently from ef73a99 to f6dd0d0 Compare March 26, 2026 03:16
Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — all previous feedback has been addressed; the final diff correctly adds only dontAsk and tightens the type signatures.

Extended reasoning...

Overview

This PR touches 4 source files and 2 test files. It adds dontAsk to the PermissionMode Literal type, updates SDKControlSetPermissionModeRequest.mode from str to PermissionMode (resolving an inline TODO), tightens the set_permission_mode method signatures in both client.py and _internal/query.py from str to PermissionMode, updates docstrings in both client.py and query.py to list plan and dontAsk, and adds test coverage for the new mode.

Security risks

No security risks. The changes are purely type annotation and documentation improvements. Permission modes are validated by the CLI at runtime regardless of the SDK type annotations.

Level of scrutiny

This is a low-risk change — type annotation tightening, docstring updates, and a new Literal value. No runtime behavior changes. The maintainer (qing-ant) has already E2E tested and confirmed correctness. All 328 unit tests pass.

Other factors

My previous inline comments went through several iterations as the PR evolved. The final state correctly excludes auto and bubble from the public PermissionMode type, consistent with the maintainer's explicit decision (commit e2a35bb) that these are internal-only coordinator modes. My last unresolved inline comment (about re-introducing auto/bubble) is now stale — the current diff does not include those modes. The PR title/description still references all three modes, but the actual implementation is correct. No CODEOWNERS file exists for this repository.

@qing-ant qing-ant changed the title fix(types): add missing permission modes (dontAsk, auto, bubble) fix(types): add missing dontAsk permission mode Mar 26, 2026
@qing-ant
Copy link
Copy Markdown
Contributor Author

E2E Test Results

Test script:

"""E2E test for PR #719: dontAsk permission mode works end-to-end.

This test verifies that the newly added 'dontAsk' permission mode can be
passed via ClaudeAgentOptions and works correctly with a live SDK instance.
"""

import asyncio
import sys

import claude_agent_sdk
from claude_agent_sdk import ClaudeAgentOptions


async def main() -> None:
    print(f"SDK version: {claude_agent_sdk.__version__}")
    print()
    print("Sending query with permission_mode='dontAsk', max_turns=1...")
    print()

    messages = []
    try:
        async for msg in claude_agent_sdk.query(
            prompt="Reply with exactly: hello world",
            options=ClaudeAgentOptions(max_turns=1, permission_mode="dontAsk"),
        ):
            messages.append(msg)
    except Exception as exc:
        print(f"FAIL: query raised {type(exc).__name__}: {exc}", file=sys.stderr)
        sys.exit(1)

    print(f"Received {len(messages)} messages:")
    print()

    found_hello = False
    for i, msg in enumerate(messages):
        msg_type = type(msg).__name__
        content = getattr(msg, "content", None)
        if isinstance(content, list):
            content_str = ", ".join(str(c)[:100] for c in content)
        elif isinstance(content, str):
            content_str = content[:200]
        else:
            content_str = str(content)[:200] if content else ""

        print(f"  [{i}] {msg_type}: {content_str}")

        if isinstance(content, str) and "hello world" in content.lower():
            found_hello = True
        elif isinstance(content, list):
            for block in content:
                text = getattr(block, "text", "")
                if "hello world" in text.lower():
                    found_hello = True

    print()
    if found_hello:
        print("PASS: query() completed successfully with permission_mode='dontAsk'")
        print("The dontAsk permission mode is properly accepted and forwarded to the CLI.")
    else:
        all_text = " ".join(str(m) for m in messages)
        if "hello world" in all_text.lower():
            print("PASS: query() completed successfully with permission_mode='dontAsk'")
        else:
            print("FAIL: Did not find expected 'hello world' in responses.", file=sys.stderr)
            sys.exit(1)


if __name__ == "__main__":
    asyncio.run(main())

Output:

SDK version: 0.1.50

Sending query with permission_mode='dontAsk', max_turns=1...

Received 4 messages:

  [0] SystemMessage: 
  [1] AssistantMessage: TextBlock(text='hello world', type='text')
  [2] RateLimitEvent: None
  [3] ResultMessage: None

PASS: query() completed successfully with permission_mode='dontAsk'
The dontAsk permission mode is properly accepted and forwarded to the CLI.

@qing-ant qing-ant enabled auto-merge (squash) March 26, 2026 06:10
Copy link
Copy Markdown
Collaborator

@bogini bogini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stamped 🤖

@qing-ant qing-ant merged commit e30c742 into main Mar 26, 2026
18 checks passed
@qing-ant qing-ant deleted the fix/add-missing-permission-modes branch March 26, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Don't ask permission mode not supported

3 participants