@@ -401,11 +401,16 @@ def test_spend_logs_payload_with_prompts_enabled(monkeypatch):
401
401
def test_large_request_no_truncation_threshold ():
402
402
"""
403
403
Test that MAX_STRING_LENGTH_PROMPT_IN_DB constant is used for request body sanitization
404
+ and that the new truncation logic keeps beginning (35%) and end (65%) of the string
404
405
"""
405
406
from litellm .constants import MAX_STRING_LENGTH_PROMPT_IN_DB , LITELLM_TRUNCATED_PAYLOAD_FIELD
406
407
407
408
# Create a large string that exceeds the threshold
408
- large_content = "x" * (MAX_STRING_LENGTH_PROMPT_IN_DB + 500 )
409
+ # Use a pattern that allows us to verify beginning and end are preserved
410
+ start_pattern = "START" * 250 # 1250 chars
411
+ middle_pattern = "MIDDLE" * 200 # 1200 chars
412
+ end_pattern = "END" * 250 # 750 chars
413
+ large_content = start_pattern + middle_pattern + end_pattern
409
414
410
415
request_body = {
411
416
"messages" : [
@@ -418,10 +423,20 @@ def test_large_request_no_truncation_threshold():
418
423
419
424
# Verify the content was truncated
420
425
truncated_content = sanitized ["messages" ][0 ]["content" ]
421
- assert len (truncated_content ) > MAX_STRING_LENGTH_PROMPT_IN_DB # includes truncation message
422
- assert truncated_content .startswith ("x" * MAX_STRING_LENGTH_PROMPT_IN_DB )
426
+
427
+ # Calculate expected character counts (35% start, 65% end)
428
+ expected_start_chars = int (MAX_STRING_LENGTH_PROMPT_IN_DB * 0.35 )
429
+ expected_end_chars = int (MAX_STRING_LENGTH_PROMPT_IN_DB * 0.65 )
430
+
431
+ # Should keep first 35% of MAX_STRING_LENGTH_PROMPT_IN_DB chars
432
+ assert truncated_content .startswith (large_content [:expected_start_chars ])
433
+
434
+ # Should keep last 65% of MAX_STRING_LENGTH_PROMPT_IN_DB chars
435
+ assert truncated_content .endswith (large_content [- expected_end_chars :])
436
+
437
+ # Should have truncation marker
423
438
assert LITELLM_TRUNCATED_PAYLOAD_FIELD in truncated_content
424
- assert "500 chars " in truncated_content
439
+ assert "skipped " in truncated_content
425
440
426
441
427
442
def test_small_request_no_truncation ():
@@ -452,7 +467,7 @@ def test_configurable_string_length_env_var(monkeypatch):
452
467
Test that MAX_STRING_LENGTH_PROMPT_IN_DB can be configured via environment variable
453
468
"""
454
469
# Set environment variable to a custom value
455
- monkeypatch .setenv ("MAX_STRING_LENGTH_PROMPT_IN_DB" , "500 " )
470
+ monkeypatch .setenv ("MAX_STRING_LENGTH_PROMPT_IN_DB" , "1000 " )
456
471
457
472
# Import after setting env var to ensure it picks up the new value
458
473
import importlib
@@ -465,10 +480,43 @@ def test_configurable_string_length_env_var(monkeypatch):
465
480
from litellm .proxy .spend_tracking .spend_tracking_utils import _sanitize_request_body_for_spend_logs_payload
466
481
467
482
# Verify the constant was set to the env var value
468
- assert MAX_STRING_LENGTH_PROMPT_IN_DB == 500
483
+ assert MAX_STRING_LENGTH_PROMPT_IN_DB == 1000
469
484
470
485
# Test truncation with the custom value
471
- large_content = "y" * 750 # 250 chars over the custom limit
486
+ large_content = "A" * 500 + "B" * 800 + "C" * 500 # 1800 chars total
487
+
488
+ request_body = {
489
+ "messages" : [
490
+ {"role" : "user" , "content" : large_content }
491
+ ],
492
+ "model" : "gpt-4"
493
+ }
494
+
495
+ sanitized = _sanitize_request_body_for_spend_logs_payload (request_body )
496
+
497
+ # Verify truncation occurred with 35% beginning and 65% end preserved
498
+ truncated_content = sanitized ["messages" ][0 ]["content" ]
499
+ expected_start = int (1000 * 0.35 ) # 350 chars from beginning
500
+ expected_end = int (1000 * 0.65 ) # 650 chars from end
501
+
502
+ assert truncated_content .startswith (large_content [:expected_start ])
503
+ assert truncated_content .endswith (large_content [- expected_end :])
504
+ assert LITELLM_TRUNCATED_PAYLOAD_FIELD in truncated_content
505
+ assert "skipped" in truncated_content
506
+ assert "800" in truncated_content # Should mention skipped 800 chars
507
+
508
+
509
+ def test_truncation_preserves_beginning_and_end ():
510
+ """
511
+ Test that truncation preserves the beginning (35%) and end (65%) of content for better debugging
512
+ """
513
+ from litellm .constants import MAX_STRING_LENGTH_PROMPT_IN_DB , LITELLM_TRUNCATED_PAYLOAD_FIELD
514
+
515
+ # Create content with distinct beginning, middle, and end
516
+ beginning = "BEGIN_" * 200 # 1200 chars
517
+ middle = "MIDDLE_" * 300 # 2100 chars
518
+ end = "_END" * 300 # 1200 chars
519
+ large_content = beginning + middle + end
472
520
473
521
request_body = {
474
522
"messages" : [
@@ -478,9 +526,26 @@ def test_configurable_string_length_env_var(monkeypatch):
478
526
}
479
527
480
528
sanitized = _sanitize_request_body_for_spend_logs_payload (request_body )
529
+ truncated_content = sanitized ["messages" ][0 ]["content" ]
530
+
531
+ # Calculate expected splits (35% beginning, 65% end)
532
+ expected_start_chars = int (MAX_STRING_LENGTH_PROMPT_IN_DB * 0.35 )
533
+ expected_end_chars = int (MAX_STRING_LENGTH_PROMPT_IN_DB * 0.65 )
481
534
482
- # Verify truncation occurred at the custom threshold
483
- truncated_content = sanitized ["messages" ][0 ]["content" ]
484
- assert truncated_content .startswith ("y" * 500 )
535
+ # Check that beginning is preserved
536
+ expected_beginning = large_content [:expected_start_chars ]
537
+ assert truncated_content .startswith (expected_beginning )
538
+
539
+ # Check that end is preserved
540
+ expected_end = large_content [- expected_end_chars :]
541
+ assert truncated_content .endswith (expected_end )
542
+
543
+ # Check truncation marker is present
485
544
assert LITELLM_TRUNCATED_PAYLOAD_FIELD in truncated_content
486
- assert "250 chars" in truncated_content
545
+ assert "skipped" in truncated_content
546
+
547
+ # Calculate expected skipped chars
548
+ total_chars = len (large_content )
549
+ kept_chars = expected_start_chars + expected_end_chars
550
+ expected_skipped = total_chars - kept_chars
551
+ assert str (expected_skipped ) in truncated_content
0 commit comments