Ë
    tPêjOL ã                   ó¸  — U d Z ddlZddlZddlZddlZddlmZmZmZm	Z	 ddl
mZ ddlmZmZ ddlmZ ddlmZmZmZmZmZmZmZ ddlmZmZ dd	lmZ dd
lmZ ddlm Z m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5m6Z6m7Z7m8Z8m9Z9 ddl:m;Z; ddl<m=Z= ddl>m?Z?m@Z@ ddlAmBZBmCZCmDZDmEZEmFZFmGZG er ddlHmIZJ ddlKmLZM ddlNmOZO ddl<m=Z= eJez  ZIeMZLneZIeZLdZPeeQd<   dZReeQd<   dZSeeQd <   d!ZTeeQd"<   d#ZUeeQd$<   d%ZVeeQd&<   d'ZWeeQd(<   d)ZXeeQd*<   d+ZYeeQd,<   d-ZZeeQd.<   d/Z[eeQd0<   d/Z\eeQd1<   d2Z]eeQd3<   d4Z^eeQd5<   d6Z_eeQd7<   eBjÀ                  jÂ                  eBjÄ                  jÂ                  fZceeQd8<   eBjÈ                  jÂ                  eBjÊ                  jÂ                  eBjÌ                  jÂ                  eBjÎ                  jÂ                  fZheeQd9<   d:ZieeQd;<   d<ZjeeQd=<   d>ZkeeQd?<   d@ZleeQdA<   dBZmeeQdC<   dDZneeQdE<   eoepz  eqz  erz  ZseeQdF<   eesdz     ZteeQdG<   eueqevf   eoz  epz  eqz  erz  ZweeQdH<    G dI„ dJedK¬L«      Zx G dM„ dNe«      Zy G dO„ dPe«      Zz G dQ„ dRe«      Z{ G dS„ dTe«      Z| G dU„ dVe«      Z} G dW„ dXe=«      Z~ G dY„ dZe«      Z G d[„ d\e«      Z€ G d]„ d^e«      Z� G d_„ d`e«      Z‚ G da„ dbe«      Zƒe„e…eq   e…eo   e…e‚   f   Z†eeQdc<    G dd„ dee«      Z‡ edf¬g«       G dh„ di«      «       Zˆ edjd¬k«      Z‰eeeˆdz        eQdl<   dmeˆdz  fdn„ZŠdmeˆfdo„Z‹dpeudmeˆfdq„ZŒdreqdz  dmeˆdz  fds„Z�dtevdmeqdz  fdu„ZŽdvevdmeodz  fdw„Z� G dx„ dye#«      Z�y)zz’
This is a rate limiter implementation based on a similar one by Envoy proxy.

This is currently in development and not yet ready for production.
é    N)ÚCallableÚMappingÚSequenceÚSet)Ú
ContextVar)Ú	dataclassÚfield)Údatetime)ÚTYPE_CHECKINGÚAnyÚFinalÚLiteralÚProtocolÚ	TypeAliasÚ	TypedDict)ÚNotRequiredÚReadOnly)Ú	DualCache)Úverbose_proxy_logger)Ú-DYNAMIC_RATE_LIMIT_ERROR_THRESHOLD_PER_MINUTEÚ!INTERNAL_CALL_ORIGIN_METADATA_KEY)ÚCustomLogger)Úget_str_from_messages)ÚUserAPIKeyAuth)ÚESTIMATED_OUTPUT_TOKENS_FIELDÚget_estimated_output_tokensÚget_key_tag_rpm_limitÚ"get_model_rate_limit_from_metadata)Úthrottled_limit)Úget_tags_from_request_body)ÚProxyRateLimitErrorÚmap_v3_rate_limit_type)ÚBATCH_ENQUEUED_REFUND_STATUSESÚBatchEnqueuedTokenReservationÚBatchEnqueuedTokenStoreÚbatch_response_viewÚcanonical_provider_batch_id)Ú#resolve_llm_provider_for_rate_limit)ÚRedisPipelineIncrementOperation)ÚBaseLiteLLMOpenAIResponseObjectÚResponseAPIUsage)Ú	CallTypesÚEmbeddingResponseÚModelResponseÚRerankResponseÚTextCompletionResponseÚUsage)ÚSpan)ÚInternalUsageCache)ÚAgentResponsea.  
local results = {}
local now = tonumber(ARGV[1])
local window_size = tonumber(ARGV[2])

-- Process each window/counter pair
for i = 1, #KEYS, 2 do
    local window_key = KEYS[i]
    local counter_key = KEYS[i + 1]
    local increment_value = 1

    -- Check if window exists and is valid
    local window_start = redis.call('GET', window_key)
    if not window_start or (now - tonumber(window_start)) >= window_size then
        -- Reset window and counter
        redis.call('SET', window_key, tostring(now))
        redis.call('SET', counter_key, increment_value)
        redis.call('EXPIRE', window_key, window_size)
        redis.call('EXPIRE', counter_key, window_size)
        table.insert(results, tostring(now)) -- window_start
        table.insert(results, increment_value) -- counter
    else
        local counter = redis.call('INCR', counter_key)
        -- This happens when window_key exists but counter_key doesn't (e.g., tokens key
        -- created after requests key when both share the same window_key)
        local current_ttl = redis.call('TTL', counter_key)
        if current_ttl == -1 then
            redis.call('EXPIRE', counter_key, window_size)
        end
        table.insert(results, window_start) -- window_start
        table.insert(results, counter) -- counter
    end
end

return results
ÚBATCH_RATE_LIMITER_SCRIPTa-  
-- Atomic check-and-increment-by-N across one or more descriptors.
-- All-or-nothing: if any descriptor would exceed its limit, no counter is
-- modified.
--
-- Uses Redis server time (`redis.call('TIME')`) instead of a client-supplied
-- timestamp so that window resets are deterministic across replicas with
-- skewed wall-clocks. This prevents a clock-skew-induced reopening of the
-- TOCTOU window across multi-replica deployments.
--
-- KEYS layout: pairs of (window_key, counter_key), one pair per descriptor.
-- ARGV layout: per-descriptor 4-tuple, starting at ARGV[1]:
--     ARGV[(i-1)*4 + 1] = limit
--     ARGV[(i-1)*4 + 2] = increment
--     ARGV[(i-1)*4 + 3] = ttl_seconds (counter TTL when window resets)
--     ARGV[(i-1)*4 + 4] = window_size_seconds (sliding-window length)
--
-- Return on success:
--     { 0, new_counter_1, window_start_1, new_counter_2, window_start_2, ... }
-- Return on over-limit: { 1, descriptor_index, current_counter, limit }
local time_reply = redis.call('TIME')
local now = tonumber(time_reply[1])
local descriptor_count = #KEYS / 2

-- Pass 1: read state, validate. Abort without writing if any over limit.
local descriptor_state = {}
for i = 1, descriptor_count do
    local window_key = KEYS[(i - 1) * 2 + 1]
    local counter_key = KEYS[(i - 1) * 2 + 2]
    local arg_base = (i - 1) * 4 + 1
    local limit = tonumber(ARGV[arg_base])
    local increment = tonumber(ARGV[arg_base + 1])
    local window_size = tonumber(ARGV[arg_base + 3])

    local window_start = redis.call('GET', window_key)
    local window_expired = (not window_start) or
        ((now - tonumber(window_start)) >= window_size)

    local current_counter
    if window_expired then
        current_counter = 0
    else
        current_counter = tonumber(redis.call('GET', counter_key) or 0)
    end

    local blocked
    if increment > 0 then
        blocked = current_counter + increment > limit
    else
        blocked = current_counter >= limit
    end
    if blocked then
        return { 1, i, current_counter, limit }
    end

    descriptor_state[i] = { window_expired, current_counter, window_start }
end

-- Pass 2: all checks passed. Apply increments.
local results = { 0 }
for i = 1, descriptor_count do
    local window_key = KEYS[(i - 1) * 2 + 1]
    local counter_key = KEYS[(i - 1) * 2 + 2]
    local arg_base = (i - 1) * 4 + 1
    local increment = tonumber(ARGV[arg_base + 1])
    local ttl = tonumber(ARGV[arg_base + 2])
    local window_size = tonumber(ARGV[arg_base + 3])

    local window_expired = descriptor_state[i][1]
    local active_window_start

    if window_expired then
        active_window_start = now
        redis.call('SET', window_key, tostring(now))
        redis.call('SET', counter_key, increment)
        redis.call('EXPIRE', window_key, window_size)
        if ttl > 0 then
            redis.call('EXPIRE', counter_key, ttl)
        end
        table.insert(results, increment)
    else
        active_window_start = tonumber(descriptor_state[i][3])
        local new_counter = redis.call('INCRBY', counter_key, increment)
        local current_ttl = redis.call('TTL', counter_key)
        if current_ttl == -1 and ttl > 0 then
            redis.call('EXPIRE', counter_key, ttl)
        end
        table.insert(results, new_counter)
    end
    table.insert(results, active_window_start)
end

return results
ÚCHECK_AND_INCREMENT_BY_N_SCRIPTa‰  
local results = {}
for i = 1, #KEYS, 2 do
    local window_key = KEYS[i]
    local counter_key = KEYS[i + 1]
    local arg_base = ((i - 1) / 2) * 3 + 1
    local expected_window_start = ARGV[arg_base]
    local increment = tonumber(ARGV[arg_base + 1])
    local ttl = tonumber(ARGV[arg_base + 2])
    local active_window_start = redis.call('GET', window_key)

    if active_window_start and active_window_start == expected_window_start then
        local new_counter = redis.call('INCRBY', counter_key, increment)
        local current_ttl = redis.call('TTL', counter_key)
        if current_ttl == -1 and ttl > 0 then
            redis.call('EXPIRE', counter_key, ttl)
        end
        table.insert(results, 1)
        table.insert(results, new_counter)
    else
        table.insert(results, 0)
        table.insert(results, tonumber(redis.call('GET', counter_key) or 0))
    end
end
return results
Ú%WINDOW_GUARDED_TOKEN_INCREMENT_SCRIPTaˆ  
-- Atomic check-and-acquire for the max_parallel_requests concurrency gauge.
-- Each gauge key is a sorted set of per-request slot ids scored by acquire
-- time (Redis server clock). In-flight requests are counted by ZCARD after
-- pruning slots older than the slot TTL, so unlike the windowed RPM/TPM
-- counters the gauge is never reset while requests are in flight, a
-- rejected request never occupies a slot, and a slot leaked by a crashed
-- worker self-heals after the slot TTL even under continuous traffic.
--
-- KEYS: one gauge zset key per descriptor.
-- ARGV: per-key triples (limit, slot_ttl_seconds, slot_id).
-- Success: { 0, in_flight_1, ... }. Over-limit: { 1, key_index, in_flight, limit }.
local time_reply = redis.call('TIME')
local now = tonumber(time_reply[1])
for i = 1, #KEYS do
    local limit = tonumber(ARGV[(i - 1) * 3 + 1])
    local slot_ttl = tonumber(ARGV[(i - 1) * 3 + 2])
    redis.call('ZREMRANGEBYSCORE', KEYS[i], '-inf', now - slot_ttl)
    local in_flight = redis.call('ZCARD', KEYS[i])
    if in_flight + 1 > limit then
        return { 1, i, in_flight, limit }
    end
end
local results = { 0 }
for i = 1, #KEYS do
    local slot_ttl = tonumber(ARGV[(i - 1) * 3 + 2])
    local slot_id = ARGV[(i - 1) * 3 + 3]
    redis.call('ZADD', KEYS[i], now, slot_id)
    redis.call('EXPIRE', KEYS[i], slot_ttl)
    table.insert(results, redis.call('ZCARD', KEYS[i]))
end
return results
ÚPARALLEL_ACQUIRE_SCRIPTa  
-- Release one slot per gauge key by removing this request's slot id.
-- ZREM of an absent member (or key) is a no-op, so a release without a
-- matching acquire (proxy-side rejection, double-fired callback, slot
-- already expired) can never free a slot owned by another request.
-- KEYS: gauge zset keys. ARGV: per-key slot_id.
-- Returns the remaining in-flight count per key.
local results = {}
for i = 1, #KEYS do
    redis.call('ZREM', KEYS[i], ARGV[i])
    table.insert(results, redis.call('ZCARD', KEYS[i]))
end
return results
ÚPARALLEL_RELEASE_SCRIPTaÂ  
-- Read the current in-flight count per gauge key (prunes expired slots
-- first so leaked slots do not inflate the reading).
-- KEYS: gauge zset keys. ARGV: per-key slot_ttl_seconds.
local time_reply = redis.call('TIME')
local now = tonumber(time_reply[1])
local results = {}
for i = 1, #KEYS do
    redis.call('ZREMRANGEBYSCORE', KEYS[i], '-inf', now - tonumber(ARGV[i]))
    table.insert(results, redis.call('ZCARD', KEYS[i]))
end
return results
ÚPARALLEL_COUNT_SCRIPTaÆ  
local results = {}

-- Process each key/increment_value/ttl triplet
for i = 1, #KEYS do
    local key = KEYS[i]
    local increment_value = tonumber(ARGV[i * 2 - 1])
    local ttl_seconds = tonumber(ARGV[i * 2])

    -- Increment the value
    local new_value = redis.call('INCRBYFLOAT', key, increment_value)

    -- Handle TTL: only set expire if ttl_seconds > 0 and key has no current TTL
    -- ttl_seconds can be 0 (no TTL) or positive (set TTL)
    if ttl_seconds and ttl_seconds > 0 then
        local current_ttl = redis.call('TTL', key)
        if current_ttl == -1 then
            redis.call('EXPIRE', key, ttl_seconds)
        end
    end

    table.insert(results, new_value)
end

return results
ÚTOKEN_INCREMENT_SCRIPTi @  ÚREDIS_CLUSTER_SLOTSÚall_keysÚREDIS_NODE_HASHTAG_NAMEi   ÚDEFAULT_MAX_TOKENS_ESTIMATEé   ÚDEFAULT_CHARS_PER_TOKENÚ_TPM_FLOOR_FRACTION)Ú
aresponsesÚ	responsesÚRESPONSES_API_CALL_TYPES)Ú
aembeddingÚ	embeddingÚEMBEDDING_API_CALL_TYPES)Úatext_completionÚtext_completionÚTEXT_COMPLETION_API_CALL_TYPESÚRERANK_API_CALL_TYPESÚGOOGLE_GENAI_NATIVE_CALL_TYPESé   ÚRESPONSES_API_MIN_OUTPUT_TOKENSi,  ÚDEFAULT_AUDIO_TOKEN_ESTIMATEi@  Ú_AUDIO_BYTES_PER_TOKENÚmodel_per_project_itpmÚPROJECT_ITPM_DESCRIPTOR_KEYÚmodel_per_project_otpmÚPROJECT_OTPM_DESCRIPTOR_KEYi  Ú!PARALLEL_REQUEST_SLOT_TTL_SECONDSÚCacheCounterValueÚCacheCounterValuesÚParallelGaugeCacheValuec                   óN   — e Zd ZU edz  ed<   edz  ed<   edz  ed<   edz  ed<   y)Ú"RateLimitDescriptorRateLimitObjectNÚrequests_per_unitÚtokens_per_unitÚmax_parallel_requestsÚwindow_size)Ú__name__Ú
__module__Ú__qualname__ÚintÚ__annotations__© ó    út/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/hooks/parallel_request_limiter_v3.pyr[   r[   …  s*   … Ø˜T‘zÓ!Ø˜4‘ZÓØ ™:Ó%Ø�t‘Ôrf   r[   F)Útotalc                   ó2   — e Zd ZU eed<   eed<   edz  ed<   y)ÚRateLimitDescriptorÚkeyÚvalueNÚ
rate_limit)r`   ra   rb   Ústrrd   r[   re   rf   rg   rj   rj   Œ  s   … Ø	ƒHØƒJØ2°TÑ9Ô9rf   rj   c                   ó,   — e Zd ZU eed<   eed<   eed<   y)ÚParallelRequestGaugeÚcounter_keyÚlimitÚdescriptor_keyN)r`   ra   rb   rn   rd   rc   re   rf   rg   rp   rp   ’  s   … ØÓØƒJØÔrf   rp   c                   ó(   — e Zd ZU eed<   ee   ed<   y)ÚParallelSlotAcquisitionÚslot_idÚcounter_keysN)r`   ra   rb   rn   rd   Úlistre   rf   rg   ru   ru   ˜  s   … ØƒLØ�s‘)Ôrf   ru   c                   ó\   — e Zd ZU eed<   eed<   eed<   ed   ed<   eed<   eee      ed<   y)	ÚRateLimitStatusÚcodeÚcurrent_limitÚlimit_remaining©ÚrequestsÚtokensr^   Úrate_limit_typers   Údescriptor_valueN)	r`   ra   rb   rn   rd   rc   r   r   r   re   rf   rg   rz   rz   �  s6   … Ø
ƒIØÓØÓØÐJÑKÓKØÓð " (¨3¡-Ñ0Ô0rf   rz   c                   óV   — e Zd ZU eed<   ee   ed<   eee	e
eeed   f            ed<   y)ÚRateLimitResponseÚoverall_codeÚstatuses©ÚredisÚlocalÚreservation_windowsN)r`   ra   rb   rn   rd   rx   rz   r   r   Ú	frozensetÚtupler   re   rf   rg   r„   r„   «  s:   … ØÓØ�?Ñ#Ó#Ø$ X¨i¸¸cÀ3ÈÐP`ÑHaÐ>aÑ8bÑ.cÑ%dÑeÔerf   r„   c                   óD   — e Zd ZU ee   ed<   ee   ed<   eed      ed<   y)Ú"ReservationAwareIncrementOperationÚ
window_keyÚexpected_window_startr‡   Úreservation_backendN)r`   ra   rb   r   rn   rd   r   re   rf   rg   rŽ   rŽ   ±  s)   … Ø˜CÑ Ó Ø& sÑ+Ó+Ø$ WÐ-=Ñ%>Ñ?Ô?rf   rŽ   c                   ó(   — e Zd ZU ee   ed<   eed<   y)Ú RateLimitResponseWithDescriptorsÚdescriptorsÚresponseN)r`   ra   rb   rx   rj   rd   r„   re   rf   rg   r“   r“   ·  s   … ØÐ)Ñ*Ó*ØÔrf   r“   c                   ó   — e Zd Zdeddfd„Zy)Ú_RateLimitDescriptorSinkÚ
descriptorÚreturnNc                 ó   — y ©Nre   )Úselfr˜   s     rg   Úappendz_RateLimitDescriptorSink.append½  s   � rf   )r`   ra   rb   rj   r�   re   rf   rg   r—   r—   ¼  s   „ ØEÐ!4ÐE¸DÔErf   r—   c                   óB   — e Zd ZU edz  ed<   edz  ed<   eed<   eed<   y)ÚWindowKeyMetadataNÚrequests_limitÚtokens_limitr_   rs   )r`   ra   rb   rc   rd   rn   re   rf   rg   rŸ   rŸ   À  s"   … Ø˜$‘JÓØ˜‘*ÓØÓØÔrf   rŸ   c                   ót   — e Zd ZU eed<   ee   ed<   eed<   ed   ed<   eed<   eed<   eed<   eed	<   eed
<   y)ÚAtomicCounterMetars   r‚   r|   ©r   r€   r�   r�   rq   Ú	incrementÚttlr_   N)r`   ra   rb   rn   rd   r   rc   r   re   rf   rg   r£   r£   Ç  s?   … ØÓØ˜s‘mÓ#ØÓØÐ1Ñ2Ó2ØƒOØÓØƒNØ	ƒHØÔrf   r£   c                   ó2   — e Zd ZU eed<   eed<   ee   ed<   y)ÚAtomicCounterStateÚwindow_expiredÚcurrentÚwindow_startN)r`   ra   rb   Úboolrd   rc   r   rn   re   rf   rg   r¨   r¨   Ó  s   … ØÓØƒLØ˜3‘-Ôrf   r¨   ÚDescriptorAtomicGroupc                   óN   — e Zd Zdededeeef   dedeez  eeef   z  dz  f
d„Z	y)ÚCallTypeRateLimiterÚuser_api_key_dictÚcacheÚdataÚ	call_typer™   Nc              ƒ   ó   K  — y ­wr›   re   )rœ   r°   r±   r²   r³   s        rg   Úasync_pre_call_hookz'CallTypeRateLimiter.async_pre_call_hookÝ  s   è ø€ ð 69ùs   ‚)
r`   ra   rb   r   r   Údictrn   ÚobjectÚ	Exceptionrµ   re   rf   rg   r¯   r¯   Ü  sW   „ ð9à)ð9ð ð9ð �3˜�;Ñð	9ð
 ð9ð 
�S‰˜4  V Ñ,Ñ	,¨tÑ	3ô9rf   r¯   T)Úslotsc                   óš  — e Zd ZU dZdZedz  ed<   dZedz  ed<   dZ	e
dz  ed<   dZeed<   dZedz  ed<    ee¬	«      Zeeeef      ed
<   dZeed<    ee¬	«      Zeeeef      ed<    ee¬	«      Zeeeeed   f      ed<   dZeed<    ee¬	«      Zeeeef      ed<    ee¬	«      Zeeeeed   f      ed<   dZedz  ed<   dZeed<   y)ÚRequestRateLimiterStashab  
    Per-request bookkeeping the pre-call hook hands to the success/failure/
    disconnect callbacks. Lives on a ContextVar instead of the request body so
    it never reaches provider-facing ``metadata`` channels.

    A single mutable instance is shared by every context forked from the
    request task (the SDK call, streaming generators, and the logging worker's
    captured context all see the same object), which is what makes the
    ``reservation_released`` flag and ``parallel_slot`` clearing effective
    across sibling callbacks: the first release wins, later callbacks observe
    the cleared state.

    Because the stash is context-inherited, nested LiteLLM calls made inside
    the request (LLM-judge guardrails, silent experiments) would also see it
    from their own logging callbacks. ``owner_litellm_call_id`` pins the stash
    to the proxy request's ``litellm_call_id`` so those callbacks can tell the
    owning request's events apart from a nested call's: router retries and
    fallbacks reuse the request's call id and keep access, while nested calls
    mint fresh ids and are ignored.
    NÚowner_litellm_call_idÚrate_limit_responseÚparallel_slotr   Úreserved_tokensÚreserved_model)Údefault_factoryÚreserved_scopesÚitpm_reserved_tokensÚitpm_reserved_scopesr‡   Úitpm_reserved_window_identitiesÚotpm_reserved_tokensÚotpm_reserved_scopesÚotpm_reserved_window_identitiesÚbatch_enqueued_reservationFÚreservation_released)r`   ra   rb   Ú__doc__r¼   rn   rd   r½   r„   r¾   ru   r¿   rc   rÀ   r	   r‹   rÂ   rŒ   rÃ   rÄ   rÅ   r   rÆ   rÇ   rÈ   rÉ   r$   rÊ   r¬   re   rf   rg   r»   r»   æ  s9  … ñð* )-Ð˜3 ™:Ó,Ø48ÐÐ*¨TÑ1Ó8Ø48€MÐ*¨TÑ1Ó8Ø€O�SÓØ!%€N�C˜$‘JÓ%Ù27È	Ô2R€O�Y˜u S¨# X™Ñ/ÓRØ !Ð˜#Ó!Ù7<ÈYÔ7WÐ˜) E¨#¨s¨(¡OÑ4ÓWÙ]bØ!ô^Ð# Y¨u°S¸#¸wÐGWÑ?XÐ5XÑ/YÑ%Zó ð !"Ð˜#Ó!Ù7<ÈYÔ7WÐ˜) E¨#¨s¨(¡OÑ4ÓWÙ]bØ!ô^Ð# Y¨u°S¸#¸wÐGWÑ?XÐ5XÑ/YÑ%Zó ð HLÐÐ =ÀÑ DÓKØ!&Ð˜$Ô&rf   r»   Ú%litellm_v3_rate_limiter_request_stash©ÚdefaultÚ_request_stashr™   c                  ó*   — t         j                  «       S r›   )rÏ   Úgetre   rf   rg   Úget_request_stashrÒ     s   € Ü×ÑÓÐrf   c                  óp   — t         j                  «       } | €t        «       } t         j                  | «       | S r›   )rÏ   rÑ   r»   Úset)Ústashs    rg   Úget_or_create_request_stashrÖ     s0   € Ü×ÑÓ €EØ€}Ü'Ó)ˆÜ×Ñ˜5Ô!Ø€Lrf   r²   c                 ój   — t        «       }| j                  d«      }t        |t        «      r||_        |S ©NÚlitellm_call_id)rÖ   rÑ   Ú
isinstancern   r¼   )r²   rÕ   Úowner_call_ids      rg   Úclaim_request_stash_for_datarÜ   "  s0   € Ü.Ó0€EØŸ8™8Ð$5Ó6€MÜ�-¤Ô%Ø&3ˆÔ#Ø€Lrf   rÙ   c                 óv   — t         j                  «       }|€y |j                  �| €|S | |j                  k(  r|S d S r›   )rÏ   rÑ   r¼   )rÙ   rÕ   s     rg   Úget_request_stash_for_callrÞ   *  sF   € Ü!×%Ñ%Ó'€EØ€}ØØ×"Ñ"Ð*¨oÐ.EØˆØ# u×'BÑ'BÒBˆ5ÐLÈÐLrf   Úkwargsc                 ón   — t        | t        «      sy | j                  d«      }t        |t        «      r|S d S rØ   )rÚ   r¶   rÑ   rn   )rß   Úcall_ids     rg   Ú_call_id_from_callback_kwargsrâ   3  s2   € Ü�fœdÔ#ØØ—Z‘ZÐ 1Ó2€GÜ  ¬#Ô.ˆ7Ð8°DÐ8rf   Ú	raw_valuec                 ó®   — t        | t        «      st        | t        t        t        f«      sy 	 t        t        | «      «      S # t
        t        f$ r Y y w xY wr›   )rÚ   r¬   rc   Úfloatrn   Ú
ValueErrorÚOverflowError)rã   s    rg   Ú_parse_output_cap_valuerè   :  sK   € Ü�)œTÔ"¬*°YÄÄeÌSÐ@QÔ*RØðÜ”5˜Ó#Ó$Ð$øÜœÐ&ò Ùðús   ®A ÁAÁAc                   óÆ  — e Zd Z	 d·dedeg ef   dz  fd„Zdedz  fd„Zdefd„Z	e
dedz  defd	„«       Ze
d
ededz  defd„«       Ze
d
ededz  deeef   dz  fd„«       Ze
d
ededz  dedz  fd„«       Zed
ededz  defd„«       Ze
d·d
ededz  defd„«       Ze
	 d·d
ededz  dedz  dedz  ddf
d„«       Z	 	 	 	 d¸d
ededz  dedz  dedz  dedz  defd„Z	 	 	 d¹d
ededz  dedz  dedz  deeef   f
d„Zdefd„Zdee   dededefd„Zdedede d   defd „Z!d!ee   d"ed#eee"f   de#fd$„Z$dedefd%„Z%dee   deeee   f   fd&„Z&dee   d'e'dz  d(ededz  fd)„Z(dee   d'e'dz  de)e*dz     dz  fd*„Z+d!ee   dedefd+„Z,	 	 	 	 dºd,e)e-   d'e'dz  d-ed.ed/edz  de#fd0„Z.d,e)e-   d.edeee   eee"f   ee/   f   fd1„Z0d2e/d3ed4ede1fd5„Z2d6e*dz  defd7„Z3	 	 d»d8ee/   d9ed'e'dz  d-ede#f
d:„Z4	 d·d;ee   d'e'dz  dee   fd<„Z5	 d·d8ee/   d9ed'e'dz  de#fd=„Z6	 d·d>e7d'e'dz  ddfd?„Z8	 d·d,ee-   d@eee dA   ef      d'e'dz  de#fdB„Z9dCe-dDee dA   ef   de:fdE„Z;	 d·dFee:   d'e'dz  de#fdG„Z<dHeee=      ddfdI„Z>dJee?   dKee=   de#fdL„Z@	 d·dKee=   d'e'dz  de#fdM„ZA	 d·d,ee-   dNed'e'dz  de#fdO„ZB eC«       dfdPe)eeef      dQedReCeeee dS   f      d'e'dz  ddf
dT„ZD	 d·d,e)e-   dUedVed'e'dz  dee#eef   f
dW„ZEdXeFdz  dYedz  dUedVeddf
dZ„ZG	 d·dXeFdYedz  dee-   fd[„ZHdXeFdYedz  d,ee-   ddfd\„ZIdXeFd
ed,ee-   ddfd]„ZJdXeFd^edz  d,ee-   ddfd_„ZKdXeFd^edz  d,ee-   ddfd`„ZLdaedz  dbedefdc„ZMddedz  daedz  dbededz  fde„ZNdfedz  dgedz  defdh„ZOdieddjfdk„ZPdXeFd
ededz  fdl„ZQd
ededz  fdm„ZRdied
edee-   fdn„ZS	 d·dXeFd
edfedz  dgedz  dbededz  dee-   fdo„ZT	 d·ded'e'dz  defdp„ZUdededz  fdq„ZVdXeFdYedz  d,ee-   ddfdr„ZWdXeFdYedz  d,ee-   ddfds„ZXdXeFdYedz  d,eYddfdt„ZZ	 d·due#d,ee-   dYedz  ddfdv„Z[e
dwedefdx„«       Z\edyedefdz„«       Z]e
dyedefd{„«       Z^e
d
ede)e   fd|„«       Z_e
dededz  fd}„«       Z`e
d
eeef   defd~„«       Zad·d
ededz  dedz  defd„Zb	 d·d,e)e-   d
edYedz  dXeFd€e)eeef      d�ededz  ddfd‚„ZcdXeFdƒedd
edefd„„Zededede d   d…eded†   f
d‡„Zfdˆegdz  de d‰   defdŠ„Zhe
dˆeiejz  eeef   z  dz  defd‹„«       Zke
dŒedeiejz  eeef   z  dz  fd�„«       ZldŽed†   ddfd�„Zm	 d·dŽed†   d'e'dz  ddfd�„Zn	 d·d‘e)eo   d'e'dz  ddfd’„Zp	 d·d‘e)eo   d'e'dz  ddfd“„Zq	 d·dŽe)eo   d'e'dz  ddfd”„Zrde d‰   fd•„Zse
d–eeef   d—ee1   deeef   fd˜„«       Zte
dŒedeeeef   dz  fd™„«       ZudŒedeeeef   fdš„Zvd›edŒede)ew   fdœ„Zxd�eeegf   d›egdžedz  deeeef      fdŸ„Zyd e)eeef      d¡ezeeef      d¢ed£edeew   f
d¤„Z{d¥eeef   d¡ezeeef      d¢ed£ed¦eCeeee dS   f      deodz  fd§„Z|d e)eeef      d¡ezeeef      d¢ed£ed¦eCeeee dS   f      deeod¨f   fd©„Z}d›egdŒegde d‰   deew   fdª„Z~d«„ Zd›ed¬ededeeef   fd­„Z€d›edŒeddfd®„Z�d¯„ Z‚dXeFddfd°„Zƒd
edXeFfd±„Z„dXeFdueddfd²„Z…	 d·d³ed´e†dXeFdµedz  ddf
d¶„Z‡y)¼Ú$_PROXY_MaxParallelRequestsHandler_v3NÚinternal_usage_cacheÚtime_providerc                 óü  — || _         |xs t        j                  | _        | j                   j                  j
                  ��‰| j                   j                  j
                  j                  t        «      | _        | j                   j                  j
                  j                  t        «      | _
        | j                   j                  j
                  j                  t        «      | _        | j                   j                  j
                  j                  t        «      | _        | j                   j                  j
                  j                  t        «      | _        | j                   j                  j
                  j                  t"        «      | _        | j                   j                  j
                  j                  t&        «      | _        n1d | _        d | _
        d | _        d | _        d | _        d | _        d | _        t+        t-        j.                  dd«      «      | _        t-        j.                  dd«      j3                  «       dk(  | _        d | _        t9        |¬«      | _        t=        j>                  «       | _         y )NÚLITELLM_RATE_LIMIT_WINDOW_SIZEé<   Ú%LITELLM_TPM_TOKEN_RESERVATION_ENABLEDÚtrue)rë   )!rë   r
   ÚnowÚ_time_providerÚ
