diff --git a/litellm/router_strategy/capability_router/capability_router.py b/litellm/router_strategy/capability_router/capability_router.py index 6d12b790d42..bb624712892 100644 --- a/litellm/router_strategy/capability_router/capability_router.py +++ b/litellm/router_strategy/capability_router/capability_router.py @@ -138,16 +138,22 @@ def _classification_context(messages: Sequence[Mapping[str, object]]) -> tuple[M ) -def _capped(value: object, cap: int) -> object: +def _capped_text(value: str, cap: int) -> str: + return value if len(value) <= cap else f"{value[:cap]}...[truncated {len(value) - cap} chars]" + + +def _capped_value(value: object, cap: int) -> object: if isinstance(value, str): - return value if len(value) <= cap else f"{value[:cap]}...[truncated {len(value) - cap} chars]" - if isinstance(value, Mapping): - return {key: _capped(item, cap) for key, item in value.items()} # mutable-ok: json.dumps needs a plain dict - if isinstance(value, Sequence) and not isinstance(value, (str, bytes)): - return tuple(_capped(item, cap) for item in value) + return _capped_text(value, cap) + if isinstance(value, Mapping) or (isinstance(value, Sequence) and not isinstance(value, (str, bytes))): + return _capped_text(json.dumps(value, default=str, ensure_ascii=False), cap) return value +def _capped_message(message: Mapping[str, object], cap: int) -> Mapping[str, object]: + return {key: _capped_value(value, cap) for key, value in message.items()} # mutable-ok: JSON payload needs dict + + def _tool_names(request_kwargs: Mapping[str, object]) -> tuple[str, ...]: tools: Final = request_kwargs.get("tools") if not isinstance(tools, Sequence) or isinstance(tools, (str, bytes)): @@ -217,7 +223,7 @@ class CapabilityRouter(CustomLogger): raise CapabilityClassifierFailure("No user task was available for capability classification") cap: Final = self.config.classifier.max_message_chars payload: Final[_ClassifierPayload] = { - "conversation": tuple(_capped(message, cap) for message in context), + "conversation": tuple(_capped_message(message, cap) for message in context), "available_tools": _tool_names(request_kwargs), } return ( diff --git a/tests/test_litellm/router_strategy/capability_router/test_capability_router.py b/tests/test_litellm/router_strategy/capability_router/test_capability_router.py index 00577184116..46c671fb298 100644 --- a/tests/test_litellm/router_strategy/capability_router/test_capability_router.py +++ b/tests/test_litellm/router_strategy/capability_router/test_capability_router.py @@ -222,7 +222,7 @@ def test_classifier_payload_caps_long_message_values() -> None: payload = strategy._classifier_payload(messages, {}) assert len(payload) < 10_000 - assert "[truncated 48000 chars]" in payload + assert "[truncated 480" in payload assert "opening user message is the original task" in payload