Skip to content

ccproxy.plugins.claude_sdk.handler

ccproxy.plugins.claude_sdk.handler

Claude SDK handler for orchestrating SDK operations.

This module contains the core business logic migrated from claude_sdk_service.py, handling SDK operations while maintaining clean separation of concerns.

ClaudeSDKHandler

ClaudeSDKHandler(
    config,
    sdk_client=None,
    auth_manager=None,
    metrics=None,
    session_manager=None,
    hook_manager=None,
)

Handler for Claude SDK operations orchestration.

This class encapsulates the business logic for SDK operations, migrated from the original claude_sdk_service.py.

Source code in ccproxy/plugins/claude_sdk/handler.py
def __init__(
    self,
    config: ClaudeSDKSettings,
    sdk_client: ClaudeSDKClient | None = None,
    auth_manager: AuthManager | None = None,
    metrics: Any | None = None,  # Metrics now handled by metrics plugin
    session_manager: SessionManager | None = None,
    hook_manager: Any | None = None,  # HookManager for emitting events
) -> None:
    """Initialize Claude SDK handler."""
    self.config = config
    self.sdk_client = sdk_client or ClaudeSDKClient(
        config=config, session_manager=session_manager
    )
    self.auth_manager = auth_manager
    self.metrics = metrics
    self.hook_manager = hook_manager
    self.message_converter = MessageConverter()
    self.options_handler = OptionsHandler(config=config)
    self.model_mapper = ModelMapper(config.model_mappings)

    # Create streaming hook if hook_manager is available
    streaming_hook = None
    if hook_manager:
        streaming_hook = ClaudeSDKStreamingHook(hook_manager=hook_manager)

    self.stream_processor = ClaudeStreamProcessor(
        message_converter=self.message_converter,
        metrics=self.metrics,
        streaming_hook=streaming_hook,
    )

create_completion async

create_completion(
    request_context,
    messages,
    model,
    temperature=None,
    max_tokens=None,
    stream=False,
    session_id=None,
    **kwargs,
)

Create a completion using Claude SDK with business logic orchestration.

Source code in ccproxy/plugins/claude_sdk/handler.py
async def create_completion(
    self,
    request_context: RequestContext,
    messages: list[dict[str, Any]],
    model: str,
    temperature: float | None = None,
    max_tokens: int | None = None,
    stream: bool = False,
    session_id: str | None = None,
    **kwargs: Any,
) -> MessageResponse | AsyncIterator[dict[str, Any]]:
    """Create a completion using Claude SDK with business logic orchestration."""
    # Extract system message and create options
    system_message = self.options_handler.extract_system_message(messages)

    if isinstance(request_context, RequestContext):
        metadata = request_context.metadata
    else:
        metadata = None

    match = self.model_mapper.map(model)
    if match.mapped != match.original and isinstance(metadata, dict):
        add_model_alias(metadata, match.original, match.mapped)
    model = match.mapped

    options = self.options_handler.create_options(
        model=model,
        temperature=temperature,
        max_tokens=max_tokens,
        system_message=system_message,
        session_id=session_id,
        **kwargs,
    )

    # Use existing context
    ctx = request_context
    metadata = {
        "endpoint": "messages",
        "model": model,
        "streaming": stream,
    }
    if session_id:
        metadata["session_id"] = session_id
    ctx.add_metadata(**metadata)
    request_id = ctx.request_id

    try:
        # Removed SDK request logging (simple_request_logger removed)
        timestamp = ctx.get_log_timestamp_prefix() if ctx else None

        if stream:
            return self._stream_completion(
                ctx, messages, options, model, session_id, timestamp
            )
        else:
            result = await self._complete_non_streaming(
                ctx, messages, options, model, session_id, timestamp
            )
            return result
    except (ClaudeProxyError, ServiceUnavailableError) as e:
        ctx.add_metadata(error_message=str(e), error_type=type(e).__name__)
        raise

validate_health async

validate_health()

Validate that the handler is healthy.

Source code in ccproxy/plugins/claude_sdk/handler.py
async def validate_health(self) -> bool:
    """Validate that the handler is healthy."""
    try:
        return await self.sdk_client.validate_health()
    except Exception as e:
        logger.error(
            "health_check_failed",
            error=str(e),
            error_type=type(e).__name__,
            exc_info=e,
        )
        return False

interrupt_session async

interrupt_session(session_id)

Interrupt a Claude session due to client disconnection.

Source code in ccproxy/plugins/claude_sdk/handler.py
async def interrupt_session(self, session_id: str) -> bool:
    """Interrupt a Claude session due to client disconnection."""
    return await self.sdk_client.interrupt_session(session_id)

close async

close()

Close the handler and cleanup resources.

Source code in ccproxy/plugins/claude_sdk/handler.py
async def close(self) -> None:
    """Close the handler and cleanup resources."""
    await self.sdk_client.close()