dual_cacheÚredis_cacheÚasync_register_scriptr5   Úbatch_rate_limiter_scriptr;   Útoken_increment_scriptr6   Úcheck_and_increment_by_n_scriptr7   Ú%window_guarded_token_increment_scriptr8   Úparallel_acquire_scriptr9   Úparallel_release_scriptr:   Úparallel_count_scriptrc   ÚosÚgetenvr_   ÚlowerÚtpm_reservation_enabledÚ_batch_rate_limiterr%   Úbatch_enqueued_token_storeÚasyncioÚLockÚ_check_and_increment_lock)rœ   rë   rì   s      rg   Ú__init__z-_PROXY_MaxParallelRequestsHandler_v3.__init__D  s   € ð
 %9ˆÔ!Ø+Ò;¬x¯|©|ˆÔØ×$Ñ$×/Ñ/×;Ñ;ÑGØ-1×-FÑ-F×-QÑ-Q×-]Ñ-]×-sÑ-sÜ)ó.ˆDÔ*ð +/×*CÑ*C×*NÑ*N×*ZÑ*Z×*pÑ*pÜ&ó+ˆDÔ'ð ×)Ñ)×4Ñ4×@Ñ@×VÑVÔWvÓwð Ô0ð ×)Ñ)×4Ñ4×@Ñ@×VÑVÜ9óð Ô6ð
 ,0×+DÑ+D×+OÑ+O×+[Ñ+[×+qÑ+qÜ'ó,ˆDÔ(ð ,0×+DÑ+D×+OÑ+O×+[Ñ+[×+qÑ+qÜ'ó,ˆDÔ(ð *.×)BÑ)B×)MÑ)M×)YÑ)Y×)oÑ)oÜ%ó*ˆDÕ&ð .2ˆDÔ*Ø*.ˆDÔ'Ø37ˆDÔ0Ø9=ˆDÔ6Ø+/ˆDÔ(Ø+/ˆDÔ(Ø)-ˆDÔ&äœrŸy™yÐ)IÈ2ÓNÓOˆÔô (*§y¡yÐ1XÐZ`Ó'a×'gÑ'gÓ'iÐmsÑ'sˆÔ$ð @DˆÔ Ü*AÐWkÔ*lˆÔ'ô  *1¯©«ˆÕ&rf   r™   c                 óø   — | j                   €,	 ddlm}  || j                  | ¬«      | _         | j                   S | j                   S # t        $ r+}t        j                  d|«       Y d}~| j                   S d}~ww xY w)z(Get or lazy-load the batch rate limiter.Nr   )Ú_PROXY_BatchRateLimiter)rë   Úparallel_request_limiterz%Could not load batch rate limiter: %s)r  Ú&litellm.proxy.hooks.batch_rate_limiterr	  rë   r¸   r   Údebug)rœ   r	  Úes      rg   Ú_get_batch_rate_limiterz<_PROXY_MaxParallelRequestsHandler_v3._get_batch_rate_limiterˆ  sƒ   € à×#Ñ#Ð+ð
Wõñ ,CØ)-×)BÑ)BØ-1ô,�Ô(ð ×'Ñ'Ð'ˆt×'Ñ'Ð'øô ò WÜ$×*Ñ*Ð+RÐTU×VÐVØ×'Ñ'Ð'ûðWús   ŽA Á	A9ÁA4Á4A9c                 ó"   — | j                  «       S )z7Return the current time for rate limiting calculations.)ró   )rœ   s    rg   Ú_get_current_timez6_PROXY_MaxParallelRequestsHandler_v3._get_current_time˜  s   € à×"Ñ"Ó$Ð$rf   Úmin_configured_tpm_limitc                 ó^   — t         t        z  }| €|S t        |t        d| t        z  «      «      S )a  Output-budget floor used when the request omits max_tokens.

        Capped at a fraction of the smallest configured TPM limit so a small
        per-tenant cap can't be tripped by the floor alone. Returns the
        baseline floor when no limit is provided.
        é   )r?   rB   ÚminÚmax)r  Úbaselines     rg   Úno_max_tokens_output_floorz?_PROXY_MaxParallelRequestsHandler_v3.no_max_tokens_output_floorœ  s5   € ô 6Ô9LÑLˆØ#Ð+ØˆOÜ�8œS Ð$<Ô@SÑ$SÓTÓUÐUrf   r²   r³   c                 ót   — |t         v ry|t        v ry|ryt        | t        «      sy| j	                  d«      d uS )NTFÚinput)rH   rE   rÚ   r¶   rÑ   ©r²   r³   s     rg   Ú_is_embedding_requestz:_PROXY_MaxParallelRequestsHandler_v3._is_embedding_request«  sA   € àÔ0Ñ0ØØÔ0Ñ0ØÙØÜ˜$¤Ô%ØØ�x‰x˜Ó ¨Ð,Ð,rf   c                 óT  — t        | t        «      r| j                  d«      nd }t        | t        «      r|t        vst        |t        t        f«      sy ddlm} d| v r| j                  d«      n| j                  d«      } |«       j                  t        | j                  d«      t        «      r| j                  d«      nd|t        |t        «      r|nd | j                  d«      | j                  d	«      | j                  d
«      | j                  d«      | j                  d«      ¬«      S )NÚcontentsr   )ÚGoogleGenAIAdapterÚconfigÚgenerationConfigÚmodelÚ ÚsystemInstructionÚsystem_instructionÚtoolsÚ
toolConfigÚtool_config)r!  r  r  r#  r$  r%  r&  r'  )	rÚ   r¶   rÑ   rM   rx   Ú,litellm.google_genai.adapters.transformationr  Ú(translate_generate_content_to_completionrn   )r²   r³   r  r  r  s        rg   Ú&_translate_google_genai_native_requestzK_PROXY_MaxParallelRequestsHandler_v3._translate_google_genai_native_request·  sð   € ô
 3=¸TÄ4Ô2H˜$Ÿ(™( :Ô.Èdˆä˜4¤Ô&ØÔ >Ñ>Ü˜h¬¬t¨Ô5àÝSà.6¸$Ñ.>˜Ÿ™ Ô*ÀDÇHÁHÐM_ÓD`ˆÙ!Ó#×LÑLÜ'1°$·(±(¸7Ó2CÄSÔ'I�$—(‘(˜7Ô#ÈrØÜ'¨´Ô5‘6¸4Ø"Ÿh™hÐ':Ó;Ø#Ÿx™xÐ(<Ó=Ø—(‘(˜7Ó#Ø—x‘x Ó-ØŸ™ Ó/ð Mó 	
ð 		
rf   c                 ó�  ‡ ‡— t        ‰ t        «      sy |t        v rGd‰ v r‰ j                  d«      n‰ j                  d«      Št	        ˆfd„dD «       «      }t        |d ¬«      S |t        v r-t        ‰ j                  d«      «      }|€y t        t        |«      S |t        v ry |rdnd}t	        ˆ fd	„|D «       «      }t        |d ¬«      S )
Nr  r   c              3   óz   •K  — | ]2  }t        ‰t        «      r t        ‰j                  |«      «      }|�|–— Œ4 y ­wr›   )rÚ   r¶   rè   rÑ   )Ú.0r	   Úparsedr  s      €rg   ú	<genexpr>zP_PROXY_MaxParallelRequestsHandler_v3._get_explicit_output_cap.<locals>.<genexpr>×  s<   øè ø€ ò -àÜ˜f¤dÔ+Ü6°v·z±zÀ%Ó7HÓI�FØÐ%ô	 ñ-ùs   ƒ8;)ÚmaxOutputTokensÚmax_output_tokensrÍ   r1  )Ú
max_tokensÚmax_completion_tokens)r2  r3  r1  c              3   ó\   •K  — | ]#  }t        ‰j                  |«      «      }|€Œ |–— Œ% y ­wr›   )rè   rÑ   )r-  r	   r.  r²   s      €rg   r/  zP_PROXY_MaxParallelRequestsHandler_v3._get_explicit_output_cap.<locals>.<genexpr>ë  s/   øè ø€ ò )
ØÔ6MÈdÏhÉhÐW\ËoÓ6^¨6ÐdjÑdvŒFñ)
ùs   ƒ!,¥,)
rÚ   r¶   rM   rÑ   rŒ   r  rE   rè   rO   rH   )r²   r³   Úgoogle_cap_valuesÚresponses_capÚfieldsÚoutput_cap_valuesr  s   `     @rg   Ú_get_explicit_output_capz=_PROXY_MaxParallelRequestsHandler_v3._get_explicit_output_capÑ  sÞ   ù€ ä˜$¤Ô%ØØÔ6Ñ6Ø2:¸dÑ2B˜DŸH™H XÔ.ÈÏÉÐQcÓHdˆFÜ',ó -àEô-ó (Ðô Ð(°$Ô7Ð7ØÔ0Ñ0Ü#:¸4¿8¹8ÐDWÓ;XÓ#YˆMØÐ$ØÜÔ6¸ÓFÐFØÔ0Ñ0Øñ ñ 4àMð 	ô
 $)ó )
Ø &ô)
ó $
Ðô Ð$¨dÔ3Ð3rf   c                 ó*   — | j                  ||«      duS )zÉWhether the caller explicitly set an output-token cap.

        Checked via ``is not None`` (not truthiness) so an explicit 0 --
        a legitimate zero-output request -- counts as explicit.
        N)r9  )Úclsr²   r³   s      rg   Ú_has_explicit_output_capz=_PROXY_MaxParallelRequestsHandler_v3._has_explicit_output_capð  s   € ð ×+Ñ+¨D°)Ó<ÀDÐHÐHrf   c                 óÎ  — t        | t        «      sy|t        v r&d| v r| j                  d«      n| j                  d«      nd }| j                  d«      | j                  d«      t        |t        «      r|j                  d«      nd t        |t        «      r|j                  d«      nd f}d}|D ]  }	 t        |t        |xs d«      «      }Œ |S # t        t        t        f$ r Y Œ7w xY w)Nr  r  r   ÚnÚbest_ofÚcandidateCountÚcandidate_count)
rÚ   r   rM   rÑ   r¶   r  rc   Ú	TypeErrorræ   rç   )r²   r³   r  Úcandidate_valuesrA  rl   s         rg   Úget_output_candidate_countz?_PROXY_MaxParallelRequestsHandler_v3.get_output_candidate_countù  sæ   € ä˜$¤Ô(Øð Ô:Ñ:ð $,¨tÑ#3ˆT�X‰X�hÔ¸¿¹ÐBTÔ9Uàð 	ð �H‰H�S‹MØ�H‰H�YÓÜ,6°v¼tÔ,DˆF�J‰JÐ'Ô(È$Ü-7¸ÄÔ-EˆF�J‰JÐ(Ô)È4ð	#
Ðð ˆØ%ò 	ˆEðÜ"% o´s¸5º:ÀA³Ó"G‘ð	ð
 Ðøô œz¬=Ð9ò Ùðús   Â0CÃC$Ã#C$Úmin_configured_limitÚconfigured_output_tokensc                 ó  — t        | t        «      syt        j                  |«      }|t        v rt        |t        «      n|}t        t        z  }t        j                  | |«      }||k\  st        j                  | |«      s|ryt        ||xs d«      }|t        v r?d| v sd| vrdnd}	| j                  |	«      }
|
�t        |
t        «      ri |
xs i ¥d|i¥| |	<   y|t        v rdnd}| j                  |«      }|�||k  r|| |<   yy)aä  Hard-cap generation length when the request has no explicit cap.

        Guards against an unbounded response overshooting a small TPM/OTPM
        budget before post-call reconciliation runs. Skips requests that
        already set an explicit cap and embeddings, which have no generation
        budget. The Responses API only honors ``max_output_tokens`` (its
        underlying chat-completion transformation ignores ``max_tokens``), so
        the cap must be written to that field for Responses call types.

        ``configured_output_tokens`` is the operator-declared per-tenant
        estimate; when it exceeds the safety floor, the cap is raised to that
        value instead of clamping every tenant to the same floor.
        Nr   r  r   r0  r1  r2  )rÚ   r¶   rê   r  rE   r  rO   r?   rB   r  r<  rM   rÑ   )r²   rE  r³   rF  Úbase_capped_floorÚcapped_floorÚbaseline_floorÚis_embeddingÚeffective_capÚconfig_fieldr  Ú	cap_fieldÚexisting_caps                rg   Ú_apply_implicit_output_capz?_PROXY_MaxParallelRequestsHandler_v3._apply_implicit_output_cap  s5  € ô( ˜$¤Ô%ØÜ#G×#bÑ#bÐcwÓ#xÐð Ô4Ñ4ô Ð!Ô#BÔCà"ð 	ô
 !<Ô?RÑ RˆÜB×XÑXÐY]Ð_hÓiˆà˜NÒ*Ü3×LÑLÈTÐS\Ô]ÙàÜ" <Ð1IÒ1NÈQÓOˆØÔ6Ñ6Ø.6¸$Ñ.>ÐBTÐ\`ÑB`¡(ÐfxˆLØ ŸH™H \Ó2ˆFØˆ~¤¨F´DÔ!9ð&Ø’| ð&à% }ñ&��\Ñ"ð Ø2;Ô?WÑ2WÑ.Ð]iˆ	Ø"Ÿh™h yÓ1ˆØÐ =°<Ò#?Ø+ˆD�ŠOð $@rf   r!  c                 óp   — | j                  ||||¬«      \  }}||z   }t        j                  d|||«       |S )añ  
        Estimate total tokens this request will consume so we can reserve them
        upfront (input + output budget):
        estimated = input_tokens + max_tokens.

        Supports chat (messages), completions (prompt), embeddings (input),
        and the Responses API (also `input`, disambiguated from embeddings
        via ``call_type``).

        ``min_configured_tpm_limit`` is the smallest ``tokens_per_unit`` among
        the TPM-bearing descriptors this request will be charged against. When
        provided, the no-``max_tokens`` output-budget floor is capped at a
        fraction of that limit so small TPM caps remain usable. Omit to
        preserve the unconstrained floor.

        ``configured_output_tokens`` is the operator-declared estimate resolved
        from key or team metadata. When provided it replaces the heuristic
        floor entirely, so the reservation reflects what this tenant's model
        actually emits rather than one constant shared by every tenant.
        )r²   r  r³   rF  z;TPM reservation estimate: input=%s, max_tokens=%s, total=%s)Ú!_estimate_input_and_output_tokensr   r  )	rœ   r²   r!  r  r³   rF  Úestimated_input_tokensÚmax_tokens_estimateÚtotal_estimateds	            rg   Ú_estimate_tokens_for_requestzA_PROXY_MaxParallelRequestsHandler_v3._estimate_tokens_for_requestC  s\   € ð8 7;×6\Ñ6\ØØ%=ØØ%=ð	 7]ó 7
