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.
Files changed (70) hide show
  1. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/PKG-INFO +1 -1
  2. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/pyproject.toml +1 -1
  3. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/__init__.py +2 -0
  4. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/query.py +20 -4
  5. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/client.py +1 -0
  6. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/__init__.py +2 -0
  7. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/content_blocks.py +7 -7
  8. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/options.py +8 -0
  9. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/permissions.py +11 -1
  10. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_session.py +2 -2
  11. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/.gitignore +0 -0
  12. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/LICENSE +0 -0
  13. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/README.md +0 -0
  14. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_bundled/.gitignore +0 -0
  15. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_errors.py +0 -0
  16. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/__init__.py +0 -0
  17. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/message_parser.py +0 -0
  18. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/transport/__init__.py +0 -0
  19. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_internal/transport/subprocess_cli.py +0 -0
  20. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/_version.py +0 -0
  21. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/anthropic_types.py +0 -0
  22. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/list_sessions.py +0 -0
  23. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/mcp_utils.py +0 -0
  24. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/agents.py +0 -0
  25. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/base.py +0 -0
  26. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/control.py +0 -0
  27. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/hooks.py +0 -0
  28. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/input_types.py +0 -0
  29. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/mcp.py +0 -0
  30. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/messages.py +0 -0
  31. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/output_types.py +0 -0
  32. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/sandbox.py +0 -0
  33. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/server_info.py +0 -0
  34. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/models/ts_output_types.py +0 -0
  35. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/py.typed +0 -0
  36. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/query.py +0 -0
  37. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/session.py +0 -0
  38. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/ARCHITECTURE.md +0 -0
  39. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/__init__.py +0 -0
  40. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/helpers.py +0 -0
  41. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/models.py +0 -0
  42. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/storage/replay.py +0 -0
  43. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/src/clawd_code_sdk/usage.py +0 -0
  44. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/conftest.py +0 -0
  45. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/__init__.py +0 -0
  46. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_agents_and_settings.py +0 -0
  47. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_dynamic_control.py +0 -0
  48. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_hook_events.py +0 -0
  49. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_hooks.py +0 -0
  50. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_include_partial_messages.py +0 -0
  51. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_mcp_tools.py +0 -0
  52. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_sdk_mcp_tools.py +0 -0
  53. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_slash_commands.py +0 -0
  54. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_stderr_callback.py +0 -0
  55. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_structured_output.py +0 -0
  56. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_subagent_invocation.py +0 -0
  57. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/e2e/test_tool_permissions.py +0 -0
  58. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/mcp_server.py +0 -0
  59. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/mock_claude_server.py +0 -0
  60. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_changelog.py +0 -0
  61. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_client.py +0 -0
  62. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_errors.py +0 -0
  63. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_image.png +0 -0
  64. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_integration.py +0 -0
  65. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_message_parser.py +0 -0
  66. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_sdk_mcp_integration.py +0 -0
  67. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_streaming_client.py +0 -0
  68. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_subprocess_buffering.py +0 -0
  69. {clawd_code_sdk-0.3.1 → clawd_code_sdk-0.3.2}/tests/test_tool_callbacks.py +0 -0
  70. {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.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "clawd-code-sdk"
3
- version = "0.3.1"
3
+ version = "0.3.2"
4
4
  description = "Python SDK for Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -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": {"path": "/tmp/test.py"},
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 == {"path": "/tmp/test.py"}
263
+ assert tc.input == {"file_path": "/tmp/test.py"}
264
264
 
265
265
  anyio.run(_test)
266
266
 
File without changes
File without changes