claude-agent-sdk 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

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.

Potentially problematic release.


This version of claude-agent-sdk might be problematic. Click here for more details.

@@ -23,6 +23,7 @@ from .types import (
23
23
  ContentBlock,
24
24
  HookCallback,
25
25
  HookContext,
26
+ HookJSONOutput,
26
27
  HookMatcher,
27
28
  McpSdkServerConfig,
28
29
  McpServerConfig,
@@ -308,6 +309,7 @@ __all__ = [
308
309
  "PermissionUpdate",
309
310
  "HookCallback",
310
311
  "HookContext",
312
+ "HookJSONOutput",
311
313
  "HookMatcher",
312
314
  # Agent support
313
315
  "AgentDefinition",
@@ -195,6 +195,7 @@ class Query:
195
195
 
196
196
  if subtype == "can_use_tool":
197
197
  permission_request: SDKControlPermissionRequest = request_data # type: ignore[assignment]
198
+ original_input = permission_request["input"]
198
199
  # Handle tool permission request
199
200
  if not self.can_use_tool:
200
201
  raise Exception("canUseTool callback is not provided")
@@ -213,13 +214,23 @@ class Query:
213
214
 
214
215
  # Convert PermissionResult to expected dict format
215
216
  if isinstance(response, PermissionResultAllow):
216
- response_data = {"allow": True}
217
- if response.updated_input is not None:
218
- response_data["input"] = response.updated_input
219
- # TODO: Handle updatedPermissions when control protocol supports it
217
+ response_data = {
218
+ "behavior": "allow",
219
+ "updatedInput": (
220
+ response.updated_input
221
+ if response.updated_input is not None
222
+ else original_input
223
+ ),
224
+ }
225
+ if response.updated_permissions is not None:
226
+ response_data["updatedPermissions"] = [
227
+ permission.to_dict()
228
+ for permission in response.updated_permissions
229
+ ]
220
230
  elif isinstance(response, PermissionResultDeny):
221
- response_data = {"allow": False, "reason": response.message}
222
- # TODO: Handle interrupt flag when control protocol supports it
231
+ response_data = {"behavior": "deny", "message": response.message}
232
+ if response.interrupt:
233
+ response_data["interrupt"] = response.interrupt
223
234
  else:
224
235
  raise TypeError(
225
236
  f"Tool permission callback must return PermissionResult (PermissionResultAllow or PermissionResultDeny), got {type(response)}"
@@ -3,7 +3,9 @@
3
3
  import json
4
4
  import logging
5
5
  import os
6
+ import re
6
7
  import shutil
8
+ import sys
7
9
  from collections.abc import AsyncIterable, AsyncIterator
8
10
  from contextlib import suppress
9
11
  from dataclasses import asdict
@@ -25,6 +27,7 @@ from . import Transport
25
27
  logger = logging.getLogger(__name__)
26
28
 
27
29
  _DEFAULT_MAX_BUFFER_SIZE = 1024 * 1024 # 1MB buffer limit
30
+ MINIMUM_CLAUDE_CODE_VERSION = "2.0.0"
28
31
 
29
32
 
30
33
  class SubprocessCLITransport(Transport):
@@ -202,6 +205,8 @@ class SubprocessCLITransport(Transport):
202
205
  if self._process:
203
206
  return
204
207
 
208
+ await self._check_claude_version()
209
+
205
210
  cmd = self._build_command()
206
211
  try:
207
212
  # Merge environment variables: system -> user -> SDK required
@@ -448,6 +453,46 @@ class SubprocessCLITransport(Transport):
448
453
  )
449
454
  raise self._exit_error
450
455
 
456
+ async def _check_claude_version(self) -> None:
457
+ """Check Claude Code version and warn if below minimum."""
458
+ version_process = None
459
+ try:
460
+ with anyio.fail_after(2): # 2 second timeout
461
+ version_process = await anyio.open_process(
462
+ [self._cli_path, "-v"],
463
+ stdout=PIPE,
464
+ stderr=PIPE,
465
+ )
466
+
467
+ if version_process.stdout:
468
+ stdout_bytes = await version_process.stdout.receive()
469
+ version_output = stdout_bytes.decode().strip()
470
+
471
+ match = re.match(r"([0-9]+\.[0-9]+\.[0-9]+)", version_output)
472
+ if match:
473
+ version = match.group(1)
474
+ version_parts = [int(x) for x in version.split(".")]
475
+ min_parts = [
476
+ int(x) for x in MINIMUM_CLAUDE_CODE_VERSION.split(".")
477
+ ]
478
+
479
+ if version_parts < min_parts:
480
+ warning = (
481
+ f"Warning: Claude Code version {version} is unsupported in the Agent SDK. "
482
+ f"Minimum required version is {MINIMUM_CLAUDE_CODE_VERSION}. "
483
+ "Some features may not work correctly."
484
+ )
485
+ logger.warning(warning)
486
+ print(warning, file=sys.stderr)
487
+ except Exception:
488
+ pass
489
+ finally:
490
+ if version_process:
491
+ with suppress(Exception):
492
+ version_process.terminate()
493
+ with suppress(Exception):
494
+ await version_process.wait()
495
+
451
496
  def is_ready(self) -> bool:
452
497
  """Check if transport is ready for communication."""
453
498
  return self._ready
@@ -1,3 +1,3 @@
1
1
  """Version information for claude-agent-sdk."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.1.2"
@@ -6,6 +6,7 @@ from collections.abc import AsyncIterable, AsyncIterator
6
6
  from dataclasses import replace
7
7
  from typing import Any
8
8
 
9
+ from . import Transport
9
10
  from ._errors import CLIConnectionError
10
11
  from .types import ClaudeAgentOptions, HookEvent, HookMatcher, Message, ResultMessage
11
12
 
@@ -51,12 +52,17 @@ class ClaudeSDKClient:
51
52
  exist.
52
53
  """
53
54
 
54
- def __init__(self, options: ClaudeAgentOptions | None = None):
55
+ def __init__(
56
+ self,
57
+ options: ClaudeAgentOptions | None = None,
58
+ transport: Transport | None = None,
59
+ ):
55
60
  """Initialize Claude SDK client."""
56
61
  if options is None:
57
62
  options = ClaudeAgentOptions()
58
63
  self.options = options
59
- self._transport: Any | None = None
64
+ self._custom_transport = transport
65
+ self._transport: Transport | None = None
60
66
  self._query: Any | None = None
61
67
  os.environ["CLAUDE_CODE_ENTRYPOINT"] = "sdk-py-client"
62
68
 
@@ -115,10 +121,14 @@ class ClaudeSDKClient:
115
121
  else:
116
122
  options = self.options
117
123
 
118
- self._transport = SubprocessCLITransport(
119
- prompt=actual_prompt,
120
- options=options,
121
- )
124
+ # Use provided custom transport or create subprocess transport
125
+ if self._custom_transport:
126
+ self._transport = self._custom_transport
127
+ else:
128
+ self._transport = SubprocessCLITransport(
129
+ prompt=actual_prompt,
130
+ options=options,
131
+ )
122
132
  await self._transport.connect()
123
133
 
124
134
  # Extract SDK MCP servers from options
@@ -222,7 +232,7 @@ class ClaudeSDKClient:
222
232
 
223
233
  Args:
224
234
  model: The model to use, or None to use default. Examples:
225
- - 'claude-sonnet-4-20250514'
235
+ - 'claude-sonnet-4-5'
226
236
  - 'claude-opus-4-1-20250805'
227
237
  - 'claude-opus-4-20250514'
228
238
 
@@ -233,7 +243,7 @@ class ClaudeSDKClient:
233
243
  await client.query("Help me understand this problem")
234
244
 
235
245
  # Switch to a different model for implementation
236
- await client.set_model('claude-3-5-sonnet-20241022')
246
+ await client.set_model('claude-sonnet-4-5')
237
247
  await client.query("Now implement the solution")
238
248
  ```
239
249
  """
claude_agent_sdk/types.py CHANGED
@@ -70,6 +70,42 @@ class PermissionUpdate:
70
70
  directories: list[str] | None = None
71
71
  destination: PermissionUpdateDestination | None = None
72
72
 
73
+ def to_dict(self) -> dict[str, Any]:
74
+ """Convert PermissionUpdate to dictionary format matching TypeScript control protocol."""
75
+ result: dict[str, Any] = {
76
+ "type": self.type,
77
+ }
78
+
79
+ # Add destination for all variants
80
+ if self.destination is not None:
81
+ result["destination"] = self.destination
82
+
83
+ # Handle different type variants
84
+ if self.type in ["addRules", "replaceRules", "removeRules"]:
85
+ # Rules-based variants require rules and behavior
86
+ if self.rules is not None:
87
+ result["rules"] = [
88
+ {
89
+ "toolName": rule.tool_name,
90
+ "ruleContent": rule.rule_content,
91
+ }
92
+ for rule in self.rules
93
+ ]
94
+ if self.behavior is not None:
95
+ result["behavior"] = self.behavior
96
+
97
+ elif self.type == "setMode":
98
+ # Mode variant requires mode
99
+ if self.mode is not None:
100
+ result["mode"] = self.mode
101
+
102
+ elif self.type in ["addDirectories", "removeDirectories"]:
103
+ # Directory variants require directories
104
+ if self.directories is not None:
105
+ result["directories"] = self.directories
106
+
107
+ return result
108
+
73
109
 
74
110
  # Tool callback types
75
111
  @dataclass
@@ -121,18 +157,74 @@ HookEvent = (
121
157
  )
122
158
 
123
159
 
160
+ # Hook-specific output types
161
+ class PreToolUseHookSpecificOutput(TypedDict):
162
+ """Hook-specific output for PreToolUse events."""
163
+
164
+ hookEventName: Literal["PreToolUse"]
165
+ permissionDecision: NotRequired[Literal["allow", "deny", "ask"]]
166
+ permissionDecisionReason: NotRequired[str]
167
+ updatedInput: NotRequired[dict[str, Any]]
168
+
169
+
170
+ class PostToolUseHookSpecificOutput(TypedDict):
171
+ """Hook-specific output for PostToolUse events."""
172
+
173
+ hookEventName: Literal["PostToolUse"]
174
+ additionalContext: NotRequired[str]
175
+
176
+
177
+ class UserPromptSubmitHookSpecificOutput(TypedDict):
178
+ """Hook-specific output for UserPromptSubmit events."""
179
+
180
+ hookEventName: Literal["UserPromptSubmit"]
181
+ additionalContext: NotRequired[str]
182
+
183
+
184
+ class SessionStartHookSpecificOutput(TypedDict):
185
+ """Hook-specific output for SessionStart events."""
186
+
187
+ hookEventName: Literal["SessionStart"]
188
+ additionalContext: NotRequired[str]
189
+
190
+
191
+ HookSpecificOutput = (
192
+ PreToolUseHookSpecificOutput
193
+ | PostToolUseHookSpecificOutput
194
+ | UserPromptSubmitHookSpecificOutput
195
+ | SessionStartHookSpecificOutput
196
+ )
197
+
198
+
124
199
  # See https://docs.anthropic.com/en/docs/claude-code/hooks#advanced%3A-json-output
125
- # for documentation of the output types. Currently, "continue", "stopReason",
126
- # and "suppressOutput" are not supported in the Python SDK.
127
- class HookJSONOutput(TypedDict):
128
- # Whether to block the action related to the hook.
200
+ # for documentation of the output types.
201
+ class AsyncHookJSONOutput(TypedDict):
202
+ """Async hook output that defers hook execution."""
203
+
204
+ async_: Literal[True] # Using async_ to avoid Python keyword
205
+ asyncTimeout: NotRequired[int]
206
+
207
+
208
+ class SyncHookJSONOutput(TypedDict):
209
+ """Synchronous hook output with control and decision fields."""
210
+
211
+ # Common control fields
212
+ continue_: NotRequired[bool] # Using continue_ to avoid Python keyword
213
+ suppressOutput: NotRequired[bool]
214
+ stopReason: NotRequired[str]
215
+
216
+ # Decision fields
217
+ # Note: "approve" is deprecated for PreToolUse (use permissionDecision instead)
218
+ # For other hooks, only "block" is meaningful
129
219
  decision: NotRequired[Literal["block"]]
130
- # Optionally add a system message that is not visible to Claude but saved in
131
- # the chat transcript.
132
220
  systemMessage: NotRequired[str]
133
- # See each hook's individual "Decision Control" section in the documentation
134
- # for guidance.
135
- hookSpecificOutput: NotRequired[Any]
221
+ reason: NotRequired[str]
222
+
223
+ # Hook-specific outputs
224
+ hookSpecificOutput: NotRequired[HookSpecificOutput]
225
+
226
+
227
+ HookJSONOutput = AsyncHookJSONOutput | SyncHookJSONOutput
136
228
 
137
229
 
138
230
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-agent-sdk
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Python SDK for Claude Code
5
5
  Project-URL: Homepage, https://github.com/anthropics/claude-agent-sdk-python
6
6
  Project-URL: Documentation, https://docs.anthropic.com/en/docs/claude-code/sdk
@@ -43,8 +43,8 @@ pip install claude-agent-sdk
43
43
 
44
44
  **Prerequisites:**
45
45
  - Python 3.10+
46
- - Node.js
47
- - Claude Code: `npm install -g @anthropic-ai/claude-code`
46
+ - Node.js
47
+ - Claude Code 2.0.0+: `npm install -g @anthropic-ai/claude-code`
48
48
 
49
49
  ## Quick Start
50
50
 
@@ -92,7 +92,7 @@ options = ClaudeAgentOptions(
92
92
  )
93
93
 
94
94
  async for message in query(
95
- prompt="Create a hello.py file",
95
+ prompt="Create a hello.py file",
96
96
  options=options
97
97
  ):
98
98
  # Process tool use and results
@@ -304,6 +304,15 @@ See [examples/quick_start.py](examples/quick_start.py) for a complete working ex
304
304
 
305
305
  See [examples/streaming_mode.py](examples/streaming_mode.py) for comprehensive examples involving `ClaudeSDKClient`. You can even run interactive examples in IPython from [examples/streaming_mode_ipython.py](examples/streaming_mode_ipython.py).
306
306
 
307
+ ## Migrating from Claude Code SDK
308
+
309
+ If you're upgrading from the Claude Code SDK (versions < 0.1.0), please see the [CHANGELOG.md](CHANGELOG.md#010) for details on breaking changes and new features, including:
310
+
311
+ - `ClaudeCodeOptions` → `ClaudeAgentOptions` rename
312
+ - Merged system prompt configuration
313
+ - Settings isolation and explicit control
314
+ - New programmatic subagents and session forking features
315
+
307
316
  ## License
308
317
 
309
318
  MIT
@@ -0,0 +1,17 @@
1
+ claude_agent_sdk/__init__.py,sha256=QRRGe-x2Hi5OhaWijWFmkdNj8KGTCWZSLnY1joHxRvo,11626
2
+ claude_agent_sdk/_errors.py,sha256=nSdJNNeszvXG1PfnXd2sQpVNORqMct-MfPaiM3XeJL4,1579
3
+ claude_agent_sdk/_version.py,sha256=gH3XIeCoHbr7H3mMURVo0sN_jBTdSnmewcxVv7F24Kc,71
4
+ claude_agent_sdk/client.py,sha256=Bye3QKb-iTg6Yq34ZPGHzaMg1isT9RvyHs5TkC2jWDI,13926
5
+ claude_agent_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ claude_agent_sdk/query.py,sha256=WebhztsMZPdaxyy1LBEZv4_j23vjp_ceX9DtrBsZqCA,4530
7
+ claude_agent_sdk/types.py,sha256=x_0tT1ZfisSUrcMdyWRIrrPNe1gWW1zU-T8onoMauxY,13308
8
+ claude_agent_sdk/_internal/__init__.py,sha256=zDdgjqp8SI9mTnwZbP2Be-w4LWlv4a3kA-TS2i75jsM,39
9
+ claude_agent_sdk/_internal/client.py,sha256=Z06Fj4t5mHkKHKBUwxmHMTEo7lzs3X4_D_c-xq6Wg4I,4603
10
+ claude_agent_sdk/_internal/message_parser.py,sha256=xxpOU3E8X21FCoy2OtLWKfEQr3AFYM454qJt6Xa0tmc,6475
11
+ claude_agent_sdk/_internal/query.py,sha256=miJS8pS215PFXirmdfgS2D5FFz4G9Dk25IHyeXUPeqQ,21165
12
+ claude_agent_sdk/_internal/transport/__init__.py,sha256=sv8Iy1b9YmPlXu4XsdN98gJIlyrLtwq8PKQyF4qnQLk,1978
13
+ claude_agent_sdk/_internal/transport/subprocess_cli.py,sha256=ViZxmHoAx3NdFNgLUFgNYuCjJZdVqKk2sxHlB57Z2ng,19097
14
+ claude_agent_sdk-0.1.2.dist-info/METADATA,sha256=ZcJHSdWOTUETMnexdpm_QhqiyZfJP8nSj3XnIKDJ7D0,9648
15
+ claude_agent_sdk-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ claude_agent_sdk-0.1.2.dist-info/licenses/LICENSE,sha256=zr3eio-57lnl6q7RlXi_gIWqcEdWIlnDHzjyJcJvaBI,1070
17
+ claude_agent_sdk-0.1.2.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- claude_agent_sdk/__init__.py,sha256=ZwJ2YpPdvDRdg1j73TGmK5FEfriv00MbgB5GbEkgqEs,11584
2
- claude_agent_sdk/_errors.py,sha256=nSdJNNeszvXG1PfnXd2sQpVNORqMct-MfPaiM3XeJL4,1579
3
- claude_agent_sdk/_version.py,sha256=y3fGkmFOHX0HMqiV3jjJZcCsNcfH9UfbiJ_Kp0cc-Eo,71
4
- claude_agent_sdk/client.py,sha256=je82F2J_BtB9Gh4PRUcjeTI1wrYVENMsAasOaUkO-3Y,13613
5
- claude_agent_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- claude_agent_sdk/query.py,sha256=WebhztsMZPdaxyy1LBEZv4_j23vjp_ceX9DtrBsZqCA,4530
7
- claude_agent_sdk/types.py,sha256=xYpyg3_nTXAHclsitZI7wr2pLbbjWTwJ5gPYrBOwjaQ,10525
8
- claude_agent_sdk/_internal/__init__.py,sha256=zDdgjqp8SI9mTnwZbP2Be-w4LWlv4a3kA-TS2i75jsM,39
9
- claude_agent_sdk/_internal/client.py,sha256=Z06Fj4t5mHkKHKBUwxmHMTEo7lzs3X4_D_c-xq6Wg4I,4603
10
- claude_agent_sdk/_internal/message_parser.py,sha256=xxpOU3E8X21FCoy2OtLWKfEQr3AFYM454qJt6Xa0tmc,6475
11
- claude_agent_sdk/_internal/query.py,sha256=G2CxNrMhrmae2V9oh8ctJsWIFOCU2VEkBQvH1-nXC6w,20721
12
- claude_agent_sdk/_internal/transport/__init__.py,sha256=sv8Iy1b9YmPlXu4XsdN98gJIlyrLtwq8PKQyF4qnQLk,1978
13
- claude_agent_sdk/_internal/transport/subprocess_cli.py,sha256=-0SeZihO871cS10GmK7QDjrrbBHK_COFvbWGL25_0pY,17229
14
- claude_agent_sdk-0.1.0.dist-info/METADATA,sha256=O8QGZfCu-C7SzZAAgjdFQwgKkjB_Tx0LviP0Cdt1KuA,9241
15
- claude_agent_sdk-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- claude_agent_sdk-0.1.0.dist-info/licenses/LICENSE,sha256=zr3eio-57lnl6q7RlXi_gIWqcEdWIlnDHzjyJcJvaBI,1070
17
- claude_agent_sdk-0.1.0.dist-info/RECORD,,