diff --git a/README.md b/README.md index c2ca38b..7fb7d33 100644 --- a/README.md +++ b/README.md @@ -163,8 +163,8 @@ print(result.report.severity) # Typed access! print(result.report.affected_files) ``` -**Note**: String signatures like `"message:str -> report:BugReport"` only work with built-in types unless you use `dspy.Signature()` with `custom_types`. For custom Pydantic models, either: -- Use `dspy.Signature("...", custom_types={...})` +**Note**: String signatures like `"message:str -> report:BugReport"` only work with built-in types unless you use `dspy.Signature()`. For custom Pydantic models, either: +- Use `dspy.Signature("...")` - Use class-based signatures (recommended) ### Push to Modaic Hub @@ -172,21 +172,12 @@ print(result.report.affected_files) ```python from claude_dspy import ClaudeCode, ClaudeCodeConfig -# Create your agent +# create your agent config = ClaudeCodeConfig(model="claude-opus-4-5-20251101") -agent = ClaudeCode( - config, - signature="message:str -> answer:str", - working_directory=".", - permission_mode="acceptEdits", -) +agent = ClaudeCode(config) -# Test it locally -result = agent(message="Test my agent") -print(result.answer) - -# Push to Modaic Hub +# push to Modaic Hub agent.push_to_hub("{USERNAME}/your-agent-name") ``` @@ -307,7 +298,7 @@ Push the agent to Modaic Hub. **Example:** ```python -agent.push_to_hub("your-username/your-agent") +agent.push_to_hub("{USERNAME}/your-agent") ``` ##### `aforward(**kwargs) -> Prediction` diff --git a/claude_dspy/agent.py b/claude_dspy/agent.py index d5a5989..751b0ee 100644 --- a/claude_dspy/agent.py +++ b/claude_dspy/agent.py @@ -383,18 +383,13 @@ class ClaudeCode(PrecompiledProgram): # create client if needed if self._client is None: - print(f"[ClaudeCode._run_async] Creating new ClaudeSDKClient") self._client = self._create_client() # connect if not already connected if not self._is_connected: - print(f"[ClaudeCode._run_async] Connecting to Claude SDK...") await self._client.connect() self._is_connected = True - print(f"[ClaudeCode._run_async] Connected successfully") - # send query (output_format already configured in options) - print(f"[ClaudeCode._run_async] Sending query to agent...") await self._client.query(prompt) print(f"[ClaudeCode._run_async] Query sent, waiting for response...") @@ -410,36 +405,21 @@ class ClaudeCode(PrecompiledProgram): # handle assistant messages if isinstance(message, AssistantMessage): - print( - f"[ClaudeCode._run_async] Received AssistantMessage #{message_count} with {len(message.content)} blocks" - ) for block in message.content: if isinstance(block, TextBlock): - print( - f"[ClaudeCode._run_async] - TextBlock: {len(block.text)} chars" - ) response_text += block.text trace.append( AgentMessageItem(text=block.text, model=message.model) ) elif isinstance(block, ThinkingBlock): - print( - f"[ClaudeCode._run_async] - ThinkingBlock: {len(block.thinking)} chars" - ) trace.append( ThinkingItem(text=block.thinking, model=message.model) ) elif isinstance(block, ToolUseBlock): - print( - f"[ClaudeCode._run_async] - ToolUseBlock: {block.name} (id={block.id})" - ) # handle StructuredOutput tool (contains JSON response) if block.name == "StructuredOutput": # the JSON is directly in the tool input (already a dict) response_text = json.dumps(block.input) - print( - f"[ClaudeCode._run_async] StructuredOutput captured ({len(response_text)} chars)" - ) trace.append( ToolUseItem( @@ -449,9 +429,6 @@ class ClaudeCode(PrecompiledProgram): ) ) elif isinstance(block, ToolResultBlock): - print( - f"[ClaudeCode._run_async] - ToolResultBlock: tool_use_id={block.tool_use_id}, is_error={block.is_error}" - ) content_str = "" if isinstance(block.content, str): content_str = block.content @@ -475,9 +452,6 @@ class ClaudeCode(PrecompiledProgram): # handle result messages (final message with usage info) elif isinstance(message, ResultMessage): - print( - f"[ClaudeCode._run_async] Received ResultMessage (is_error={getattr(message, 'is_error', False)})" - ) # store session ID if hasattr(message, "session_id"): self._session_id = message.session_id @@ -493,9 +467,6 @@ class ClaudeCode(PrecompiledProgram): ), output_tokens=usage_data.get("output_tokens", 0), ) - print( - f"[ClaudeCode._run_async] - Usage: {usage.input_tokens} in, {usage.output_tokens} out, {usage.cached_input_tokens} cached" - ) # check for errors if hasattr(message, "is_error") and message.is_error: @@ -504,7 +475,6 @@ class ClaudeCode(PrecompiledProgram): if hasattr(message, "result") else "Unknown error" ) - print(f"[ClaudeCode._run_async] - ERROR: {error_msg}") trace.append( ErrorItem(message=error_msg, error_type="execution_error") ) @@ -516,41 +486,23 @@ class ClaudeCode(PrecompiledProgram): and message.structured_output is not None ): structured_output = message.structured_output - print( - f"[ClaudeCode._run_async] - Structured output captured: {type(structured_output).__name__} ({len(str(structured_output))} chars)" - ) # fallback to result field for text outputs elif hasattr(message, "result") and message.result: response_text = message.result - print( - f"[ClaudeCode._run_async] - Result extracted from message ({len(response_text)} chars)" - ) # handle system messages elif isinstance(message, SystemMessage): - print(f"[ClaudeCode._run_async] Received SystemMessage") # log system messages to trace but don't error if hasattr(message, "data") and message.data: data_str = str(message.data) - print( - f"[ClaudeCode._run_async] - Data: {data_str[:100]}..." - if len(data_str) > 100 - else f"[ClaudeCode._run_async] - Data: {data_str}" - ) trace.append( AgentMessageItem(text=f"[System: {data_str}]", model="system") ) - print( - f"[ClaudeCode._run_async] Completed: {message_count} messages processed, {len(trace)} trace items" - ) - # return structured_output if available (for Pydantic outputs), otherwise text if structured_output is not None: - print(f"[ClaudeCode._run_async] Returning structured output") return structured_output, trace, usage else: - print(f"[ClaudeCode._run_async] Returning text response") return response_text, trace, usage def forward(self, **kwargs: Any) -> Prediction: @@ -571,8 +523,6 @@ class ClaudeCode(PrecompiledProgram): >>> print(result.trace) # List of execution items >>> print(result.usage) # Token usage stats """ - print(f"\n[ClaudeCode.forward] Called with fields: {list(kwargs.keys())}") - # extract input value if self.input_field_name not in kwargs: raise ValueError( @@ -581,20 +531,11 @@ class ClaudeCode(PrecompiledProgram): ) input_value = kwargs[self.input_field_name] - print( - f"[ClaudeCode.forward] Input field '{self.input_field_name}': {input_value[:100]}..." - if len(str(input_value)) > 100 - else f"[ClaudeCode.forward] Input field '{self.input_field_name}': {input_value}" - ) # build prompt prompt = self._build_prompt(input_value) - print( - f"[ClaudeCode.forward] Built prompt ({len(prompt)} chars): {prompt[:200]}..." - ) # run async execution in event loop - print(f"[ClaudeCode.forward] Starting async execution (model={self.model})") try: loop = asyncio.get_event_loop() if loop.is_running(): @@ -613,37 +554,19 @@ class ClaudeCode(PrecompiledProgram): # no event loop, create one response_text, trace, usage = asyncio.run(self._run_async(prompt)) - # log response details - response_type = type(response_text).__name__ - response_len = len(str(response_text)) if response_text else 0 - print( - f"[ClaudeCode.forward] Received response (type={response_type}, {response_len} chars, {len(trace)} trace items)" - ) - print( - f"[ClaudeCode.forward] Token usage: {usage.input_tokens} input, {usage.output_tokens} output, {usage.cached_input_tokens} cached" - ) - # parse response based on output type output_type = self.output_field.annotation if is_pydantic_model(output_type): - print( - f"[ClaudeCode.forward] Parsing structured output (type: {output_type})" - ) try: # response_text can be dict/list (from structured_output) or str (legacy) parsed_output = parse_json_response(response_text, output_type) - print(f"[ClaudeCode.forward] Successfully parsed structured output") except Exception as e: - print(f"[ClaudeCode.forward] ERROR: Failed to parse structured output") raise ValueError( f"Failed to parse Claude response as {output_type}: {e}\n" f"Response type: {type(response_text)}\n" f"Response: {response_text}" ) else: - print( - f"[ClaudeCode.forward] Extracting text response (output type: {output_type})" - ) # string output - extract text if isinstance(response_text, str): parsed_output = extract_text_from_response(response_text) @@ -651,9 +574,6 @@ class ClaudeCode(PrecompiledProgram): # Shouldn't happen, but handle gracefully parsed_output = str(response_text) - print( - f"[ClaudeCode.forward] Returning Prediction with session_id={self._session_id}\n" - ) # return prediction with typed output, trace, and usage return Prediction( @@ -675,7 +595,6 @@ class ClaudeCode(PrecompiledProgram): Returns: Prediction with typed output, trace, and usage """ - print(f"\n[ClaudeCode.aforward] Called with fields: {list(kwargs.keys())}") # extract input value if self.input_field_name not in kwargs: @@ -685,51 +604,26 @@ class ClaudeCode(PrecompiledProgram): ) input_value = kwargs[self.input_field_name] - print( - f"[ClaudeCode.aforward] Input field '{self.input_field_name}': {input_value[:100]}..." - if len(str(input_value)) > 100 - else f"[ClaudeCode.aforward] Input field '{self.input_field_name}': {input_value}" - ) # build prompt prompt = self._build_prompt(input_value) - print(f"[ClaudeCode.aforward] Built prompt ({len(prompt)} chars)") # run async execution - print(f"[ClaudeCode.aforward] Starting async execution (model={self.model})") response_text, trace, usage = await self._run_async(prompt) - # Log response details - response_type = type(response_text).__name__ - response_len = len(str(response_text)) if response_text else 0 - print( - f"[ClaudeCode.aforward] Received response (type={response_type}, {response_len} chars, {len(trace)} trace items)" - ) - print( - f"[ClaudeCode.aforward] Token usage: {usage.input_tokens} input, {usage.output_tokens} output, {usage.cached_input_tokens} cached" - ) - # parse response based on output type output_type = self.output_field.annotation if is_pydantic_model(output_type): - print( - f"[ClaudeCode.aforward] Parsing structured output (type: {output_type})" - ) try: # response_text can be dict/list (from structured_output) or str (legacy) parsed_output = parse_json_response(response_text, output_type) - print(f"[ClaudeCode.aforward] Successfully parsed structured output") except Exception as e: - print(f"[ClaudeCode.aforward] ERROR: Failed to parse structured output") raise ValueError( f"Failed to parse Claude response as {output_type}: {e}\n" f"Response type: {type(response_text)}\n" f"Response: {response_text}" ) else: - print( - f"[ClaudeCode.aforward] Extracting text response (output type: {output_type})" - ) # string output - extract text if isinstance(response_text, str): parsed_output = extract_text_from_response(response_text) @@ -737,10 +631,6 @@ class ClaudeCode(PrecompiledProgram): # Shouldn't happen, but handle gracefully parsed_output = str(response_text) - print( - f"[ClaudeCode.aforward] Returning Prediction with session_id={self._session_id}\n" - ) - # return prediction with typed output, trace, and usage return Prediction( **{ diff --git a/main.py b/main.py index f27d7e6..d609892 100644 --- a/main.py +++ b/main.py @@ -36,7 +36,7 @@ def main(): cc.push_to_hub( "farouk1/claude-code", with_code=True, - commit_message="Use structured outputs with Pydantic models instead of text parsing", + commit_message="Remove debug prints", )