Ñ3ÐÐ 3ð "8Ð:MÑ!Mˆä×"Ñ"ØIØ"ØØô		
ð Ðrf   c                 óö  — t        |t        «      sy| j                  ||«      }|�|n|}|t        v s|t        v rdd|j                  d«      fnc|t        v rd|j                  d«      dfnG|r|j                  d«      ddfn1|j                  d«      |j                  d«      |j                  d«      f}|\  }}	}
t        |t        «      r|rt        t        |«      «      n{t        |	t        «      rt        |	«      n`t        |	t        «      rt        d„ |	D «       «      n>t        |
t        «      rt        |
«      n#t        |
t        «      rt        d„ |
D «       «      nd}|dkD  rt        d	|t        z  «      nd}| j                  ||«      }| j                  ||«      }| j!                  |«      }|t        v rt        |t"        «      n|}|s	|€	|dk(  r|€dn|�|n|�|nt        ||«      }||| j%                  ||«      z  fS )
a´  
        Estimate input tokens and output (max_tokens) budget separately, so
        callers needing independent ITPM/OTPM reservations (rather than one
        combined TPM reservation) can use each half on its own.

        ``min_configured_tpm_limit`` is the smallest ``tokens_per_unit`` among
        the TPM-bearing descriptors this request will be charged against. When
        provided, the no-``max_tokens`` output-budget floor is capped at a
        fraction of that limit so small TPM caps remain usable. Omit to
        preserve the unconstrained floor.

        ``call_type`` disambiguates embeddings from the Responses API: both
        put their prompt in ``data["input"]``, but only embeddings have no
        output tokens. Unset (the default) preserves the historical
        "any `input` means zero output" behavior for callers that don't have
        a call type to pass.

        ``configured_output_tokens`` is the operator-declared estimate resolved
        from key or team metadata. When provided it replaces the heuristic
        floor entirely, so the reservation reflects what this tenant's model
        actually emits rather than one constant shared by every tenant.
        )r   r   Nr  ÚpromptÚmessagesc              3   óD   K  — | ]  }t        t        |«      «      –— Œ y ­wr›   ©Úlenrn   ©r-  Úitems     rg   r/  zY_PROXY_MaxParallelRequestsHandler_v3._estimate_input_and_output_tokens.<locals>.<genexpr>¥  s   è ø€ Ò7¨”Sœ˜T›—^Ñ7ùó   ‚ c              3   óD   K  — | ]  }t        t        |«      «      –— Œ y ­wr›   r[  r]  s     rg   r/  zY_PROXY_MaxParallelRequestsHandler_v3._estimate_input_and_output_tokens.<locals>.<genexpr>©  s   è ø€ Ò;¨”Sœ˜T›—^Ñ;ùr_  r   r  )rÚ   r¶   r*  rE   rH   rÑ   rK   rx   r\  r   rn   Úsumr  rA   r9  r  r  rO   rD  )rœ   r²   r  r³   rF  Útranslated_dataÚestimable_dataÚselected_fieldsrY  rX  Ú
input_textÚtotal_charsrS  Úexplicit_max_tokensrK  Úbase_output_floorÚoutput_floorrT  s                     rg   rR  zF_PROXY_MaxParallelRequestsHandler_v3._estimate_input_and_output_tokensp  sH  € ô: ˜$¤Ô%ØØ!%×!LÑ!LÈTÐS\Ó!]ˆØ3BÐ3N¡ÐTXˆð Ô4Ñ4¸	ÔE]Ñ8]ð �4˜×+Ñ+¨GÓ4Ñ5ð Ô:Ñ:ð ˜×*Ñ*¨8Ó4°dÑ;ñ ð !×$Ñ$ ZÓ0°$¸Ñ=ð ×"Ñ" :Ó.Ø×"Ñ" 8Ó,Ø×"Ñ" 7Ó+ðð 	ð (7Ñ$ˆ�&˜*ô ˜(¤DÔ)©hô Ô% hÓ/Ô0ô ˜&¤#Ô&ô �V”ô ˜&¤$Ô'ô Ñ7°Ô7Ô7ô ˜*¤cÔ*ô �Z”ô ˜*¤dÔ+ô Ñ;°
Ô;Ô;àð 	ð [fÐhiÒZi¬¨A¨{Ô>UÑ/UÔ(VÐopÐà%)×%BÑ%BÀ4ÈÓ%SÐØ"×8Ñ8¸¸yÓIˆà#'×#BÑ#BÐC[Ó#\Ðð Ô4Ñ4ô Ð!Ô#BÔCà"ð 	ñ Ð 3Ð ;ÀÈqÒ@PÐUmÐUuñ ð #Ð.ñ %ð (Ð3ñ *äÐ+¨\Ó:ð 	ð &Ð':¸T×=\Ñ=\Ð]aÐclÓ=mÑ'mÐmÐmrf   c                 óª   — ddl m} | j                  j                  j                  duxr* t        | j                  j                  j                  |«      S )z“
        Check if the dual cache is using Redis cluster.

        Returns:
            bool: True if using Redis cluster, False otherwise.
        r   )ÚRedisClusterCacheN)Ú#litellm.caching.redis_cluster_cacherk  rë   rô   rõ   rÚ   )rœ   rk  s     rg   Ú_is_redis_clusterz6_PROXY_MaxParallelRequestsHandler_v3._is_redis_clusterÅ  sM   € õ 	Jà×(Ñ(×3Ñ3×?Ñ?ÀtÐKò 
ÔPZØ×%Ñ%×0Ñ0×<Ñ<Ð>OóQ
ð 	
rf   ÚkeysÚnow_intr_   c              ƒ   ó   K  — g }t        dt        |«      d«      D �]R  }||   }||dz      }d}| j                  j                  |dd¬«      ƒ d{  –—† }	|	�|t	        |	«      z
  |k\  r…| j                  j                  |t        |«      |dd¬«      ƒ d{  –—†  | j                  j                  |||dd¬«      ƒ d{  –—†  |j                  t        |«      «       |j                  |«       ŒÑ| j                  j                  |dd¬«      ƒ d{  –—† }
|
�t	        |
«      nd|z   }| j                  j                  |||dd¬«      ƒ d{  –—†  |j                  |	«       |j                  |«       �ŒU |S 7 �Œ$7 Œâ7 Œ¼7 Œl7 Œ4­w)z½
        Implement sliding window rate limiting logic using in-memory cache operations.
        This follows the same logic as the Redis Lua script but uses async cache operations.
        r   é   r  NT©rk   Úlitellm_parent_otel_spanÚ
local_only©rk   rl   r¦   rs  rt  )Úranger\  rë   Úasync_get_cacherc   Úasync_set_cachern   r�   )rœ   rn  ro  r_   ÚresultsÚir�   rq   Úincrement_valuer«   Úcurrent_counterÚnew_counter_values               rg   Úin_memory_cache_sliding_windowzC_PROXY_MaxParallelRequestsHandler_v3.in_memory_cache_sliding_windowÒ  s×  è ø€ ð :<ˆô �qœ#˜d›) QÓ'ó /	2ˆAØ˜a™ˆJØ˜q 1™u™+ˆKØˆOð <@×;TÑ;T×;dÑ;dØØ)-Øð <eó <÷ 6ˆLð Ð#¨´#°lÓ2CÑ(CÈÒ'Sà×/Ñ/×?Ñ?Ø"Ü˜g›,Ø#Ø-1Ø#ð @ó ÷ ð ð ×/Ñ/×?Ñ?Ø#Ø)Ø#Ø-1Ø#ð @ó ÷ ð ð —‘œs 7›|Ô,Ø—‘˜Õ/ð CG×B[ÑB[×BkÑBkØ#Ø-1Ø#ð Cló C÷ =�ð
 >MÐ=X¤S¨Ô%9Ð^_ÐcrÑ$rÐ!Ø×/Ñ/×?Ñ?Ø#Ø+Ø#Ø-1Ø#ð @ó ÷ ð ð —‘˜|Ô,Ø—‘Ð0Ö1ð_/	2ðb ˆðW6ùðøðøð=øðús\   ‚AE>ÁE3ÁAE>ÂE6Â'E>Â;E8Â<AE>ÄE:Ä9E>ÅE<Å,E>Å6E>Å8E>Å:E>Å<E>rk   rl   r�   r~   c                 ó   — d|› d|› d|› �}|S )zI
        Create the rate limit keys for the given key and value.
        ú{ú:z}:re   )rœ   rk   rl   r�   rq   s        rg   Úcreate_rate_limit_keysz;_PROXY_MaxParallelRequestsHandler_v3.create_rate_limit_keys  s#   € ð  " #  a¨ w¨c°/Ð1BÐCˆàÐrf   Úkeys_to_fetchÚcache_valuesÚkey_metadatac           	      ó–  — g }d}t        dt        |«      d«      D ]   }d}||   }||dz      }	||dz      }
||   d   }||   d   }d}d}|	j                  d«      r|}d	}n|	j                  d
«      r|}d}|�|€Œ^|
�t        |
«      |kD  rd}d}|
�|t        |
«      z
  n|}|j	                  ||||||   d   dœ«       Œ¢ t        ||¬«      S )z?
        Check if the cache values are over the limit.
        ÚOKr   rq  r  r    r¡   Nz	:requestsr   z:tokensr€   Ú
OVER_LIMITrs   ©r{   r|   r}   r�   rs   ©r…   r†   )rv  r\  Úendswithrc   r�   r„   )rœ   rƒ  r„  r…  r†   r…   rz  Ú	item_coder�   rq   Úcounter_valuer    r¡   r|   r�   r}   s                   rg   Úis_cache_list_over_limitz=_PROXY_MaxParallelRequestsHandler_v3.is_cache_list_over_limit  s1  € ð 24ˆØˆä�qœ#˜lÓ+¨QÓ/ò $	ˆAØˆIØ& qÑ)ˆJØ'¨¨A©Ñ.ˆKØ(¨¨Q©Ñ/ˆMØ)¨*Ñ5Ð6FÑGˆNØ'¨
Ñ3°NÑCˆLð )-ˆMØ]aˆOØ×#Ñ# KÔ0Ø .�Ø",‘Ø×%Ñ% iÔ0Ø ,�Ø"*�àÐ$¨Ð(?ØàÐ(¬S°Ó-?À-Ò-OØ+�Ø(�	ð ERÐD]˜m¬c°-Ó.@Ò@ÐcpˆOà�O‰Oà%Ø%2Ø'6Ø'6Ø&2°:Ñ&>Ð?OÑ&Pñõð9$	ôL !¨lÀXÔNÐNrf   c                 óÞ   — |j                  d«      }|dk7  r*|j                  d|dz   «      }|dk7  r||dz   k7  r||dz   | }t        j                  |j                  d«      d«      }|t        z  S )a†  
        Compute the Redis Cluster slot for a given key.

        Simple implementation of `HASH_SLOT = CRC16(key) mod 16384`

        Read more about hash slots here: https://medium.com/@linz07m/how-hash-slots-power-data-distribution-in-redis-cluster-bc5b7e74ca7d

        Args:
            key (str): The Redis key.

        Returns:
            int: The slot number (0-16383).


        r€  éÿÿÿÿú}r  zutf-8r   )ÚfindÚbinasciiÚcrc_hqxÚencoder<   )rœ   rk   ÚstartÚendÚcrcs        rg   Úkeyslot_for_redis_clusterz>_PROXY_MaxParallelRequestsHandler_v3.keyslot_for_redis_clusterS  sw   € ð" —x‘x “}ˆØ�BŠ;ØŸ™ # u¨q¡yÓ1ˆCØ�bŠy˜S E¨A¡IÒ-Ø˜% !™) cÐ*�ô ×%Ñ% c§j¡j°Ó&9¸1Ó=ˆØÔ(Ñ(Ð(rf   c                 ó´   — i }| j                  «       r<|D ]5  }| j                  |«      }d|› �}||vrg ||<   ||   j                  |«       Œ7 |S ||t        <   |S )a  
        Group keys by their Redis hash tag to ensure cluster compatibility.

        For Redis clusters, uses slot calculation to group keys that belong to the same slot.
        For regular Redis, no grouping is needed - all keys can be processed together.
        Úslot_)rm  r™  r�   r>   )rœ   rn  Úgroupsrk   ÚslotÚslot_keys         rg   Ú_group_keys_by_hash_tagz<_PROXY_MaxParallelRequestsHandler_v3._group_keys_by_hash_tagn  s   € ð /1ˆð ×!Ñ!Ô#Øò -�Ø×5Ñ5°cÓ:�Ø" 4 &˜>�à 6Ñ)Ø')�F˜8Ñ$Ø�xÑ ×'Ñ'¨Õ,ð-ð ˆð /3ˆFÔ*Ñ+àˆrf   Úparent_otel_spanrt  c              ƒ   óZ   K  — | j                   j                  |||¬«      ƒ d{  –—† S 7 Œ­w)z@Typed view over the DualCache batch read of window/counter keys.©rn  r   rt  N©rë   Úasync_batch_get_cache)rœ   rn  r   rt  s       rg   Ú_batch_get_counter_valuesz>_PROXY_MaxParallelRequestsHandler_v3._batch_get_counter_values†  s:   è ø€ ð ×.Ñ.×DÑDØØ-Ø!ð Eó 
÷ 
ð 	
ð 
úó   ‚"+¤)¥+c              ƒ   óZ   K  — | j                   j                  ||d¬«      ƒ d{  –—† S 7 Œ­w)zDTyped view over the DualCache batch read of parallel-request gauges.Tr¢  Nr£  )rœ   rn  r   s      rg   Ú_batch_get_gauge_valuesz<_PROXY_MaxParallelRequestsHandler_v3._batch_get_gauge_values“  s:   è ø€ ð ×.Ñ.×DÑDØØ-Øð Eó 
÷ 
ð 	
ð 
úr¦  c              ƒ   óÀ  K  — | j                   €g S | j                  |«      }g }|j                  «       D ]>  \  }}	 | j                  ||| j                  g¬«      ƒ d{  –—† }|j	                  |«       Œ@ |S 7 Œ# t
        $ rY}t        j                  d||«       | j                  ||| j                  ¬«      ƒ d{  –—†7  }|j	                  |«       Y d}~Œ¢d}~ww xY w­w)a  
        Execute Redis operations grouped by hash tag for cluster compatibility.

        Args:
            keys_to_fetch: List[str] - List of keys to fetch
            now_int: int - Current timestamp

        Returns:
            List of cache values
        N©rn  Úargsz+Redis Lua script failed for hash tag %s: %s©rn  ro  r_   )	r÷   rŸ  Úitemsr_   Úextendr¸   r   Úwarningr~  )	rœ   rƒ  ro  Ú
key_groupsÚall_cache_valuesÚhash_tagÚ
group_keysÚgroup_cache_valuesr  s	            rg   Ú(_execute_redis_batch_rate_limiter_scriptzM_PROXY_MaxParallelRequestsHandler_v3._execute_redis_batch_rate_limiter_scriptŸ  s  è ø€ ð ×)Ñ)Ð1ØˆIà ×8Ñ8¸ÓGˆ
ØBDÐà$.×$4Ñ$4Ó$6ò 	<Ñ ˆH�jð<Ø?C×?]Ñ?]Ø#Ø! 4×#3Ñ#3Ð4ð @^ó @÷ :Ð"ð !×'Ñ'Ð(:Õ;ð	<ð"  Ðð:ùô
 ò <Ü$×,Ñ,Ð-ZÐ\dÐfgÔhà+/×+NÑ+NØ#Ø#Ø $× 0Ñ 0ð ,Oó ,÷ &ð &Ð"ð
 !×'Ñ'Ð(:×;Ñ;ûð<üsL   ‚8C»"A9ÁA7ÁA9Á3CÁ7A9Á9	CÂ8CÂ:B=Â;CÃCÃCÃCr”   Ú	read_onlyÚskip_tpm_checkÚparallel_slot_idc              ƒ   ó¨  K  — | j                  «       }|j                  «       }t        |«      }| j                  ||¬«      \  }	}
}t	        dg ¬«      }|	�rŒ| j                  |	|d¬«      ƒ d{  –—† }|�| j                  |	||
«      }|d   dk(  r|S |rK| j                  |	|d	¬«      ƒ d{  –—† }|�€|	D �cg c]   }|j                  d
«      rt        |«      nd‘Œ" }}nç| j                  �µ| j                  |	|¬«      ƒ d{  –—† }t        dt        |«      d«      D ]€  }|	|   }|	|dz      }||   }||dz      }| j                  j                  ||| j                  |d¬«      ƒ d{  –—†  | j                  j                  ||| j                  |d¬«      ƒ d{  –—†  Œ‚ n&| j!                  |	|| j                  ¬«      ƒ d{  –—† }| j                  |	||
«      }|d   dk(  r|S |s|S | j#                  ||xs t%        j&                  «       j(                  ||¬«      ƒ d{  –—† }t	        |d   g |d   ¢|d   ¢¬«      S 7 �ŒÐ7 �Œ–c c}w 7 �ŒH7 Œå7 Œµ7 ŒŽ7 Œ2­w)uú  
        Check if any of the rate limit descriptors should be rate limited.
        Returns a RateLimitResponse with the overall code and status for each descriptor.
        Uses batch operations for Redis to improve performance.

        Args:
            descriptors: List of rate limit descriptors to check
            parent_otel_span: Optional OpenTelemetry span for tracing
            read_only: If True, only check limits without incrementing counters
            skip_tpm_check: If True, ignore each descriptor's ``tokens_per_unit``
                â€” the :tokens counter is neither read nor incremented by this
                pass. Callers that handle TPM via the atomic
                ``reserve_tpm_tokens`` reservation path should set this to
                avoid the +1-per-key Lua / in-memory increment double-charging
                the tokens counter.

        ``max_parallel_requests`` descriptors are enforced by the dedicated
        concurrency-gauge path (``_check_parallel_request_gauges``), never by
        the windowed counters. The gauge phase must stay AFTER the windowed
        check so a windowed rejection never strands an acquired slot; the
        reverse order would leak one gauge slot per RPM/TPM rejection.
        ``parallel_slot_id`` names the slot an admission registers; callers
        that enforce (not read_only) should pass the id they will later
        release with â€” when omitted, a generated slot id is used and the slot
        can only be reclaimed by TTL expiry.
        )r”   r·  r‡  rŠ  Tr¢  Nr…   rˆ  Fz:windowr   )rƒ  ro  rq  r  ru  r¬  )Úgaugesrv   r   r¶  r†   )r  Ú	timestamprc   Ú!_collect_windowed_keys_and_gaugesr„   r¥  rŽ  r‹  rn   r÷   rµ  rv  r\  rë   rx  r_   r~  Ú_check_parallel_request_gaugesÚuuidÚuuid4Úhex)rœ   r”   r   r¶  r·  r¸  Úcurrent_timerò   ro  rƒ  r…  rº  Úwindowed_responser„  r½   rk   rz  r�   rq   Úwindow_valuer�  Úgauge_responses                         rg   Úshould_rate_limitz6_PROXY_MaxParallelRequestsHandler_v3.should_rate_limitÇ  s   è ø€ ðF #×4Ñ4Ó6ˆØ!×+Ñ+Ó-ˆÜ˜S›ˆà.2×.TÑ.TØ#Ø)ð /Uó /
Ñ+ˆ�| Vô
 .¸4È"ÔMÐÚà!%×!?Ñ!?Ø"Ø!1Øð "@ó "÷ ˆLð Ð'Ø-1×-JÑ-JÈ=ÐZfÐhtÓ-uÐ#Ø& ~Ñ6¸,ÒFØ.Ð.ñ à%)×%CÑ%CØ&Ø%5Ø$ð &Dó &÷  �ð  Ñ'àR_ö$ØKN¨¯©°YÔ(?œ˜GœÀQÑFð$�Lñ $ð ×/Ñ/Ð;ð &*×%RÑ%RØ"/Ø#ð &Só &÷  �ô ˜q¤# lÓ"3°QÓ7ò �AØ!.¨qÑ!1�JØ"/°°A±Ñ"6�KØ#/°¡?�LØ$0°°Q±Ñ$7�MØ×3Ñ3×CÑCØ'Ø+Ø ×,Ñ,Ø1AØ#'ð Dó ÷ ð ð ×3Ñ3×CÑCØ&Ø*Ø ×,Ñ,Ø1AØ#'ð Dó ÷ ñ ñð* &*×%HÑ%HØ&Ø#Ø $× 0Ñ 0ð &Ió &÷  �ð !%× =Ñ =¸mÈ\Ð[gÓ hÐØ  Ñ0°LÒ@Ø(Ð(áØ$Ð$à&*×&IÑ&IØØ$Ò8¬¯
©
«×(8Ñ(8Ø-Øð	 'Jó '
÷ !
ˆô !Ø'¨Ñ7ØRÐ(¨Ñ4ÐR°~ÀjÑ7QÐRô
ð 	
ðUùð ûò$ð ùðøðøð øð!
úsŒ   ‚A*IÁ,H<Á-<IÂ)H?Â*IÂ5%IÃ%IÃ?IÄ A$IÅ$I
Å%1IÆIÆ(IÆ?IÇ AIÈIÈIÈ?IÉIÉ
IÉIÉIÉIc           
      ó¶  — g }i }g }|D �]I  }|d   }|d   }|j                  d«      xs
 t        «       }	|	j                  d«      }
|rdn|	j                  d«      }|	j                  d«      }|	j                  d«      xs | j                  }d	|› d
|› d�}|�7|j                  t	        | j                  ||d«      t        |«      |¬«      «       d}|
�(| j                  ||d«      }|j                  ||g«       d}|�(| j                  ||d«      }|j                  ||g«       d}|s�Œ|
�t        |
«      nd|�t        |«      ndt        |«      |dœ||<   �ŒL |||fS )zÛ
        Split descriptors into the windowed (window_key, counter_key) fetch
        list with its per-window metadata, and the concurrency gauges for
        descriptors carrying a max_parallel_requests limit.
        rk   rl   rm   r\   Nr]   r^   r_   r€  r�  ú}:window)rq   rr   rs   Fr   Tr€   )r    r¡   r_   rs   )rÑ   r[   r_   r�   rp   r‚  rc   r®  )rœ   r”   r·  rƒ  r…  rº  r˜   rs   r‚   rm   r    r¡   Úmax_parallel_requests_limitr_   r�   Úrate_limit_setÚrpm_keyÚtpm_keys                     rg   r¼  zF_PROXY_MaxParallelRequestsHandler_v3._collect_windowed_keys_and_gaugesE  s´  € ð +-ˆØ<>ˆØ46ˆØ%ó *	ˆJØ'¨Ñ.ˆNØ)¨'Ñ2Ðà—‘˜|Ó,ÒTÔ0RÓ0Tð ð (Ÿ^™^Ð,?Ó@ˆNÙ#1™4°z·~±~ÐFWÓ7XˆLØ*4¯.©.Ð9PÓ*QÐ'Ø$Ÿ.™.¨Ó7ÒK¸4×;KÑ;KˆKà˜nÐ-¨QÐ/?Ð.@À	ÐJˆJà*Ð6Ø—‘Ü(Ø$(×$?Ñ$?Ø*Ð,<Ð>Uó%ô "Ð"=Ó>Ø'5ôôð #ˆNØÐ)Ø×5Ñ5°nÐFVÐXbÓc�Ø×$Ñ$ j°'Ð%:Ô;Ø!%�ØÐ'Ø×5Ñ5°nÐFVÐX`Óa�Ø×$Ñ$ j°'Ð%:Ô;Ø!%�á!Ùð ;IÐ:T¤3 ~Ô#6ÐZ^Ø5AÐ5M¤ LÔ 1ÐSWÜ" ;Ó/Ø"0ñ	(ˆL˜Ó$ðK*	ðV ˜l¨FÐ2Ð2rf   ÚgaugeÚ	in_flightr{   c           	      óN   — t        ||d   t        d|d   |z
  «      d|d   ¬«      S )Nrr   r   r^   rs   r‰  )rz   r  )rœ   rÌ  rÍ  r{   s       rg   Ú_gauge_statusz2_PROXY_MaxParallelRequestsHandler_v3._gauge_status  s8   € ÜØØ ™.Ü  5¨¡>°IÑ#=Ó>Ø3Ø Ð!1Ñ2ô
ð 	
rf   rã   c                 óâ   ‡— |€yt        |t        «      rG| j                  «       j                  «       t        z
  Št        ˆfd„|j                  «       D «       «      S t        dt        |«      «      S )zâ
        In-flight count from a cached gauge value: a dict of slot_id ->
        acquire timestamp when the in-memory registry is authoritative, or
        the mirrored integer count from the last Redis script result.
        r   c              3   ó\   •K  — | ]#  }t        |t        t        f«      sŒ|‰k\  sŒ d –— Œ% y­w)r  N)rÚ   rc   rå   )r-  ÚtsÚcutoffs     €rg   r/  zY_PROXY_MaxParallelRequestsHandler_v3._gauge_in_flight_from_cache_value.<locals>.<genexpr>’  s'   øè ø€ Òg˜R¼ÀBÌÌeÈÕ9UÐZ\Ð`fÓZf”qÑgùs   ƒ,Ÿ,¥,)	rÚ   r¶   r  r»  rV   ra  Úvaluesr  rc   )rœ   rã   rÓ  s     @rg   Ú!_gauge_in_flight_from_cache_valuezF_PROXY_MaxParallelRequestsHandler_v3._gauge_in_flight_from_cache_valueˆ  s`   ø€ ð ÐØÜ�i¤Ô&Ø ×2Ñ2Ó4×>Ñ>Ó@ÔCdÑdˆFÜÓg 9×#3Ñ#3Ó#5ÔgÓgÐgÜ�1”c˜)“nÓ%Ð%rf   rº  rv   c           
   ƒ   ót  K  — |D �cg c]  }|d   ‘Œ	 }}|rÑ| j                   �Q	 | j                  ||D �cg c]  }t        ‘Œ
 c}¬«      ƒ d{  –—† }|D �	cg c]  }	t        dt        |	«      «      ‘Œ }
}	n| j                  ||«      ƒ d{  –—† }
g }d}t        ||
«      D ]:  \  }}||d   k\  rdnd}|dk(  rd}|j                  | j                  |||«      «       Œ< t        ||¬	«      S | j                  ||«      ƒ d{  –—† }t        ||«      D ].  \  }}||d   k\  sŒt        d| j                  ||d«      g¬	«      c S  | j                  ��	 | j                  ||D ��cg c]  }|d   t        |fD ]  }|‘Œ Œ c}}¬«      ƒ d{  –—† }t        d   «      dk(  r?|t        |d   «      dz
     }t        d| j                  |t        |d   «      d«      g¬	«      S g }t        ||dd «      D ]h  \  }}| j                  j!                  |d   t        |«      t        |d¬«      ƒ d{  –—†  |j                  | j                  |t        |«      d«      «       Œj t        d|¬	«      S | j                  4 ƒd{  –—†  | j                  |||«      ƒ d{  –—† cddd«      ƒd{  –—†  S c c}w c c}w 7 �Œac c}	w # t        $ r<}t        j                  d|«       | j                  ||«      ƒ d{  –—†7  }
Y d}~�Œgd}~ww xY w7 �Œt7 �Œc c}}w 7 �Œ…# t        $ r}t        j                  d
|«       | j                  4 ƒd{  –—†7   | j                  |||«      ƒ d{  –—†7  cddd«      ƒd{  –—†7   cY d}~S # 1 ƒd{  –—†7  sw Y   nxY wY d}~�Œd}~ww xY w7 �Œt7 �Œ(7 �Œ7 �Œ# 1 ƒd{  –—†7  sw Y   yxY w­w)a¯  
        Enforce max_parallel_requests as a concurrency gauge over a per-slot
        registry: each admitted request registers ``slot_id`` with its
        acquire time, and admission requires in_flight + 1 <= limit over the
        unexpired slots. Unlike the windowed RPM/TPM counters, the gauge is
        never reset while requests are in flight, a rejected request never
        occupies a slot, and a slot leaked by a crashed worker is pruned
        after PARALLEL_REQUEST_SLOT_TTL_SECONDS even under continuous
        traffic. Releases remove exactly this request's slot id, so a
        double-fired or unmatched release can never free another request's
        slot.
        rq   Nrª  r   z4parallel_count_script failed, using local mirror: %sr‡  rr   rˆ  rŠ  zCparallel_acquire_script failed, falling back to in-memory gauge: %sr  rq  Tru  )rý   rV   r  rc   r¸   r   r¯  Ú_read_local_gauge_countsÚzipr�   rÏ  r„   rû   r  Ú!_acquire_parallel_slots_in_memoryrë   rx  )rœ   rº  rv   r   r¶  rÌ  Ú
gauge_keysÚ_Ú
raw_countsrl   Úcountsr  r†   r…   rÍ  r{   Úlocal_countsÚargÚraws                      rg   r½  zC_PROXY_MaxParallelRequestsHandler_v3._check_parallel_request_gauges•  s  è ø€ ð& @FÖF°e˜U =Ó1ÐFˆ
ÐFáØ×)Ñ)Ð5ð_ØGK×GaÑGaØ'ØIOÖPÀAÖ?ÒPð Hbó H÷ B�Jð ?IÖI°Uœc !¤S¨£ZÕ0ÐI�FÑIð
  $×<Ñ<¸ZÐIYÓZ×Z�ØˆHØˆLÜ$'¨°Ó$7ò LÑ ��yØ'0°E¸'±NÒ'B‘|È�Ø˜<Ò'Ø#/�LØ—‘ × 2Ñ 2°5¸)ÀTÓ JÕKð	Lô
 %°,ÈÔRÐRà$(×$AÑ$AÀ*ÐN^Ó$_×_ˆÜ # F¨LÓ 9ò 	ÑˆE�9Ø˜E '™NÓ*Ü(Ø!-Ø"×0Ñ0°¸	À<ÓPÐQôò ð	ð ×'Ñ'Ñ3ð
kØ<@×<XÑ<XØ#à)/÷Ø %¸EÀ'¹NÔLmÐovÐ;wòØ47šðØóð =Yó =÷ 7�ô �3�q‘6‹{˜aÒØœs 3 q¡6›{¨Q™Ñ/�Ü(Ø!-Ø"×0Ñ0°¼¸CÀ¹F»À\ÓRÐSôð ð ˆHÜ$'¨°°A°B°Ó$8ò QÑ ��yØ×/Ñ/×?Ñ?Ø˜mÑ,Ü˜i›.Ü9Ø-=Ø#ð @ó ÷ ð ð —‘ × 2Ñ 2°5¼#¸i».È$Ó OÕPðQô %°$ÀÔJÐJà×1Ñ1÷ 	cñ 	cØ×?Ñ?ÀÈÐQaÓb×b÷	c÷ 	cñ 	cùò} Gùò QðBûò JøÜ ò _Ü(×0Ñ0Ð1gÐijÔkØ#'×#@Ñ#@ÀÐM]Ó#^×^Ð^–Fûð_úð [ùð `ûóð7úô ò kÜ$×,Ñ,Ð-rÐtuÔvØ×9Ñ9÷ kò kØ!%×!GÑ!GÈÐPWÐYiÓ!j×jÐj÷k÷ k÷ k÷ k÷ kñ kúõ kûðkúðùð	cùØbùð	cù÷ 	c÷ 	cñ 	cüsœ  ‚N8‡J#“N8¤J5 ´J(
ÁJ5 ÁJ-ÁJ5 ÁJ0Á1J5 Á3N8Â	K=Â
A3N8Ã=L Ã>N8Ä/N8ÅL ÅLÅ8L ÆL	ÆL Æ	BN8È#NÈ$AN8É2NÉ3N8É6N#ÊNÊN#ÊN8ÊN Ê
N8Ê(J5 Ê0J5 Ê5	K:Ê>+K5Ë)K,Ë*K5Ë/N8Ë5K:Ë:N8Ì N8ÌL Ì	NÌ&NÌ;L>Ì<NÍ M4ÍMÍM4ÍNÍ(M+Í)NÍ.NÍ/N8Í4N	Í:M=Í;N	ÎNÎ	N8ÎNÎN8ÎN8ÎN#Î N8Î#N5Î)N,Î*N5Î1N8rÚ  c              ƒ   óº   K  — | j                  ||¬«      ƒ d {  –—† }|€|D �cg c]  }d‘Œ c}S |D �cg c]  }| j                  |«      ‘Œ c}S 7 Œ5c c}w c c}w ­w)N)rn  r   r   )r¨  rÕ  )rœ   rÚ  r   rÔ  rÛ  rl   s         rg   r×  z=_PROXY_MaxParallelRequestsHandler_v3._read_local_gauge_countsé  si   è ø€ ð
 #×:Ñ:ØØ-ð ;ó 
÷ 
ˆð ˆ>Ø)Ö*˜!’AÒ*Ð*ØKQÖRÀ%�×6Ñ6°uÕ=ÒRÐRð
úò
 +ùÚRùs*   ‚A™Aš
A¤	A­A´AÁAÁ
Ac           
   ƒ   óp  K  — | j                  «       j                  «       }|t        z
  }g }|D ]ñ  }| j                  j	                  |d   |d¬«      ƒ d{  –—† }t        |t        «      rY|j                  «       D �	�
ci c].  \  }	}
t        |
t        t        f«      sŒ|
|k\  sŒ#|	t        |
«      “Œ0 }}	}
t        |xs i «      }n|€i }d}nd}t        dt        |«      «      }|dz   |d   kD  r!t        d| j                  ||d«      g¬	«      c S |j                  ||f«       Œó g }t        ||«      D ]k  \  }\  }}|�i |¥||i¥n|dz   }| j                  j!                  |d   |t        |d¬
«      ƒ d{  –—†  |j                  | j                  ||dz   d«      «       Œm t        d|¬	«      S 7 �ŒVc c}
}	w 7 ŒA­w)a  
        All-or-nothing in-memory slot-registry acquire. Caller holds the lock.

        A cached dict is the authoritative in-memory registry. A cached
        integer is the count mirrored from the last successful Redis script
        call: when Redis fails over to this path, that mirror still counts
        the slots in flight on the Redis side, so it is carried forward as
        an integer counter (not discarded as an empty registry, which would
        briefly double the admitted concurrency during a Redis outage).
        rq   Trr  Nr   r  rr   rˆ  rŠ  ru  r‡  )r  r»  rV   rë   rw  rÚ   r¶   r­  rc   rå   r\  r  r„   rÏ  r�   rØ  rx  )rœ   rº  rv   r   rò   rÓ  ÚstatesrÌ  rã   rk   rÒ  ÚregistryrÍ  r†   Ú	new_values                  rg   rÙ  zF_PROXY_MaxParallelRequestsHandler_v3._acquire_parallel_slots_in_memoryö  sý  è ø€ ð  ×+Ñ+Ó-×7Ñ7Ó9ˆØÔ?Ñ?ˆØCEˆØò 	1ˆEØ>B×>WÑ>W×>gÑ>gØ˜-Ñ(Ø)9Øð ?hó ?÷ 9ˆIô
 ˜)¤TÔ*à2;·/±/Ó2C÷5Ù'. s¨BÄzÐRTÔWZÔ\aÐVbÕGcÐhjÐntÓht�Cœ˜r›‘Nð5�ñ 5ô   ¢¨BÓ/‘	ØÐ"Ø�Ø‘	à�Ü ¤3 y£>Ó2�	Ø˜1‰}˜u W™~Ò-Ü(Ø!-Ø"×0Ñ0°¸	À<ÓPÐQôò ð �M‰M˜8 YÐ/Õ0ð-	1ð0 ˆÜ,/°¸Ó,?ò 		LÑ(ˆEÑ(�H˜iØNVÐNbÐ0J°8Ð0J¸WÀcÒ0JÐhqÐtuÑhuˆIØ×+Ñ+×;Ñ;Ø˜-Ñ(ØÜ5Ø)9Øð <ó ÷ ð ð �O‰O˜D×.Ñ.¨u°iÀ!±mÀTÓJÕKð		Lô !¨d¸XÔFÐFðE9ûó5ð(ús=   ‚AF6ÁF+Á'F6Á=F.ÂF.Â"F.Â0CF6Å2F4Å39F6Æ.F6Úacquisitionc           
   ƒ   ó¢  K  — |d   }|d   }|r|sy| j                   �~	 | j                  ||D �cg c]  }|‘Œ c}¬«      ƒ d{  –—† }t        ||«      D ]D  \  }}| j                  j                  |t	        dt        |«      «      t        |d¬«      ƒ d{  –—†  ŒF y| j                  4 ƒd{  –—†  |D ]®  }| j                  j                  ||d¬	«      ƒ d{  –—† }
t        |
t        «      r/||
vrŒ>|
j                  «       D ��ci c]  \  }}||k7  sŒ||“Œ }}}n|
€Œkt	        dt        |
«      d
z
  «      }| j                  j                  ||t        |d¬«      ƒ d{  –—†  Œ° ddd«      ƒd{  –—†  yc c}w 7 �Œ77 Œè# t        $ r!}	t        j                  d|	«       Y d}	~	�Œd}	~	ww xY w7 Œÿ7 ŒÖc c}}w 7 ŒX7 ŒH# 1 ƒd{  –—†7  sw Y   yxY w­w)aÆ  
        Release the max_parallel_requests slots acquired at pre-call by
        removing this request's slot id from every gauge it was registered
        under. Removing an absent slot id is a no-op, so a release without a
        matching acquire or a double-fired release can never free another
        request's slot. The in-memory fallback decrements integer mirror
        values (floored at 0) because the mirror carries no per-slot ids.
        rw   rv   Nrª  r   Tru  zEparallel_release_script failed, falling back to in-memory release: %srr  r  )rü   rØ  rë   rx  r  rc   rV   r¸   r   r¯  r  rw  rÚ   r¶   r­  )rœ   ræ  r   rw   rv   rÛ  rà  rq   Ú	remainingr  rã   rk   rÒ  rå  s                 rg   Ú_release_parallel_request_slotszD_PROXY_MaxParallelRequestsHandler_v3._release_parallel_request_slots.  s  è ø€ ð *¨.Ñ9ˆØ$ YÑ/ˆÙ¡7ØØ×'Ñ'Ð3ðyØ<@×<XÑ<XØ%Ø+7Ö8 aš'Ò8ð =Yó =÷ 7�ô /2°,ÀÓ.Dò Ñ*�K Ø×3Ñ3×CÑCØ'Ü! !¤S¨£^Ó4Ü=Ø1AØ#'ð Dó ÷ ñ ðð ð ×1Ñ1÷ 	ñ 	Ø+ò �ØBF×B[ÑB[×BkÑBkØ#Ø-=Ø#ð Cló C÷ =�	ô
 ˜i¬Ô.Ø iÑ/Ø ØQZ×Q`ÑQ`ÓQb×9uÁgÀcÈ2ÐfiÐmtÓft¸#¸r¹'Ð9u�IÒ9uØÐ&Øä # A¤s¨9£~¸Ñ'9Ó :�IØ×/Ñ/×?Ñ?Ø#Ø#Ü9Ø-=Ø#ð @ó ÷ ñ ð÷	÷ 	ð 	ùò 9ð7ùð
ùô ò yÜ$×,Ñ,Ð-tÐvw×xÒxûðyúð	øð=úó :vð
øð	ø÷ 	÷ 	ñ 	üsÖ   ‚GŸE? ¯	E5
¸E? ÁE:ÁAE? ÂE=ÂE? ÂGÂ,F,Â-GÂ0'F:ÃF.Ã,F:ÄF0
ÄF0
ÄAF:ÅF6ÅF:Å$GÅ/F8Å0GÅ5E? Å=E? Å?	F)ÆF$ÆGÆ$F)Æ)GÆ.F:Æ0F:Æ8GÆ:GÇ GÇGÇGÚ
incrementsr¤   c           	   ƒ   óN  K  — t        |«      t        |«      k7  rt        d«      ‚g }t        ||«      D ]3  \  }}| j                  ||¬«      \  }}}	|sŒ |j	                  |||	f«       Œ5 |st        dg ¬«      S | j                  �| j                  ||¬«      ƒ d{  –—† S |D �
���cg c]  \  }
}}|D ]  }|‘Œ Œ }}}}
}| j                  4 ƒd{  –—†  | j                  ||¬«      ƒ d{  –—† cddd«      ƒd{  –—†  S 7 Œec c}}}}
w 7 Œ:7 Œ!7 Œ# 1 ƒd{  –—†7  sw Y   yxY w­w)u5  
        Atomic check-and-increment-by-N across one or more descriptors.

        All-or-nothing: if any descriptor would exceed its limit, no counter is
        modified and the response carries `overall_code = "OVER_LIMIT"` with
        the offending descriptor's status. Closes the TOCTOU window between
        read and increment in both single-process and multi-process (Redis)
        deployments.

        Cluster-safety: each descriptor's keys all share a `{key:value}` hash
        tag, so the Redis Lua path issues one Lua call per descriptor â€” every
        call's keys co-locate on a single Redis Cluster slot, avoiding
        CROSSSLOT errors. Cross-descriptor atomicity is preserved via
        refund-on-rollback: if descriptor i is OVER_LIMIT, descriptors 0..i-1
        get a direct INCRBY refund (refunds need no atomicity guarantee).

        Args:
            descriptors: rate-limit descriptors to check
            increments: per-descriptor increment amounts, indexed parallel to
                `descriptors`. Each entry is `{"requests": int, "tokens": int}`
                â€” values default to 0 when a descriptor has no matching limit.

        Returns:
            RateLimitResponse with one status per (descriptor, rate_limit_type)
            counter, mirroring `should_rate_limit`'s shape.
        zUatomic_check_and_increment_by_n: descriptors and increments must have the same length)r˜   Úincrement_amountsr‡  rŠ  N)Údescriptor_groupsr   ©Úper_counter_metar   )
r\  ræ   rØ  Ú _build_descriptor_atomic_payloadr�   r„   rù   Ú_atomic_lua_per_descriptorr  Ú%_atomic_check_and_increment_in_memory)rœ   r”   rê  r   rí  r˜   rì  rn  r«  ÚmetaÚ_keysÚ_argsÚ
group_metaÚmÚ	flat_metas                  rg   Úatomic_check_and_increment_by_nzD_PROXY_MaxParallelRequestsHandler_v3.atomic_check_and_increment_by_nh  st  è ø€ ô@ ˆ{Óœs :›Ò.ÜÐtÓuÐuð
 ACÐÜ-0°¸jÓ-Iò 	=Ñ)ˆJÐ)Ø#×DÑDØ%Ø"3ð  Eó  ÑˆD�$˜ò Ø!×(Ñ(¨$°°dÐ);Õ<ð	=ñ !Ü$°$ÀÔDÐDð ×/Ñ/Ð;Ø×8Ñ8Ø"3Ø!1ð 9ó ÷ ð ð /@÷5
ñ 5
Ù*�%˜ 
Èò5
ØDEŠAð5
Øð5
ˆ	ó 5
ð ×1Ñ1÷ 	ñ 	Ø×CÑCØ!*Ø!1ð Dó ÷ ÷	÷ 	ñ 	ðúõ
5
ð	øðøð	ø÷ 	÷ 	ñ 	üs   ‚AD%ÁAD%ÂD ÂD%Â&D
Â:D%ÃD
ÃD%ÃDÃ*DÃ+DÃ.D%Ã:DÃ;D%Ä	D%ÄDÄD%ÄD"ÄDÄD"ÄD%r˜   rì  c                 ó   — |d   }|d   }|j                  d«      xs
 t        «       }|j                  d«      xs | j                  }d|› d|› d�}g }g }	g }
d}|D ]î  }|d	k(  r1|j                  d
«      }t        |j                  d	d«      xs d«      }n0|j                  d«      }t        |j                  dd«      xs d«      }|�|dk  rŒq| j	                  |||«      }t        |«      }t        |«      }|j                  ||g«       |	j                  t        |«      |||g«       |
j                  ||t        |«      ||||||dœ	«       Œð ||	|
fS )z¡
        Build (KEYS, ARGV, per-counter meta) for a single descriptor's Lua
        call. All keys returned share the descriptor's {key:value} hash tag.
        rk   rl   rm   r_   r€  r�  rÇ  r¤   r   r\   r   r]   r€   )	rs   r‚   r|   r�   r�   rq   r¥   r¦   r_   )rÑ   r[   r_   rc   r‚  r®  r�   )rœ   r˜   rì  rs   r‚   rm   r_   r�   rn  r«  ró  Úrate_limit_typesÚrltÚlimit_valueÚ
