| 298 | |
| 299 | |
| 300 | class TokenCountRequest(BaseModel): |
| 301 | model: str |
| 302 | messages: List[Message] |
| 303 | system: Optional[Union[str, List[SystemContent]]] = None |
| 304 | tools: Optional[List[Tool]] = None |
| 305 | thinking: Optional[ThinkingConfig] = None |
| 306 | tool_choice: Optional[Dict[str, Any]] = None |
| 307 | original_model: Optional[str] = None # Will store the original model name |
| 308 | |
| 309 | @field_validator("model") |
| 310 | def validate_model_token_count(cls, v, info): # Renamed to avoid conflict |
| 311 | # Use the same logic as MessagesRequest validator |
| 312 | # NOTE: Pydantic validators might not share state easily if not class methods |
| 313 | # Re-implementing the logic here for clarity, could be refactored |
| 314 | original_model = v |
| 315 | new_model = v # Default to original value |
| 316 | |
| 317 | logger.debug( |
| 318 | f"📋 TOKEN COUNT VALIDATION: Original='{original_model}', Preferred='{PREFERRED_PROVIDER}', BIG='{BIG_MODEL}', SMALL='{SMALL_MODEL}'" |
| 319 | ) |
| 320 | |
| 321 | # Remove provider prefixes for easier matching |
| 322 | clean_v = v |
| 323 | if clean_v.startswith("anthropic/"): |
| 324 | clean_v = clean_v[10:] |
| 325 | elif clean_v.startswith("openai/"): |
| 326 | clean_v = clean_v[7:] |
| 327 | elif clean_v.startswith("gemini/"): |
| 328 | clean_v = clean_v[7:] |
| 329 | |
| 330 | # --- Mapping Logic --- START --- |
| 331 | mapped = False |
| 332 | # Map Haiku to SMALL_MODEL based on provider preference |
| 333 | if "haiku" in clean_v.lower(): |
| 334 | if PREFERRED_PROVIDER == "google" and SMALL_MODEL in GEMINI_MODELS: |
| 335 | new_model = f"gemini/{SMALL_MODEL}" |
| 336 | mapped = True |
| 337 | else: |
| 338 | new_model = f"openai/{SMALL_MODEL}" |
| 339 | mapped = True |
| 340 | |
| 341 | # Map Sonnet to BIG_MODEL based on provider preference |
| 342 | elif "sonnet" in clean_v.lower(): |
| 343 | if PREFERRED_PROVIDER == "google" and BIG_MODEL in GEMINI_MODELS: |
| 344 | new_model = f"gemini/{BIG_MODEL}" |
| 345 | mapped = True |
| 346 | else: |
| 347 | new_model = f"openai/{BIG_MODEL}" |
| 348 | mapped = True |
| 349 | |
| 350 | # Add prefixes to non-mapped models if they match known lists |
| 351 | elif not mapped: |
| 352 | if clean_v in GEMINI_MODELS and not v.startswith("gemini/"): |
| 353 | new_model = f"gemini/{clean_v}" |
| 354 | mapped = True # Technically mapped to add prefix |
| 355 | elif clean_v in OPENAI_MODELS and not v.startswith("openai/"): |
| 356 | new_model = f"openai/{clean_v}" |
| 357 | mapped = True # Technically mapped to add prefix |
nothing calls this directly
no outgoing calls
no test coverage detected