diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index 2ff63cc2d7f..ed5c8c1ac31 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -1409,6 +1409,8 @@ class BaseLLMHTTPHandler: document=document, optional_params=optional_params, headers=headers, + api_key=api_key, + api_base=api_base, ) # All providers return OCRRequestData @@ -1477,6 +1479,8 @@ class BaseLLMHTTPHandler: document=document, optional_params=optional_params, headers=headers, + api_key=api_key, + api_base=api_base, ) # All providers return OCRRequestData diff --git a/litellm/llms/fireworks_ai/chat/transformation.py b/litellm/llms/fireworks_ai/chat/transformation.py index cc0b4f6a91f..182d384d004 100644 --- a/litellm/llms/fireworks_ai/chat/transformation.py +++ b/litellm/llms/fireworks_ai/chat/transformation.py @@ -272,8 +272,11 @@ class FireworksAIConfig(OpenAIGPTConfig): # Fallback: preserve historical substring matching for model name # variants (e.g. fine-tuned or regionally-suffixed versions of a - # known model). Look for any fireworks_ai entry whose normalized - # short name is a substring of our normalized short name. + # known model). Pick the *longest* matching entry so a more specific + # known model (e.g. "qwen3-8b-instruct") wins over a less specific + # one (e.g. "qwen3-8b") when the query model is more specific still. + best_match_short: Optional[str] = None + best_match_value: Optional[bool] = None for key, model_info in litellm.model_cost.items(): if not key.startswith("fireworks_ai/"): continue @@ -284,10 +287,13 @@ class FireworksAIConfig(OpenAIGPTConfig): key_short = key[len("fireworks_ai/") :] if key_short.startswith("accounts/fireworks/models/"): key_short = key_short[len("accounts/fireworks/models/") :] - if key_short and key_short in short_name: - return cast(Optional[bool], model_info.get(capability)) + if not key_short or key_short not in short_name: + continue + if best_match_short is None or len(key_short) > len(best_match_short): + best_match_short = key_short + best_match_value = cast(Optional[bool], model_info.get(capability)) - return None + return best_match_value def get_provider_info(self, model: str) -> ProviderSpecificModelInfo: supports_function_calling_value = self._get_model_cost_capability( diff --git a/litellm/llms/reducto/ocr/transformation.py b/litellm/llms/reducto/ocr/transformation.py index 64269a1e458..cc338ecc484 100644 --- a/litellm/llms/reducto/ocr/transformation.py +++ b/litellm/llms/reducto/ocr/transformation.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, Tuple import httpx @@ -19,11 +19,6 @@ from litellm.llms.reducto.common import ( class _BaseReductoOCRConfig(BaseOCRConfig): - def __init__(self) -> None: - super().__init__() - self._api_key: Optional[str] = None - self._api_base: Optional[str] = None - def map_ocr_params( self, non_default_params: dict, @@ -54,9 +49,6 @@ class _BaseReductoOCRConfig(BaseOCRConfig): "Missing REDUCTO_API_KEY - set it in the environment or pass api_key to litellm.ocr()/litellm.aocr()" ) - self._api_key = resolved_key - self._api_base = (api_base or REDUCTO_API_BASE).rstrip("/") - return { "Authorization": f"Bearer {resolved_key}", "Content-Type": "application/json", @@ -83,32 +75,56 @@ class _BaseReductoOCRConfig(BaseOCRConfig): ) return source_url - def _ensure_file_id_sync(self, model: str, document: DocumentType) -> str: + @staticmethod + def _resolve_credentials( + api_key: Optional[str], api_base: Optional[str] + ) -> Tuple[str, str]: + from litellm.secret_managers.main import get_secret_str + + resolved_key = api_key or get_secret_str("REDUCTO_API_KEY") + if resolved_key is None: + raise ValueError( + "Missing REDUCTO_API_KEY - set it in the environment or pass api_key to litellm.ocr()/litellm.aocr()" + ) + resolved_base = (api_base or REDUCTO_API_BASE).rstrip("/") + return resolved_key, resolved_base + + def _ensure_file_id_sync( + self, + model: str, + document: DocumentType, + api_key: Optional[str], + api_base: Optional[str], + ) -> str: source_url = self._get_source_url(document=document, model=model) file_id, raw_bytes, mime = extract_file_id_or_bytes(source_url, model=model) if file_id is not None: return file_id - if self._api_key is None: - raise ValueError("Reducto API key was not initialized before OCR upload.") + resolved_key, resolved_base = self._resolve_credentials(api_key, api_base) return upload_bytes_sync( raw_bytes=raw_bytes or b"", mime=mime, - api_key=self._api_key, - api_base=self._api_base, + api_key=resolved_key, + api_base=resolved_base, ) - async def _ensure_file_id_async(self, model: str, document: DocumentType) -> str: + async def _ensure_file_id_async( + self, + model: str, + document: DocumentType, + api_key: Optional[str], + api_base: Optional[str], + ) -> str: source_url = self._get_source_url(document=document, model=model) file_id, raw_bytes, mime = extract_file_id_or_bytes(source_url, model=model) if file_id is not None: return file_id - if self._api_key is None: - raise ValueError("Reducto API key was not initialized before OCR upload.") + resolved_key, resolved_base = self._resolve_credentials(api_key, api_base) return await upload_bytes_async( raw_bytes=raw_bytes or b"", mime=mime, - api_key=self._api_key, - api_base=self._api_base, + api_key=resolved_key, + api_base=resolved_base, ) def transform_ocr_response( @@ -146,7 +162,12 @@ class ReductoParseV3Config(_BaseReductoOCRConfig): headers: dict, **kwargs, ) -> OCRRequestData: - file_id = self._ensure_file_id_sync(model=model, document=document) + file_id = self._ensure_file_id_sync( + model=model, + document=document, + api_key=kwargs.get("api_key"), + api_base=kwargs.get("api_base"), + ) return OCRRequestData(data={"input": file_id, **optional_params}, files=None) async def async_transform_ocr_request( @@ -157,7 +178,12 @@ class ReductoParseV3Config(_BaseReductoOCRConfig): headers: dict, **kwargs, ) -> OCRRequestData: - file_id = await self._ensure_file_id_async(model=model, document=document) + file_id = await self._ensure_file_id_async( + model=model, + document=document, + api_key=kwargs.get("api_key"), + api_base=kwargs.get("api_base"), + ) return OCRRequestData(data={"input": file_id, **optional_params}, files=None) @@ -180,7 +206,12 @@ class ReductoParseLegacyConfig(_BaseReductoOCRConfig): headers: dict, **kwargs, ) -> OCRRequestData: - file_id = self._ensure_file_id_sync(model=model, document=document) + file_id = self._ensure_file_id_sync( + model=model, + document=document, + api_key=kwargs.get("api_key"), + api_base=kwargs.get("api_base"), + ) return OCRRequestData( data=self._build_legacy_body( file_id=file_id, optional_params=optional_params @@ -196,7 +227,12 @@ class ReductoParseLegacyConfig(_BaseReductoOCRConfig): headers: dict, **kwargs, ) -> OCRRequestData: - file_id = await self._ensure_file_id_async(model=model, document=document) + file_id = await self._ensure_file_id_async( + model=model, + document=document, + api_key=kwargs.get("api_key"), + api_base=kwargs.get("api_base"), + ) return OCRRequestData( data=self._build_legacy_body( file_id=file_id, optional_params=optional_params