diff --git a/litellm/proxy/spend_tracking/spend_tracking_utils.py b/litellm/proxy/spend_tracking/spend_tracking_utils.py index a6b6375fd9c..33b53cb8dba 100644 --- a/litellm/proxy/spend_tracking/spend_tracking_utils.py +++ b/litellm/proxy/spend_tracking/spend_tracking_utils.py @@ -769,12 +769,17 @@ def _sanitize_request_body_for_spend_logs_payload( # Calculate how many characters are being skipped skipped_chars: Final = len(value) - total_keep - # Build the truncated string: beginning + truncation marker + end + # Build the truncated string: beginning + truncation marker + end. + # The tail is indexed from the front rather than written as + # `value[-end_chars:]`, which is the whole string when end_chars is 0. + # Both shares floor to 0 at MAX_STRING_LENGTH_PROMPT_IN_DB of 1 or less, + # so the tightest limits stored the entire prompt plus the marker saying + # it had been skipped, larger than the value the limit exists to bound. truncated_value: Final = ( f"{value[:start_chars]}" f"... ({LITELLM_TRUNCATED_PAYLOAD_FIELD} skipped {skipped_chars} chars. " f"{LITELLM_TRUNCATION_DB_SAFEGUARD_NOTE}) ..." - f"{value[-end_chars:]}" + f"{value[len(value) - end_chars :]}" ) return truncated_value return value diff --git a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py index 5022dab32be..00ce8e3b96b 100644 --- a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py +++ b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py @@ -300,6 +300,22 @@ def test_sanitize_request_body_for_spend_logs_payload_long_string(): assert sanitized["normal_text"] == "short text" +@pytest.mark.parametrize("limit", [0, 1, -1]) +def test_sanitize_request_body_never_stores_more_than_it_was_given(monkeypatch, limit): + """The truncation is a database-size safeguard, so the tightest limits must be + the ones that store least. Both shares floor to zero at a limit of 1 or less, + and `value[-0:]` is the whole string, so the entire prompt was written out + behind a marker saying it had been skipped.""" + monkeypatch.setenv("MAX_STRING_LENGTH_PROMPT_IN_DB", str(limit)) + long_string: Final = "a" * 5000 + + sanitized = _sanitize_request_body_for_spend_logs_payload({"text": long_string}) + + assert long_string not in sanitized["text"] + assert len(sanitized["text"]) < len(long_string) + assert LITELLM_TRUNCATED_PAYLOAD_FIELD in sanitized["text"] + + def test_sanitize_request_body_for_spend_logs_payload_nested_dict(): from litellm.constants import MAX_STRING_LENGTH_PROMPT_IN_DB