"""Anthropic native endpoint (passthrough).""" import time from typing import Optional, List from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import StreamingResponse from pydantic import BaseModel from ..models import ClientKey from ..middleware.auth import get_current_client from ..services.router import ModelRouter from ..services.key_selector import key_selector from ..services.logger import async_logger, LogEntry from ..providers.litellm_wrapper import LiteLLMWrapper router = APIRouter(prefix="/v1/anthropic", tags=["anthropic"]) class Message(BaseModel): role: str content: str class AnthropicRequest(BaseModel): model: str messages: List[Message] max_tokens: int = 1024 stream: bool = False temperature: Optional[float] = None @router.post("/messages") async def anthropic_messages( request: AnthropicRequest, client: ClientKey = Depends(get_current_client) ): """Anthropic native messages endpoint.""" start_time = time.time() # Get Anthropic provider provider = await ModelRouter.get_provider("anthropic") if not provider: raise HTTPException(status_code=503, detail={"error": "Anthropic provider not configured"}) # Get next API key provider_key = await key_selector.get_next_key(provider.id) if not provider_key: raise HTTPException(status_code=503, detail={"error": "No available Anthropic API key"}) messages = [{"role": m.role, "content": m.content} for m in request.messages] kwargs = {"max_tokens": request.max_tokens} if request.temperature is not None: kwargs["temperature"] = request.temperature try: response, prompt_tokens, completion_tokens = await LiteLLMWrapper.chat_completion( provider=provider, api_key=provider_key.key, model=request.model, messages=messages, stream=request.stream, **kwargs ) if request.stream: return StreamingResponse( LiteLLMWrapper.stream_response( response, client.id, provider.id, request.model, start_time ), media_type="text/event-stream" ) else: latency_ms = int((time.time() - start_time) * 1000) await async_logger.log(LogEntry( client_key_id=client.id, provider_id=provider.id, model=request.model, prompt_tokens=prompt_tokens, completion_tokens=completion_tokens, latency_ms=latency_ms, success=True )) return response except Exception as e: latency_ms = int((time.time() - start_time) * 1000) await async_logger.log(LogEntry( client_key_id=client.id, provider_id=provider.id, model=request.model, latency_ms=latency_ms, success=False, error_message=str(e) )) raise HTTPException(status_code=500, detail={"error": str(e)}) @router.get("/models") async def anthropic_models(client: ClientKey = Depends(get_current_client)): """List Anthropic models.""" return { "object": "list", "data": [ {"id": "claude-3-opus-20240229", "object": "model", "owned_by": "anthropic"}, {"id": "claude-3-sonnet-20240229", "object": "model", "owned_by": "anthropic"}, {"id": "claude-3-haiku-20240307", "object": "model", "owned_by": "anthropic"}, ] }