inc_amountrq   Úttl_secondsÚwindow_size_secondss                     rg   rð  zE_PROXY_MaxParallelRequestsHandler_v3._build_descriptor_atomic_payload®  s”  € ð !+¨5Ñ 1ˆØ",¨WÑ"5Ðà�N‰N˜<Ó(ÒPÔ,NÓ,Pð 	ð (Ÿ^™^¨MÓ:ÒN¸d×>NÑ>NˆØ  Ð 0°Ð2BÐ1CÀ9ÐMˆ
à!#ˆØ!#ˆØ/1ˆàMcÐØ#ò  	ˆCØ�jÒ Ø(Ÿn™nÐ-@ÓA�Ü Ð!2×!6Ñ!6°zÀ1Ó!EÒ!JÈÓK‘
à(Ÿn™nÐ->Ó?�Ü Ð!2×!6Ñ!6°xÀÓ!CÒ!HÀqÓI�
ØÐ" j°1¢nØØ×5Ñ5°nÐFVÐX[Ó\ˆKô
 ˜kÓ*ˆKÜ"% kÓ"2ÐØ�K‰K˜ [Ð1Ô2ð �K‰Kœ˜[Ó)¨:°{ÐDWÐXÔYØ�K‰Kà&4Ø(8Ü%(¨Ó%5Ø'*Ø",Ø#.Ø!+Ø&Ø#6ñ
õð) 	ðB �T˜4ÐÐrf   rí  c              ƒ   óš  K  — |st        dg ¬«      S g }g }t        |«      D ]“  \  }\  }}}	 | j                  ||¬«      ƒ d{  –—† }	| j                  	|«      }|d   dk(  r| j                  |«      ƒ d{  –—†  |c S t        |«      d	k(  r|c S |j                  |«       |j                  |d
   «       Œ• t        d|t!        «       ¬«      S 7 ŒŠ# t        $ rí}
t	        j
                  dt        |
«      j                  |
t        |«      | j                  «       | j                  |«      ƒ d{  –—†7   |D ����cg c]  \  }}}|D ]  }|‘Œ Œ nc c}}}}w }}}}}| j                  4 ƒd{  –—†7   | j                  ||¬«      ƒ d{  –—†7  cddd«      ƒd{  –—†7   cY d}
~
c S # 1 ƒd{  –—†7  sw Y   nxY wY d}
~
�Œyd}
~
ww xY w7 �ŒS­w)a3  
        Run Lua check-and-increment one descriptor at a time so each call's
        keys co-locate on a single Redis Cluster slot. On OVER_LIMIT for
        descriptor i, refund descriptors 0..i-1's increments. On Lua failure
        mid-loop, refund applied increments and fall back to in-memory.
        r‡  rŠ  rª  NuÛ   atomic_check_and_increment_by_n: Redis Lua execution failed (%s: %s). Refunding %s prior descriptors and falling back to in-memory enforcement â€” counters will diverge from Redis until window expires (window_size=%ss).rî  r…   rˆ  r  r†   ©r…   r†   rŠ   )r„   Ú	enumeraterù   r¸   r   ÚerrorÚtyper`   r\  r_   Ú!_refund_applied_descriptor_groupsr  rò  Ú_build_atomic_responser�   r®  r‹   )rœ   rí  r   Úappliedr†   Ú_idxrn  r«  ró  rà  r  Ú_kÚ_arö  r÷  rø  r•   s                    rg   rñ  z?_PROXY_MaxParallelRequestsHandler_v3._atomic_lua_per_descriptorç  sì  è ø€ ñ !Ü$Ø!Øôð ð 9;ˆØ13ˆô )2Ð2CÓ(Dò !	2Ñ$ˆDÑ$�4˜˜tðØ ×@Ñ@ØØð Aó ÷ �ð0 ×2Ñ2°3¸Ó=ˆHØ˜Ñ'¨<Ò7Ø×<Ñ<¸WÓE×EÐEØ’ÜÐ$Ó%¨Ò*Ø’Ø�N‰N˜4Ô Ø�O‰O˜H ZÑ0Õ1ðC!	2ôF !ØØÜ )£ô
ð 	
ðCùô ò ô
 %×*Ñ*ð rÜ˜“G×$Ñ$ØÜ˜“LØ×$Ñ$ôð ×<Ñ<¸WÓE×EÑEØRc×5xÑ5xÑ<N¸BÀÀJÐmwÒ5xÐhi²aÐ5x°aÑ5xùÕ5x�	Ó5xØ×9Ñ9÷ ò Ø!%×!KÑ!KØ)2Ø)9ð "Ló "÷ ð ÷÷ ÷ ÷ ÷ ó úõ ûðúð, Fûsº   ‚)G¬CÁCÁCÁ.GÁ5GÁ6AGÃCÃ	GÃAG Ä+D.Ä,G Ä8EÅG Å*E-
Å+G Å/F%ÆF	
ÆF%ÆG ÆF
ÆG ÆGÆGÆ%F7Æ+F.Æ,F7Æ3G Æ:GÇ GÇGr  c              ƒ   ó  K  — |sy| j                   j                  j                  }|€y|D ],  }|D ]%  }	 |j                  |d   |d    ¬«      ƒ d{  –—†  Œ' Œ. y7 Œ	# t        $ r$}t        j                  d|d   |«       Y d}~ŒUd}~ww xY w­w)ué   
        Decrement counters for descriptor groups already applied via Lua.
        Best-effort: refund failures are logged but not raised â€” the original
        OVER_LIMIT / fallback decision is what matters to the caller.
        Nrq   r¥   )rk   rl   z4Failed to refund %s on cross-descriptor rollback: %s)rë   rô   rõ   Úasync_incrementr¸   r   r¯  )rœ   r  rõ   rö  Úentryr  s         rg   r  zF_PROXY_MaxParallelRequestsHandler_v3._refund_applied_descriptor_groups$  s¹   è ø€ ñ ØØ!×6Ñ6×AÑA×MÑMˆØÐØØ!ò 
	ˆJØ#ò 	�ðØ%×5Ñ5Ø! -Ñ0Ø$ [Ñ1Ð1ð 6ó ÷ ñ ñ	ñ
	ðùô !ò Ü(×0Ñ0ØNÐPUÐVcÑPdÐfg÷ñ ûðüs@   ‚1B´AÁAÁAÁBÁAÁ	B
Á&BÂ BÂB
Â
Brà  rï  c                 ó.  ‡— ‰st        dg ¬«      S t        ‰d   «      }|dk(  ret        ‰d   «      dz
  }t        ‰d   «      }t        ‰d   «      }||   }t        dt        d|t        d||z
  «      |d   |d	   |d
   ¬«      g¬«      S g }t	        |«      D ]U  \  }	}‰d|	dz  z      }
|j                  t        d|d   t        d|d   t        |
«      z
  «      |d   |d	   |d
   ¬«      «       ŒW t        d|t        ˆfd„t	        |«      D «       «      ¬«      S )uy  Convert Lua script return value to RateLimitResponse.

        Indexing invariant: `per_counter_meta` and `KEYS` are parallel-indexed
        at the COUNTER level, not the descriptor level. A descriptor with both
        RPM and TPM limits emits two `(window_key, counter_key)` pairs and
        two meta entries â€” one per counter. The Lua script's loop variable
        `i` therefore enumerates counters, and the over-limit return tuple
        `{1, i, ...}` carries a counter index that maps directly to
        `per_counter_meta[i - 1]`. Keep these arrays parallel at the counter
        level when modifying this code.
        r‡  rŠ  r   r  rq  é   rˆ  r�   rs   r‚   ©r{   r|   r}   r�   rs   r‚   r|   c           
   3   ój   •K  — | ]*  \  }}|d    t        t        ‰d|dz  z      «      «      df–— Œ, y­w)rq   rq  rˆ   N)rn   rc   )r-  Úindexró  rà  s      €rg   r/  zN_PROXY_MaxParallelRequestsHandler_v3._build_atomic_response.<locals>.<genexpr>v  sF   øè ø€ ò *ñ  �E˜4ð	 ˜Ñ'Üœ˜C  E¨A¡I¡Ñ.Ó/Ó0Øôñ*ùs   ƒ03r  )r„   rc   rz   r  r  r�   r‹   )rœ   rà  rï  Ústatus_codeÚdescriptor_indexr|  rr   ró  r†   r  Únew_counters    `         rg   r  z;_PROXY_MaxParallelRequestsHandler_v3._build_atomic_response>  se  ø€ ñ  Ü$°$ÀÔDÐDä   Q¡›[ˆØ˜!Òä&)¨#¨a©&£k°A¡oÐÜ%(¨¨Q©£[ˆOÜ˜s 1™v›;ˆEØ#Ð$4Ñ5ˆDÜ$Ø)ä#Ø)Ø&+Ü(+¨A¨u°Ñ/FÓ(GØ(,Ð->Ñ(?Ø'+Ð,<Ñ'=Ø)-Ð.@Ñ)Aôð	ôð ð 24ˆÜ$Ð%5Ó6ò 	‰KˆE�4Ø˜a %¨!¡)™mÑ,ˆKØ�O‰OÜØØ"& Ñ"7Ü$'¨¨4°Ñ+@Ä3À{ÓCSÑ+SÓ$TØ$(Ð):Ñ$;Ø#'Ð(8Ñ#9Ø%)Ð*<Ñ%=ôõ	ð	ô !ØØÜ )ó *ô $-Ð-=Ó#>ô*ó !ô
ð 	
rf   c              ƒ   óŠ  K  — t        | j                  «       j                  «       «      }g }|D �]  }|d   }| j                  j	                  |d   |d¬«      ƒ d{  –—† }|du xs |t        |«      z
  |k\  }|rdn(| j                  j	                  |d   |d¬«      ƒ d{  –—† }	|rdnt        |	xs d«      }
|d   dkD  r|
|d   z   |d	   kD  n|
|d	   k\  }|r;t        d
t        d
|d	   t        d|d	   |
z
  «      |d   |d   |d   ¬«      g¬«      c S |j                  ||
t        |r|n
t        |«      «      dœ«       �Œ g }t        ||«      D ]À  \  }}|d   r|d   n
|d   |d   z   }|d   r7| j                  j                  |d   t        |«      |d   |d¬«      ƒ d{  –—†  | j                  j                  |d   ||d   |d¬«      ƒ d{  –—†  |j                  t        d|d	   t        d|d	   |z
  «      |d   |d   |d   ¬«      «       ŒÂ t        d|t        d„ t        ||«      D «       «      ¬«      S 7 �ŒÞ7 �Œ�7 Œž7 Œr­w)u`  In-memory all-or-nothing check-and-increment. Caller holds lock.

        Reads/writes the LOCAL DualCache (`local_only=True`) â€” note this is
        a different store from Redis. When this fallback fires after a Lua
        failure, in-memory counters will diverge from Redis until each key's
        window expires (TTL bounds divergence).
        r_   r�   Trr  Nrq   r   r¥   r|   rˆ  r�   rs   r‚   r  rŠ  )r©   rª   r«   r©   rª   ru  r¦   r‡  c              3   ó8   K  — | ]  \  }}|d    |d   df–— Œ y­w)rq   r«   r‰   Nre   )r-  ró  Ústates      rg   r/  z]_PROXY_MaxParallelRequestsHandler_v3._atomic_check_and_increment_in_memory.<locals>.<genexpr>ß  s-   è ø€ ò *á�D˜%ð �mÑ$ e¨NÑ&;¸WÔEñ*ùó   ‚r  )rc   r  r»  rë   rw  r„   rz   r  r�   rn   rØ  rx  r‹   )rœ   rï  r   ro  Údescriptor_stateró  r_   r«   r©   Úraw_counterr|  Ú
over_limitr†   r  r  s                  rg   rò  zJ_PROXY_MaxParallelRequestsHandler_v3._atomic_check_and_increment_in_memory€  s  è ø€ ô ˜T×3Ñ3Ó5×?Ñ?ÓAÓBˆð =?ÐØ$ó +	ˆDØ˜}Ñ-ˆKØ;?×;TÑ;T×;dÑ;dØ˜Ñ&Ø)9Øð <eó <÷ 6ˆLð
 *¨TÐ1Òa°gÄÀLÓ@QÑ6QÐVaÑ5aˆNñ "ñ à×4Ñ4×DÑDØ˜]Ñ+Ø-=Ø#ð Eó ÷ ð ñ $2™a´s¸;Ò;KÈ!Ó7LˆOð ˜Ñ$ qÒ(ð   $ {Ñ"3Ñ3°d¸?Ñ6KÒKà$¨¨_Ñ(=Ñ=ð ñ
 Ü(Ø!-ä'Ø!-Ø*.¨Ñ*?Ü,/°°4¸Ñ3HÈ?Ñ3ZÓ,[Ø,0Ð1BÑ,CØ+/Ð0@Ñ+AØ-1Ð2DÑ-Eôð	ôò ð ×#Ñ#à&4Ø.Ü$'±>©ÄsÈ<ÓGXÓ$YñöðK+	ð\ 24ˆÜÐ/Ð1AÓBò 	‰KˆD�%Ø/4Ð5EÒ/F˜$˜{Ò+ÈEÐR[ÑL\Ð_cÐdoÑ_pÑLpˆKØÐ%Ò&Ø×/Ñ/×?Ñ?Ø˜\Ñ*Ü˜g›,Ø˜]Ñ+Ø-=Ø#ð @ó ÷ ð ð ×+Ñ+×;Ñ;Ø˜Ñ'Ø!Ø˜‘KØ)9Øð <ó ÷ ð ð �O‰OÜØØ"& Ñ"7Ü$'¨¨4°Ñ+@À;Ñ+NÓ$OØ$(Ð):Ñ$;Ø#'Ð(8Ñ#9Ø%)Ð*<Ñ%=ôõ	ð#	ô6 !ØØÜ )ñ *ä#&Ð'7Ð9IÓ#Jô*ó !ô
ð 	
ðQ6ùðùðNøðúsK   ‚AIÁH9ÁAIÂH<Â D IÆ H?Æ!-IÇIÇA+IÈ<IÈ?IÉIÚestimated_tokensc              ƒ   óä  K  — |D �cg c]š  }|d   t         t        fvr‡|j                  d«      xs i j                  d«      �ct        |d   |d   t	        |j                  d«      xs i j                  d«      |j                  d«      xs i j                  d«      ¬«      ¬«      ‘Œœ }}|st        d	g ¬
«      S |D �cg c]  }d|i‘Œ }}| j                  |||¬«      ƒ d{  –—† S c c}w c c}w 7 Œ­w)aq  
        Reserve ``estimated_tokens`` against every TPM-bearing descriptor
        BEFORE the upstream call, so concurrent requests cannot all observe
        "under limit" before any of them increments the counter.

        Thin wrapper around ``atomic_check_and_increment_by_n``: builds a
        TPM-only descriptor/increment list and delegates the all-or-nothing
        atomicity (Lua on Redis, asyncio-locked DualCache otherwise) to the
        shared primitive.

        Excludes project ITPM/OTPM descriptors -- those are reserved
        separately (different estimate per bucket) via ``reserve_io_tokens``.
        rk   rm   r]   Nrl   r_   )r]   r_   ©rk   rl   rm   r‡  rŠ  r€   ©r”   rê  r   )rS   rU   rÑ   rj   r[   r„   rù  )rœ   r”   r  r   ÚdÚtpm_descriptorsrÛ  rê  s           rg   Úreserve_tpm_tokensz7_PROXY_MaxParallelRequestsHandler_v3.reserve_tpm_tokenså  s  è ø€ ð8 !ö=
ð Ø�‰xÔ ;Ô=XÐYÑYØ—‘�|Ó$Ò*¨×/Ñ/Ð0AÓBÐNô  Ø�e‘HØ˜‘jÜ=Ø%&§U¡U¨<Ó%8Ò%>¸B×$CÑ$CÐDUÓ$VØ!"§¡ |Ó!4Ò!:¸× ?Ñ ?ÀÓ Nôöð=
ˆð =
ñ Ü$°$ÀÔDÐDð 3BöM
Ø-.ˆXÐ'Ò(ðM
ˆ
ð M
ð ×9Ñ9Ø'Ø!Ø-ð :ó 
÷ 
ð 	
ùò'=
ùò M
ð
ús)   ‚C0‡BC$Â&C0Â;C)ÃC0ÃC.Ã C0ÚscopesÚamountrŠ   r‡   c              ƒ   ó  K  — |dk  s|sy|s8| j                  | j                  |t        |«      d|¬«      |¬«      ƒ d{  –—†  y| j                  |t        |«      d||¬«      }| j	                  ||¬«      ƒ d{  –—†  y7 Œ@7 Œ­w)ap  
        Directly decrement previously-reserved token counters for ``scopes``
        by ``amount``. Used to roll back a reservation that already
        succeeded once a *different* bucket in the same request turns out to
        be over its limit (e.g. ITPM reserved fine, OTPM then hits its
        limit -- the ITPM reservation must not be left inflated).
        r   N©ÚtargetsrÂ   Úactual_tokensr¿   ©Úpipeline_operationsr   ©r)  rÂ   r*  r¿   Úreservation_window_identities)Ú,async_increment_tokens_with_ttl_preservationÚ _build_reservation_aware_tpm_opsr‹   Ú_build_project_reservation_opsÚ(async_increment_reservation_aware_tokens)rœ   r%  r&  rŠ   r   r,  s         rg   Ú_refund_reserved_tokensz<_PROXY_MaxParallelRequestsHandler_v3._refund_reserved_tokens  s¿   è ø€ ð �QŠ;™fØÙ"Ø×CÑCØ$(×$IÑ$IØ"Ü$-¨fÓ$5Ø"#Ø$*ð	 %Jó %ð "2ð Dó ÷ ð ð Ø%)×%HÑ%HØÜ% fÓ-ØØ"Ø*=ð &Ió &
Ðð ×;Ñ;Ø 3Ø-ð <ó 
÷ 	
ñ 	
ð#øð"	
ús"   ‚=B¿B Á :BÁ:BÁ;BÂBrS  Úestimated_output_tokensc           
   ƒ   óZ  K  — |D �cg c]  }|d   t         k(  sŒ|‘Œ }}|D �cg c]  }|d   t        k(  sŒ|‘Œ }}|s|st        dg ¬«      ddfS |r,| j                  ||D �cg c]  }d|i‘Œ c}|¬«      ƒ d{  –—† nd}	|	�|	d   d	k(  r|	ddfS |	�|nd}
|rì| j                  ||D �cg c]  }d|i‘Œ c}|¬«      ƒ d{  –—† }|d   d	k(  rU|
dkD  rK| j	                  |D �cg c]  }|d   |d
   f‘Œ c}|
|	j                  dt        «       «      |¬«      ƒ d{  –—†  |ddfS |	�g |	d   ¢|d   ¢n|d   }t        d||	�|	j                  dt        «       «      n	t        «       |j                  dt        «       «      z  ¬«      |
|fS |	€J ‚|	|
dfS c c}w c c}w c c}w 7 �Œ"c c}w 7 Œäc c}w 7 Œ“­w)a]  
        Reserve ``estimated_input_tokens`` against project ITPM descriptors
        and ``estimated_output_tokens`` against project OTPM descriptors.

        ITPM and OTPM are reserved from different-sized estimates, so unlike
        same-size TPM descriptors they can't share a single
        ``atomic_check_and_increment_by_n`` call -- each bucket gets its own
        all-or-nothing atomic call. If the OTPM reservation is over limit
        after ITPM already succeeded, the ITPM reservation this call made is
        rolled back before returning, so a partial reservation never leaks.

        Returns ``(response, itpm_reserved, otpm_reserved)`` -- the latter two
        are the amounts actually reserved (0 if that bucket wasn't
        configured, or if the reservation failed), for the caller to stash
        for post-call reconciliation.
        rk   r‡  rŠ  r   r€   r!  Nr…   rˆ  rl   rŠ   )r%  r&  rŠ   r   r†   r  )rS   rU   r„   rù  r3  rÑ   r‹   )rœ   r”   rS  r4  r   r"  Úitpm_descriptorsÚotpm_descriptorsrÛ  Úitpm_responseÚitpm_reservedÚotpm_responser†   s                rg   Úreserve_io_tokensz6_PROXY_MaxParallelRequestsHandler_v3.reserve_io_tokens8  s’  è ø€ ð0 #ö#
Ø a¨¡hÔ2MÓ&MŠAð#
Ðð #
ð #ö#
Ø a¨¡hÔ2MÓ&MŠAð#
Ðð #
ñ  Ñ(8Ü$°$ÀÔDÀaÈÐJÐJñ  ð ×6Ñ6Ø,ð .öàð Ð5Ò6òð "2ð 7ó ÷ ð ð ð 	ð Ð$¨°~Ñ)FÈ,Ò)VØ  ! QÐ&Ð&Ø9FÐ9RÑ5ÐXYˆáØ)-×)MÑ)MØ,ð .öàð Ð6Ò7òð "2ð *Nó *÷ $ˆMð ˜^Ñ,°Ò<Ø  1Ò$Ø×6Ñ6à<Lö Ø78˜Q˜u™X q¨¡zÒ2ò ð  -Ø,9×,=Ñ,=Ð>SÔU^ÓU`Ó,aØ)9ð 7ó ÷ ð ð % a¨Ð*Ð*ð !Ð,ð	Ø" :Ñ.ðà" :Ñ.ñð
 # :Ñ.ð ô "Ø!%Ø%ð  -Ð8ð *×-Ñ-Ð.CÄYÃ[ÔQä!*£à'×+Ñ+Ð,AÄ9Ã;ÓOñPô	ð Ø'ðð ð" Ð(Ð(Ð(Ø˜m¨QÐ.Ð.ùòQ#
ùò#
ùòðûò$ð$úò ðúsx   ‚F+‡F™F�F+£FµF¹(F+Á!F
Á,F+Á8FÁ9-F+Â&F
Â1F+Â=F"Â> F+ÃF$Ã/&F+ÄF)ÄBF+ÆF+Æ$F+r°   Úrequested_modelc              ƒ   óÖ   K  — |€yg }| j                  |||¬«       |sy| j                  ||||j                  ¬«      ƒ d{  –—† \  }}}|d   dk(  r| j                  |||«       yy7 Œ%­w)a]  Reserve one WebSocket ``response.create`` frame's tokens against
        the caller's project ITPM/OTPM quota.

        The Responses WebSocket connection-level pre-call hook only runs once
        per connection, but a connection accepts many ``response.create``
        frames over its lifetime. Without this, a project caller could send
        unlimited high-token generations after a single minimal reservation.
        There is no per-frame post-call hook to reconcile against, so --
        like the batch rate limiter -- this charges the estimate immediately
        and never refunds it.
        N©r°   r<  r”   ©r”   rS  r4  r   r…   rˆ  )Ú9add_project_io_token_rate_limit_descriptors_from_metadatar;  r   Ú_handle_rate_limit_error)	rœ   r°   r<  rS  r4  r”   r•   Ú_itpm_reservedÚ_otpm_reserveds	            rg   Ú(enforce_project_io_token_quota_for_framezM_PROXY_MaxParallelRequestsHandler_v3.enforce_project_io_token_quota_for_frame™  sš   è ø€ ð$ Ð$ØØ8:ˆØ×FÑFØ/Ø+Ø#ð 	Gô 	
ñ
 ØØ9=×9OÑ9OØ#Ø#9Ø$;Ø.×?Ñ?ð	 :Pó :
÷ 4
Ñ0ˆ�. .ð �NÑ# |Ò3Ø×)Ñ)¨(°KÀÕQð 4ð4
ús   ‚?A)ÁA'Á&A)c           
      ó  — g }|j                   �a|j                  €|j                  �I|j                  t	        d|j                   |j                  |j                  | j
                  dœ¬«      «       t        |dd«      	 €t        |dd«      	 �€t        |dd«      xs i }t        |dd«      xs i }d}||v s||v rd}|rPd }d }||v r||   }||v r||   }|j                  t	        d	|j                   › d
|› �||| j
                  dœ¬«      «       |S )NÚorganization©r\   r]   r_   r   Úorganization_metadataÚmodel_rpm_limitÚmodel_tpm_limitFTÚmodel_per_organizationr�  )Úorg_idÚorganization_rpm_limitÚorganization_tpm_limitr�   rj   r_   r   ©	rœ   r°   r<  r”   Ú_tpm_limit_for_team_modelÚ_rpm_limit_for_team_modelÚshould_check_rate_limitÚmodel_specific_tpm_limitÚmodel_specific_rpm_limits	            rg   Ú)create_organization_rate_limit_descriptorzN_PROXY_MaxParallelRequestsHandler_v3.create_organization_rate_limit_descriptor¾  sz  € ð 9;ˆð ×#Ñ#Ð/Ø×4Ñ4Ð@ÐDU×DlÑDlÐDxà×ÑÜ#Ø&Ø+×2Ñ2à->×-UÑ-UØ+<×+SÑ+SØ'+×'7Ñ'7ñ ôô
ô /Ð/@ÐBYÐ[lÓmØðä1Ð2CÐE\Ð^oÓpØðô 3Ð3DÐF]Ð_pÓqÒwÐuwð &ô 3Ð3DÐF]Ð_pÓqÒwÐuwð &ð ',Ð#ØÐ";Ñ;¸ÐRkÑ?kØ*.Ð'á&Ø+/Ð(Ø+/Ð(Ø"Ð&?Ñ?Ø/HÈÑ/YÐ,Ø"Ð&?Ñ?Ø/HÈÑ/YÐ,Ø×"Ñ"Ü'Ø4Ø!2×!9Ñ!9Ð :¸!¸OÐ;LÐMà1IØ/GØ+/×+;Ñ+;ñ$ôô
ð Ðrf   c           
      ó6  — ddl m}m} |sy |||¬«      } |||¬«      }|€|€y|xs i }|xs i }||v xs ||v }|sy|j                  |«      }	|j                  |«      }
|j	                  t        d|j                  › d|› �|
|	| j                  dœ¬«      «       y)	a&  
        Add model-specific rate limit descriptor for API key if applicable.

        Args:
            user_api_key_dict: User API key authentication dictionary
            requested_model: The model being requested
            descriptors: List of rate limit descriptors to append to
        r   )Úget_key_model_rpm_limitÚget_key_model_tpm_limitN©Ú
model_nameÚmodel_per_keyr�  rG  r   )Úlitellm.proxy.auth.auth_utilsrW  rX  rÑ   r�   rj   Úapi_keyr_   )rœ   r°   r<  r”   rW  rX  Ú_tpm_limit_for_key_modelÚ_rpm_limit_for_key_modelrR  rS  rT  s              rg   Ú(_add_model_per_key_rate_limit_descriptorzM_PROXY_MaxParallelRequestsHandler_v3._add_model_per_key_rate_limit_descriptorú  sß   € ÷	
ñ
 Øá#:Ð;LÐYhÔ#iÐ Ù#:Ð;LÐYhÔ#iÐ à#Ð+Ð0HÐ0PØà#;Ò#A¸rÐ Ø#;Ò#A¸rÐ ð Ð7Ð7Òf¸?ÐNfÐ;fð 	 ñ 'Øð 7O×6RÑ6RÐSbÓ6cÐ Ø6N×6RÑ6RÐSbÓ6cÐ à×ÑÜØ#Ø*×2Ñ2Ð3°1°_Ð4EÐFà)AØ'?Ø#'×#3Ñ#3ñôõ
	
rf   c                 ó$  — |j                   syt        |«      xs i }|syt        j                  t	        |«      «      D ]P  }|j                  |«      }|€Œ|j                  t        d|j                   › d|› �|d| j                  dœ¬«      «       ŒR y)aZ  
        Add per-request-tag rpm limit descriptors for the API key.

        Each tag carried on the request that has a configured limit gets its own
        ``{api_key}:{tag}`` counter, so a burst on one tag/group never consumes
        another's budget. Tags without a configured limit fall through to the
        key-level descriptor.
        NÚtag_per_keyr�  rG  r   )	r]  r   r¶   Úfromkeysr    rÑ   r�   rj   r_   )rœ   r°   r²   r”   Útag_rpm_limitÚtagÚ	rpm_limits          rg   Ú&_add_tag_per_key_rate_limit_descriptorzK_PROXY_MaxParallelRequestsHandler_v3._add_tag_per_key_rate_limit_descriptor1	  sŸ   € ð !×(Ò(Øä4Ð5FÓGÒMÈ2ˆÙØä—=‘=Ô!;¸DÓ!AÓBò 	ˆCØ%×)Ñ)¨#Ó.ˆIØÐ ØØ×ÑÜ#Ø%Ø.×6Ñ6Ð7°q¸¸Ð>à-6Ø+/Ø'+×'7Ñ'7ñ ôõ
ñ		rf   Úmcp_server_namec           
      óà   — ddl m} |r|j                  sy ||«      }|sy|j                  |«      }|€y|j	                  t        d|j                  › d|› �|d| j                  dœ¬«      «       y)a$  
        Add a per-MCP-server rpm descriptor for the API key, if a limit is
        configured for the server being called.

        MCP tool calls have no token usage, so only requests_per_unit is set;
        tokens_per_unit stays None so the TPM reservation path is never engaged.
        r   )Úget_key_mcp_rpm_limitNÚmcp_per_keyr�  rG  r   )r\  rj  r]  rÑ   r�   rj   r_   )rœ   r°   rh  r”   rj  Úmcp_rpm_limitÚserver_rpm_limits          rg   Ú&_add_mcp_per_key_rate_limit_descriptorzK_PROXY_MaxParallelRequestsHandler_v3._add_mcp_per_key_rate_limit_descriptorV	  s…   € õ 	HáÐ&7×&?Ò&?Øá4Ð5FÓGˆÙØà"/×"3Ñ"3°OÓ"DÐØÐ#Øà×ÑÜØ!Ø*×2Ñ2Ð3°1°_Ð4EÐFà)9Ø'+Ø#'×#3Ñ#3ñôõ
	
