claude-agent-sdk 0.1.2__py3-none-any.whl → 0.1.4__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.

@@ -18,11 +18,13 @@ from .query import query
18
18
  from .types import (
19
19
  AgentDefinition,
20
20
  AssistantMessage,
21
+ BaseHookInput,
21
22
  CanUseTool,
22
23
  ClaudeAgentOptions,
23
24
  ContentBlock,
24
25
  HookCallback,
25
26
  HookContext,
27
+ HookInput,
26
28
  HookJSONOutput,
27
29
  HookMatcher,
28
30
  McpSdkServerConfig,
@@ -33,8 +35,13 @@ from .types import (
33
35
  PermissionResultAllow,
34
36
  PermissionResultDeny,
35
37
  PermissionUpdate,
38
+ PostToolUseHookInput,
39
+ PreCompactHookInput,
40
+ PreToolUseHookInput,
36
41
  ResultMessage,
37
42
  SettingSource,
43
+ StopHookInput,
44
+ SubagentStopHookInput,
38
45
  SystemMessage,
39
46
  TextBlock,
40
47
  ThinkingBlock,
@@ -42,6 +49,7 @@ from .types import (
42
49
  ToolResultBlock,
43
50
  ToolUseBlock,
44
51
  UserMessage,
52
+ UserPromptSubmitHookInput,
45
53
  )
46
54
 
47
55
  # MCP Server Support
@@ -195,7 +203,7 @@ def create_sdk_mcp_server(
195
203
  - ClaudeAgentOptions: Configuration for using servers with query()
196
204
  """
197
205
  from mcp.server import Server
198
- from mcp.types import TextContent, Tool
206
+ from mcp.types import ImageContent, TextContent, Tool
199
207
 
200
208
  # Create MCP server instance
201
209
  server = Server(name, version=version)
@@ -265,11 +273,19 @@ def create_sdk_mcp_server(
265
273
  # Convert result to MCP format
266
274
  # The decorator expects us to return the content, not a CallToolResult
267
275
  # It will wrap our return value in CallToolResult
268
- content = []
276
+ content: list[TextContent | ImageContent] = []
269
277
  if "content" in result:
270
278
  for item in result["content"]:
271
279
  if item.get("type") == "text":
272
280
  content.append(TextContent(type="text", text=item["text"]))
281
+ if item.get("type") == "image":
282
+ content.append(
283
+ ImageContent(
284
+ type="image",
285
+ data=item["data"],
286
+ mimeType=item["mimeType"],
287
+ )
288
+ )
273
289
 
274
290
  # Return just the content list - the decorator wraps it
275
291
  return content
@@ -307,8 +323,17 @@ __all__ = [
307
323
  "PermissionResultAllow",
308
324
  "PermissionResultDeny",
309
325
  "PermissionUpdate",
326
+ # Hook support
310
327
  "HookCallback",
311
328
  "HookContext",
329
+ "HookInput",
330
+ "BaseHookInput",
331
+ "PreToolUseHookInput",
332
+ "PostToolUseHookInput",
333
+ "UserPromptSubmitHookInput",
334
+ "StopHookInput",
335
+ "SubagentStopHookInput",
336
+ "PreCompactHookInput",
312
337
  "HookJSONOutput",
313
338
  "HookMatcher",
314
339
  # Agent support
@@ -71,7 +71,8 @@ class InternalClient:
71
71
  chosen_transport = transport
72
72
  else:
73
73
  chosen_transport = SubprocessCLITransport(
74
- prompt=prompt, options=configured_options
74
+ prompt=prompt,
75
+ options=configured_options,
75
76
  )
76
77
 
77
78
  # Connect transport
@@ -31,6 +31,25 @@ if TYPE_CHECKING:
31
31
  logger = logging.getLogger(__name__)
32
32
 
33
33
 
34
+ def _convert_hook_output_for_cli(hook_output: dict[str, Any]) -> dict[str, Any]:
35
+ """Convert Python-safe field names to CLI-expected field names.
36
+
37
+ The Python SDK uses `async_` and `continue_` to avoid keyword conflicts,
38
+ but the CLI expects `async` and `continue`. This function performs the
39
+ necessary conversion.
40
+ """
41
+ converted = {}
42
+ for key, value in hook_output.items():
43
+ # Convert Python-safe names to JavaScript names
44
+ if key == "async_":
45
+ converted["async"] = value
46
+ elif key == "continue_":
47
+ converted["continue"] = value
48
+ else:
49
+ converted[key] = value
50
+ return converted
51
+
52
+
34
53
  class Query:
35
54
  """Handles bidirectional control protocol on top of Transport.
36
55
 
@@ -244,11 +263,13 @@ class Query:
244
263
  if not callback:
245
264
  raise Exception(f"No hook callback found for ID: {callback_id}")
246
265
 
247
- response_data = await callback(
266
+ hook_output = await callback(
248
267
  request_data.get("input"),
249
268
  request_data.get("tool_use_id"),
250
269
  {"signal": None}, # TODO: Add abort signal support
251
270
  )
271
+ # Convert Python-safe field names (async_, continue_) to CLI-expected names (async, continue)
272
+ response_data = _convert_hook_output_for_cli(hook_output)
252
273
 
253
274
  elif subtype == "mcp_message":
254
275
  # Handle SDK MCP request
@@ -37,12 +37,13 @@ class SubprocessCLITransport(Transport):
37
37
  self,
38
38
  prompt: str | AsyncIterable[dict[str, Any]],
39
39
  options: ClaudeAgentOptions,
40
- cli_path: str | Path | None = None,
41
40
  ):
42
41
  self._prompt = prompt
43
42
  self._is_streaming = not isinstance(prompt, str)
44
43
  self._options = options
45
- self._cli_path = str(cli_path) if cli_path else self._find_cli()
44
+ self._cli_path = (
45
+ str(options.cli_path) if options.cli_path is not None else self._find_cli()
46
+ )
46
47
  self._cwd = str(options.cwd) if options.cwd else None
47
48
  self._process: Process | None = None
48
49
  self._stdout_stream: TextReceiveStream | None = None
@@ -79,8 +80,8 @@ class SubprocessCLITransport(Transport):
79
80
  " npm install -g @anthropic-ai/claude-code\n"
80
81
  "\nIf already installed locally, try:\n"
81
82
  ' export PATH="$HOME/node_modules/.bin:$PATH"\n'
82
- "\nOr specify the path when creating transport:\n"
83
- " SubprocessCLITransport(..., cli_path='/path/to/claude')"
83
+ "\nOr provide the path via ClaudeAgentOptions:\n"
84
+ " ClaudeAgentOptions(cli_path='/path/to/claude')"
84
85
  )
85
86
 
86
87
  def _build_command(self) -> list[str]:
@@ -205,7 +206,8 @@ class SubprocessCLITransport(Transport):
205
206
  if self._process:
206
207
  return
207
208
 
208
- await self._check_claude_version()
209
+ if not os.environ.get("CLAUDE_AGENT_SDK_SKIP_VERSION_CHECK"):
210
+ await self._check_claude_version()
209
211
 
210
212
  cmd = self._build_command()
211
213
  try:
@@ -1,3 +1,3 @@
1
1
  """Version information for claude-agent-sdk."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.4"
claude_agent_sdk/types.py CHANGED
@@ -157,6 +157,73 @@ HookEvent = (
157
157
  )
158
158
 
159
159
 
160
+ # Hook input types - strongly typed for each hook event
161
+ class BaseHookInput(TypedDict):
162
+ """Base hook input fields present across many hook events."""
163
+
164
+ session_id: str
165
+ transcript_path: str
166
+ cwd: str
167
+ permission_mode: NotRequired[str]
168
+
169
+
170
+ class PreToolUseHookInput(BaseHookInput):
171
+ """Input data for PreToolUse hook events."""
172
+
173
+ hook_event_name: Literal["PreToolUse"]
174
+ tool_name: str
175
+ tool_input: dict[str, Any]
176
+
177
+
178
+ class PostToolUseHookInput(BaseHookInput):
179
+ """Input data for PostToolUse hook events."""
180
+
181
+ hook_event_name: Literal["PostToolUse"]
182
+ tool_name: str
183
+ tool_input: dict[str, Any]
184
+ tool_response: Any
185
+
186
+
187
+ class UserPromptSubmitHookInput(BaseHookInput):
188
+ """Input data for UserPromptSubmit hook events."""
189
+
190
+ hook_event_name: Literal["UserPromptSubmit"]
191
+ prompt: str
192
+
193
+
194
+ class StopHookInput(BaseHookInput):
195
+ """Input data for Stop hook events."""
196
+
197
+ hook_event_name: Literal["Stop"]
198
+ stop_hook_active: bool
199
+
200
+
201
+ class SubagentStopHookInput(BaseHookInput):
202
+ """Input data for SubagentStop hook events."""
203
+
204
+ hook_event_name: Literal["SubagentStop"]
205
+ stop_hook_active: bool
206
+
207
+
208
+ class PreCompactHookInput(BaseHookInput):
209
+ """Input data for PreCompact hook events."""
210
+
211
+ hook_event_name: Literal["PreCompact"]
212
+ trigger: Literal["manual", "auto"]
213
+ custom_instructions: str | None
214
+
215
+
216
+ # Union type for all hook inputs
217
+ HookInput = (
218
+ PreToolUseHookInput
219
+ | PostToolUseHookInput
220
+ | UserPromptSubmitHookInput
221
+ | StopHookInput
222
+ | SubagentStopHookInput
223
+ | PreCompactHookInput
224
+ )
225
+
226
+
160
227
  # Hook-specific output types
161
228
  class PreToolUseHookSpecificOutput(TypedDict):
162
229
  """Hook-specific output for PreToolUse events."""
@@ -198,18 +265,56 @@ HookSpecificOutput = (
198
265
 
199
266
  # See https://docs.anthropic.com/en/docs/claude-code/hooks#advanced%3A-json-output
200
267
  # for documentation of the output types.
268
+ #
269
+ # IMPORTANT: The Python SDK uses `async_` and `continue_` (with underscores) to avoid
270
+ # Python keyword conflicts. These fields are automatically converted to `async` and
271
+ # `continue` when sent to the CLI. You should use the underscore versions in your
272
+ # Python code.
201
273
  class AsyncHookJSONOutput(TypedDict):
202
- """Async hook output that defers hook execution."""
274
+ """Async hook output that defers hook execution.
203
275
 
204
- async_: Literal[True] # Using async_ to avoid Python keyword
276
+ Fields:
277
+ async_: Set to True to defer hook execution. Note: This is converted to
278
+ "async" when sent to the CLI - use "async_" in your Python code.
279
+ asyncTimeout: Optional timeout in milliseconds for the async operation.
280
+ """
281
+
282
+ async_: Literal[
283
+ True
284
+ ] # Using async_ to avoid Python keyword (converted to "async" for CLI)
205
285
  asyncTimeout: NotRequired[int]
206
286
 
207
287
 
208
288
  class SyncHookJSONOutput(TypedDict):
209
- """Synchronous hook output with control and decision fields."""
289
+ """Synchronous hook output with control and decision fields.
290
+
291
+ This defines the structure for hook callbacks to control execution and provide
292
+ feedback to Claude.
293
+
294
+ Common Control Fields:
295
+ continue_: Whether Claude should proceed after hook execution (default: True).
296
+ Note: This is converted to "continue" when sent to the CLI.
297
+ suppressOutput: Hide stdout from transcript mode (default: False).
298
+ stopReason: Message shown when continue is False.
299
+
300
+ Decision Fields:
301
+ decision: Set to "block" to indicate blocking behavior.
302
+ systemMessage: Warning message displayed to the user.
303
+ reason: Feedback message for Claude about the decision.
304
+
305
+ Hook-Specific Output:
306
+ hookSpecificOutput: Event-specific controls (e.g., permissionDecision for
307
+ PreToolUse, additionalContext for PostToolUse).
308
+
309
+ Note: The CLI documentation shows field names without underscores ("async", "continue"),
310
+ but Python code should use the underscore versions ("async_", "continue_") as they
311
+ are automatically converted.
312
+ """
210
313
 
211
314
  # Common control fields
212
- continue_: NotRequired[bool] # Using continue_ to avoid Python keyword
315
+ continue_: NotRequired[
316
+ bool
317
+ ] # Using continue_ to avoid Python keyword (converted to "continue" for CLI)
213
318
  suppressOutput: NotRequired[bool]
214
319
  stopReason: NotRequired[str]
215
320
 
@@ -227,21 +332,22 @@ class SyncHookJSONOutput(TypedDict):
227
332
  HookJSONOutput = AsyncHookJSONOutput | SyncHookJSONOutput
228
333
 
229
334
 
230
- @dataclass
231
- class HookContext:
232
- """Context information for hook callbacks."""
335
+ class HookContext(TypedDict):
336
+ """Context information for hook callbacks.
233
337
 
234
- signal: Any | None = None # Future: abort signal support
338
+ Fields:
339
+ signal: Reserved for future abort signal support. Currently always None.
340
+ """
341
+
342
+ signal: Any | None # Future: abort signal support
235
343
 
236
344
 
237
345
  HookCallback = Callable[
238
346
  # HookCallback input parameters:
239
- # - input
240
- # See https://docs.anthropic.com/en/docs/claude-code/hooks#hook-input for
241
- # the type of 'input', the first value.
242
- # - tool_use_id
243
- # - context
244
- [dict[str, Any], str | None, HookContext],
347
+ # - input: Strongly-typed hook input with discriminated unions based on hook_event_name
348
+ # - tool_use_id: Optional tool use identifier
349
+ # - context: Hook context with abort signal support (currently placeholder)
350
+ [HookInput, str | None, HookContext],
245
351
  Awaitable[HookJSONOutput],
246
352
  ]
247
353
 
@@ -406,6 +512,7 @@ class ClaudeAgentOptions:
406
512
  model: str | None = None
407
513
  permission_prompt_tool_name: str | None = None
408
514
  cwd: str | Path | None = None
515
+ cli_path: str | Path | None = None
409
516
  settings: str | None = None
410
517
  add_dirs: list[str | Path] = field(default_factory=list)
411
518
  env: dict[str, str] = field(default_factory=dict)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-agent-sdk
3
- Version: 0.1.2
3
+ Version: 0.1.4
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
@@ -313,6 +313,16 @@ If you're upgrading from the Claude Code SDK (versions < 0.1.0), please see the
313
313
  - Settings isolation and explicit control
314
314
  - New programmatic subagents and session forking features
315
315
 
316
+ ## Development
317
+
318
+ If you're contributing to this project, run the initial setup script to install git hooks:
319
+
320
+ ```bash
321
+ ./scripts/initial-setup.sh
322
+ ```
323
+
324
+ This installs a pre-push hook that runs lint checks before pushing, matching the CI workflow. To skip the hook temporarily, use `git push --no-verify`.
325
+
316
326
  ## License
317
327
 
318
328
  MIT
@@ -0,0 +1,17 @@
1
+ claude_agent_sdk/__init__.py,sha256=6yJ1bjfcLc0oMo-EesY19-uSi-B5dBIZDrCYkwyegXs,12429
2
+ claude_agent_sdk/_errors.py,sha256=nSdJNNeszvXG1PfnXd2sQpVNORqMct-MfPaiM3XeJL4,1579
3
+ claude_agent_sdk/_version.py,sha256=8-5mrhPr_CAF6E5TLSV6Klk6VLu4QNMtphl-yDq8qCg,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=7rrnHBG7279wWPtor8b7vpIekSzZcUriSbvNBHXoAcE,16685
8
+ claude_agent_sdk/_internal/__init__.py,sha256=zDdgjqp8SI9mTnwZbP2Be-w4LWlv4a3kA-TS2i75jsM,39
9
+ claude_agent_sdk/_internal/client.py,sha256=ySaWYtZUrYMwN93r7qANaD-RGiFlkB49j0njQNVPHRM,4620
10
+ claude_agent_sdk/_internal/message_parser.py,sha256=xxpOU3E8X21FCoy2OtLWKfEQr3AFYM454qJt6Xa0tmc,6475
11
+ claude_agent_sdk/_internal/query.py,sha256=mfSiIfs58U1LYMnbj5GeLATvdI_cRVIxStV1He-cMTE,22015
12
+ claude_agent_sdk/_internal/transport/__init__.py,sha256=sv8Iy1b9YmPlXu4XsdN98gJIlyrLtwq8PKQyF4qnQLk,1978
13
+ claude_agent_sdk/_internal/transport/subprocess_cli.py,sha256=FaVKvXJ9hAbBG-aCnPwUkXxa096DEw_zjI38aiiDiaU,19169
14
+ claude_agent_sdk-0.1.4.dist-info/METADATA,sha256=YRlqbPASEmldUn9VotzoaiOc8fMyR4eOGvc7deGal-M,9949
15
+ claude_agent_sdk-0.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ claude_agent_sdk-0.1.4.dist-info/licenses/LICENSE,sha256=zr3eio-57lnl6q7RlXi_gIWqcEdWIlnDHzjyJcJvaBI,1070
17
+ claude_agent_sdk-0.1.4.dist-info/RECORD,,
@@ -1,17 +0,0 @@
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,,