diff options
| author | Louis Burda <dev@sinitax.com> | 2026-02-02 08:10:56 +0100 |
|---|---|---|
| committer | Louis Burda <dev@sinitax.com> | 2026-02-02 08:11:17 +0100 |
| commit | d69c5b355c450e2c79b62b8a1a7946f375ac207d (patch) | |
| tree | a20cc4b977e400b2cd08b25f5ea9581156524356 /packages/multillm-claude/src/multillm_claude/provider.py | |
| parent | 43ddca6e4de9ed2b8615dedd9a31ee42881fdcb5 (diff) | |
| download | multillm-main.tar.gz multillm-main.zip | |
Diffstat (limited to 'packages/multillm-claude/src/multillm_claude/provider.py')
| -rw-r--r-- | packages/multillm-claude/src/multillm_claude/provider.py | 97 |
1 files changed, 89 insertions, 8 deletions
diff --git a/packages/multillm-claude/src/multillm_claude/provider.py b/packages/multillm-claude/src/multillm_claude/provider.py index 051f845..f74564e 100644 --- a/packages/multillm-claude/src/multillm_claude/provider.py +++ b/packages/multillm-claude/src/multillm_claude/provider.py @@ -1,4 +1,5 @@ import os +import sys from typing import Any, AsyncIterator from claude_agent_sdk import ( @@ -67,6 +68,17 @@ class ClaudeAgentProvider(BaseAgentProvider): if merged_config.get("api_key"): env["ANTHROPIC_API_KEY"] = merged_config["api_key"] + # Enable debug mode if requested + if os.environ.get("MULTILLM_DEBUG") or os.environ.get("DEBUG"): + env["DEBUG"] = "1" + print(f"[DEBUG] Claude Agent SDK options:", file=sys.stderr) + print(f" System prompt: {options.system_prompt if options else None}", file=sys.stderr) + print(f" Max turns: {options.max_turns if options else None}", file=sys.stderr) + print(f" Allowed tools: {options.allowed_tools if options else None}", file=sys.stderr) + print(f" Permission mode: {options.permission_mode if options else None}", file=sys.stderr) + print(f" Working dir: {options.working_directory if options else None}", file=sys.stderr) + print(f" Environment vars: {list(env.keys())}", file=sys.stderr) + if options is None: return ClaudeAgentOptions(env=env) if env else ClaudeAgentOptions() @@ -170,16 +182,85 @@ class ClaudeAgentProvider(BaseAgentProvider): yield parsed except ProcessError as e: - error_msg = f"Claude Agent SDK process error: {e}" - if hasattr(e, 'stderr') and e.stderr: - error_msg += f"\nStderr: {e.stderr}" - if hasattr(e, 'stdout') and e.stdout: - error_msg += f"\nStdout: {e.stdout}" - raise ProviderError(error_msg) from e + # Build detailed error message + error_parts = [f"Claude Agent SDK process error: {e}"] + + # Print to stderr immediately so user sees it + print(f"\n{'='*70}", file=sys.stderr) + print("CLAUDE AGENT SDK ERROR", file=sys.stderr) + print(f"{'='*70}", file=sys.stderr) + print(f"Error: {e}", file=sys.stderr) + + # Collect all available error information + error_info = {} + for attr in ['stderr', 'stdout', 'exit_code', 'command', 'output', 'message', 'args']: + if hasattr(e, attr): + val = getattr(e, attr) + if val: + error_info[attr] = val + + # Print all error details to stderr + if error_info: + print("\nError Details:", file=sys.stderr) + for key, val in error_info.items(): + print(f" {key}: {val}", file=sys.stderr) + # Also add to error message + error_parts.append(f"{key}: {val}") + + # Check exception's __dict__ for any other attributes + if hasattr(e, '__dict__'): + other_attrs = {k: v for k, v in e.__dict__.items() if k not in error_info and not k.startswith('_')} + if other_attrs: + print("\nAdditional Info:", file=sys.stderr) + for key, val in other_attrs.items(): + print(f" {key}: {val}", file=sys.stderr) + error_parts.append(f"{key}: {val}") + + print(f"{'='*70}\n", file=sys.stderr) + + raise ProviderError("\n".join(error_parts)) from e + except ClaudeSDKError as e: - raise ProviderError(f"Claude Agent SDK error: {e}") from e + # Print to stderr immediately + print(f"\n{'='*70}", file=sys.stderr) + print("CLAUDE SDK ERROR", file=sys.stderr) + print(f"{'='*70}", file=sys.stderr) + print(f"Error: {e}", file=sys.stderr) + + # Get all attributes from the error + error_parts = [f"Claude Agent SDK error: {e}"] + if hasattr(e, '__dict__'): + for key, val in e.__dict__.items(): + if not key.startswith('_') and val: + print(f" {key}: {val}", file=sys.stderr) + error_parts.append(f"{key}: {val}") + + print(f"{'='*70}\n", file=sys.stderr) + + raise ProviderError("\n".join(error_parts)) from e + except Exception as e: - raise ProviderError(f"Unexpected error: {e}") from e + # Print unexpected errors to stderr + print(f"\n{'='*70}", file=sys.stderr) + print("UNEXPECTED ERROR IN CLAUDE PROVIDER", file=sys.stderr) + print(f"{'='*70}", file=sys.stderr) + print(f"Type: {type(e).__name__}", file=sys.stderr) + print(f"Error: {e}", file=sys.stderr) + + if hasattr(e, '__dict__'): + print("\nError attributes:", file=sys.stderr) + for key, val in e.__dict__.items(): + if not key.startswith('_'): + print(f" {key}: {val}", file=sys.stderr) + + # Print full traceback + import traceback + print("\nTraceback:", file=sys.stderr) + traceback.print_exc(file=sys.stderr) + + print(f"{'='*70}\n", file=sys.stderr) + + raise ProviderError(f"Unexpected error: {type(e).__name__}: {e}") from e async def run_interactive( self, |