rf   c                 ó�  — ddl m} |syg }|j                  r#|j                  |j                   ||«      f«       |j                  xs i j                  «       D ]  \  }}|j                  ||f«       Œ |D ]N  \  }}	|r|	sŒ|	j                  |«      }
|
€Œ|j                  t        d|› d|› �|
d| j                  dœ¬«      «       ŒP y)z�
        Add a per-MCP-server rpm descriptor for the team, if a limit is
        configured for the server being called.
        r   )Úget_team_mcp_rpm_limitNÚmcp_per_teamr�  rG  r   )	r\  rp  Úteam_idr�   Úmcp_source_team_rpm_limitsr­  rÑ   rj   r_   )rœ   r°   rh  r”   rp  Úteam_limitsÚsource_team_idÚsource_limitrr  rl  rm  s              rg   Ú'_add_mcp_per_team_rate_limit_descriptorzL_PROXY_MaxParallelRequestsHandler_v3._add_mcp_per_team_rate_limit_descriptor|	  sñ   € õ 	IáØð NPˆØ×$Ò$Ø×ÑÐ 1× 9Ñ 9Ñ;QÐRcÓ;dÐeÔfØ->×-YÑ-YÒ-_Ð]_×,fÑ,fÓ,hò 	?Ñ(ˆN˜LØ×Ñ °Ð=Õ>ð	?ð '2ò 	Ñ"ˆG�]Ù¡-ØØ,×0Ñ0°ÓAÐØÐ'ØØ×ÑÜ#Ø&Ø$˜I Q Ð&7Ð8à-=Ø+/Ø'+×'7Ñ'7ñ ôõ
ñ	rf   Ú
limit_typeÚmodel_has_failuresc                 ó   — |dk(  r|S y)a  
        Determine if rate limit should be enforced based on limit type and model health.

        Args:
            limit_type: Type of rate limit ("dynamic", "guaranteed_throughput", "best_effort_throughput", or None)
            model_has_failures: Whether the model has recent failures

        Returns:
            True if rate limit should be enforced, False otherwise
        ÚdynamicTre   )rœ   rx  ry  s      rg   Ú_should_enforce_rate_limitz?_PROXY_MaxParallelRequestsHandler_v3._should_enforce_rate_limit©	  s   € ð ˜Ò"à%Ð%àrf   rý  c                 ó4   — |€y| j                  ||¬«      r|S y)a®  
        Get the rate limit value to enforce based on limit type and model health.

        Args:
            limit_value: The configured limit value
            limit_type: Type of rate limit ("dynamic", "guaranteed_throughput", "best_effort_throughput", or None)
            model_has_failures: Whether the model has recent failures

        Returns:
            The limit value if it should be enforced, None otherwise
        N)rx  ry  )r|  )rœ   rý  rx  ry  s       rg   Ú_get_enforced_limitz8_PROXY_MaxParallelRequestsHandler_v3._get_enforced_limit¾	  s1   € ð" ÐØà×*Ñ*Ø!Ø1ð +ô 
ð Ðàrf   Úrpm_limit_typeÚtpm_limit_typec                 ó   — |dk(  xs |dk(  S )a  
        Check if dynamic rate limiting is enabled for either RPM or TPM.

        Args:
            rpm_limit_type: RPM rate limit type
            tpm_limit_type: TPM rate limit type

        Returns:
            True if dynamic mode is enabled for either limit type
        r{  re   )rœ   r  r€  s      rg   Ú!_is_dynamic_rate_limiting_enabledzF_PROXY_MaxParallelRequestsHandler_v3._is_dynamic_rate_limiting_enabledÚ	  s   € ð  Ñ*ÒI¨nÀ	Ñ.IÐIrf   Úagent_idzAgentResponse | Nonec                 ó2   — ddl m} |j                  |¬«      S )z3Look up an agent from the in-memory registry by ID.r   )Úglobal_agent_registry)rƒ  )Ú,litellm.proxy.agent_endpoints.agent_registryr…  Úget_agent_by_id)rœ   rƒ  r…  s      rg   Ú_get_agent_from_registryz=_PROXY_MaxParallelRequestsHandler_v3._get_agent_from_registryë	  s   € åVà$×4Ñ4¸hÐ4ÓGÐGrf   c                 óp   — t        |dd«      }|r|S |j                  d«      xs i }|j                  d«      S )z§
        Resolve the agent_id from either the API key or request metadata.
        Key-level agent_id takes precedence over metadata/header-supplied agent_id.
        rƒ  NÚmetadata)ÚgetattrrÑ   )rœ   r°   r²   Úkey_agent_idrŠ  s        rg   Ú_get_resolved_agent_idz;_PROXY_MaxParallelRequestsHandler_v3._get_resolved_agent_idñ	  s>   € ô
 &Ð&7¸ÀTÓJˆÙØÐØŸ(™( :Ó.Ò4°"ˆØ�|‰|˜JÓ'Ð'rf   c                 ó  — |j                  d«      }|rt        |«      S |j                  d«      xs i }|j                  d«      }|rt        |«      S |j                  d«      xs i }|j                  d«      }|rt        |«      S y)z?Extract session_id from request metadata or litellm_session_id.Úlitellm_session_idrŠ  Ú
session_idÚlitellm_metadataN)rÑ   rn   )rœ   r²   r�  rŠ  r‘  s        rg   Ú_get_session_id_from_dataz>_PROXY_MaxParallelRequestsHandler_v3._get_session_id_from_dataü	  s�   € à—X‘XÐ2Ó3ˆ
ÙÜ�z“?Ð"ØŸ(™( :Ó.Ò4°"ˆØ—\‘\ ,Ó/ˆ
ÙÜ�z“?Ð"Ø"&§(¡(Ð+=Ó">Ò"DÀ"ÐØ%×)Ñ)¨,Ó7ˆ
ÙÜ�z“?Ð"Ørf   c           
      óˆ  — g }| j                  |«      }|€|S t        |dd«      }t        |dd«      }|€|�+|j                  t        d|||| j                  dœ¬«      «       t        |dd«      }t        |dd«      }|€|�C| j                  |«      }	|	�0|j                  t        d	|› d
|	› �||| j                  dœ¬«      «       |S )a  
        Create rate limit descriptors for agent-level and session-level limits.

        Agent-level: caps total RPM/TPM across all sessions for a given agent.
        Session-level: caps RPM/TPM within a single session (identified by session_id).
        Nrf  Ú	tpm_limitÚagentrG  r   Úsession_rpm_limitÚsession_tpm_limitÚagent_sessionr�  )rˆ  r‹  r�   rj   r_   r’  )
rœ   rƒ  r²   r”   r•  Ú	agent_rpmÚ	agent_tpmÚsession_rpmÚsession_tpmr�  s
             rg   Ú$_create_agent_rate_limit_descriptorszI_PROXY_MaxParallelRequestsHandler_v3._create_agent_rate_limit_descriptors
  sÿ   € ð 9;ˆà×4Ñ4°XÓ>ˆØˆ=ØÐä" 5¨+°tÓ<ˆ	Ü" 5¨+°tÓ<ˆ	ØÐ  IÐ$9Ø×ÑÜ#ØØ"à-6Ø+4Ø'+×'7Ñ'7ñ ôô
ô % UÐ,?ÀÓFˆÜ$ UÐ,?ÀÓFˆØÐ" kÐ&=Ø $× >Ñ >¸tÓ DˆJØÐ%Ø×"Ñ"Ü'Ø+Ø!) 
¨!¨J¨<Ð8à1<Ø/:Ø+/×+;Ñ+;ñ$ôô
ð Ðrf   c                 óÖ  — ddl m}m} g }	|j                  r¼|j                  €|j
                  €|j                  �˜|j                  }
|	j                  t        d|j                  | j                  t        |j                  |
«      ||¬«      | j                  t        |j
                  |
«      ||¬«      |j                  | j                  dœ¬«      «       |j                  ra|j                  €|j                  �I|	j                  t        d|j                  |j                  |j                  | j                  d	œ¬«      «       |j                   ra|j"                  €|j$                  �I|	j                  t        d
|j                   |j"                  |j$                  | j                  d	œ¬«      «       |j                  rr|j&                  €|j(                  �Z|j                   › d|j                  › �}|	j                  t        d||j&                  |j(                  | j                  d	œ¬«      «       |j*                  ra|j,                  €|j.                  �I|	j                  t        d|j*                  |j,                  |j.                  | j                  d	œ¬«      «       |j1                  dd«      }| j3                  |||	¬«       | j5                  |||	¬«       |t6        j8                  j:                  k(  r>d|vr:|j1                  dd«      }| j=                  |||	¬«       | j?                  |||	¬«        ||«      € ||«      �v ||«      xs i } ||«      xs i }d}||v s||v rd}|rPd}d}||v r||   }||v r||   }|	j                  t        d|j                   › d|› �||| j                  d	œ¬«      «       | jA                  ||«      }|r"|	jC                  | jE                  ||¬«      «       |	S )zÒ
        Create all rate limit descriptors for the request.

        Returns list of descriptors for API key, user, team, team member, end user,
        model-specific, agent, and agent-session limits.
        r   )Úget_team_model_rpm_limitÚget_team_model_tpm_limitNr]  )rý  rx  ry  )r\   r]   r^   r_   r   ÚuserrG  Úteamr�  Úteam_memberÚend_userr!  r>  )r°   r²   r”   Ú	server_idrh  )r°   rh  r”   FTÚmodel_per_team)rƒ  r²   )#r\  rŸ  r   r]  rf  r”  r^   Úbudget_throttle_pctr�   rj   r~  r   r_   Úuser_idÚuser_rpm_limitÚuser_tpm_limitrr  Úteam_rpm_limitÚteam_tpm_limitÚteam_member_rpm_limitÚteam_member_tpm_limitÚend_user_idÚend_user_rpm_limitÚend_user_tpm_limitrÑ   r`  rg  r,   Úcall_mcp_toolrl   rn  rw  r�  r®  r�  )rœ   r°   r²   r  r€  ry  r³   rŸ  r   r”   Úthrottle_pctÚteam_member_valuer<  rh  rP  rQ  rR  rS  rT  Úresolved_agent_ids                       rg   Ú_create_rate_limit_descriptorszC_PROXY_MaxParallelRequestsHandler_v3._create_rate_limit_descriptors>
  s^  € ÷	
ð
  ˆð ×$Ò$Ø×'Ñ'Ð3Ø ×*Ñ*Ð6Ø ×6Ñ6ÐBà"3×"GÑ"GˆLØ×ÑÜ#Ø!Ø+×3Ñ3à-1×-EÑ-EÜ(7Ð8I×8SÑ8SÐUaÓ(bØ'5Ø/Að .Fó .ð
 ,0×+CÑ+CÜ(7Ð8I×8SÑ8SÐUaÓ(bØ'5Ø/Að ,Dó ,ð
 2C×1XÑ1XØ'+×'7Ñ'7ñ ôôð, ×$Ò$Ø×,Ñ,Ð8Ð<M×<\Ñ<\Ð<hà×ÑÜ#ØØ+×3Ñ3à->×-MÑ-MØ+<×+KÑ+KØ'+×'7Ñ'7ñ ôô
ð ×$Ò$Ø×,Ñ,Ð8Ð<M×<\Ñ<\Ð<hà×ÑÜ#ØØ+×3Ñ3à->×-MÑ-MØ+<×+KÑ+KØ'+×'7Ñ'7ñ ôô
ð ×$Ò$Ø×3Ñ3Ð?ÐCT×CjÑCjÐCvà*;×*CÑ*CÐ)DÀAÐFW×F_ÑF_ÐE`Ð'aÐØ×ÑÜ#Ø%Ø+à->×-TÑ-TØ+<×+RÑ+RØ'+×'7Ñ'7ñ ôô
ð ×(Ò(Ø×0Ñ0Ð<Ð@Q×@dÑ@dÐ@pà×ÑÜ#Ø"Ø+×7Ñ7à->×-QÑ-QØ+<×+OÑ+OØ'+×'7Ñ'7ñ ôô
ð "&§¡¨'°4Ó!8ˆØ×5Ñ5Ø/Ø+Ø#ð 	6ô 	
ð 	×3Ñ3Ø/ØØ#ð 	4ô 	
ð œ	×/Ñ/×5Ñ5Ò5¸+ÈTÑ:QØ%)§X¡XÐ.?ÀÓ%FˆOØ×7Ñ7Ø"3Ø /Ø'ð 8ô ð
 ×8Ñ8Ø"3Ø /Ø'ð 9ô ñ %Ð%6Ó7ÐCÙ'Ð(9Ó:ÐFá/GÐHYÓ/ZÒ/`Ð^`Ð%Ù/GÐHYÓ/ZÒ/`Ð^`Ð%Ø&+Ð#ØÐ";Ñ;¸ÐRkÑ?kØ*.Ð'á&Ø+/Ð(Ø+/Ð(Ø"Ð&?Ñ?Ø/HÈÑ/YÐ,Ø"Ð&?Ñ?Ø/HÈÑ/YÐ,Ø×"Ñ"Ü'Ø,Ø!2×!:Ñ!:Ð ;¸1¸_Ð<MÐNà1IØ/GØ+/×+;Ñ+;ñ$ôô
ð $(×#>Ñ#>Ð?PÐRVÓ#WÐáØ×ÑØ×9Ñ9Ø.Øð :ó ôð Ðrf   c              ƒ   óŠ  K  — ddl m} ddlm} |€y	 |j	                  |¬«      }|sy|D ]S  }|j                  di «      j                  d«      }|sŒ' |||¬	«      }|t        kD  sŒ;t        j                  d
|||«        y t        j                  d|«       y# t        $ r }	t        j                  d|	«       Y d}	~	yd}	~	ww xY w­w)zÑ
        Check if any deployment for this model has recent failures by using
        the router's existing failure tracking.

        Returns True if any deployment has failures in the current minute.
        r   )Ú
llm_router)Ú*get_deployment_failures_for_current_minuteNFrY  Ú
model_infoÚid)Úlitellm_router_instanceÚdeployment_idzi[Dynamic Rate Limit] Deployment %s has %s failures in current minute - enforcing rate limits for model %sTzS[Dynamic Rate Limit] No failures detected for model %s - allowing dynamic exceedingzEError checking model failure status: %s, defaulting to enforce limits)
Úlitellm.proxy.proxy_serverr¸  Ú>litellm.router_utils.router_callbacks.track_deployment_metricsr¹  Úget_model_listrÑ   r   r   r  r¸   )
rœ   r!  r   r¸  r¹  Ú
model_listÚ
deploymentr½  Úfailure_countr  s
             rg   Ú _check_model_has_recent_failureszE_PROXY_MaxParallelRequestsHandler_v3._check_model_has_recent_failuresù
  sê   è ø€ õ 	:õ	
ð ÐØð#	à *× 9Ñ 9ÀUÐ 9Ó KˆJÙØð )ò  �
Ø *§¡¨|¸RÓ @× DÑ DÀTÓ J�Ù$Øñ !KØ,6Ø"/ô!�ð
 !Ô#PÓPÜ(×.Ñ.ð DØ%Ø%Øô	ñ  ð% ô( !×&Ñ&ØeÐglôð øäò 	Ü ×&Ñ&Ð'nÐpqÔräûð	üsJ   ‚C“B §C¨<B Á%B Á>CÁ?B ÂCÂ	C Â B;Â6CÂ;C Ã Cc                 ó2   — |dk(  r| j                  «       }|S y)z'Get the rate limiter for the call type.Úacreate_batchN)r  )rœ   r³   Úbatch_limiters      rg   Úget_rate_limiter_for_call_typezC_PROXY_MaxParallelRequestsHandler_v3.get_rate_limiter_for_call_type1  s!   € à˜Ò'Ø#'×#?Ñ#?Ó#AˆMØ Ð Ørf   c           
      óV  — t        |dd«      €t        |dd«      ��t        |dd«      xs i }t        |dd«      xs i }||v xs ||v }|r`|�]|j                  |«      }|j                  |«      }|j                  t        d|j                  › d|› �||| j
                  dœ¬«      «       yyyy)	zFAdd team model rate limit descriptor from team_metadata if applicable.Úteam_metadatarI  NrJ  r¦  r�  rG  r   )r   rÑ   r�   rj   rr  r_   rO  s	            rg   Ú3_add_team_model_rate_limit_descriptor_from_metadatazX_PROXY_MaxParallelRequestsHandler_v3._add_team_model_rate_limit_descriptor_from_metadata8  s÷   € ô /Ð/@À/ÐSdÓeÐqÜ1Ð2CÀ_ÐVgÓhÐtô 3Ð3DÀoÐWhÓiÒoÐmoð &ô 3Ð3DÀoÐWhÓiÒoÐmoð &ð  Ð#<Ð<ÒlÀÐSlÐ@lð $ñ '¨?Ð+FØ2K×2OÑ2OÐP_Ó2`Ð(Ø2K×2OÑ2OÐP_Ó2`Ð(Ø×"Ñ"Ü'Ø,Ø!2×!:Ñ!:Ð ;¸1¸_Ð<MÐNà1IØ/GØ+/×+;Ñ+;ñ$ôõ
ð ,GÐ&ð urf   c           
      óV  — t        |dd«      €t        |dd«      ��t        |dd«      xs i }t        |dd«      xs i }||v xs ||v }|r`|�]|j                  |«      }|j                  |«      }|j                  t        d|j                  › d|› �||| j
                  dœ¬«      «       yyyy)	zLAdd project model rate limit descriptor from project_metadata if applicable.Úproject_metadatarI  NrJ  Úmodel_per_projectr�  rG  r   )r   rÑ   r�   rj   Ú
project_idr_   )	rœ   r°   r<  r”   Ú_tpm_limit_for_project_modelÚ_rpm_limit_for_project_modelrR  rS  rT  s	            rg   Ú6_add_project_model_rate_limit_descriptor_from_metadataz[_PROXY_MaxParallelRequestsHandler_v3._add_project_model_rate_limit_descriptor_from_metadata\  sû   € ô /Ð/@ÐBTÐVgÓhÐtÜ1Ð2CÐEWÐYjÓkÐwô 3Ð3DÐFXÐZkÓlÒrÐprð )ô 3Ð3DÐFXÐZkÓlÒrÐprð )ð  Ð#?Ð?ÒrÀ?ÐVrÐCrð $ñ '¨?Ð+FØ2N×2RÑ2RÐSbÓ2cÐ(Ø2N×2RÑ2RÐSbÓ2cÐ(Ø×"Ñ"Ü'Ø/Ø!2×!=Ñ!=Ð >¸aÀÐ?PÐQà1IØ/GØ+/×+;Ñ+;ñ$ôõ
ð ,GÐ&ð xrf   c           
      óœ  — |�|j                   €yt        |dd«      xs i }t        |dd«      xs i }|j                  |«      }|j                  |«      }|€|€y|j                   › d|› �}|�/|j                  t	        t
        |d|| j                  dœ¬«      «       |�0|j                  t	        t        |d|| j                  dœ¬«      «       yy)a  Add project-scoped ITPM/OTPM descriptors from project_metadata.

        Enforced independently of, and alongside, the combined ``model_per_project``
        TPM descriptor above -- these give Bedrock Mantle-style separate input/output
        token quotas at the project level.
        NrÍ  Úmodel_itpm_limitÚmodel_otpm_limitr�  rG  r   )rÏ  r   rÑ   r�   rj   rS   r_   rU   )	rœ   r°   r<  r”   Úitpm_limit_for_project_modelÚotpm_limit_for_project_modelrÔ  rÕ  r‚   s	            rg   r@  z^_PROXY_MaxParallelRequestsHandler_v3.add_project_io_token_rate_limit_descriptors_from_metadata€  s  € ð Ð"Ð&7×&BÑ&BÐ&JØô /Ð/@ÐBTÐVhÓiò Øð 	%ô
 /Ð/@ÐBTÐVhÓiò Øð 	%ð
 #?×"BÑ"BÀ?Ó"SÐØ">×"BÑ"BÀ?Ó"SÐàÐ#Ð(8Ð(@Øà%6×%AÑ%AÐ$BÀ!ÀOÐCTÐ"UÐØÐ'Ø×ÑÜ#Ü3Ø*à-1Ø+;Ø'+×'7Ñ'7ñ ôô
ð Ð'Ø×ÑÜ#Ü3Ø*à-1Ø+;Ø'+×'7Ñ'7ñ ôõ
ð (rf   r•   c                 ó  ‡— |d   D ]ø  }|d   dk(  sŒ|d   Št        ˆfd„|D «       d«      }|�|d   nd}| j                  «       j                  «       }|| j                  z   }t	        j
                  |«      j                  d	«      }	t        d
|d   «      }
|d   }|d   }d‰› d|› d|› d|› d|
› d|	› �}t        |«      \  }}t        |t        | j                  «      t        |d   «      |	dœt        |d   «      ||¬«      ‚ y)zKHandle rate limit exceeded by raising :class:`ProxyRateLimitError` (a 429).r†   r{   rˆ  rs   c              3   ó4   •K  — | ]  }|d    ‰k(  sŒ|–— Œ y­w©rk   Nre   )r-  Údescrs   s     €rg   r/  zP_PROXY_MaxParallelRequestsHandler_v3._handle_rate_limit_error.<locals>.<genexpr>Ã  s   øè ø€ ÒS˜d°T¸%±[ÀNÓ5R”TÑSùs   ƒ‘Nrl   Úunknownz%Y-%m-%d %H:%M:%S UTCr   r}   r�   r|   zRate limit exceeded for z: z. Limit type: z. Current limit: z, Remaining: z. Limit resets at: )zretry-afterr�   Úreset_at)ÚdetailÚheadersr�   r!  Úllm_provider)Únextr  r»  r_   r
   ÚfromtimestampÚstrftimer  r(   r!   rn   r"   )rœ   r•   r”   r<  ÚstatusÚmatching_descriptorr‚   rò   Ú
reset_timeÚreset_time_formattedÚremaining_displayr�   r|   rÞ  Úresolved_modelrà  rs   s                   @rg   rA  z=_PROXY_MaxParallelRequestsHandler_v3._handle_rate_limit_error¸  sm  ø€ ð ˜zÑ*ò #	ˆFØ�f‰~ Ó-Ø!'Ð(8Ñ!9�Ü&*ÛS kÔSØó'Ð#ð DWÐCbÐ#6°wÒ#?ÐhqÐ à×,Ñ,Ó.×8Ñ8Ó:�Ø  4×#3Ñ#3Ñ3�
Ü'/×'=Ñ'=¸jÓ'I×'RÑ'RÐSjÓ'kÐ$ä$'¨¨6Ð2CÑ+DÓ$EÐ!Ø"(Ð):Ñ";�Ø & Ñ 7�ð /¨~Ð.>¸bÐAQÐ@Rð S#Ø#2Ð"3ð 4&Ø&3 _°MÐBSÐATð U(Ø(<Ð'=ð?ð ô 0SÐSbÓ/cÑ,� Ü)Ø!ä'*¨4×+;Ñ+;Ó'<Ü+.¨vÐ6GÑ/HÓ+IØ$8ñô
 %;¸6ÐBSÑ;TÓ$UØ(Ø!-ô
ð 
ñ3#	rf   Úblockc                 ó  — t        | t        «      st        S | j                  d«      }t        |t        «      r|j                  d«      nd}|r8t        |t        «      r(t        |«      dz  dz  }t        |t        z  t        «      S t        S )aÿ  
        Token estimate for one ``input_audio`` content block.

        When the block carries a base64 ``data`` payload, the estimate comes
        from the decoded byte count (``len(b64) * 3 // 4 // _AUDIO_BYTES_PER_TOKEN``),
        assuming the lowest reasonable audio bitrate so we never under-reserve
        for higher-quality recordings of the same duration.

        When no payload is present (reference-only block or missing ``data``),
        falls back to ``DEFAULT_AUDIO_TOKEN_ESTIMATE``.
        Úinput_audior²   Nr  r@   )rÚ   r¶   rP   rÑ   rn   r\  r  rQ   )rê  rì  Úb64_dataÚdecoded_bytess       rg   Ú_estimate_audio_block_tokenszA_PROXY_MaxParallelRequestsHandler_v3._estimate_audio_block_tokensä  su   € ô ˜%¤Ô&Ü/Ð/Ø"ŸY™Y }Ó5ˆÜ5?ÀÌTÔ5R˜+Ÿ/™/¨&Ô1ÐX\ˆÙœ
 8¬SÔ1Ü#& x£=°1Ñ#4¸Ñ#9ˆMÜ�}Ô(>Ñ>Ô@\Ó]Ð]Ü+Ð+rf   rY  c                 óN   ‡ — t        |t        «      syt        ˆ fd„|D «       «      S )zÚ
        Sum of per-block audio token estimates across all ``messages``.
        Returns 0 when there are no ``input_audio`` blocks, which the caller
        uses to skip the (relatively expensive) strip pass.
        r   c              3   óø   •K  — | ]q  }t        |t        «      r_|j                  d «      }t        |t        «      r>|D ]9  }t        |t        «      r'|j                  d«      dk(  r‰j	                  |«      –— Œ; Œs y­w)Úcontentr  rì  N)rÚ   r¶   rÑ   rx   rï  )r-  Úmessagerò  rê  r;  s       €rg   r/  zV_PROXY_MaxParallelRequestsHandler_v3._estimate_audio_content_tokens.<locals>.<genexpr>  su   øè ø€ ò 
àÜ˜'¤4Ô(Ø#ŸK™K¨	Ó2�Ü˜'¤4Ô(Ø ò
ð Ü˜%¤Ô&¨5¯9©9°VÓ+<ÀÒ+Mð ×,Ñ,¨U×3ð
Ø3ñ
ùs   ƒA7A:)rÚ   rx   ra  )r;  rY  s   ` rg   Ú_estimate_audio_content_tokenszC_PROXY_MaxParallelRequestsHandler_v3._estimate_audio_content_tokensú  s,   ø€ ô ˜(¤DÔ)ØÜó 
à#ô
ó 
ð 	
rf   c                 ó†  — t        | t        «      s| S g }| D ]¢  }t        |t        «      s|j                  |«       Œ%|j	                  d«      }t        |t        «      s|j                  |«       ŒX|D �cg c])  }t        |t        «      r|j	                  d«      dk(  rŒ(|‘Œ+ }}|j                  i |¥d|i¥«       Œ¤ |S c c}w )aÅ  
        Drop ``input_audio`` content blocks before passing ``messages`` to
        ``token_counter``, which raises ``ValueError`` on them (no per-type
        handling, unlike images). The audio contribution is added back
        separately via ``DEFAULT_AUDIO_TOKEN_ESTIMATE`` so the rest of the
        message (text/images/tools) still gets counted accurately instead of
        the whole call falling back to the cheap char-count estimate.
        rò  r  rì  )rÚ   rx   r¶   r�   rÑ   )rY  Ú	sanitizedró  rò  rê  Úfiltered_contents         rg   Ú_strip_audio_content_blocksz@_PROXY_MaxParallelRequestsHandler_v3._strip_audio_content_blocks  sÎ   € ô ˜(¤DÔ)ØˆOØ)+ˆ	Øò 	ˆGÜ˜g¤tÔ,Ø× Ñ  Ô)ØØ—k‘k )Ó,ˆGÜ˜g¤tÔ,Ø× Ñ  Ô)Øà#*ö Ø´:¸eÄTÔ3JÈuÏyÉyÐY_ÓO`ÐdqÓOq’ð Ðð  ð ×ÑØ8�7Ð8˜IÐ'7Ñ8õð	ð Ðùò s   Á3)B>ÂB>c                 ó|   — ddl m} t        | t        «      sy|j	                  | j                  d«      xs d| ¬«      S )aÔ  
        Convert a Responses API ``input`` (string or list of input items) into
        chat-completion-style messages via the standard LiteLLM transformation
        (the same one guardrails use, e.g. ``purview_dlp.py``), so multimodal
        ``input_image``/``input_text`` content blocks get counted by
        ``token_counter``'s ``messages`` path instead of silently contributing
        zero tokens via its ``text`` path, which only joins plain strings.
        r   )Ú LiteLLMCompletionResponsesConfigre   r  r"  )r  Úresponses_api_request)ÚBlitellm.responses.litellm_completion_transformation.transformationrú  rÚ   r¶   Ú)transform_responses_api_input_to_messagesrÑ   )r²   rú  s     rg   Ú!_responses_input_to_chat_messageszF_PROXY_MaxParallelRequestsHandler_v3._responses_input_to_chat_messages*  sC   € õ	
