From 15afcff04481762c09af4895dfb5133712a8c63b Mon Sep 17 00:00:00 2001 From: Kashyap Murali Date: Tue, 2 Sep 2025 16:17:00 -0700 Subject: [PATCH] fix: Remove duplicate get_server_info method and fix linting issues --- examples/streaming_mode_ipython.py | 17 +++++----- examples/tool_permission_callback.py | 51 ++++++++++++++-------------- src/claude_code_sdk/client.py | 25 -------------- 3 files changed, 34 insertions(+), 59 deletions(-) diff --git a/examples/streaming_mode_ipython.py b/examples/streaming_mode_ipython.py index 7265afa..27b9031 100644 --- a/examples/streaming_mode_ipython.py +++ b/examples/streaming_mode_ipython.py @@ -14,7 +14,7 @@ bash commands, edit files, search the web, fetch web content) to accomplish. # BASIC STREAMING # ============================================================================ -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, ResultMessage, TextBlock async with ClaudeSDKClient() as client: print("User: What is 2+2?") @@ -32,7 +32,8 @@ async with ClaudeSDKClient() as client: # ============================================================================ import asyncio -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock + +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock async with ClaudeSDKClient() as client: async def send_and_receive(prompt): @@ -53,7 +54,7 @@ async with ClaudeSDKClient() as client: # PERSISTENT CLIENT FOR MULTIPLE QUESTIONS # ============================================================================ -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock # Create client client = ClaudeSDKClient() @@ -88,8 +89,7 @@ await client.disconnect() # IMPORTANT: Interrupts require active message consumption. You must be # consuming messages from the client for the interrupt to be processed. -import asyncio -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock async with ClaudeSDKClient() as client: print("\n--- Sending initial message ---\n") @@ -141,7 +141,7 @@ async with ClaudeSDKClient() as client: # ERROR HANDLING PATTERN # ============================================================================ -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock try: async with ClaudeSDKClient() as client: @@ -168,7 +168,8 @@ except Exception as e: # SENDING ASYNC ITERABLE OF MESSAGES # ============================================================================ -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock + async def message_generator(): """Generate multiple messages as an async iterable.""" @@ -209,7 +210,7 @@ async with ClaudeSDKClient() as client: # COLLECTING ALL MESSAGES INTO A LIST # ============================================================================ -from claude_code_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage +from claude_code_sdk import AssistantMessage, ClaudeSDKClient, TextBlock async with ClaudeSDKClient() as client: print("User: What are the primary colors?") diff --git a/examples/tool_permission_callback.py b/examples/tool_permission_callback.py index a520755..8bcab46 100644 --- a/examples/tool_permission_callback.py +++ b/examples/tool_permission_callback.py @@ -7,18 +7,17 @@ which tools Claude can use and modify their inputs. import asyncio import json + from claude_code_sdk import ( + AssistantMessage, ClaudeCodeOptions, ClaudeSDKClient, - ToolPermissionCallback, - ToolPermissionResponse, - ToolPermissionContext, - TextBlock, - AssistantMessage, ResultMessage, + TextBlock, + ToolPermissionContext, + ToolPermissionResponse, ) - # Track tool usage for demonstration tool_usage_log = [] @@ -29,17 +28,17 @@ async def my_permission_callback( context: ToolPermissionContext ) -> ToolPermissionResponse: """Control tool permissions based on tool type and input.""" - + # Log the tool request tool_usage_log.append({ "tool": tool_name, "input": input_data, "suggestions": context.suggestions }) - + print(f"\nšŸ”§ Tool Permission Request: {tool_name}") print(f" Input: {json.dumps(input_data, indent=2)}") - + # Always allow read operations if tool_name in ["Read", "Glob", "Grep"]: print(f" āœ… Automatically allowing {tool_name} (read-only operation)") @@ -47,7 +46,7 @@ async def my_permission_callback( allow=True, reason="Read operations are always allowed" ) - + # Deny write operations to system directories if tool_name in ["Write", "Edit", "MultiEdit"]: file_path = input_data.get("file_path", "") @@ -57,7 +56,7 @@ async def my_permission_callback( allow=False, reason=f"Cannot write to system directory: {file_path}" ) - + # Redirect writes to a safe directory if not file_path.startswith("/tmp/") and not file_path.startswith("./"): safe_path = f"./safe_output/{file_path.split('/')[-1]}" @@ -69,12 +68,12 @@ async def my_permission_callback( input=modified_input, reason=f"Redirected to safe path: {safe_path}" ) - + # Check dangerous bash commands if tool_name == "Bash": command = input_data.get("command", "") dangerous_commands = ["rm -rf", "sudo", "chmod 777", "dd if=", "mkfs"] - + for dangerous in dangerous_commands: if dangerous in command: print(f" āŒ Denying dangerous command: {command}") @@ -82,19 +81,19 @@ async def my_permission_callback( allow=False, reason=f"Dangerous command pattern detected: {dangerous}" ) - + # Allow but log the command print(f" āœ… Allowing bash command: {command}") return ToolPermissionResponse( allow=True, reason="Command appears safe" ) - + # For all other tools, ask the user print(f" ā“ Unknown tool: {tool_name}") print(f" Input: {json.dumps(input_data, indent=6)}") user_input = input(" Allow this tool? (y/N): ").strip().lower() - + return ToolPermissionResponse( allow=user_input in ("y", "yes"), reason=f"User {'approved' if user_input in ('y', 'yes') else 'denied'}" @@ -103,7 +102,7 @@ async def my_permission_callback( async def main(): """Run example with tool permission callbacks.""" - + print("=" * 60) print("Tool Permission Callback Example") print("=" * 60) @@ -113,7 +112,7 @@ async def main(): print("3. Log tool usage") print("4. Prompt for unknown tools") print("=" * 60) - + # Configure options with our callback options = ClaudeCodeOptions( tool_permission_callback=my_permission_callback, @@ -121,7 +120,7 @@ async def main(): permission_mode="default", cwd="." # Set working directory ) - + # Create client and send a query that will use multiple tools async with ClaudeSDKClient(options) as client: print("\nšŸ“ Sending query to Claude...") @@ -131,26 +130,26 @@ async def main(): "2. Create a simple Python hello world script at hello.py\n" "3. Run the script to test it" ) - + print("\nšŸ“Ø Receiving response...") message_count = 0 - + async for message in client.receive_response(): message_count += 1 - + if isinstance(message, AssistantMessage): # Print Claude's text responses for block in message.content: if isinstance(block, TextBlock): print(f"\nšŸ’¬ Claude: {block.text}") - + elif isinstance(message, ResultMessage): - print(f"\nāœ… Task completed!") + print("\nāœ… Task completed!") print(f" Duration: {message.duration_ms}ms") if message.total_cost_usd: print(f" Cost: ${message.total_cost_usd:.4f}") print(f" Messages processed: {message_count}") - + # Print tool usage summary print("\n" + "=" * 60) print("Tool Usage Summary") @@ -163,4 +162,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/src/claude_code_sdk/client.py b/src/claude_code_sdk/client.py index bc865eb..201526e 100644 --- a/src/claude_code_sdk/client.py +++ b/src/claude_code_sdk/client.py @@ -201,31 +201,6 @@ class ClaudeSDKClient: if not self._query: raise CLIConnectionError("Not connected. Call connect() first.") await self._query.interrupt() - - async def get_server_info(self) -> dict[str, Any] | None: - """Get server initialization info including available commands and output styles. - - Returns initialization information from the Claude Code server including: - - Available commands (slash commands, system commands, etc.) - - Current and available output styles - - Server capabilities - - Returns: - Dictionary with server info, or None if not in streaming mode - - Example: - ```python - async with ClaudeSDKClient() as client: - info = await client.get_server_info() - if info: - print(f"Commands available: {len(info.get('commands', []))}") - print(f"Output style: {info.get('output_style', 'default')}") - ``` - """ - if not self._query: - raise CLIConnectionError("Not connected. Call connect() first.") - # Return the initialization result that was already obtained during connect - return getattr(self._query, '_initialization_result', None) async def get_server_info(self) -> dict[str, Any] | None: """Get server initialization info including available commands and output styles.