mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-06-02 06:13:46 +02:00
178 lines
4.7 KiB
Python
178 lines
4.7 KiB
Python
"""Pydantic models for API requests and responses."""
|
|
|
|
import logging
|
|
from typing import List, Dict, Any, Optional, Union, Literal
|
|
from pydantic import BaseModel, field_validator, model_validator
|
|
|
|
from config.settings import get_settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# =============================================================================
|
|
# Content Block Types
|
|
# =============================================================================
|
|
|
|
|
|
class ContentBlockText(BaseModel):
|
|
type: Literal["text"]
|
|
text: str
|
|
|
|
|
|
class ContentBlockImage(BaseModel):
|
|
type: Literal["image"]
|
|
source: Dict[str, Any]
|
|
|
|
|
|
class ContentBlockToolUse(BaseModel):
|
|
type: Literal["tool_use"]
|
|
id: str
|
|
name: str
|
|
input: Dict[str, Any]
|
|
|
|
|
|
class ContentBlockToolResult(BaseModel):
|
|
type: Literal["tool_result"]
|
|
tool_use_id: str
|
|
content: Union[str, List[Dict[str, Any]], Dict[str, Any], List[Any], Any]
|
|
|
|
|
|
class ContentBlockThinking(BaseModel):
|
|
type: Literal["thinking"]
|
|
thinking: str
|
|
|
|
|
|
class SystemContent(BaseModel):
|
|
type: Literal["text"]
|
|
text: str
|
|
|
|
|
|
# =============================================================================
|
|
# Message Types
|
|
# =============================================================================
|
|
|
|
|
|
class Message(BaseModel):
|
|
role: Literal["user", "assistant"]
|
|
content: Union[
|
|
str,
|
|
List[
|
|
Union[
|
|
ContentBlockText,
|
|
ContentBlockImage,
|
|
ContentBlockToolUse,
|
|
ContentBlockToolResult,
|
|
ContentBlockThinking,
|
|
]
|
|
],
|
|
]
|
|
reasoning_content: Optional[str] = None
|
|
|
|
|
|
class Tool(BaseModel):
|
|
name: str
|
|
description: Optional[str] = None
|
|
input_schema: Dict[str, Any]
|
|
|
|
|
|
class ThinkingConfig(BaseModel):
|
|
enabled: bool = True
|
|
|
|
|
|
# =============================================================================
|
|
# Request/Response Models
|
|
# =============================================================================
|
|
|
|
|
|
class MessagesRequest(BaseModel):
|
|
model: str
|
|
max_tokens: int
|
|
messages: List[Message]
|
|
system: Optional[Union[str, List[SystemContent]]] = None
|
|
stop_sequences: Optional[List[str]] = None
|
|
stream: Optional[bool] = False
|
|
temperature: Optional[float] = 1.0
|
|
top_p: Optional[float] = None
|
|
top_k: Optional[int] = None
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
tools: Optional[List[Tool]] = None
|
|
tool_choice: Optional[Dict[str, Any]] = None
|
|
thinking: Optional[ThinkingConfig] = None
|
|
extra_body: Optional[Dict[str, Any]] = None
|
|
original_model: Optional[str] = None
|
|
|
|
@model_validator(mode="after")
|
|
def map_model(self) -> "MessagesRequest":
|
|
settings = get_settings()
|
|
if self.original_model is None:
|
|
self.original_model = self.model
|
|
|
|
clean_v = self.model
|
|
for prefix in ["anthropic/", "openai/", "gemini/"]:
|
|
if clean_v.startswith(prefix):
|
|
clean_v = clean_v[len(prefix) :]
|
|
break
|
|
|
|
if "haiku" in clean_v.lower():
|
|
self.model = settings.small_model
|
|
elif "sonnet" in clean_v.lower() or "opus" in clean_v.lower():
|
|
self.model = settings.big_model
|
|
|
|
if self.model != self.original_model:
|
|
logger.debug(f"MODEL MAPPING: '{self.original_model}' -> '{self.model}'")
|
|
|
|
return self
|
|
|
|
|
|
class TokenCountRequest(BaseModel):
|
|
model: str
|
|
messages: List[Message]
|
|
system: Optional[Union[str, List[SystemContent]]] = None
|
|
tools: Optional[List[Tool]] = None
|
|
thinking: Optional[ThinkingConfig] = None
|
|
tool_choice: Optional[Dict[str, Any]] = None
|
|
|
|
@field_validator("model")
|
|
@classmethod
|
|
def validate_model_field(cls, v, info):
|
|
settings = get_settings()
|
|
clean_v = v
|
|
for prefix in ["anthropic/", "openai/", "gemini/"]:
|
|
if clean_v.startswith(prefix):
|
|
clean_v = clean_v[len(prefix) :]
|
|
break
|
|
|
|
if "haiku" in clean_v.lower():
|
|
return settings.small_model
|
|
elif "sonnet" in clean_v.lower() or "opus" in clean_v.lower():
|
|
return settings.big_model
|
|
return v
|
|
|
|
|
|
class TokenCountResponse(BaseModel):
|
|
input_tokens: int
|
|
|
|
|
|
class Usage(BaseModel):
|
|
input_tokens: int
|
|
output_tokens: int
|
|
cache_creation_input_tokens: int = 0
|
|
cache_read_input_tokens: int = 0
|
|
|
|
|
|
class MessagesResponse(BaseModel):
|
|
id: str
|
|
model: str
|
|
role: Literal["assistant"] = "assistant"
|
|
content: List[
|
|
Union[
|
|
ContentBlockText, ContentBlockToolUse, ContentBlockThinking, Dict[str, Any]
|
|
]
|
|
]
|
|
type: Literal["message"] = "message"
|
|
stop_reason: Optional[
|
|
Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]
|
|
] = None
|
|
stop_sequence: Optional[str] = None
|
|
usage: Usage
|