ô ˜$¤Ô%ØØ/×YÑYØ—(‘(˜7Ó#Ò) rØ"&ð Zó 
ð 	
rf   c                 ó¨   — t        | t        «      sy t        d„ | D «       «      rt        | «      S t        d„ | D «       «      rt	        d„ | D «       «      S y )Nc              3   ó<   K  — | ]  }t        |t        «      –— Œ y ­wr›   ©rÚ   rc   ©r-  Útokens     rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._count_pretokenized_embedding_input.<locals>.<genexpr>C  s   è ø€ Ò9¨%Œz˜%¤×%Ñ9ùó   ‚c              3   ód   K  — | ](  }t        |t        «      xr t        d „ |D «       «      –— Œ* y­w)c              3   ó<   K  — | ]  }t        |t        «      –— Œ y ­wr›   r  r  s     rg   r/  ze_PROXY_MaxParallelRequestsHandler_v3._count_pretokenized_embedding_input.<locals>.<genexpr>.<genexpr>F  s   è ø€ Ò/^È5´
¸5Ä#×0FÑ/^ùr  N)rÚ   rx   Úall©r-  Ú	token_idss     rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._count_pretokenized_embedding_input.<locals>.<genexpr>E  s0   è ø€ ò 
ØclŒJ�y¤$Ó'Ò^¬CÑ/^ÐT]Ô/^Ó,^Ó^ñ
ùs   ‚.0c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wr›   )r\  r  s     rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._count_pretokenized_embedding_input.<locals>.<genexpr>H  s   è ø€ Ò=¨)”s˜9—~Ñ=ùs   ‚)rÚ   rx   r  r\  ra  )rl   s    rg   Ú#_count_pretokenized_embedding_inputzH_PROXY_MaxParallelRequestsHandler_v3._count_pretokenized_embedding_input?  sR   € ä˜%¤Ô&ØÜÑ9°5Ô9Ô9Ü�u“:ÐÜñ 
Øpuô
ô 
ô Ñ=°uÔ=Ó=Ð=Ørf   c                 ó¦   — | j                  d«      }t        |t        «      r|nd}| j                  d«      g|¢­}dj                  d„ |D «       «      S )NÚ	documentsre   Úqueryú
c              3   ó^   K  — | ]%  }t        |t        t        f«      rt        |«      –— Œ' y ­wr›   )rÚ   rn   r¶   )r-  Úparts     rg   r/  zM_PROXY_MaxParallelRequestsHandler_v3._rerank_input_to_text.<locals>.<genexpr>S  s*   è ø€ ò 
àÜ˜$¤¤d Ô,ô ��Iñ
ùs   ‚+-)rÑ   rÚ   rx   Újoin)r²   r  Údocument_itemsÚinput_partss       rg   Ú_rerank_input_to_textz:_PROXY_MaxParallelRequestsHandler_v3._rerank_input_to_textK  s]   € àŸ8™8 KÓ0ˆ	Ü?IÈ)ÔUYÔ?Z±)Ð`bˆà�H‰H�WÓð2
àñ2
ˆð �y‰yñ 
à#ô
ó 
ð 	
rf   c                 ó  — ddl m} t        |t        «      sy|t        v }|rdn| j                  ||«      }| j                  ||«      }|r|j                  d«      nd}|r| j                  |«      nd}	|	�|	S |j                  d«      }
|
�|
n|j                  d«      }|r3| j                  |«      d|j                  d«      |j                  d«      fnô|�3|j                  d«      d|j                  d«      |j                  d«      fn¿|r$d||j                  d«      |j                  d«      fn™|t        v r3d| j                  |«      |j                  d«      |j                  d«      fn^|t        v r$d|
|j                  d«      |j                  d«      fn2|j                  d«      ||j                  d«      |j                  d«      f}|\  }}}}| j                  |«      }|dkD  r| j                  |«      n|}	 t        dt!         ||xs d	||||d
¬«      «      «      }||z   S # t"        $ rT |t        v r.t        |t$        «      rt        dt'        |«      t(        z  «      cY S | j+                  ||¬«      \  }}||z   cY S w xY w)a  
        Model-aware input token estimate for the project ITPM reservation,
        using ``litellm.token_counter`` -- the same approach the
        deployment-level itpm/otpm check uses in
        ``io_token_rate_limit_check.py``. Unlike the cheap char-count
        estimate the combined-TPM path uses, this accounts for image/tool
        content and derives per-``input_audio``-block estimates from the
        base64 payload size (assuming the lowest reasonable bitrate so
        longer recordings always reserve proportionally more), so a burst
        of multimodal, tool-heavy, or audio-heavy requests can't each
        reserve only the one-token floor and blow past ITPM before
        post-call reconciliation catches up.

        For the Responses API, ``input`` is converted to chat messages first
        (via ``_responses_input_to_chat_messages``) so its own multimodal
        content blocks are counted the same way; ``token_counter``'s ``text``
        argument can only see plain strings in a list, not content blocks.

        Falls back to the cheap char-count estimate if ``token_counter``
        can't resolve a tokenizer for this model (e.g. an unrecognized
        custom model name) or otherwise raises -- the audio add-on still
        applies on top of the fallback.
        r   )Útoken_counterNr  rX  r%  Útool_choicerY  r"  T)r!  rY  Útextr%  r  Úuse_default_image_token_countr  )Úlitellmr  rÚ   r¶   rE   r*  r  rÑ   r  rþ  rL   r  rK   rô  rø  r  rc   r¸   rn   r\  rA   rR  )rœ   r²   r!  r³   r  Úis_responses_requestÚtranslated_requestÚis_embedding_requestÚembedding_textÚpretokenized_input_tokensrX  Úfallback_textÚselected_inputsrY  Úselected_textÚcountable_toolsÚcountable_tool_choiceÚaudio_token_estimateÚcountable_messagesÚestimaterS  rÛ  s                         rg   Ú_estimate_precise_input_tokenszC_PROXY_MaxParallelRequestsHandler_v3._estimate_precise_input_tokensY  s»  € õ0 	*ä˜$¤Ô%ØØ&/Ô3KÐ&KÐá(‰D¨d×.YÑ.YÐZ^Ð`iÓ.jð 	ð '+×&@Ñ&@ÀÀyÓ&QÐÙ5I §¡¨Ô 1ÈtˆáH\ˆD×4Ñ4°^ÔDÐbfð 	"ð %Ð0Ø,Ð,àŸ™ Ó*ˆØ)/Ð);™vÀÇÁÈ'ÓARˆñ $ð ×3Ñ3°DÓ9¸4ÀÇÁÈ'ÓARÐTX×T\ÑT\Ð]jÓTkÑlð "Ð-ð #×&Ñ& zÓ2ØØ"×&Ñ& wÓ/Ø"×&Ñ& }Ó5ñ	ñ $ð ˜¨¯©°Ó(9¸4¿8¹8ÀMÓ;RÑSð Ô1Ñ1ð ˜×2Ñ2°4Ó8¸$¿(¹(À7Ó:KÈTÏXÉXÐVcÓMdÑeð Ô:Ñ:ð ˜ §¡¨Ó 1°4·8±8¸MÓ3JÑKà—(‘(˜:Ó&¨°t·x±xÀÓ7HÈ$Ï(É(ÐS`ÓJaÐbð! 	ð$ KZÑGˆ�- Ð2Gà&*×&IÑ&IÈ(Ó&SÐØRfÐijÒRj D×$DÑ$DÀXÔ$NÐpxÐð	AÜ!ØÜÙ!Ø#šk rØ!3Ø*Ø-Ø$9Ø6:ôó	óˆHð Ð2Ñ2Ð2øÜò 	AØÔ1Ñ1´jÀÔPSÔ6TÜ˜1œc -Ó0Ô4KÑKÓLÒLØ(,×(NÑ(NÐTXÐdmÐ(NÓ(nÑ%Ð" AØ)Ð,@Ñ@Ò@ð		Aús   Ç7)H! È!=I>É I>É=I>Útpm_reservation_scopesÚtpm_reservation_amountc              ƒ   ó¾  K  — t        |t        «      syt        |«      }|D �	cg c]  }	|	d   t        t        fv sŒ|	‘Œ }
}	|
sy|
D �	�cg c]?  }	|	d   t        k(  r1|	j                  d«      xs i j                  d«      }|�t        |«      ‘ŒA }}	}|rt        |«      nd}| j                  |||¬«      \  }}| j                  |||¬«      }t        |d«      }| j                  ||«      r|nt        |d«      }| j                  |||¬«       | j                  |
|||j                  ¬	«      ƒ d{  –—† \  }}}|d
   dk(  r€|dkD  r-| j                  |||j                  ¬«      ƒ d{  –—†  d|_        |j"                  }|�,| j%                  ||j                  ¬«      ƒ d{  –—†  d|_        | j'                  |||¬«       |dkD  rXt)        d„ |
D «       «      }||_        t-        |«      |_        t-        d„ |j                  dt-        «       «      D «       «      |_        |dkD  rXt)        d„ |
D «       «      }||_        t-        |«      |_        t-        d„ |j                  dt-        «       «      D «       «      |_        |j8                  �"|j8                  d   j;                  |d   «       n|d   r||_        t=        j>                  d|||«       yc c}	w c c}}	w 7 �Œ©7 �Œu7 �Œ>­w)a  
        Reserve project-scoped ITPM/OTPM tokens (Bedrock Mantle-style
        separate input/output token buckets), independently of -- and, when
        both are configured, in addition to -- the combined-TPM reservation
        the caller already made. Raises (via ``_handle_rate_limit_error``) on
        an over-limit reservation, first rolling back the combined-TPM
        reservation named by ``tpm_reservation_scopes``/``tpm_reservation_amount``
        if one was made, so a partial reservation never leaks.
        Nrk   rm   r]   )r²   r  r³   )r²   r!  r³   r  )r²   rE  r³   r?  r…   rˆ  r   )r%  r&  r   T©ræ  r   ©r•   r”   r<  c              3   óJ   K  — | ]  }|d    t         k(  sŒ|d    |d   f–— Œ y­w©rk   rl   N)rS   ©r-  r"  s     rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._reserve_project_io_tokens_or_raise.<locals>.<genexpr>  ó.   è ø€ ò 'Ø+,ÈÈ%ÉÔToÓHo��5‘˜1˜W™:Ô&ñ'ùó   ‚#”#c              3   ó6   K  — | ]  \  }}}d |v r|||f–— Œ y­w)rR   Nre   ©r-  rq   r«   Úbackends       rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._reserve_project_io_tokens_or_raise.<locals>.<genexpr>  ó-   è ø€ ò >á6�K ¨wØ+¨{Ñ:ð ˜l¨GÔ4ñ>ùó   ‚rŠ   c              3   óJ   K  — | ]  }|d    t         k(  sŒ|d    |d   f–— Œ y­wr0  )rU   r1  s     rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._reserve_project_io_tokens_or_raise.<locals>.<genexpr>  r2  r3  c              3   ó6   K  — | ]  \  }}}d |v r|||f–— Œ y­w)rT   Nre   r5  s       rg   r/  z[_PROXY_MaxParallelRequestsHandler_v3._reserve_project_io_tokens_or_raise.<locals>.<genexpr>"  r7  r8  r†   z8ITPM/OTPM tokens reserved: itpm=%s, otpm=%s for model %s) rÚ   r¶   rÜ   rS   rU   rÑ   rc   r  rR  r)  r  r<  rP  r;  r   r3  rÊ   r¾   ré  rA  rŒ   rÃ   r‹   rÄ   rÅ   rÆ   rÇ   rÈ   r½   r®  r   r  )rœ   r”   r²   r<  r°   r*  r+  r³   rÕ   r"  Úio_token_descriptorsÚvÚconfigured_otpm_limitsÚmin_configured_otpm_limitrÛ  Úraw_estimated_output_tokensÚraw_estimated_input_tokensrS  r4  Úio_responser9  Úotpm_reservedræ  Úitpm_scopesÚotpm_scopess                            rg   Ú#_reserve_project_io_tokens_or_raisezH_PROXY_MaxParallelRequestsHandler_v3._reserve_project_io_tokens_or_raise¯  s{  è ø€ ô& ˜$¤Ô%ØÜ3°DÓ9ˆà"ö'
Ø a¨¡hÔ3NÔPkÐ2lÒ&lŠAð'
Ðð '
ñ $Øð *÷
)
àØ�‰xÔ6Ò6à—‘�|Ó$Ò*¨×/Ñ/Ø%óð ð
 ˆ}ô ��Fð
)
Ðñ 
)
ñ Ka¬3Ð/EÔ+FÐfjÐ!Ø)-×)OÑ)OØØ%>Øð *Pó *
Ñ&ˆÐ&ð
 -1×,OÑ,OØ˜_¸	ð -Pó -
Ð"ô ),Ð,FÈÓ(JÐð ×,Ñ,¨T°9Ô=ñ (äÐ0°!Ó4ð 	 ð 	×'Ñ'ØØ!:Øð 	(ô 	
ð ;?×:PÑ:PØ,Ø#9Ø$;Ø.×?Ñ?ð	 ;Qó ;
÷ 5
Ñ1ˆ�] Mð �~Ñ&¨,Ò6ð &¨Ò)Ø×2Ñ2Ø1Ø1Ø%6×%GÑ%Gð 3ó ÷ ð ð
 .2�Ô*Ø!&×!4Ñ!4ˆKØÐ&Ø×:Ñ:Ø +Ø%6×%GÑ%Gð ;ó ÷ ð ð '+�Ô#Ø×)Ñ)Ø$Ø'Ø /ð *ô ð ˜1ÒÜ!&ñ 'Ø0Dô'ó "ˆKð *7ˆEÔ&Ü)2°;Ó)?ˆEÔ&Ü4=ñ >à:E¿/¹/ÐJ_ÔajÓalÓ:mô>ó 5ˆEÔ1ð
 ˜1ÒÜ!&ñ 'Ø0Dô'ó "ˆKð *7ˆEÔ&Ü)2°;Ó)?ˆEÔ&Ü4=ñ >à:E¿/¹/ÐJ_ÔajÓalÓ:mô>ó 5ˆEÔ1ð ×$Ñ$Ð0Ø×%Ñ% jÑ1×8Ñ8¸ÀZÑ9PÕQØ˜Ò$Ø(3ˆEÔ%ä×"Ñ"ØFØØØõ		
ùòQ'
ùó
)
ðH5
ùðùðûsS   ‚!K£K	ºK	¾
KÁAKÂBKÄ+KÄ,6KÅ"KÅ#9KÆKÆD8KËKËKr±   c           	   ƒ   ó¬  K  — t        j                  d«       t        |«      }| j                  |¬«      }|r|j	                  ||||¬«      ƒ d{  –—† S |j
                  xs i }|j                  d«      }|j                  d«      }	d}
|j                  dd«      }| j                  ||	¬	«      r'|r%| j                  ||j                  ¬
«      ƒ d{  –—† }
| j                  ||||	|
|¬«      }| j                  |||¬«       | j                  |||¬«       | j                  |||¬«       |j                  | j                  ||«      «       |�rí|D �cg c]?  }|j                  d«      xs i j                  d«      �| j!                  |d   |d   d«      ‘ŒA }}|rt#        j$                  «       j&                  nd}| j(                  r|nt+        d„ |D «       «      }| j-                  ||j                  | j(                  |¬«      ƒ d{  –—† }|d   dk(  r| j/                  |||¬«       n||_        |�t3        ||¬«      |_        |D ��cg c]D  }|d   t6        t8        fvr1|j                  d«      xs i j                  d«      }|�t;        |«      ‘ŒF }}}t=        |«      }d}d}|�rt| j(                  �rgt?        |«      }tA        ||¬«      }| jC                  ||||¬«       tE        | jG                  |||||¬«      d«      }|�#||kD  rt        j                  d||tH        ||«       | jK                  |||j                  ¬«      ƒ d{  –—† }|d   dk(  rO|j4                  }|�,| jM                  ||j                  ¬ «      ƒ d{  –—†  d|_        | j/                  |||¬«       nx||_'        ||_(        tS        d!„ |D «       «      |_*        t+        |jT                  «      }|}|j0                  }|�|d"   j                  |d"   «       t        j                  d#||«       | jW                  |||||||¬$«      ƒ d{  –—†  yy7 �Œê7 �Œmc c}w 7 �ŒAc c}}w 7 �Œ
7 ŒÑ7 Œ­w)%z“
        Pre-call hook to check rate limits before making the API call.
        Supports dynamic rate limiting based on deployment health.
        zInside Rate Limit Pre-Call Hook)r³   )r°   r±   r²   r³   Nr  r€  Fr!  )r  r€  )r!  r   )r°   r²   r  r€  ry  r³   r>  rm   r^   rk   rl   c              3   óD   K  — | ]  }|d    t         t        fvsŒ|–— Œ y­wrÚ  )rS   rU   r1  s     rg   r/  zK_PROXY_MaxParallelRequestsHandler_v3.async_pre_call_hook.<locals>.<genexpr>Ÿ  s'   è ø€ ò Ø¨a°©hÔ?ZÔ\wÐ>xÒ.x”Añùs   ‚ ™ )r”   r   r·  r¸  r…   rˆ  r.  )rv   rw   r]   re   r   )r°   rZ  )r²   rE  r³   rF  )r²   r!  r  r³   rF  r  zùReserving %s tokens for model %s (declared %s=%s plus the input estimate) exceeds the smallest TPM limit this request is charged against (%s), so it cannot be admitted even against an empty window. Lower the declared estimate or raise the TPM limit.)r”   r  r   r-  c              3   óœ   K  — | ]D  }|d    t         t        fvr1|j                  d«      xs i j                  d«      	 �|d    |d   f–— ŒF y­w)rk   rm   r]   Nrl   )rS   rU   rÑ   r1  s     rg   r/  zK_PROXY_MaxParallelRequestsHandler_v3.async_pre_call_hook.<locals>.<genexpr>  sa   è ø€ ò 6àØ˜U™8Ô,GÔIdÐ+eÑeØŸU™U <Ó0Ò6°B×;Ñ;Ø-óð  $ð$ð ˜5™ 1 W¡:Ô.ñ6ùs   ‚A
Ar†   z$TPM tokens reserved: %s for model %s)r”   r²   r<  r°   r*  r+  r³   ),r   r  rÜ   rÈ  rµ   rŠ  rÑ   r‚  rÄ  r   r¶  rË  rÒ  r@  r®  rU  r‚  r¾  r¿  rÀ  r  rŒ   rÅ  rA  r½   ru   r¾   rS   rU   rc   r¬   r  r   rP  r  rV  r   r$  ré  r¿   rÀ   r‹   rÂ   rE  )rœ   r°   r±   r²   r³   rÕ   Úcall_type_specific_rate_limiterrŠ  r  r€  ry  r<  r”   r"  Úparallel_counter_keysr¸  Úfirst_pass_descriptorsr•   r<  Úconfigured_tpm_limitsÚhas_tpm_limitsr*  r+  r  rF  r  Útpm_responseræ  Ústored_responses                                rg   rµ   z8_PROXY_MaxParallelRequestsHandler_v3.async_pre_call_hook4  sz  è ø€ ô 	×"Ñ"Ð#DÔEä3°DÓ9ˆð 26×1TÑ1TÐ_hÐ1TÓ1iÐ'Ù*Ø8×LÑLØ"3ØØØ#ð	 Mó ÷ ð ð ,×4Ñ4Ò:¸ˆØ (§¡Ð-=Ó >ˆØ (§¡Ð-=Ó >ˆð #ÐØ!%§¡¨'°4Ó!8ˆð ×2Ñ2Ø-Ø-ð 3ô ñ  à'+×'LÑ'LØ%Ø!2×!CÑ!Cð (Mó (÷ "Ðð "×@Ñ@Ø/ØØ)Ø)Ø1Øð Aó 
ˆð 	×@Ñ@Ø/Ø+Ø#ð 	Aô 	
ð 	×CÑCØ/Ø+Ø#ð 	Dô 	
ð
 	×FÑFØ/Ø+Ø#ð 	Gô 	
ð 	×Ñ˜4×IÑIÐJ[Ð]lÓmÔnò ð" %ö,àØ—E‘E˜,Ó'Ò-¨2×2Ñ2Ð3JÓKÐWð ×+Ñ+¨A¨e©H°a¸±jÐBYÕZð,Ð!ð ,ñ
 ;P¤d§j¡j£l×&6Ò&6ÐUYÐð ×/Ò/ñ äñ Ø*ôó ð #ð %)×$:Ñ$:Ø2Ø!2×!CÑ!CØ#×;Ñ;Ø!1ð	 %;ó %÷ ˆHð ˜Ñ'¨<Ò7Ø×-Ñ-Ø%Ø +Ø$3ð .õ ð -5�Ô)Ø#Ð/Ü*AØ 0Ø%:ô+�EÔ'ð  %÷,àØ�U‘8Ô$?ÔA\Ð#]Ñ]ØŸ5™5 Ó.Ò4°"×9Ñ9Ð:KÓL�AØ�=ô	 �A•ð,Ð!ñ ,ô %)Ð)>Ó$?ˆNð ACÐ"Ø%&Ð"â $×">Ó">Ü25Ð6KÓ2LÐ(ä2MØ&7Ø.ô3Ð(ð ×/Ñ/ØØ)AØ'Ø-Eð	 0ô ô +.Ø×5Ñ5Ø!Ø-Ø1IØ"+Ø1Ið 6ó ð ó	+Ð ð ,Ð7Ð<LÐOgÒ<gÜ(×.Ñ.ðgð )Ø'Ü5Ø0Ø0ô	ð -1×,CÑ,CØ +Ø%5Ø%6×%GÑ%Gð -Dó -÷ '�ð   Ñ/°<Ò?Ø).×)<Ñ)<�KØ"Ð.Ø"×BÑBØ(3Ø->×-OÑ-Oð Có ÷ ð ð /3˜Ô+Ø×1Ñ1Ø!-Ø$/Ø(7ð 2õ ð -=�EÔ)Ø+:�EÔ(Ü,5ñ 6à!,ô6ó -�EÔ)ô .3Ø×-Ñ-ó.Ð*ð .>Ð*ð .3×-FÑ-F�OØ&Ð2Ø'¨
Ñ3×:Ñ:¸<È
Ñ;SÔTä(×.Ñ.Ø>Ð@PÐRaôð ×:Ñ:Ø'ØØ /Ø"3Ø'=Ø'=Ø#ð ;ó ÷ ñ ðe ð{ùð."ûòj,ðûó<,ðF'ùðøðVúsŒ   ‚AQÁP9ÁA?QÃP<ÃA?QÅAP?ÆA0QÈQÈAQÉA	QÊB5QÍQÍ:QÍ>QÍ?B3QÐ2QÐ3QÐ<QÐ?QÑQÑQÑQÚtotal_tokensr)   c                 ó€   — g }| j                  ||d¬«      }|j                  t        ||| j                  ¬«      «       |S )z?
        Create pipeline operations for TPM increments
        r€   )rk   rl   r�   ©rk   r{  r¦   )r‚  r�   r)   r_   )rœ   rk   rl   r�   rP  r,  rq   s          rg   Ú_create_pipeline_operationsz@_PROXY_MaxParallelRequestsHandler_v3._create_pipeline_operationsB  sY   € ð MOÐØ!×8Ñ8ØØØ$ð 9ó 
ˆð
 	×"Ñ"Ü+ØØ ,Ø×$Ñ$ôô	
ð #Ð"rf   Úusage©Úoutputr  rh   c                 ó’  — d}d}|�r+t        |t        «      ry|dk(  r|j                  xs d}n+|dk(  r|j                  xs d}n|dk(  r|j                  xs d}|dv rÖt        |d«      rÊ|j                  �¾t        |j                  dd«      xs d}n¢t        |t        «      r’|dk(  r|j                  dd«      xs d}n7|dk(  r|j                  d	d«      xs d}n|dk(  r|j                  d
d«      xs d}|dv r;|j                  d«      xs i }t        |t        «      r|j                  dd«      xs d}|dkD  rt        d||z
  «      }|S )a6  
        Get total tokens from response usage for rate limiting.

        For 'input' and 'total' rate limit types, cached tokens are excluded
        because providers like AWS Bedrock don't count cached tokens toward
        rate limits. This aligns LiteLLM's TPM calculation with provider behavior.
        r   rV  r  rh   )r  rh   Úprompt_tokens_detailsÚcached_tokensÚcompletion_tokensÚprompt_tokensrP  )rÚ   r1   rZ  r[  rP  ÚhasattrrX  r‹  r¶   rÑ   r  )rœ   rT  r�   rP  rY  Úprompt_detailss         rg   Ú_get_total_tokens_from_usagezA_PROXY_MaxParallelRequestsHandler_v3._get_total_tokens_from_usage\  sd  € ð ˆØˆâÜ˜%¤Ô'Ø" hÒ.Ø#(×#:Ñ#:Ò#?¸a‘LØ$¨Ò/Ø#(×#6Ñ#6Ò#;¸!‘LØ$¨Ò/Ø#(×#5Ñ#5Ò#:¸�Lð #Ð&8Ñ8Ü˜uÐ&=Ô>À5×C^ÑC^ÐCjÜ(/°×0KÑ0KÈ_Ð^_Ó(`Ò(eÐde™ä˜E¤4Ô(à" hÒ.Ø#(§9¡9Ð-@À!Ó#DÒ#IÈ‘LØ$¨Ò/Ø#(§9¡9¨_¸aÓ#@Ò#EÀA‘LØ$¨Ò/Ø#(§9¡9¨^¸QÓ#?Ò#DÀ1�Lð #Ð&8Ñ8Ø,1¯I©IÐ6MÓ,NÒ,TÐRT�NÜ! .´$Ô7Ø(6×(:Ñ(:¸?ÈAÓ(NÒ(SÐRS˜ð ˜1ÒÜ˜q ,°Ñ">Ó?ˆLàÐrf   c                 ó  — | €yt        | t        «      r/| j                  xs d| j                  xs d| j                  xs dfn¢t        | t
        «      r/| j                  xs d| j                  xs d| j                  xs dfnc| j                  d«      xs | j                  d«      xs d| j                  d«      xs | j                  d«      xs d| j                  d«      xs df}|\  }}}|s|st        |t        «      sy|S )aÐ  Total for usage that carries no input/output split, else 0.

        A source that can only report one number for the whole request (a
        pass-through target pricing its own multi-model call) charges that
        number under every ``token_rate_limit_type``. Splitting it is
        impossible, and reading 0 out of it would leave the window
        uncharged, which is how pass-through traffic slips past a TPM limit
        it is supposed to share.
        r   r[  Úinput_tokensrZ  Úoutput_tokensrP  )
