litellm/litellm/proxy/hooks
mateo-berri 5e4dec4b88 merge: bring litellm_internal_staging into litellm_fix_agent_mcp_grants
Take staging's test_bedrock_knowledgebase_hook.py, which drops the duplicate
embedding_executor parameter that turned the lint check red, and make the two
cross-module helpers this branch added public (raise_denied_scoped_mcp_access
and routes_through_gateway) so the private-usage budget stays at its base count
2026-09-07 16:35:40 -07:00
..
litellm_skills Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_skills_hook_import_side_effect 2026-09-02 15:46:31 +00:00
mcp_semantic_filter merge: bring litellm_internal_staging into litellm_fix_agent_mcp_grants 2026-09-07 16:35:40 -07:00
__init__.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
azure_content_safety.py fix(proxy): scan batch records with the content hooks that are not guardrails (#37786) 2026-08-21 11:20:23 -07:00
batch_enqueued_tokens.py fix(proxy): clamp reservation record TTL so stale records never outlive their counters 2026-08-19 19:12:22 -07:00
batch_rate_limiter.py refactor(typing): replace Any with proven types in 89 more backend files 2026-09-02 23:08:42 +00:00
batch_redis_get.py chore(lint): clear grandfathered over-limit lint drift and ratchet budgets down 2026-08-05 12:18:13 -07:00
cache_control_check.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
dynamic_rate_limiter.py chore(lint): strip inert type: ignore comments and zero LIT009, LIT010, LIT011 headroom 2026-08-05 02:37:24 -07:00
dynamic_rate_limiter_v3.py feat(proxy): add project-level ITPM and OTPM quotas 2026-08-05 12:53:22 +05:30
example_presidio_ad_hoc_recognizer.json fix(presidio_pii_masking.py): enable user to pass ad hoc recognizer for pii masking 2024-02-20 16:01:15 -08:00
key_management_event_hooks.py refactor(typing): replace Any with proven types in 89 more backend files 2026-09-02 23:08:42 +00:00
max_budget_limiter.py feat(proxy): add apply_user_budget_to_team_keys opt-in (#36102) 2026-08-07 15:40:13 +00:00
max_budget_per_session_limiter.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
max_iterations_limiter.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
model_max_budget_limiter.py fix(proxy): share per-model budget counters across replicas through the spend counter cache (#39375) 2026-09-02 12:40:59 -07:00
parallel_request_limiter.py chore(typing): clear 1.6k basedpyright Any errors across 56 files 2026-08-11 06:47:39 -07:00
parallel_request_limiter_v3.py fix(proxy): settle rate-limit reservations at a failed stream's partial usage 2026-09-03 12:52:58 -07:00
prompt_injection_detection.py fix(proxy): scan batch records with the content hooks that are not guardrails (#37786) 2026-08-21 11:20:23 -07:00
proxy_track_cost_callback.py Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_lit_7048_batch_cost_row_once 2026-09-05 23:03:41 -07:00
rate_limiter_utils.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
README.dynamic_rate_limiter_v3.md [Feat] Fixes to dynamic rate limiter v3 - add saturatation detection (#15119) 2025-10-01 18:35:34 -07:00
responses_id_security.py fix(responses): encrypt the response id on every streamed event 2026-09-03 02:41:04 -07:00
sensitive_data_routing.py feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) 2026-08-04 12:54:39 -07:00
user_management_event_hooks.py feat(proxy)!: default audit logs on for enterprise licenses (#37518) 2026-08-19 18:49:21 -07:00

Dynamic Rate Limiter v3 - Saturation-Aware Priority-Based Rate Limiting

Overview

The v3 dynamic rate limiter implements saturation-aware rate limiting with priority-based allocation. It balances resource efficiency (allowing unused capacity to be borrowed) with fairness guarantees (enforcing priorities during high load).

Key Behavior:

  • When system is under 80% capacity: Generous mode - allows priority borrowing
  • When system is at/above 80% capacity: Strict mode - enforces normalized priority limits

How It Works

Flow Diagram

┌─────────────────────────────────────────────────────────────┐
│                    Incoming Request                          │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Check Model Saturation                                   │
│     - Query v3 limiter's Redis counters                      │
│     - Calculate: current_usage / capacity                    │
│     - Returns: 0.0 (empty) to 1.0+ (saturated)              │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
                ┌────────┴────────┐
                │  Saturation?    │
                └────────┬────────┘
                         │
         ┌───────────────┴───────────────┐
         │                               │
         ▼                               ▼
   < 80% (Generous)                >= 80% (Strict)
         │                               │
         ▼                               ▼
┌─────────────────────┐         ┌─────────────────────┐
│  Generous Mode      │         │  Strict Mode        │
│                     │         │                     │
│  - Enforce model-   │         │  - Normalize        │
│    wide capacity    │         │    priority weights │
│  - No priority      │         │    (if over 1.0)    │
│    restrictions     │         │                     │
│  - Allows borrowing │         │  - Create priority- │
│                     │         │    specific         │
│  - First-come-      │         │    descriptors      │
│    first-served     │         │                     │
│    until capacity   │         │  - Enforce strict   │
│                     │         │    limits per       │
│                     │         │    priority         │
└──────────┬──────────┘         └──────────┬──────────┘
           │                               │
           │                               ▼
           │                    ┌──────────────────────┐
           │                    │  Track model usage   │
           │                    │  for future          │
           │                    │  saturation checks   │
           │                    └──────────┬───────────┘
           │                               │
           └───────────────┬───────────────┘
                           │
                           ▼
                    ┌──────────────┐
                    │  v3 Limiter  │
                    │  Check       │
                    └──────┬───────┘
                           │
           ┌───────────────┴───────────────┐
           │                               │
           ▼                               ▼
     OVER_LIMIT                        OK
           │                               │
           ▼                               ▼
   Return 429 Error              Allow Request

Configuration

Priority Reservation

Set priority weights in your proxy configuration:

litellm.priority_reservation = {
    "premium": 0.75,    # 75% of capacity
    "standard": 0.25    # 25% of capacity
}

Priority Reservation Settings

Configure saturation-aware behavior:

litellm.priority_reservation_settings = PriorityReservationSettings(
    default_priority=0.5,           # Default weight for users without explicit priority
    saturation_threshold=0.80,      # 80% - threshold for strict mode enforcement
    tracking_multiplier=10          # 10x - multiplier for non-blocking tracking in strict mode
)

Settings:

  • default_priority (default: 0.5) - Priority weight for users without explicit priority metadata
  • saturation_threshold (default: 0.80) - Saturation level (0.0-1.0) at which strict priority enforcement begins
  • tracking_multiplier (default: 10) - Multiplier for model-wide tracking limits in strict mode

User Priority Assignment

Set priority in user metadata:

user_api_key_dict.metadata = {"priority": "premium"}

Priority Weight Normalization

If priorities sum to > 1.0, they are automatically normalized:

Input:  {key_a: 0.60, key_b: 0.80} = 1.40 total
Output: {key_a: 0.43, key_b: 0.57} = 1.00 total

This ensures total allocation never exceeds model capacity.

Implementation Details

Saturation Detection

  • Queries v3 limiter's Redis counters for model-wide usage
  • Checks both RPM and TPM, returns higher saturation value
  • Non-blocking reads (doesn't increment counters)

Mode Selection

Generous Mode (< 80% saturation):

  • Creates single model-wide descriptor
  • Enforces total capacity only
  • Allows any priority to use available capacity
  • Prevents over-subscription via model-wide limit

Strict Mode (>= 80% saturation):

  • Creates priority-specific descriptors with normalized weights
  • Each priority gets its reserved allocation
  • Tracks model-wide usage separately (non-blocking, 10x multiplier)
  • Ensures fairness under load

Test scenarios covered:

  1. No rate limiting when under capacity
  2. Priority queue behavior during saturation
  3. Spillover capacity for default keys
  4. Over-allocated priorities with normalization
  5. Default priority value handling

_PROXY_DynamicRateLimitHandlerV3

Main handler class inheriting from CustomLogger.

Key Methods:

  • async_pre_call_hook() - Main entry point, routes to generous/strict mode
  • _check_model_saturation() - Queries Redis for current usage
  • _handle_generous_mode() - Enforces model-wide capacity only
  • _handle_strict_mode() - Enforces normalized priority limits
  • _normalize_priority_weights() - Handles over-allocation
  • _create_priority_based_descriptors() - Creates rate limit descriptors