clawd-code-sdk 0.3.1__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/PKG-INFO +1 -1
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/pyproject.toml +1 -1
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/__init__.py +2 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/query.py +20 -4
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/client.py +1 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/__init__.py +2 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/content_blocks.py +7 -7
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/options.py +8 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/permissions.py +11 -1
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_session.py +2 -2
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/.gitignore +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/LICENSE +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/README.md +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_bundled/.gitignore +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_errors.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/__init__.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/message_parser.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/transport/__init__.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/transport/subprocess_cli.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_version.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/anthropic_types.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/list_sessions.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/mcp_utils.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/agents.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/base.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/control.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/hooks.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/input_types.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/mcp.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/messages.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/output_types.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/sandbox.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/server_info.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/ts_output_types.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/py.typed +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/query.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/session.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/ARCHITECTURE.md +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/__init__.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/helpers.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/models.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/replay.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/usage.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/conftest.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/__init__.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_agents_and_settings.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_dynamic_control.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_hook_events.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_hooks.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_include_partial_messages.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_mcp_tools.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_sdk_mcp_tools.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_slash_commands.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_stderr_callback.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_structured_output.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_subagent_invocation.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_tool_permissions.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/mcp_server.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/mock_claude_server.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_changelog.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_client.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_errors.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_image.png +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_integration.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_message_parser.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_sdk_mcp_integration.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_streaming_client.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_subprocess_buffering.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_tool_callbacks.py +0 -0
- {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_transport.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clawd-code-sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python SDK for Claude Code
|
|
5
5
|
Project-URL: Documentation, https://github.com/phil65/claude-agent-sdk-python
|
|
6
6
|
Project-URL: Homepage, https://github.com/phil65/claude-agent-sdk-python
|
|
@@ -28,6 +28,7 @@ from .models import (
|
|
|
28
28
|
BaseHookInput,
|
|
29
29
|
CanUseTool,
|
|
30
30
|
ClaudeAgentOptions,
|
|
31
|
+
OnUserQuestion,
|
|
31
32
|
ContentBlock,
|
|
32
33
|
HookCallback,
|
|
33
34
|
HookContext,
|
|
@@ -141,6 +142,7 @@ __all__ = [
|
|
|
141
142
|
"ContentBlock",
|
|
142
143
|
# Tool callbacks
|
|
143
144
|
"CanUseTool",
|
|
145
|
+
"OnUserQuestion",
|
|
144
146
|
"ToolPermissionContext",
|
|
145
147
|
"PermissionResult",
|
|
146
148
|
"PermissionResultAllow",
|
|
@@ -44,9 +44,10 @@ if TYPE_CHECKING:
|
|
|
44
44
|
from clawd_code_sdk.models import ControlRequestUnion, PermissionMode
|
|
45
45
|
from clawd_code_sdk.models.agents import AgentDefinition
|
|
46
46
|
from clawd_code_sdk.models.hooks import HookEvent, HookMatcher
|
|
47
|
+
from clawd_code_sdk.models.input_types import AskUserQuestionInput
|
|
47
48
|
from clawd_code_sdk.models.mcp import JSONRPCMessage, JSONRPCResponse, RequestId
|
|
48
49
|
from clawd_code_sdk.models.messages import UserPromptMessage
|
|
49
|
-
from clawd_code_sdk.models.permissions import CanUseTool, PermissionResult
|
|
50
|
+
from clawd_code_sdk.models.permissions import CanUseTool, OnUserQuestion, PermissionResult
|
|
50
51
|
|
|
51
52
|
logger = logging.getLogger(__name__)
|
|
52
53
|
|
|
@@ -93,6 +94,7 @@ class Query:
|
|
|
93
94
|
self,
|
|
94
95
|
transport: Transport,
|
|
95
96
|
can_use_tool: CanUseTool | None = None,
|
|
97
|
+
on_user_question: OnUserQuestion | None = None,
|
|
96
98
|
hooks: dict[HookEvent, list[HookMatcher]] | None = None,
|
|
97
99
|
sdk_mcp_servers: dict[str, McpServer] | None = None,
|
|
98
100
|
initialize_timeout: float = 60.0,
|
|
@@ -107,6 +109,7 @@ class Query:
|
|
|
107
109
|
Args:
|
|
108
110
|
transport: Low-level transport for I/O
|
|
109
111
|
can_use_tool: Optional callback for tool permission requests
|
|
112
|
+
on_user_question: Optional callback for AskUserQuestion elicitation
|
|
110
113
|
hooks: Optional hook configurations
|
|
111
114
|
sdk_mcp_servers: Optional SDK MCP server instances
|
|
112
115
|
initialize_timeout: Timeout in seconds for the initialize request
|
|
@@ -119,6 +122,7 @@ class Query:
|
|
|
119
122
|
self._initialize_timeout = initialize_timeout
|
|
120
123
|
self.transport = transport
|
|
121
124
|
self.can_use_tool = can_use_tool
|
|
125
|
+
self.on_user_question = on_user_question
|
|
122
126
|
self.hooks = convert_hooks_to_internal_format(hooks) if hooks else {}
|
|
123
127
|
self.sdk_mcp_servers = sdk_mcp_servers or {}
|
|
124
128
|
self._agents = {name: agent_def.to_dict() for name, agent_def in (agents or {}).items()}
|
|
@@ -317,16 +321,28 @@ class Query:
|
|
|
317
321
|
async def _handle_permission_request(
|
|
318
322
|
self, req: SDKControlPermissionRequest
|
|
319
323
|
) -> PermissionResult:
|
|
320
|
-
"""Handle a tool permission request.
|
|
321
|
-
if not self.can_use_tool:
|
|
322
|
-
raise RuntimeError("canUseTool callback is not provided")
|
|
324
|
+
"""Handle a tool permission request.
|
|
323
325
|
|
|
326
|
+
Dispatches AskUserQuestion to on_user_question if set,
|
|
327
|
+
otherwise falls through to can_use_tool for backwards compatibility.
|
|
328
|
+
"""
|
|
324
329
|
context = ToolPermissionContext(
|
|
325
330
|
tool_use_id=req.tool_use_id,
|
|
326
331
|
suggestions=req.permission_suggestions or [],
|
|
327
332
|
blocked_path=req.blocked_path,
|
|
328
333
|
)
|
|
329
334
|
|
|
335
|
+
# Dispatch elicitation requests to dedicated callback if available
|
|
336
|
+
if req.tool_name == "AskUserQuestion" and self.on_user_question:
|
|
337
|
+
input_data: AskUserQuestionInput = req.input # type: ignore[assignment]
|
|
338
|
+
result = await self.on_user_question(input_data, context)
|
|
339
|
+
if isinstance(result, PermissionResultAllow) and result.updated_input is None:
|
|
340
|
+
result.updated_input = req.input
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
if not self.can_use_tool:
|
|
344
|
+
raise RuntimeError("canUseTool callback is not provided")
|
|
345
|
+
|
|
330
346
|
result = await self.can_use_tool(req.tool_name, req.input, context)
|
|
331
347
|
if isinstance(result, PermissionResultAllow) and result.updated_input is None:
|
|
332
348
|
result.updated_input = req.input
|
|
@@ -141,6 +141,7 @@ class ClaudeSDKClient:
|
|
|
141
141
|
self._query = Query(
|
|
142
142
|
transport=self._transport,
|
|
143
143
|
can_use_tool=self.options.can_use_tool,
|
|
144
|
+
on_user_question=self.options.on_user_question,
|
|
144
145
|
hooks=self.options.hooks,
|
|
145
146
|
sdk_mcp_servers=sdk_mcp_servers,
|
|
146
147
|
initialize_timeout=initialize_timeout,
|
|
@@ -244,6 +244,7 @@ from .options import (
|
|
|
244
244
|
)
|
|
245
245
|
from .permissions import (
|
|
246
246
|
CanUseTool,
|
|
247
|
+
OnUserQuestion,
|
|
247
248
|
PermissionResult,
|
|
248
249
|
PermissionResultAllow,
|
|
249
250
|
PermissionResultDeny,
|
|
@@ -272,6 +273,7 @@ __all__ = [
|
|
|
272
273
|
"ToolsPreset",
|
|
273
274
|
# permissions
|
|
274
275
|
"CanUseTool",
|
|
276
|
+
"OnUserQuestion",
|
|
275
277
|
"PermissionBehavior",
|
|
276
278
|
"PermissionResult",
|
|
277
279
|
"PermissionResultAllow",
|
|
@@ -17,24 +17,24 @@ if TYPE_CHECKING:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
# Content block types
|
|
20
|
-
@dataclass
|
|
20
|
+
@dataclass(kw_only=True)
|
|
21
21
|
class TextBlock:
|
|
22
22
|
"""Text content block."""
|
|
23
23
|
|
|
24
24
|
type: Literal["text"] = field(default="text", repr=False)
|
|
25
|
-
text: str
|
|
25
|
+
text: str
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
@dataclass
|
|
28
|
+
@dataclass(kw_only=True)
|
|
29
29
|
class ThinkingBlock:
|
|
30
30
|
"""Thinking content block."""
|
|
31
31
|
|
|
32
32
|
type: Literal["thinking"] = field(default="thinking", repr=False)
|
|
33
|
-
thinking: str
|
|
34
|
-
signature: str
|
|
33
|
+
thinking: str
|
|
34
|
+
signature: str
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
@dataclass
|
|
37
|
+
@dataclass(kw_only=True)
|
|
38
38
|
class ToolUseBlock:
|
|
39
39
|
"""Tool use content block."""
|
|
40
40
|
|
|
@@ -45,7 +45,7 @@ class ToolUseBlock:
|
|
|
45
45
|
caller: dict[str, str] | None = None
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
@dataclass
|
|
48
|
+
@dataclass(kw_only=True)
|
|
49
49
|
class ToolResultBlock:
|
|
50
50
|
"""Tool result content block."""
|
|
51
51
|
|
|
@@ -13,6 +13,7 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from collections.abc import Callable
|
|
14
14
|
|
|
15
15
|
from clawd_code_sdk.models.base import ModelName
|
|
16
|
+
from clawd_code_sdk.models.permissions import OnUserQuestion
|
|
16
17
|
|
|
17
18
|
from .agents import AgentDefinition, SystemPromptPreset, ToolsPreset
|
|
18
19
|
from .base import PermissionMode, ReasoningEffort, SettingSource, ThinkingConfig
|
|
@@ -155,6 +156,13 @@ class ClaudeAgentOptions:
|
|
|
155
156
|
"""MCP tool to handle permission prompts."""
|
|
156
157
|
can_use_tool: CanUseTool | None = None
|
|
157
158
|
"""Tool permission callback."""
|
|
159
|
+
on_user_question: OnUserQuestion | None = None
|
|
160
|
+
"""Callback for handling AskUserQuestion elicitation requests.
|
|
161
|
+
|
|
162
|
+
Called when Claude asks the user a clarifying question via the
|
|
163
|
+
AskUserQuestion tool. If not set, these requests fall through
|
|
164
|
+
to can_use_tool (if set) for backwards compatibility.
|
|
165
|
+
"""
|
|
158
166
|
# Session
|
|
159
167
|
session: str | SessionConfig | None = None
|
|
160
168
|
"""Session configuration.
|
|
@@ -6,12 +6,12 @@ from collections.abc import Awaitable, Callable
|
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from typing import Any, Literal
|
|
8
8
|
|
|
9
|
-
from clawd_code_sdk.models import ToolInput
|
|
10
9
|
from clawd_code_sdk.models.base import (
|
|
11
10
|
ClaudeCodeBaseModel,
|
|
12
11
|
PermissionBehavior, # noqa: TC001
|
|
13
12
|
PermissionMode, # noqa: TC001
|
|
14
13
|
)
|
|
14
|
+
from clawd_code_sdk.models.input_types import AskUserQuestionInput, ToolInput
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
# Permission Update types (matching TypeScript SDK)
|
|
@@ -107,3 +107,13 @@ PermissionResult = PermissionResultAllow | PermissionResultDeny
|
|
|
107
107
|
CanUseTool = Callable[
|
|
108
108
|
[str, ToolInput | dict[str, Any], ToolPermissionContext], Awaitable[PermissionResult]
|
|
109
109
|
]
|
|
110
|
+
|
|
111
|
+
OnUserQuestion = Callable[
|
|
112
|
+
[AskUserQuestionInput, ToolPermissionContext], Awaitable[PermissionResult]
|
|
113
|
+
]
|
|
114
|
+
"""Callback for handling AskUserQuestion elicitation requests.
|
|
115
|
+
|
|
116
|
+
Called when Claude asks the user a clarifying question.
|
|
117
|
+
The callback should return a PermissionResultAllow with updated_input
|
|
118
|
+
containing the answers, or a PermissionResultDeny to cancel.
|
|
119
|
+
"""
|
|
@@ -89,7 +89,7 @@ TOOL_USE_MSG = {
|
|
|
89
89
|
"type": "tool_use",
|
|
90
90
|
"id": "tool-123",
|
|
91
91
|
"name": "Read",
|
|
92
|
-
"input": {"
|
|
92
|
+
"input": {"file_path": "/tmp/test.py"},
|
|
93
93
|
},
|
|
94
94
|
],
|
|
95
95
|
model="claude-sonnet-4-5-20250514",
|
|
@@ -260,7 +260,7 @@ class TestSession:
|
|
|
260
260
|
tc = turn.tool_calls[0]
|
|
261
261
|
assert tc.tool_use_id == "tool-123"
|
|
262
262
|
assert tc.tool_name == "Read"
|
|
263
|
-
assert tc.input == {"
|
|
263
|
+
assert tc.input == {"file_path": "/tmp/test.py"}
|
|
264
264
|
|
|
265
265
|
anyio.run(_test)
|
|
266
266
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/message_parser.py
RENAMED
|
File without changes
|
{clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/transport/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|