rÚ   r1   r[  rZ  rP  r+   r`  ra  rÑ   rc   )rT  Útoken_countsr[  rZ  rP  s        rg   Ú_aggregate_only_total_tokenszA_PROXY_MaxParallelRequestsHandler_v3._aggregate_only_total_tokensŒ  s  € ð ˆ=Øô ˜%¤Ô'ð × Ñ Ò% A u×'>Ñ'>Ò'CÀ!ÀU×EWÑEWÒE\Ð[\Ñ]ô ˜%Ô!1Ô2ð ×$Ñ$Ò)¨¨5×+>Ñ+>Ò+CÀ!ÀU×EWÑEWÒE\Ð[\Ñ]ð —	‘	˜/Ó*ÒL¨e¯i©i¸Ó.GÒLÈ1Ø—	‘	Ð-Ó.ÒQ°%·)±)¸OÓ2LÒQÐPQØ—	‘	˜.Ó)Ò.¨Qðð 	ð :FÑ6ˆÐ(¨,ÙÑ-´ZÀÌcÔ5RØØÐrf   Úresponse_objc                 óL  — t        | t        t        f«      r| S t        | t        t        t
        t        f«      r,t        | dd «      }t        |t        t        t        f«      r|S d S t        | t        «      r0| j                  d«      }t        |t        t        t        f«      r|S | S y )NrT  )
rÚ   r1   r+   r.   r-   r0   r*   r‹  r¶   rÑ   )rd  rT  Únested_usages      rg   Ú_response_usagez4_PROXY_MaxParallelRequestsHandler_v3._response_usage©  sœ   € ô �l¤UÔ,<Ð$=Ô>ØÐÜØÜÔ-Ô/EÔGfÐgô
ô # <°¸$Ó?ˆEÜ& u¬uÔ6FÌÐ.MÔN�5ÐXÐTXÐXÜ�l¤DÔ)Ø".×"2Ñ"2°7Ó";ˆLÜ˜,¬Ô0@Ä$Ð(GÔHØ#Ð#ØÐØrf   r,  c              ƒ   óÖ  K  — | j                   €y|D �cg c]  }|d   ‘Œ	 }}| j                  |«      }|j                  «       D ]–  \  }}|D �cg c]  }|d   |v sŒ|‘Œ }}g }g }	|D ]V  }|d   �|d   nd}
t        j                  d|d   |d   |
«       |j                  |d   «       |	j                  |d   |
g«       ŒX | j                  ||	¬«      ƒ d{  –—†  Œ˜ yc c}w c c}w 7 Œ­w)z_
        Execute token increment script grouped by hash tag for cluster compatibility.
        Nrk   r¦   r   zCExecuting TTL-preserving increment for key=%s, increment=%s, ttl=%sr{  rª  )rø   rŸ  r­  r   r  r�   r®  )rœ   r,  ÚopÚoperation_keysr°  Ú	_hash_tagr³  Úgroup_operationsrn  r«  Ú	ttl_values              rg   Ú_execute_token_increment_scriptzD_PROXY_MaxParallelRequestsHandler_v3._execute_token_increment_script¼  s0  è ø€ ð ×&Ñ&Ð.Øð 6IÖ I¨r  E£Ð IˆÐ IØ ×8Ñ8¸ÓHˆ
à%/×%5Ñ%5Ó%7ò 	Ñ!ˆI�zà-@Ö\ rÀBÀuÁIÐQ[ÒD[¢Ð\ÐÐ\àˆDØˆDà&ò @�à)+¨E©Ð)>˜B˜ušIÀA�	ä$×*Ñ*ØYØ�u‘IØÐ(Ñ)Øô	ð —‘˜B˜u™IÔ&Ø—‘˜RÐ 1Ñ2°IÐ>Õ?ð@ð ×-Ñ-ØØð .ó ÷ ñ ñ)	ùò !Jùò
  ]ð$ús.   ‚C)”C -C)ÁC"ÁC"ÁA7C)ÃC'ÃC)c              ƒ   óæ  K  — |sy| j                   €Et        j                  d«       | j                  j                  j                  ||¬«      ƒ d{  –—†  y	 | j                  |«      ƒ d{  –—†  t        j                  dt        |«      «       y7 Œ?7 Œ&# t        $ rP}t        j                  d|«       | j                  j                  j                  ||¬«      ƒ d{  –—†7   Y d}~yd}~ww xY w­w)z�
        Increment token counters using Lua script to preserve existing TTL.
        This prevents TTL reset on every token increment.
        Nz=TTL preservation script not available, using regular pipeline©Úincrement_listrs  z:Successfully executed TTL-preserving increment for %s keysz=TTL preservation failed, falling back to regular pipeline: %s)
rø   r   r  rë   rô   Úasync_increment_cache_pipelinern  r\  r¸   r¯  )rœ   r,  r   r  s       rg   r/  zQ_PROXY_MaxParallelRequestsHandler_v3.async_increment_tokens_with_ttl_preservationã  sò   è ø€ ñ #Øð ×&Ñ&Ð.Ü ×&Ñ&Ð'fÔgØ×+Ñ+×6Ñ6×UÑUØ2Ø)9ð Vó ÷ ð ð ð	Ø×6Ñ6Ð7JÓK×KÐKä ×&Ñ&ØLÌcÐReÓNfõðøð Lùô ò 	Ü ×(Ñ(Ð)hÐjkÔlà×+Ñ+×6Ñ6×UÑUØ2Ø)9ð Vó ÷ ö ûð	üs[   ‚AC1ÁBÁC1ÁB Á,BÁ-#B ÂC1ÂB Â	C.ÂA C)ÃC!ÃC)Ã$C1Ã)C.Ã.C1Ú
operationsc           	   ƒ   ó2  K  — | j                   4 ƒd {  –—†  |D ]Ê  }|j                  d«      }|j                  d«      }|�|€Œ*| j                  j                  ||d¬«      ƒ d {  –—† }|�t	        |«      |k7  rŒa| j                  j                  |d   |d¬«      ƒ d {  –—† xs d}| j                  j                  |d   t        |«      |d   z   |d   |d¬	«      ƒ d {  –—†  ŒÌ d d d «      ƒd {  –—†  y 7 Œä7 Œ”7 Œ\7 Œ7 Œ# 1 ƒd {  –—†7  sw Y   y xY w­w)
Nr�   r�   Trr  rk   r   r{  r¦   ru  )r  rÑ   rë   rw  rn   rx  rå   )rœ   rs  r   Ú	operationr�   r�   Úactive_window_startr|  s           rg   Ú,_apply_local_window_guarded_token_incrementszQ_PROXY_MaxParallelRequestsHandler_v3._apply_local_window_guarded_token_increments  s]  è ø€ ð
 ×1Ñ1÷ 	ñ 	Ø'ò �	Ø&Ÿ]™]¨<Ó8�
Ø(1¯©Ð6MÓ(NÐ%ØÐ%Ð)>Ð)FØØ,0×,EÑ,E×,UÑ,UØ"Ø-=Ø#ð -Vó -÷ 'Ð#ð
 'Ð.´#Ð6IÓ2JÐNcÒ2cØà×3Ñ3×CÑCØ% eÑ,Ø1AØ#'ð Dó ÷ ò ð
 ð  ð ×/Ñ/×?Ñ?Ø! %Ñ(Ü Ó0°9Ð=NÑ3OÑOØ! %Ñ(Ø-=Ø#ð @ó ÷ ñ ð)÷	÷ 	ñ 	øð'øðøðøð+	ø÷ 	÷ 	ñ 	üs|   ‚D“C8”D—ADÁ%C:Á&9DÂC<Â A DÃ C>Ã!DÃ'DÃ2D Ã3DÃ:DÃ<DÃ>DÄ DÄDÄDÄ	DÄDc              ƒ   ó¸  K  — |D ]�  }|j                  d«      }|j                  d«      }|�|€Œ*| j                  �/	 | j                  ||d   g||d   |d   xs dg¬«      ƒ d {  –—†  Œe|d   dkD  sŒn| j
                  j                  |d   |d   ||d   ¬	«      ƒ d {  –—†  ŒŸ y 7 ŒA# t        $ r$}t        j                  d|d   |«       Y d }~Œfd }~ww xY w7 Œ9­w)
Nr�   r�   rk   r{  r¦   r   rª  z1Window-guarded token adjustment failed for %s: %s©rk   rl   rs  r¦   )rÑ   rú   r¸   r   r¯  rë   Úasync_increment_cache)rœ   rs  r   ru  r�   r�   r  s          rg   Ú,_apply_redis_window_guarded_token_incrementszQ_PROXY_MaxParallelRequestsHandler_v3._apply_redis_window_guarded_token_increments)  s5  è ø€ ð
 $ò 	ˆIØ"Ÿ™ |Ó4ˆJØ$-§M¡MÐ2IÓ$JÐ!ØÐ!Ð%:Ð%BØØ×9Ñ9ÐEðØ×DÑDà&Ø% eÑ,ðð
 2Ø%Ð&7Ñ8Ø% eÑ,Ò1°ðð Eó 
÷ 
ð 
ð ð Ð*Ñ+¨aÓ/Ø×/Ñ/×EÑEØ! %Ñ(Ø#Ð$5Ñ6Ø-=Ø! %Ñ(ð	 Fó ÷ ñ ñ5	ð
ùô !ò Ü(×0Ñ0ØKØ! %Ñ(Ø÷ñ ûðúðúsR   ‚9C¼(B(Á$B&Á%B(Á)	CÁ3+CÂCÂCÂ&B(Â(	CÂ1CÃCÃCÃCc              ƒ   óŠ  K  — |D ]U  }|j                  d«      �|j                  d«      �Œ&| j                  j                  |d   |d   ||d   ¬«      ƒ d {  –—†  ŒW t        d„ |D «       «      }t        d„ |D «       «      }|r| j	                  ||¬	«      ƒ d {  –—†  |r| j                  ||¬	«      ƒ d {  –—†  y y 7 Œf7 Œ%7 Œ
­w)
Nr�   r�   rk   r{  r¦   ry  c              3   óŒ   K  — | ]<  }|j                  d «      �)|j                  d«      �|j                  d«      dk(  r|–— Œ> y­w©r�   Nr�   r‘   r‰   ©rÑ   ©r-  ru  s     rg   r/  z`_PROXY_MaxParallelRequestsHandler_v3.async_increment_reservation_aware_tokens.<locals>.<genexpr>\  óI   è ø€ ò 0
àØ�}‰}˜\Ó*Ð6Ø—‘Ð5Ó6ÐBØ—‘Ð3Ó4¸Ò?ô	 ñ0
ùó   ‚AAc              3   óŒ   K  — | ]<  }|j                  d «      �)|j                  d«      �|j                  d«      dk7  r|–— Œ> y­wr~  r  r€  s     rg   r/  z`_PROXY_MaxParallelRequestsHandler_v3.async_increment_reservation_aware_tokens.<locals>.<genexpr>c  r�  r‚  )rs  r   )rÑ   rë   rz  rŒ   rw  r{  )rœ   r,  r   ru  Úlocal_guarded_operationsÚredis_guarded_operationss         rg   r2  zM_PROXY_MaxParallelRequestsHandler_v3.async_increment_reservation_aware_tokensO  s  è ø€ ð
 -ò 	ˆIØ�}‰}˜\Ó*Ð2°i·m±mÐD[Ó6\Ñ6dØ×/Ñ/×EÑEØ! %Ñ(Ø#Ð$5Ñ6Ø-=Ø! %Ñ(ð	 Fó ÷ ñ ð	ô +0ñ 0
à0ô0
ó +
Ð ô +0ñ 0
à0ô0
ó +
Ð ñ $Ø×CÑCØ3Ø!1ð Dó ÷ ð ñ $Ø×CÑCØ3Ø!1ð Dó ÷ ñ ð $ð3øð*øð
ús;   ‚(C«+CÁB=ÁACÂB?ÂCÂ6CÂ7CÂ?CÃCc                 ó@   — ddl m} |j                  dd«      }|dvry|S )Nr   )Úgeneral_settingsÚtoken_rate_limit_typerh   rU  )r¾  r‡  rÑ   )rœ   r‡  Úspecified_rate_limit_types      rg   Úget_rate_limit_typez8_PROXY_MaxParallelRequestsHandler_v3.get_rate_limit_typeu  s2   € Ý?à+;×+?Ñ+?Ð@WÐY`Ó+aÐ!Ø$ð -
ñ 
ð
 Ø(Ð(rf   Úadditional_headersr†   c                 óz   — t        | «      }|D ]*  }d|d   › �}|d   ||› d|d   › �<   |d   ||› d|d   › �<   Œ, |S )zÏ
        Return ``additional_headers`` extended with
        ``x-ratelimit-{descriptor_key}-{remaining|limit}-{rate_limit_type}``
        entries. Non-mutating so callers pick their own target dict.
        zx-ratelimit-rs   r}   z-remaining-r�   r|   z-limit-)r¶   )r‹  r†   Úmergedrä  Úprefixs        rg   Ú1_merge_ratelimit_statuses_into_additional_headerszV_PROXY_MaxParallelRequestsHandler_v3._merge_ratelimit_statuses_into_additional_headers�  s}   € ô ,0Ð0BÓ+CˆØò 	\ˆFØ# FÐ+;Ñ$<Ð#=Ð>ˆFØHNÐO`ÑHaˆF�f�X˜[¨Ð0AÑ)BÐ(CÐDÑEØDJÈ?ÑD[ˆF�f�X˜W VÐ,=Ñ%>Ð$?Ð@ÒAð	\ð ˆrf   c                 óŒ  — t        | t        «      r| j                  €y | j                  j                  d«      }|�G|j                  d«      xs d}|j                  d«      xs d}|s|rt	        d|«      t	        d|«      dfS | j                  j                  d«      }|�&|j                  d«      xs d}|rt	        d|«      ddfS y )Nr€   r`  r   ra  TÚbilled_unitsrP  )rÚ   r/   ró  rÑ   r  )rd  Úrerank_tokensr`  ra  r‘  rP  s         rg   Ú_resolve_rerank_token_usagez@_PROXY_MaxParallelRequestsHandler_v3._resolve_rerank_token_usage’  sË   € ä˜,¬Ô7¸<×;LÑ;LÐ;TØà+×0Ñ0×4Ñ4°XÓ>ˆØÐ$Ø"/×"3Ñ"3°NÓ"CÒ"HÀqˆLØ#0×#4Ñ#4°_Ó#EÒ#JÈˆMÙ™}Ü˜1˜lÓ+¬S°°MÓ-BÀDÐHÐHà*×/Ñ/×3Ñ3°NÓCˆØÐ#Ø".×"2Ñ"2°>Ó"BÒ"GÀaˆLÙÜ˜1˜lÓ+¨Q°Ð4Ð4Ørf   c                 óX  — | j                  |«      }|�|S | j                  |«      }t        |t        «      rf|j                  xs d}|j
                  xs d}|j                  �t        |j                  dd«      xs dnd}|dk(  r|dk(  ryt        d||z
  «      |dfS t        |t        «      re|j                  xs d}|j                  xs d}|j                  �|j                  j                  xs dnd}	|dk(  r|dk(  ryt        d||	z
  «      |dfS t        |t        «      �r|j                  d«      xs |j                  d«      xs d}
|j                  d«      xs |j                  d«      xs d}t        |
t         «      r|
nd}t        |t         «      r|nd}|j                  d	«      xs |j                  d
«      }t        |t"        «      r|j                  dd«      ndxs |j                  d«      xs d}t        |t         «      r|nd}|dk(  r|dk(  ryt        d||z
  «      |dfS y)a`  
        Resolve ``(billable_input_tokens, completion_tokens, usage_resolved)``
        for ITPM/OTPM reconciliation. Cache-read tokens are excluded from
        billable input -- Bedrock Mantle doesn't count them toward ITPM --
        but they're untouched everywhere else (cost/usage logging still sees
        the full prompt token count).
        r   rY  )r   r   FTr[  r`  rZ  ra  rX  Úinput_tokens_detailsÚcache_read_input_tokens)r“  rg  rÚ   r1   r[  rZ  rX  r‹  r  r+   r`  ra  r•  rY  r   rÑ   rc   r¶   )rœ   rd  Úrerank_usagerT  r[  rZ  rY  Úresponse_input_tokensÚresponse_output_tokensÚresponse_cached_tokensÚraw_prompt_tokensÚraw_completion_tokensÚmapped_prompt_tokensÚmapped_completion_tokensr]  Úraw_cached_tokensÚmapped_cached_tokenss                    rg   Ú!_resolve_io_token_reconcile_usagezF_PROXY_MaxParallelRequestsHandler_v3._resolve_io_token_reconcile_usage¥  sa  € ð #×>Ñ>¸|ÓLˆØÐ#ØÐà×+Ñ+¨LÓ9ˆä�eœUÔ#Ø#(×#6Ñ#6Ò#;¸!ˆMØ',×'>Ñ'>Ò'CÀ!Ðð ×.Ñ.Ð:ô ˜×3Ñ3°_ÀaÓHÒMÉAàð ð
  Ò!Ð&7¸1Ò&<Ø"Ü�q˜-¨-Ñ7Ó8Ð:KÈTÐQÐQä�eÔ-Ô.Ø+0×+=Ñ+=Ò+BÀÐ!Ø,1×,?Ñ,?Ò,DÀ1Ð"àAF×A[ÑA[ÐAg�×*Ñ*×8Ñ8Ò=¹AÐmnð #ð %¨Ò)Ð.DÈÒ.IØ"Ü�qÐ/Ð2HÑHÓIÐKaÐcgÐgÐgä�eœWÕ%Ø',§y¡y°Ó'AÒ'cÀUÇYÁYÈ~ÓE^Ò'cÐbcÐØ+0¯9©9Ð5HÓ+IÒ+lÈUÏYÉYÐWfÓMgÒ+lÐklÐ!Ü?IÐJ[Ô]`Ô?aÑ*;ÐghÐ ÜGQÐRgÔilÔGmÑ.CÐstÐ$Ø$)§I¡IÐ.EÓ$FÒ$kÈ%Ï)É)ÐTjÓJkˆNä;EÀnÔVZÔ;[�×#Ñ# O°QÔ7Ðabò Ø—9‘9Ð6Ó7òàð ô
 @JÐJ[Ô]`Ô?aÑ*;ÐghÐ Ø# qÒ(Ð-EÈÒ-JØ"Ü�qÐ.Ð1EÑEÓFÐH`ÐbfÐfÐfàrf   rß   c                 óR  — t        |t        «      syt        t        |«      «      }|€y|j                  }|j
                  }|dk  r|dk  ry| j                  |«      }| j                  |j                  d«      «      }| j                  | j                  |«      «      xs/ | j                  | j                  |j                  d«      «      «      }|d   s|d   s|dk  r|j                  sy|d   r|n|d   r|n|dkD  r||dfn||df}	|	\  }
}}|j                  s|j                  sÀ|j                  s´| j                  t        |j                  «      |j                  r
t!        «       n|j                  |
|j                  rdn|¬«      | j                  t        |j"                  «      |j                  r
t!        «       n|j"                  ||j                  r	d¬«      z   S |¬«      z   S |dkD  rS| j%                  t        |j                  «      |j                  r
t!        «       n|j                  |
||j                  ¬«      nd}|dkD  rS| j%                  t        |j"                  «      |j                  r
t!        «       n|j"                  |||j                  ¬«      nd}t        g |¢|¢­«      S )	aÔ  
        Reconcile project ITPM/OTPM reservations to actual usage on success:
        ITPM to billable input tokens, OTPM to actual completion tokens.
        Reuses ``_build_reservation_aware_tpm_ops``'s delta pattern -- ITPM/OTPM
        are stored in the same ":tokens" cache bucket as combined TPM, just
        under distinct scope keys, so the reservation-aware increment math is
        identical; only the usage fields being reconciled against differ.
        re   r   Úcombined_usage_objectrq  TFr(  r-  )rÚ   r¶   rÞ   râ   rÃ   rÆ   r¡  rÑ   rc  rg  rÊ   rÅ   rÈ   r0  rŒ   rÄ   r‹   rÇ   r1  )rœ   rß   rd  rÕ   r9  rB  Úresponse_usageÚcombined_usageÚaggregate_totalÚresolved_usageÚbillable_inputrZ  rÛ  Úitpm_opsÚotpm_opss                  rg   Ú_build_io_token_reservation_opszD_PROXY_MaxParallelRequestsHandler_v3._build_io_token_reservation_opsÞ  sÖ  € ô ˜&¤$Ô'ØÜ1Ô2OÐPVÓ2WÓXˆØˆ=Øà$×9Ñ9ˆØ$×9Ñ9ˆØ˜AÒ -°1Ò"4Øà $× FÑ FÀ|Ó TˆØ $× FÑ FÀvÇzÁzÐRiÓGjÓ kˆØ!%×!BÑ!BØ× Ñ  Ó.ó"
ò "jà×.Ñ.¨t×/CÑ/CÀFÇJÁJÐOfÓDgÓ/hÓið 	ð ˜aÒ ¨¸Ò):¸ÐRSÒ?SÐ\a×\vÒ\vØð ˜aÒ ñ ð ˜aÒ ñ  ð  Ò"ð " ?°DÑ9à °Ð6ð 	ð 0>Ñ,ˆÐ)¨1à×%Ò%Ø×5Ò5¸e×>cÒ>cà×8Ñ8Ü˜e×8Ñ8Ó9Ø/4×/IÒ/I¤	¤Èu×OiÑOiØ,Ø%*×%?Ò%?¡À]ð	 9ó ð
 ×5Ñ5Ü˜e×8Ñ8Ó9Ø/4×/IÒ/I¤	¤Èu×OiÑOiØ/Ø%*×%?Ò%? ð	 6ó ñ
ð 
ð FSð	 6ó ñ
ð 
ð( ˜qÒ ð ×/Ñ/Ü˜e×8Ñ8Ó9Ø/4×/IÒ/I¤	¤Èu×OiÑOiØ,Ø -Ø.3×.SÑ.Sð 0ô ð ð 	ð& ˜qÒ ð ×/Ñ/Ü˜e×8Ñ8Ó9Ø/4×/IÒ/I¤	¤Èu×OiÑOiØ/Ø -Ø.3×.SÑ.Sð 0ô ð ð 	ô Ð+�xÐ+ (Ñ+Ó,Ð,rf   Ústandard_logging_metadataÚmodel_groupc                 óÆ  — |j                  d«      }|j                  d«      }|j                  d«      }|j                  d«      }|j                  d«      }t        |t        «      r|j                  d«      ndxs |j                  d«      }	|j                  d	«      }
|j                  d
«      xs |j                  d«      }g }|r|j                  d|f«       |r|j                  d|f«       |r|j                  d|f«       |r|r|j                  d|› d|› �f«       |	r|j                  d|	f«       |r|j                  d|f«       |rh|r|j                  d|› d|› �f«       |r|j                  d|› d|› �f«       |r|j                  d|› d|› �f«       |r|j                  d|› d|› �f«       |
r-|j                  d|
f«       |r|j                  d|
› d|› �f«       |S )uf  
        Enumerate every (scope_key, scope_value) pair that *might* carry a
        TPM counter for this request â€” independent of whether each scope had
        a configured TPM limit at pre-call. Reservation awareness happens at
        the emitter; this helper just lists the candidate scopes so callers
        can split reserved-vs-unreserved.
        Úuser_api_key_hashÚuser_api_key_user_idÚuser_api_key_team_idÚuser_api_key_org_idÚuser_api_key_project_idr¡  NÚuser_api_key_end_user_idrƒ  r�  Útrace_idr]  r¢  r£  r�  r¤  rF  r[  r¦  rK  rÎ  r•  r˜  )rÑ   rÚ   r¶   r�   )rœ   r¬  rß   r­  Úuser_api_keyr°  r±  Úuser_api_key_organization_idr³  r´  rƒ  r�  r)  s                rg   Ú_collect_tpm_scope_targetsz?_PROXY_MaxParallelRequestsHandler_v3._collect_tpm_scope_targets0  s!  € ð 8×;Ñ;Ð<OÓPˆØ&?×&CÑ&CÐDZÓ&[ÐØ&?×&CÑ&CÐDZÓ&[ÐØ.G×.KÑ.KÐLaÓ.bÐ$Ø)B×)FÑ)FÐG`Ó)aÐä",¨V´TÔ":ˆF�J‰J�vÔÀò+Gà&×*Ñ*Ð+EÓFð 	!ð 4×7Ñ7¸
ÓCˆØ5×9Ñ9¸,ÓGÒtÐKd×KhÑKhÐisÓKtˆ
à02ˆÙØ�N‰N˜I |Ð4Ô5ÙØ�N‰N˜FÐ$8Ð9Ô:ÙØ�N‰N˜FÐ$8Ð9Ô:ÙÑ$8Ø�N‰N˜MÐ.BÐ-CÀ1ÐEYÐDZÐ+[Ð\Ô]Ù#Ø�N‰N˜JÐ(@ÐAÔBÙ'Ø�N‰N˜NÐ,HÐIÔJÙÙØ—‘ °L°>ÀÀ;À-Ð1PÐQÔRÙ#Ø—‘Ð 0Ð5IÐ4JÈ!ÈKÈ=Ð2YÐZÔ[Ù+Ø—‘à0Ø7Ð8¸¸+¸ÐGðôñ 'Ø—‘à+Ø2Ð3°1°[°MÐBðôñ Ø�N‰N˜G XÐ.Ô/ÙØ—‘ °H°:¸Q¸z¸lÐ1KÐLÔMØˆrf   r)  rÂ   r*  r¿   c           
      ó¶   — g }|D ]Q  \  }}||f|v r||z
  }n|}|dk(  rŒ|j                  t        | j                  ||d«      || j                  ¬«      «       ŒS |S )u  
        Emit per-scope TPM increment ops with reservation awareness.

        - Reserved scope (counter already at +reserved from pre-call):
          reconcile to actual via ``actual - reserved``.
        - Unreserved scope (counter never touched at pre-call):
          charge the full ``actual``.

        Same primitive serves success reconciliation, over-reservation
        release, and failure refund â€” pass ``actual_tokens=0`` for the pure
        refund case (reserved scopes get -reserved, unreserved get 0/skip).
        r   r€   rR  )r�   r)   r‚  r_   )	rœ   r)  rÂ   r*  r¿   ÚopsÚ	scope_keyÚscope_valuer¥   s	            rg   r0  zE_PROXY_MaxParallelRequestsHandler_v3._build_reservation_aware_tpm_opsn  s|   € ð& =?ˆØ&-ò 	Ñ"ˆI�{Ø˜;Ð'¨?Ñ:Ø)¨OÑ;‘	à)�	Ø˜AŠ~ØØ�J‰JÜ/Ø×3Ñ3°I¸{ÈHÓUØ$-Ø×(Ñ(ôõð	ð ˆ
rf   Úscoper.  c           
      ó  ‡— |\  }}||v }|r||z
  n|}	|	dk(  ry | j                  ||d«      Št        ˆfd„|D «       d «      }
|r|
€t        ‰|	| j                  ¬«      S t        ‰|	| j                  d|› d|› d�|
d   |
d   ¬	«      S )
Nr   r€   c              3   ó8   •K  — | ]  \  }}}|‰k(  r||f–— Œ y ­wr›   re   )r-  Úidentity_counter_keyr«   r6  rq   s       €rg   r/  zU_PROXY_MaxParallelRequestsHandler_v3._build_project_reservation_op.<locals>.<genexpr>¡  s-   øè ø€ ò á?Ð(¨,¸Ø'¨;Ò6ð ˜wÔ'ñùs   ƒrR  r€  r�  rÇ  r  )rk   r{  r¦   r�   r�   r‘   )r‚  rá  rŽ   r_   )rœ   r½  rÂ   r*  r¿   r.  r»  r¼  Úis_reserved_scoper¥   Úwindow_identityrq   s              @rg   Ú_build_project_reservation_opzB_PROXY_MaxParallelRequestsHandler_v3._build_project_reservation_op’  sÊ   ø€ ð "'Ñˆ	�;Ø#(¨OÐ#;ÐÙ>O˜=¨?Ò:ÐUbˆ	Ø˜Š>ØØ!×8Ñ8¸ÀKÐQYÓZˆÜ!%óàC`ôð
 ó"
ˆñ ! OÐ$;Ü5ØØ )Ø×$Ñ$ôð ô
 2ØØ%Ø× Ñ Ø˜I˜; a¨ }°IÐ>Ø"1°!Ñ"4Ø /°Ñ 2ô
ð 	
rf   .c                 ó@   ‡ ‡‡‡‡‡— t        ˆˆˆˆˆˆ fd„|D «       «      S )Nc              3   óT   •K  — | ]  }‰j                  |‰‰‰‰¬ «      xŠ	 �‰–— Œ! y­w))r½  rÂ   r*  r¿   r.  N)rÃ  )r-  r½  r*  ru  r.  rÂ   r¿   rœ   s     €€€€€€rg   r/  zV_PROXY_MaxParallelRequestsHandler_v3._build_project_reservation_ops.<locals>.<genexpr>¿  sM   øè ø€ ò 
àà!×?Ñ?ØØ$3Ø"/Ø$3Ø2Oð @ó ð �	ð ð	ô ñ
ùs   ƒ%()rŒ   )rœ   r)  rÂ   r*  r¿   r.  ru  s   ` ````@rg   r1  zC_PROXY_MaxParallelRequestsHandler_v3._build_project_reservation_ops·  s$   ý€ ô ÷ 
ð 
à ô
ó 
ð 	
rf   c                 ó  — ddl m} ddlm} |j	                  d«      xs i } ||«      }|j	                  t
        «      rg S |j	                  d«      xs i } ||«      }	d}
t        |t        t        t        t        f«      rt        |dd«      }
n#|j	                  d«      }t        |t        «      r|}
| j                  |
|¬	«      }|dk(  r| j                  |
¬
«      }t        t!        |«      «      }|�|j"                  nd}|�|j$                  nd}|�|j&                  n	t)        «       }|xs |	}g }| j+                  |||¬«      }|dkD  r ||k  rt-        j.                  d||||z
  «       |j1                  | j3                  ||||¬«      «       |S )zGBuild Redis pipeline increment ops for TPM / parallel-request counters.r   )Ú get_litellm_metadata_from_kwargs)Ú#get_model_group_from_litellm_kwargsÚstandard_logging_objectrŠ  NrT  r£  )rT  r�   )rT  )r¬  rß   r­  zJReleasing unused TPM budget on success: reserved=%s, actual=%s, release=%sr(  )Ú'litellm.litellm_core_utils.core_helpersrÇ  Ú)litellm.proxy.common_utils.callback_utilsrÈ  rÑ   r   rÚ   r.   r-   r0   r*   r‹  r1   r^  rc  rÞ   râ   r¿   rÀ   rÂ   r‹   r¸  r   r  r®  r0  )rœ   rß   rd  r�   rÇ  rÈ  rÉ  Úrequest_metadatar¬  r­  Ú_usageÚ_combined_usagerP  rÕ   r¿   rÀ   rÂ   Úreconcile_modelr,  r)  s                       rg   Ú(_build_success_event_pipeline_operationszM_PROXY_MaxParallelRequestsHandler_v3._build_success_event_pipeline_operationsÎ  sÎ  € õ 	]õ	
ð *0¯©Ð4MÓ)NÒ)TÐRTÐÙ"BÀ6Ó"JÐØ×ÑÔ AÔBð ˆIØ+B×+FÑ+FÀzÓ+RÒ+XÐVXÐ!á@ÀÓHˆð '+ˆÜØäÜ!Ü&Ü/ð	ô
ô ˜\¨7°DÓ9‰Fà%+§Z¡ZÐ0GÓ%HˆOÜ˜/¬5Ô1Ø(�Ø×8Ñ8¸vÐWfÐ8ÓgˆØ˜1ÒØ×<Ñ<À6Ð<ÓJˆLä1Ô2OÐPVÓ2WÓXˆØ:?Ð:K ×!6Ò!6ÐQRˆØ8=Ð8I × 4Ò 4ÈtˆØV[ÐVg¸U×=RÒ=RÔmvÓmxˆð
 "0Ò!>°;ˆàLNÐð ×8Ñ8Ø&?ØØ'ð 9ó 
ˆð
 ˜QÒ <°/Ò#AÜ ×&Ñ&Ø\ØØØ ,Ñ.ô	ð 	×"Ñ"Ø×1Ñ1ØØ /Ø*Ø /ð	 2ó ô	
ð #Ð"rf   c              ƒ   óŒ  K  — ddl m} | j                  «       } ||«      }	 t        j                  d«       t        t        |«      «      }|�|j                  nd}	|�$|	�"| j                  |	|¬«      ƒ d{  –—†  d|_        | j                  |||¬«      }
|
r| j                  |
|¬«      ƒ d{  –—†  | j                  ||¬«      }|rHt        |t        «      r| j                  ||¬«      ƒ d{  –—†  y| j                  ||¬«      ƒ d{  –—†  yy7 Œš7 Œd7 Œ&7 Œ# t        $ r }t        j                   d	|«       Y d}~yd}~ww xY w­w)
zb
        Update TPM usage on successful API calls by incrementing counters using pipeline
        r   ©Ú!_get_parent_otel_span_from_kwargsz5INSIDE parallel request limiter ASYNC SUCCESS LOGGINGNr-  )rß   rd  r�   r+  ©rß   rd  z%Error in rate limit success event: %s)rÊ  rÓ  rŠ  r   r  rÞ   râ   r¾   ré  rÐ  r/  r«  rÚ   rx   r2  r¸   Ú	exception)rœ   rß   rd  Ú
start_timeÚend_timerÓ  r�   rs  rÕ   ræ  r,  Úio_token_operationsr  s                rg   Úasync_log_success_eventz<_PROXY_MaxParallelRequestsHandler_v3.async_log_success_event,  s�  è ø€ õ	
ð "&×!9Ñ!9Ó!;ˆá7XÐY_Ó7`Ð ð'	WÜ ×&Ñ&Ð'^Ô_ä5Ô6SÐTZÓ6[Ó\ˆEØ8=Ð8I ×!4Ò!4ÈtˆKØÐ  [Ð%<Ø×:Ñ:Ø +Ø%=ð ;ó ÷ ð ð '+�Ô#à)-×)VÑ)VØØ)Ø /ð *Wó *Ðñ
 #Ø×GÑGØ(;Ø%=ð Hó ÷ ð ð *.×)MÑ)MØØ)ð *Nó *Ðñ #ÜÐ1´4Ô8Ø×KÑKØ,?Ø)Að Ló ÷ ñ ð
 ×GÑGØ,?Ø)Að Hó ÷ ñ ð #ð)øðøðøð
ùô
 ò 	WÜ ×*Ñ*Ð+RÐTU×VÑVûð	Wüsƒ   ‚E¢AD Á5DÁ67D Â-DÂ.?D Ã-DÃ.D Ã2EÃ3D Ä	DÄ
D ÄEÄD ÄD ÄD ÄD Ä	EÄ!D<Ä7EÄ<EÅEÚresultc              ƒ   ó8   K  — | j                  ||¬«       ||fS ­w)a®  
        Mirror the pre-call rate-limit snapshot into the SLP so streaming
        success callbacks see the same ``x-ratelimit-*`` headers the
        non-streaming path writes via ``async_post_call_success_hook``.
        Runs in the earlier of the two callback loops inside
        ``async_success_handler`` so downstream callbacks see the values
        regardless of registration order. Idempotent for non-streaming.
        rÔ  )Ú/_mirror_ratelimit_response_into_logging_payload)rœ   rß   rÚ  r³   s       rg   Úasync_logging_hookz7_PROXY_MaxParallelRequestsHandler_v3.async_logging_hook`  s-   è ø€ ð 	×<Ñ<ØØð 	=ô 	
ð �vˆ~Ðùr  c                 ó8  — t        |t        «      syt        t        |«      «      }|�|j                  nd}|�|d   ng }|sy|j                  d«      }t        |t        «      ra|j                  d«      }t        |t        «      si }|j                  d«      }| j                  t        |t        «      r|ni |¬«      |d<   ||d<   t        |dd«      }	t        |	t        «      r:|	j                  d«      }| j                  t        |t        «      r|ni |¬«      |	d<   yy)zÙ
        Copy the stashed ``RateLimitResponse`` into the SLP's
        ``hidden_params.additional_headers`` and the response object's
        ``_hidden_params.additional_headers`` (when the latter is a dict).
        Nr†   rÉ  Úhidden_paramsr‹  ©r‹  r†   Ú_hidden_params)rÚ   r¶   rÞ   râ   r½   rÑ   r�  r‹  )
rœ   rß   rd  rÕ   r½   r†   rÉ  rß  ÚexistingÚresponse_hiddens
             rg   rÜ  zT_PROXY_MaxParallelRequestsHandler_v3._mirror_ratelimit_response_into_logging_payloadt  s1  € ô ˜&¤$Ô'Øä1Ô2OÐPVÓ2WÓXˆØBGÐBS U×%>Ò%>ÐY]ÐØ=PÐ=\Ð-¨jÒ9ÐbdˆÙØà)/¯©Ð4MÓ)NÐÜÐ-¬tÔ4Ø3×7Ñ7¸ÓHˆMÜ˜m¬TÔ2Ø "�Ø$×(Ñ(Ð)=Ó>ˆHØ26×2hÑ2hÜ/9¸(ÄDÔ/I¡8ÈrØ!ð 3ió 3ˆMÐ.Ñ/ð 8EÐ# OÑ4ä!(¨Ð7GÈÓ!NˆÜ�o¤tÔ,Ø&×*Ñ*Ð+?Ó@ˆHØ48×4jÑ4jÜ/9¸(ÄDÔ/I¡8ÈrØ!ð 5kó 5ˆOÐ0Ò1ð -rf   c              ƒ   óæ  K  — ddl m} 	  ||«      }g }t        t        |«      «      }|�|j                  nd}	|�$|	�"| j                  |	|¬«      ƒ d{  –—†  d|_        |�|j                  rdn"|j                  |j                  |j                  f\  }
}}|�\|
dkD  rWt        j                  d|
«       |j                  | j                  t        |j                  «      |j                  d|
¬«      «       |�N|dkD  rI|j                   r=| j#                  t%        |j&                  «      |j&                  d||j                   ¬«      n:|�7|dkD  r2| j                  t%        |j&                  «      |j&                  d|¬«      nd	}|�N|dkD  rI|j(                  r=| j#                  t%        |j*                  «      |j*                  d||j(                  ¬«      n:|�7|dkD  r2| j                  t%        |j*                  «      |j*                  d|¬«      nd	}|r/| j,                  j.                  j1                  ||¬
«      ƒ d{  –—†  ||fD ]`  }t3        |t        «      r0| j,                  j.                  j1                  ||¬
«      ƒ d{  –—†  ŒC|sŒF| j5                  ||¬«      ƒ d{  –—†  Œb |�|
dkD  s
|dkD  s|dkD  rd|_        yyy7 �Œj7 Œ‰7 ŒE7 Œ(# t6        $ r }t        j8                  d|«       Y d}~yd}~ww xY w­w)a"  
        On failure: decrement max_parallel_requests and refund the upfront
        TPM reservation only against the scopes the reservation actually
        charged. Unreserved scopes were never incremented at pre-call, so
        refunding them would drive their counter negative.
        r   rÒ  Nr-  )r   r   r   z,Releasing reserved TPM tokens on failure: %sr(  r-  re   rp  r+  Tz%Error in rate limit failure event: %s)rÊ  rÓ  rÞ   râ   r¾   ré  rÊ   r¿   rÃ   rÆ   r   r  r®  r0  rx   rÂ   rÅ   r1  rŒ   rÄ   rÈ   rÇ   rë   rô   rr  rÚ   r2  r¸   rÕ  )rœ   rß   rd  rÖ  r×  rÓ  rs  r,  rÕ   ræ  r¿   r9  rB  Úitpm_operationsÚotpm_operationsÚproject_operationsr  s                    rg   Úasync_log_failure_eventz<_PROXY_MaxParallelRequestsHandler_v3.async_log_failure_event›  sw  è ø€ õ	
ðd	WÙ;\Ð]cÓ;dÐ$àPRÐä5Ô6SÐTZÓ6[Ó\ˆEØ8=Ð8I ×!4Ò!4ÈtˆKØÐ  [Ð%<Ø×:Ñ:Ø +Ø%=ð ;ó ÷ ð ð '+�Ô#ð �= E×$>Ò$>ñ à×+Ñ+¨U×-GÑ-GÈ×IcÑIcÐdñ :ˆO˜]¨Mð Ð  _°qÒ%8Ü$×*Ñ*Ð+YÐ[jÔkð $×*Ñ*Ø×9Ñ9Ü $ U×%:Ñ%:Ó ;Ø(-×(=Ñ(=Ø&'Ø(7ð	 :ó ôð( Ð$¨¸Ò):¸u×?dÒ?dð ×3Ñ3Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1Ø27×2WÑ2Wð 4ô ð Ð$¨¸Ò):ð ×:Ñ:Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1ð	 ;ô ð ð! ð6 Ð$¨¸Ò):¸u×?dÒ?dð ×3Ñ3Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1Ø27×2WÑ2Wð 4ô ð Ð$¨¸Ò):ð ×:Ñ:Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1ð	 ;ô ð ð! ñ& #Ø×/Ñ/×:Ñ:×YÑYØ#6Ø-Eð Zó ÷ ð ð (7¸Ð&Hò 
Ð"ÜÐ0´$Ô7Ø×3Ñ3×>Ñ>×]Ñ]Ø'9Ø1Ið ^ó ÷ ñ ò (Ø×GÑGØ,>Ø)Að Hó ÷ ñ ð
ð Ð  o¸Ò&9¸]ÈQÒ=NÐR_ÐbcÒRcØ-1�Õ*ð SdÐ ðsùðTøðøð
ùô ò 	WÜ ×*Ñ*Ð+RÐTU×VÑVûð	Wüs   ‚K1ŠAK ÁJ<ÁG"K È5J?È6AK É;KÉ<K ÊK ÊKÊK Ê9K1Ê<K Ê?K ËK ËK Ë	K.ËK)Ë$K1Ë)K.Ë.K1c              ƒ   óš   K  — t        «       }|�|j                  €y| j                  |j                  d¬«      ƒ d{  –—†  d|_        y7 Œ­w)a  
        Release the api-key ``max_parallel_requests`` slot that
        ``async_pre_call_hook`` acquired, for a request that ended without
        either logging callback firing.

        The slot is normally released by ``async_log_success_event`` (natural
        stream completion) or ``async_log_failure_event`` (LLM error). When a
        client cancels a stream mid-flight, the cancellation surfaces as
        ``asyncio.CancelledError`` / ``GeneratorExit`` and neither callback
        runs, so without this the slot leaks per cancelled stream until its
        TTL prunes it. The stashed acquisition's presence (not the key
        object's current max_parallel_requests configuration, which can
        change mid-request) decides whether there is anything to release.
        Nr-  )rÒ   r¾   ré  )rœ   r°   rÕ   s      rg   Ú1async_release_max_parallel_requests_on_disconnectzV_PROXY_MaxParallelRequestsHandler_v3.async_release_max_parallel_requests_on_disconnect  s[   è ø€ ô$ )Ó*ˆØˆ=˜E×/Ñ/Ð7Øà×2Ñ2Ø×+Ñ+Ø!ð 3ó 
