diff --git a/litellm/router.py b/litellm/router.py index 73398db867e..a782ed499cb 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -13119,9 +13119,10 @@ class Router: if not isinstance(strategy, ComplexityRouter): return frozenset() + tiers: Final[Mapping[str, str | Sequence[str]]] = strategy.config.tiers tier_models: Final = frozenset( model_name - for tier_value in strategy.config.tiers.values() + for tier_value in tiers.values() for model_name in ((tier_value,) if isinstance(tier_value, str) else tuple(tier_value)) ) default_model: Final = strategy.config.default_model @@ -13137,7 +13138,7 @@ class Router: selected_strategy: "TaggedPreRoutingStrategy[PreRoutingStrategy]", request_kwargs: Mapping[str, object], messages: list[dict[str, Any]] | None = None, - input: str | list | None = None, + input: str | Sequence[object] | None = None, ) -> Optional["PreRoutingHookResponse"]: """Keep a follow-up carrying encrypted reasoning on the deployment that produced it. @@ -13164,8 +13165,8 @@ class Router: if not affinity_registered: return None - request_input: Final = input if input is not None else request_kwargs.get("input") - originating_model_id: Final = EncryptedContentAffinityCheck._extract_model_id_from_input(request_input) + request_input: Final[object] = input if input is not None else request_kwargs.get("input") + originating_model_id: Final = EncryptedContentAffinityCheck.extract_model_id_from_input(request_input) if not originating_model_id: return None diff --git a/litellm/router_utils/pre_call_checks/encrypted_content_affinity_check.py b/litellm/router_utils/pre_call_checks/encrypted_content_affinity_check.py index b623e31ce06..51a56857d25 100644 --- a/litellm/router_utils/pre_call_checks/encrypted_content_affinity_check.py +++ b/litellm/router_utils/pre_call_checks/encrypted_content_affinity_check.py @@ -108,11 +108,16 @@ class EncryptedContentAffinityCheck(CustomLogger): ) @staticmethod - def _extract_model_id_from_input(request_input: object) -> str | None: + def extract_model_id_from_input(request_input: object) -> str | None: """ Scan ``input`` items for litellm-encoded encrypted-content markers and return the ``model_id`` embedded in the first one found. + Public because the Router's pre-routing hook needs the same answer before a + model group has been chosen: a complexity router would otherwise reclassify the + follow-up into a tier on the far side of the encryption boundary, and this + callback's deployment filtering only ever runs within one group. + Checks both: 1. Encoded item IDs (encitem_...) - for clients that send IDs 2. Wrapped encrypted_content (litellm_enc:...) - for clients like Codex that don't send IDs @@ -249,7 +254,7 @@ class EncryptedContentAffinityCheck(CustomLogger): request_kwargs["litellm_metadata"]["encrypted_content_affinity_enabled"] = True request_input: Final = request_kwargs.get("input") - model_id: Final = self._extract_model_id_from_input(request_input) + model_id: Final = self.extract_model_id_from_input(request_input) if not model_id: return typed_healthy_deployments