÷ 	
ð 	
ð #ˆÕð		
ús   ‚:A¼A	½Ac              ƒ   ób  K  — 	 ddl m} t        «       }|�|j                  nd}|�’t	        |d«      rt        |d«      }nd}|�ut        ||«      st        |t        «      rYt        ||«      r|j                  «       }| j                  |j                  di «      xs i |d   ¬«      }t        |di |¥d|i¥«       	 | j                  ||¬	«      ƒ d{  –—†  y# t        $ r }	t        j                  d|	«       Y d}	~	ŒAd}	~	ww xY w7 Œ1# t        $ r }	t        j                  d
|	«       Y d}	~	yd}	~	ww xY w­w)zN
        Post-call hook to update rate limit headers in the response.
        r   )Ú	BaseModelNrá  r‹  r†   rà  z&Error in rate limit post-call hook: %s)r°   r•   z0Error in batch enqueued-token post-call hook: %s)Úpydanticrì  rÒ   r½   r\  r‹  rÚ   r¶   Ú
model_dumpr�  rÑ   Úsetattrr¸   r   rÕ  Ú _handle_batch_enqueued_post_call)
rœ   r²   r°   r•   rì  rÕ   Ú!litellm_proxy_rate_limit_responserá  Ú_additional_headersr  s
             rg   Úasync_post_call_success_hookzA_PROXY_MaxParallelRequestsHandler_v3.async_post_call_success_hook(  sN  è ø€ ð	XÝ*ä,Ó.ˆEØTYÐTe°u×7PÒ7PÐkoÐ-à0Ð<ä˜8Ð%5Ô6Ü%,¨XÐ7GÓ%H‘Nà%)�Nà!Ð-Ü˜~¨yÔ9¼ZÈÔX\Ô=]ä! .°)Ô<Ø)7×)BÑ)BÓ)D˜à15×1gÑ1gØ+9×+=Ñ+=Ð>RÐTVÓ+WÒ+]Ð[]Ø!BÀ:Ñ!Nð 2hó 2Ð'ô
 Ø Ø(ØU˜>ÐUÐ+?ÐATÑUôð	bØ×7Ñ7ÐJ[ÐfnÐ7Óo×oÑoøô	 ò 	XÜ ×*Ñ*Ð+SÐUV×WÑWûð	Xúð pùÜò 	bÜ ×*Ñ*Ð+]Ð_`×aÑaûð	büse   ‚D/„B4C Â9D ÃDÃD ÃD/Ã	C>ÃC9Ã4D/Ã9C>Ã>D/ÄD Ä	D,ÄD'Ä"D/Ä'D,Ä,D/c              ƒ   ó  K  — t        |«      }|€y |j                  }t        «       }|�V|j                  �J| j                  j                  t        |j                  «      |j                  |¬«      ƒ d {  –—†  d |_        |j                  j                  «       t        v ra| j                  j                  t        |j                  «      |¬«      ƒ d {  –—† }|�&| j                  j                  ||¬«      ƒ d {  –—†  y y y 7 Œ�7 Œ07 Œ­w)N)Úbatch_idÚreservationrs  )rõ  rs  ©rö  rs  )r&   r   rÒ   rÉ   r  Úsave_reservationr'   r»  rä  r   r#   Úpop_reservationÚrefund)rœ   r°   r•   ÚviewÚspanrÕ   Úpoppeds          rg   rð  zE_PROXY_MaxParallelRequestsHandler_v3._handle_batch_enqueued_post_callR  s  è ø€ Ü)¨(Ó3ˆØˆ<ØØ'×8Ñ8ˆÜ(Ó*ˆØÐ ×!AÑ!AÐ!MØ×1Ñ1×BÑBÜ4°T·W±WÓ=Ø!×<Ñ<Ø)-ð Có ÷ ð ð
 04ˆEÔ,Ø�;‰;×ÑÓÔ"@Ñ@Ø"&×"AÑ"A×"QÑ"QÜ4°T·W±WÓ=Ø)-ð #Ró #÷ ˆFð Ð!Ø×5Ñ5×<Ñ<ÈÐjnÐ<Óo×oÑoð "ð Aðøðøð
 pús7   ‚A1DÁ3DÁ4ADÃDÃ&DÃ9DÃ:DÄDÄDÚrequest_dataÚoriginal_exceptionÚtraceback_strc              ƒ   óz  K  — 	 t        «       }|€y|j                  �6| j                  |j                  |j                  ¬«      ƒ d{  –—†  d|_        |j                  �@| j
                  j                  |j                  |j                  ¬«      ƒ d{  –—†  d|_        |j                  ry|j                  }|j                  }|j                  }|dk  r|dk  r|dk  ry|dkD  r2| j                  t        |j                  «      |j                  d|¬«      nd}	|dkD  rI|j                  r=| j                  t        |j                   «      |j                   d||j                  ¬«      n8|dkD  r2| j                  t        |j                   «      |j                   d|¬«      nd}
|dkD  rI|j"                  r=| j                  t        |j$                  «      |j$                  d||j"                  ¬«      n8|dkD  r2| j                  t        |j$                  «      |j$                  d|¬«      nd}|	s|
s|rt'        j(                  d|||«       |	r9| j*                  j,                  j/                  |	|j                  ¬	«      ƒ d{  –—†  |
|fD ]t  }t1        |t2        «      r:| j*                  j,                  j/                  ||j                  ¬	«      ƒ d{  –—†  ŒM|sŒP| j5                  ||j                  ¬
«      ƒ d{  –—†  Œv d|_        y7 �Œ¼7 �Œs7 Œ�7 Œ?7 Œ# t6        $ r }t'        j8                  d|«       Y d}~yd}~ww xY w­w)um  
        Release the parallel-request slot and any TPM/ITPM/OTPM reservation
        when the request is rejected after the pre-call hook acquired them
        but before the LLM call ran (e.g. a downstream guardrail/auth hook
        raised). Without this, those resources are stranded â€”
        async_log_failure_event is a litellm completion-level callback and
        never fires for proxy-side rejections, so a leaked slot would occupy
        the gauge for the full PARALLEL_REQUEST_SLOT_TTL_SECONDS.

        Idempotent: the slot release clears the stashed acquisition (and slot
        removal is a no-op ZREM on a second run), and the TPM/ITPM/OTPM
        refund is guarded by the stash's ``reservation_released`` flag â€” if
        both this hook and async_log_failure_event end up running in the same
        flow, only the first release/refund applies.
        Nr-  r÷  r   r(  re   r-  zLReleasing reserved tokens on proxy-level rejection: tpm=%s, itpm=%s, otpm=%srp  r+  Tz8Error releasing TPM reservation on post-call failure: %s)rÒ   r¾   ré  r   rÉ   r  rú  rÊ   r¿   rÃ   rÆ   r0  rŒ   rÂ   rÅ   r1  rÄ   rÈ   rÇ   r   r  rë   rô   rr  rÚ   rx   r2  r¸   rÕ  )rœ   rþ  rÿ  r°   r   rÕ   r¿   r9  rB  Úcombined_opsr©  rª  Úproject_opsr  s                 rg   Úasync_post_call_failure_hookzA_PROXY_MaxParallelRequestsHandler_v3.async_post_call_failure_hookg  sœ  è ø€ ð,a	jÜ,Ó.ˆEØˆ}ØØ×"Ñ"Ð.Ø×:Ñ:Ø %× 3Ñ 3Ø%6×%GÑ%Gð ;ó ÷ ð ð '+�Ô#à×/Ñ/Ð;Ø×5Ñ5×<Ñ<Ø %× @Ñ @Ø->×-OÑ-Oð =ó ÷ ð ð 48�Ô0à×)Ò)ØØ%*×%:Ñ%:ˆOØ#(×#=Ñ#=ˆMØ#(×#=Ñ#=ˆMØ !Ò#¨¸Ò(:¸}ÐPQÒ?QØð # QÒ&ð ×5Ñ5Ü! %×"7Ñ"7Ó8Ø$)×$9Ñ$9Ø"#Ø$3ð	 6ô ð ð ð$ ! 1Ò$¨×)NÒ)Nð ×3Ñ3Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1Ø27×2WÑ2Wð 4ô ð ! 1Ò$ð ×:Ñ:Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1ð	 ;ô ð ð! ð4 ! 1Ò$¨×)NÒ)Nð ×3Ñ3Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1Ø27×2WÑ2Wð 4ô ð ! 1Ò$ð ×:Ñ:Ü! %×"<Ñ"<Ó=Ø$)×$>Ñ$>Ø"#Ø$1ð	 ;ô ð ð! ñ$ ™x©8Ü$×*Ñ*ØbØ#Ø!Ø!ô	ñ Ø×/Ñ/×:Ñ:×YÑYØ#/Ø->×-OÑ-Oð Zó ÷ ð ð !)¨(Ð3ò 
�Ü˜k¬4Ô0Ø×3Ñ3×>Ñ>×]Ñ]Ø'2Ø1B×1SÑ1Sð ^ó ÷ ñ ò !Ø×GÑGØ,7Ø):×)KÑ)Kð Hó ÷ ñ ð
ð *.ˆEÔ&ð 	ð{ùðùðHøðøð
ùô
 ò 	jÜ ×*Ñ*Ð+eÐgh×iÐiØûð	jüs³   ‚L;„L �L;‘6L ÁLÁAL ÂLÂL Â+L;Â,3L ÃL;Ã FL É;L	É<AL ËLËL Ë L Ë4LË5L ÌL;ÌL ÌL Ì	L ÌL ÌL Ì	L8ÌL3Ì.L;Ì3L8Ì8L;r›   )NNNN)NNN)NFFN)NF)ˆr`   ra   rb   r3   r   r
   r  r¯   r  r  Ústaticmethodrc   r  r·   rn   r¬   r  r   r*  r9  Úclassmethodr<  rD  rP  r¶   rV  rŒ   rR  rm  rx   rX   r~  r   r‚  rŸ   r„   rŽ  r™  rŸ  r2   r¥  r   rY   r¨  rµ  rj   rÅ  rp   r¼  rz   rÏ  rÕ  r½  r×  rÙ  ru   ré  rù  r­   rð  rñ  r£   r  rW   r  rò  r$  r‹   r3  r;  r   rD  rU  r`  rg  rn  rw  r|  r~  r‚  rˆ  r�  r’  r�  r¶  rÄ  rÈ  rË  rÒ  r—   r@  rA  rï  rô  rø  rþ  r  r  r)  rE  r   rµ   rS  r   r^  r1   r+   rc  rg  rn  r/  rŽ   rw  r{  r2  rŠ  r�  r“  r¡  r)   r«  r¸  r   r0  rÃ  r1  rÐ  rÙ  rÝ  rÜ  rè  rê  ró  rð  r¸   r  re   rf   rg   rê   rê   C  s  „ ð 8<ñB8à0ðB8ð    H Ñ-°Ñ4óB8ðH(Ð)<¸tÑ)Có (ð % 8ó %ð ðVØ"%¨¡*ðVà	òVó ðVð ð	- Fð 	-°s¸T±zð 	-Àdò 	-ó ð	-ð ð
Øð
à˜‘:ð
ð 
��f�Ñ	 Ñ	$ò
ó ð
ð2 ð4 vð 4¸#À¹*ð 4ÈÈtÉò 4ó ð4ð< ðI¨Fð I¸sÀT¹zð IÈdò Ió ðIð ñ¨ð ¸CÀ$¹Jð ÐRUò ó ðð, ð
 04ñ	0,Øð0,à! D™jð0,ð ˜‘:ð0,ð #&¨¡*ð	0,ð
 
ò0,ó ð0,ðj !Ø/3Ø $Ø/3ñ+àð+ð �T‰zð+ð #&¨¡*ð	+ð
 ˜‘:ð+ð #&¨¡*ð+ð 
ó+ð` 04Ø $Ø/3ñSnàðSnð #&¨¡*ðSnð ˜‘:ð	Snð
 #&¨¡*ðSnð 
ˆs�Cˆx‰óSnðj
 4ó 
ð>à�3‰ið>ð ð>ð ð	>ð
 
ó>ð@àðð ðð !Ð!NÑOð	ð
 
óð2Oà˜C‘yð2Oð )ð2Oð ˜3Ð 1Ð1Ñ2ð	2Oð
 
ó2Oðh)¨Sð )°Só )ð6¨D°©Ið ¸$¸sÀDÈÁI¸~Ñ:Nó ð0
à�3‰ið
ð  ™+ð
ð ð	
ð
 
˜dÑ	"ó
ð

à�3‰ið

ð  ™+ð

ð 
Ð)¨DÑ0Ñ	1°DÑ	8ó	

ð& à˜C‘yð& ð ð& ð 
ó	& ðV )-ØØ$Ø'+ñ|
àÐ1Ñ2ð|
ð  ™+ð|
ð ð	|
ð
 ð|
ð  ™*ð|
ð 
ó|
ð|83àÐ1Ñ2ð83ð ð83ð 
ˆt�C‰y˜$˜sÐ$5Ð5Ñ6¸Ð=QÑ8RÐRÑ	Só	83ðt
Ð#7ð 
ÀCð 
Èsð 
ÐWfó 
ð&Ð;RÐUYÑ;Yð &Ð^aó &ð" )-ØñRcàÐ)Ñ*ðRcð ðRcð  ™+ð	Rcð
 ðRcð 
óRcðn )-ñSà˜‘IðSð  ™+ðSð 
ˆc‰ó	Sð" )-ñ	6GàÐ)Ñ*ð6Gð ð6Gð  ™+ð	6Gð
 
ó6Gðv )-ñ8à,ð8ð  ™+ð8ð 
ó	8ð| )-ñ	DàÐ-Ñ.ðDð ˜˜gÐ&:Ñ;¸SÐ@ÑAÑBðDð  ™+ð	Dð
 
óDðL7 à'ð7 ð   Ð(<Ñ =¸sÐ BÑCð7 ð 
ó	7 ðx )-ñ;
àÐ 5Ñ6ð;
ð  ™+ð;
ð 
ó	;
ðzà�dÐ,Ñ-Ñ.ðð 
óð4@
àÐ#Ñ$ð@
ð Ð0Ñ1ð@
ð 
ó	@
ðJ )-ñc
àÐ0Ñ1ðc
ð  ™+ðc
ð 
ó	c
ðR )-ñ	*
àÐ-Ñ.ð*
ð ð*
ð  ™+ð	*
ð
 
ó*
ñ` V_ÓU`Ø(,ñ%
à˜˜s C˜x™Ñ)ð%
ð ð%
ð ' u¨S°#°wÐ?OÑ7PÐ-PÑ'QÑRð	%
ð
  ™+ð%
ð 
ó%
ðX )-ñ_/àÐ1Ñ2ð_/ð !$ð_/ð "%ð	_/ð
  ™+ð_/ð 
Ð  # sÐ*Ñ	+ó_/ðB#Rà)¨DÑ0ð#Rð ˜t™ð#Rð !$ð	#Rð
 "%ð#Rð 
ó#RðL PTñ:Ø!/ð:ØBEÈÁ*ð:à	Ð!Ñ	"ó:ðx5
à)ð5
ð ˜t™ð5
ð Ð-Ñ.ð	5
ð
 
ó5
ðn#à)ð#ð ð#ð Ð-Ñ.ð	#ð
 
ó#ðJ$
à)ð$
ð ˜t™ð$
ð Ð-Ñ.ð	$
ð
 
ó$
ðL+à)ð+ð ˜t™ð+ð Ð-Ñ.ð	+ð
 
ó+ðZà˜$‘Jðð !ðð 
ó	ð*à˜4‘Zðð ˜$‘Jðð !ð	ð
 
ˆt‰óð8Jà˜d™
ðJð ˜d™
ðJð 
ó	Jð"H°ð HÐ9Oó Hð	(¸ð 	(Èdð 	(ÐWZÐ]aÑWaó 	(ð¨dð °s¸T±zó ð1àð1ð ð1ð 
Ð!Ñ	"ó	1ðt !%ñyà)ðyð ðyð ˜d™
ð	yð
 ˜d™
ðyð !ðyð ˜‘:ðyð 
Ð!Ñ	"óyð| )-ñ6àð6ð  ™+ð6ð 
ó	6ðp¸ð Ð@SÐVZÑ@Zó ð"à)ð"ð ˜t™ð"ð Ð-Ñ.ð	"ð
 
ó"ðH"à)ð"ð ˜t™ð"ð Ð-Ñ.ð	"ð
 
ó"ðH6à)ð6ð ˜t™ð6ð .ð	6ð
 
ó6ðx '+ñ	*à#ð*ð Ð-Ñ.ð*ð ˜t™ð	*ð
 
ó*ðX ð,¨Fð ,°sò ,ó ð,ð* ð
°fð 
Àò 
ó ð
ð$ ð¨fð ¸ò ó ðð8 ð
°ð 
¸8ÀFÑ;Kò 
ó ð
ð( ð	°6ð 	¸cÀD¹jò 	ó ð	ð ð
 G¨C°¨KÑ$8ð 
¸Sò 
ó ð
ñTA°6ð TAÀ#ÈÁ*ð TAÐY\Ð_cÑYcð TAÐoró TAð| !%ñC
àÐ1Ñ2ðC
ð ðC
ð ˜t™ð	C
ð
 *ðC
ð !)¨¨s°C¨x©Ñ 9ðC
ð !$ðC
ð ˜‘:ðC
ð 
óC
ðJLà)ðLð ðLð ð	Lð
 óLð\#àð#ð ð#ð !Ð!NÑOð	#ð
 ð#ð 
Ð/Ñ	0ó#ð4.Ø˜4‘Zð.Ø29Ð:TÑ2Uð.à	ó.ð` ð¨EÐ4DÑ,DÀwÈsÐTZÈ{ÑG[Ñ,[Ð^bÑ,bð Ðgjò ó ðð8 ðØðà	Ð!Ñ	! G¨C°¨KÑ$8Ñ	8¸4Ñ	?òó ðð$%à!Ð"CÑDð%ð 
ó%ðT )-ñ"à!Ð"CÑDð"ð  ™+ð"ð 
ó	"ðN )-ñ àÐ?Ñ@ð ð  ™+ð ð 
ó	 ðJ )-ñ$àÐ?Ñ@ð$ð  ™+ð$ð 
ó	$ðR )-ñ$à%Ð&HÑIð$ð  ™+ð$ð 
ó	$ðL
) WÐ-GÑ%Hó 
)ð ðØ   f Ñ-ðà�Ñ'ðð 
ˆc�6ˆkÑ	òó ðð  ð°&ð ¸UÀ3ÈÈTÀ>Ñ=RÐUYÑ=Yò ó ðð$7àð7ð 
ˆs�C˜ˆ~Ñ	ó7ðrP-àðP-ð ðP-ð 
Ð1Ñ	2ó	P-ðd<à#'¨¨S¨¡>ð<ð ð<ð ˜4‘Zð	<ð
 
ˆe�C˜�H‰oÑ	ó<ð|"à˜%  S ™/Ñ*ð"ð ˜U 3¨ 8™_Ñ-ð"ð ð	"ð
 ð"ð 
Ð-Ñ	.ó"ðH#
à�S˜#�X‰ð#
ð ˜U 3¨ 8™_Ñ-ð#
ð ð	#
ð
 ð#
ð (1°°s¸CÀÐIYÑAZÐ7ZÑ1[Ñ'\ð#
ð 
,¨dÑ	2ó#
ðJ
à˜%  S ™/Ñ*ð
ð ˜U 3¨ 8™_Ñ-ð
ð ð	
ð
 ð
ð (1°°s¸CÀÐIYÑAZÐ7ZÑ1[Ñ'\ð
ð 
Ð1°3Ð6Ñ	7ó
ð.\#àð\#ð ð\#ð !Ð!;Ñ<ð	\#ð
 
Ð-Ñ	.ó\#ò|2Wðhàðð ðð ð	ð
 
ˆt�Vˆ|Ñ	óð(%àð%ð ð%ð 
ó	%òNoWðb#à)ð#ð 
ó#ð8(b°tð (bÐP^ó (bðTpÈð pÐbhð pÐmqó pð4 %)ñxàðxð &ðxð *ð	xð
 ˜T‘zðxð 
ôxrf   rê   )‘rË   r  r“  rþ   r¾  Úcollections.abcr   r   r   r   Úcontextvarsr   Údataclassesr   r	   r
   Útypingr   r   r   r   r   r   r   Útyping_extensionsr   r   r  r   Úlitellm._loggingr   Úlitellm.constantsr   r   Ú"litellm.integrations.custom_loggerr   Ú8litellm.litellm_core_utils.prompt_templates.common_utilsr   Úlitellm.proxy._typesr   r\  r   r   r   r   Ú"litellm.proxy.auth.budget_throttler   Ú-litellm.proxy.common_utils.http_parsing_utilsr    Ú1litellm.proxy.common_utils.proxy_rate_limit_errorr!   r"   Ú)litellm.proxy.hooks.batch_enqueued_tokensr#   r$   r%   r&   r'   Ú&litellm.proxy.hooks.rate_limiter_utilsr(   Úlitellm.types.cachingr)   Úlitellm.types.llms.openair*   r+   Úlitellm.types.utilsr,   r-   r.   r/   r0   r1   Úopentelemetry.tracer2   Ú_SpanÚlitellm.proxy.utilsr3   Ú_InternalUsageCacheÚlitellm.types.agentsr4   r5   rd   r6   r7   r8   r9   r:   r;   r<   r>   r?   rA   rB   rE   rH   rK   Úrerankrl   ÚarerankrL   Úgenerate_contentÚagenerate_contentÚgenerate_content_streamÚagenerate_content_streamrM   rO   rP   rQ   rS   rU   rV   rc   rå   rn   ÚbytesrW   rX   r¶   r·   rY   r[   rj   rp   ru   rz   r„   rŽ   r“   r—   rŸ   r£   r¨   rŒ   rx   r­   r¯   r»   rÏ   rÒ   rÖ   rÜ   rÞ   râ   rè   rê   re   rf   rg   ú<module>r%     sA  ðòó Û Û 	Û ß <Ó <Ý "ß (Ý ÷÷ ñ ÷ 4å Ý 1ß nÝ ;õõ 0÷ó õ ?Ý T÷÷õ õ WÝ Aß W÷÷ ñ Ý1åMÝ2ÝEà�3‰;€DØ,Ñà€DØÐð#$Ð ˜5ó #ðJ]*Ð  ó ]ð~0Ð % uó ð6 "Ð ˜ó  ðD"Ð ˜ó ð Ð �uó ð!Ð ˜ó ð8 #Ð �UÓ "Ø!+Ð ˜Ó +ð
 &*Ð ˜UÓ )Ø!"Ð ˜Ó "ð
 Ð �UÓ ð
 #>Ð ˜%Ó =Ø"=Ð ˜%Ó =Ø(OÐ  Ó OØ )× 0Ñ 0× 6Ñ 6¸	×8IÑ8I×8OÑ8OÐPÐ �uÓ Pà×Ñ×$Ñ$Ø×Ñ×%Ñ%Ø×%Ñ%×+Ñ+Ø×&Ñ&×,Ñ,ð	)Ð  ó ð *,Ð  Ó +ð '*Ð ˜eÓ )ð
 !%Ð ˜Ó $ð &>Ð ˜UÓ =Ø%=Ð ˜UÓ =ð
 ,0Ð ! 5Ó /ð  # U™{¨SÑ0°5Ñ8Ð �9Ó 8à (Ð):¸TÑ)AÑ BÐ �IÓ Bà%)¨#¨v¨+Ñ%6¸Ñ%<¸uÑ%DÀsÑ%JÈUÑ%RÐ ˜Ó Rô¨¸%õ ô:˜)ô :ô˜9ô ô˜iô ô
1�iô 1ôf˜	ô fô@Ð)Hô @ô  yô  ô
F˜xô Fô˜	ô ô	˜	ô 	ô ˜ô  ð $)¨¨c©°D¸±I¸tÐDUÑ?VÐ)VÑ#WÐ �yÓ Wô9˜(ô 9ñ �Ô÷''ð ''ó ð''ñT EOØ+°TôE€��jÐ!8¸4Ñ!?Ñ@ÑAó ð
 Ð2°TÑ9ó  ðÐ%<ó ð tð Ð0Gó ðM°°d±
ð MÐ?VÐY]Ñ?]ó Mð9¨&ð 9°S¸4±Zó 9ð vð °#¸±*ó ô\B¨<õ \Brf   