Ë
    uPêjGL  ã                   ó¤   — d 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
 ddlmZ ddlmZ dd	lmZmZ erdd
lmZ ddlmZ neZeZ G d„ de
«      Zy)aù  
Quality-tier Auto Router.

Routes a request to a model at a target quality tier. The quality tier is
inferred by re-using the existing ComplexityRouter's classification, then
mapped through an admin-configured `complexity_to_quality` table. Each
candidate model declares its own `quality_tier` in
`model_info.litellm_routing_preferences`.

Optional keyword override: deployments may also declare `keywords` in
`litellm_routing_preferences`. If any declared keyword appears in the user
message (case-insensitive substring match), the router short-circuits the
complexity-classification flow and routes to the matching deployment. When
multiple deployments match, ties are broken by (highest quality_tier first,
then cheapest `model_info.input_cost_per_token`).
é    N)ÚTYPE_CHECKINGÚAnyÚFinalÚOptional)Úverbose_router_logger)ÚCustomLogger)ÚComplexityRouter)ÚStandardLoggingRoutingDecisioné   )ÚQualityRouterConfigÚRoutingPreferences)ÚRouter©ÚPreRoutingHookResponsec                   ó¦  — e Zd ZdZ	 	 ddedddedz  deeef   dz  fd„Zed	ee	e
e   f   fd
„«       Zded	eeef   dz  fd„Zded	edz  fd„Zded	edz  fd„Zd	ee	e
e   f   fd„Zded	efd„Zded	efd„Zded	eeef   dz  fd„Zde	d	efd„Zdeeef   dz  deeef   d	dfd„Z	 	 	 d dedede
eeef      dz  dee
z  dz  dedz  d	ed   fd„Zy)!ÚQualityRouterze
    Routes requests to a model at a target quality tier, with an optional
    keyword override.
    NÚ
model_nameÚlitellm_router_instancer   Údefault_modelÚquality_router_configc                 óz  — || _         || _        |rt        di |¤Ž| _        nt        «       | _        |r|| j                  _        t        |› d�|¬«      | _        i | _        i | _        i | _	        i | _
        d | _        t        j                  d|| j                  j                  | j                  j                  «       y )Nz::scorer)r   r   zKQualityRouter initialized for %s with available_models=%s, default_model=%s© )r   r   r   Úconfigr   r	   Ú_scorerÚ_model_keywordsÚ_model_qualityÚ_model_costÚ_model_orderÚ_tier_to_models_cacher   ÚdebugÚavailable_models)Úselfr   r   r   r   s        úz/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/router_strategy/quality_router/quality_router.pyÚ__init__zQualityRouter.__init__,   s¸   € ð %ˆŒØ'>ˆÔ$á Ü-ÑFÐ0EÑFˆD�Kä-Ó/ˆDŒKñ Ø(5ˆD�K‰KÔ%ô (Ø$˜ XÐ.Ø$;ô
ˆŒð 68ˆÔØ.0ˆÔØ46ˆÔØ35ˆÔð CGˆÔ"ä×#Ñ#ØYØØ�K‰K×(Ñ(Ø�K‰K×%Ñ%õ		
ó    Úreturnc                 ó\   — | j                   €| j                  «       | _         | j                   S )u0   Lazy tierâ†’models index; built on first access.)r   Ú_build_tier_index)r"   s    r#   Ú_tier_to_modelszQualityRouter._tier_to_models^   s-   € ð ×%Ñ%Ð-Ø)-×)?Ñ)?Ó)AˆDÔ&Ø×)Ñ)Ð)r%   Ú
deploymentc                 ó$  — t        |t        «      rC|j                  d«      xs i }t        |t        «      r|j                  d«      S t        |dd«      S t        |dd«      }|€yt        |t        «      r|j                  d«      S t        |dd«      S )z’
        Extract litellm_routing_preferences from a deployment, handling both
        dict-shaped and Pydantic-object-shaped deployments.
        Ú
model_infoÚlitellm_routing_preferencesN©Ú
isinstanceÚdictÚgetÚgetattr)r"   r*   r,   s      r#   Ú_get_routing_preferencesz&QualityRouter._get_routing_preferencese   sŽ   € ô �j¤$Ô'Ø#Ÿ™¨Ó5Ò;¸ˆJÜ˜*¤dÔ+Ø!—~‘~Ð&CÓDÐDä˜:Ð'DÀdÓKÐKô ˜Z¨°tÓ<ˆ
ØÐØÜ�j¤$Ô'Ø—>‘>Ð"?Ó@Ð@Ü�zÐ#@À$ÓGÐGr%   c                 ó  — t        |t        «      r|j                  d«      xs i }nt        |dd«      xs i }t        |t        «      r|j                  d«      }nt        |dd«      }|€y	 t	        |«      S # t
        t        f$ r Y yw xY w)u;  
        Extract `input_cost_per_token` from a deployment's model_info.

        Returns None when not declared â€” None is treated as "infinite cost"
        for the cheapest-tiebreak ordering, so unpriced models lose ties to
        priced ones. (Admins who want a model to win on price must declare it.)
        r,   NÚinput_cost_per_token)r/   r0   r1   r2   ÚfloatÚ	TypeErrorÚ
ValueError)r"   r*   r,   Úcosts       r#   Ú_get_deployment_input_costz(QualityRouter._get_deployment_input_costz   sŠ   € ô �j¤$Ô'Ø#Ÿ™¨Ó5Ò;¸‰Jä  ¨\¸4Ó@ÒFÀBˆJä�j¤$Ô'Ø—>‘>Ð"8Ó9‰Dä˜:Ð'=¸tÓDˆDàˆ<Øð	Ü˜“;ÐøÜœ:Ð&ò 	Ùð	ús   Á+
A6 Á6BÂBc                 ó^   — t        |t        «      r|j                  d«      S t        |dd«      S )z>Extract `model_name` from a dict- or object-shaped deployment.r   Nr.   )r"   r*   s     r#   Ú_get_deployment_model_namez(QualityRouter._get_deployment_model_name“   s*   € ä�j¤$Ô'Ø—>‘> ,Ó/Ð/Ü�z <°Ó6Ð6r%   c           	      óŽ  ‡ — t        ‰ j                  dd«      xs g }t        ‰ j                  j                  «      }|D �ci c]  }|d“Œ }}i }|D �]_  }‰ j                  |«      }|�||vrŒ‰ j                  |«      }|€t        d|› d�«      ‚	 t        |t        «      r|}nLt        |t        «      rt        di |¤Ž}n0t        di t        |d«      r|j                  «       n
t        |«      ¤Ž}t        |j                  «      }
|j!                  |
g «      j#                  |«       |j$                  D �cg c]  }|sŒt'        |«      j)                  «       ‘Œ  c}‰ j*                  |<   |
‰ j,                  |<   ‰ j/                  |«      ‰ j0                  |<   |j2                  ‰ j4                  |<   d||<   �Œb |j7                  «       D ��cg c]
  \  }}|rŒ	|‘Œ }}}|rt        d	|› �«      ‚|j9                  «       D ]  }|j;                  ˆ fd
„¬«       Œ |S c c}w # t        $ r}	t        d|› d|	› �«      |	‚d}	~	ww xY wc c}w c c}}w )a  
        Build {quality_tier: [model_name, ...]} for every model in
        `available_models`, plus side indices `_model_keywords`,
        `_model_quality`, and `_model_cost`. Raises if any listed model is
        missing `litellm_routing_preferences`.
        Ú
model_listNFzQualityRouter: model 'zQ' is listed in available_models but has no model_info.litellm_routing_preferencesÚ
model_dumpz+' has invalid litellm_routing_preferences: TzQualityRouter: the following available_models are not present in the router's model_list (or are missing routing preferences): c                 óJ   •— ‰j                  | «      ‰j                  | «      | fS ©N)Ú
_order_keyÚ	_cost_key)Únr"   s    €r#   ú<lambda>z1QualityRouter._build_tier_index.<locals>.<lambda>Ø   s    ø€  t§¡°qÓ'9¸4¿>¹>È!Ó;LÈaÐ&P€ r%   ©Úkeyr   )r2   r   Úsetr   r!   r<   r3   r8   r/   r   r0   Úhasattrr?   Ú	ExceptionÚintÚquality_tierÚ
setdefaultÚappendÚkeywordsÚstrÚlowerr   r   r:   r   Úorderr   ÚitemsÚvaluesÚsort)r"   r>   Ú	availableÚnameÚseenÚtier_to_modelsr*   Ú	raw_prefsÚprefsÚeÚtier_intÚkÚfoundÚmissingÚmodelss   `              r#   r(   zQualityRouter._build_tier_index™   sr  ø€ ô $ D×$@Ñ$@À,ÐPTÓUÒ[ÐY[ˆ
Ü˜tŸ{™{×;Ñ;Ó<ˆ	ð AJÖ'J¸¨¨e©Ð'JˆÐ'JØ68ˆà$ó #	ˆJØ×2Ñ2°:Ó>ˆDØˆ|˜t¨9Ñ4Øà×5Ñ5°jÓAˆIØÐ Ü Ø,¨T¨Fð 3Hð Ióð ðwÜ˜iÔ);Ô<Ø%‘EÜ 	¬4Ô0Ü.Ñ;°Ñ;‘Eô /ñ Ü5<¸YÈÔ5U˜9×/Ñ/Ô1Ô[_Ð`iÓ[jñ�Eô ˜5×-Ñ-Ó.ˆHØ×%Ñ% h°Ó3×:Ñ:¸4Ô@ØBGÇ.Á.Ö)V¸QÒTU¬#¨a«&¯,©,­.Ò)VˆD× Ñ  Ñ&Ø(0ˆD×Ñ Ñ%Ø%)×%DÑ%DÀZÓ%PˆD×Ñ˜TÑ"Ø&+§k¡kˆD×Ñ˜dÑ#ØˆD�‹JðG#	ðJ 37·*±*³,×L¡; 4¨Âeš$ÐLˆÑLÙÜðQØQXÐPYð[óð ð %×+Ñ+Ó-ò 	RˆFØ�K‰KÓPˆKÕQð	Rð Ðùòm (Køô: ò wÜ Ð#9¸$¸Ð?jÐklÐjmÐ!nÓoÐuvÐvûðwüò
 *Wùó Ms7   Á 
HÂAHÄ2H<Ä:H<Ç
IÇIÈ	H9È"H4È4H9c                 ór   — | j                   j                  |«      }|�t        |«      S t        j                  S )uB   `order` lookup as a float â€” unset becomes +inf so explicit wins.)r   r1   r6   ÚmathÚinf)r"   r   rR   s      r#   rB   zQualityRouter._order_keyÜ   s0   € à×(Ñ(×,Ñ,¨ZÓ8ˆØ$Ð0Œu�U‹|Ð>´d·h±hÐ>r%   c                 ór   — | j                   j                  |«      }|�t        |«      S t        j                  S )u9   `input_cost_per_token` as a float â€” unset becomes +inf.)r   r1   r6   rc   rd   )r"   r   r9   s      r#   rC   zQualityRouter._cost_keyá   s0   € à×&Ñ&×*Ñ*¨:Ó6ˆØ"Ð.Œu�T‹{Ð<´D·H±HÐ<r%   Úuser_messagec                 ój  ‡ — ‰ j                   }|j                  «       }g }‰ j                  j                  «       D ](  \  }}|D ]  }|sŒ||v sŒ|j	                  ||f«        Œ( Œ* |sydt
        t        t        f   dt
        t        t        t        t        f   fˆ fd„}|j                  |¬«       |d   S )u  
        Find a deployment whose declared keywords appear in `user_message`.

        Returns (model_name, matched_keyword) or None when no keyword matches.
        When multiple deployments match, sorts by:
            1. quality_tier DESC (best quality always wins first)
            2. `order` ASC (explicit priority â€” unset = +inf so explicit wins
               within the same tier)
            3. input_cost_per_token ASC (unpriced = +inf so priced wins)
            4. model_name ASC (deterministic stability)
        NÚmatchr&   c                 óÔ   •— | d   }‰j                   j                  |d«      }‰j                  |«      }‰j                  j                  |«      }|�|nt        j
                  }| |||fS )Nr   )r   r1   rB   r   rc   rd   )rh   rW   ÚqualityÚ	order_valr9   Úcost_valr"   s         €r#   Úsort_keyz1QualityRouter._keyword_override.<locals>.sort_key  si   ø€ Ø ™(ˆDØ!×0Ñ0×4Ñ4°T¸1Ó=ˆGØ#Ÿ™¨tÓ4ˆIØ×*Ñ*×.Ñ.¨tÓ4ˆDØ&*Ð&6™d¼D¿H¹HˆHà�H˜i¨°4Ð8Ð8r%   rF   r   )
r)   rQ   r   rS   rN   ÚtuplerP   rK   r6   rU   )	r"   rf   Ú_ÚtextÚmatchesr   rO   Úkwrm   s	   `        r#   Ú_keyword_overridezQualityRouter._keyword_overrideæ   s½   ø€ ð × Ñ ˆà"×(Ñ(Ó*ˆà02ˆØ$(×$8Ñ$8×$>Ñ$>Ó$@ò 	Ñ ˆJ˜Øò �Ú˜" š*Ø—N‘N J°Ð#3Ô4Ùñð	ñ Øð	9œE¤#¤s (™Oð 	9´´c¼5Ä%ÌÐ6LÑ0Mõ 	9ð 	�‰˜ˆÔ"Ø�q‰zÐr%   Útierc                 ó`  ‡— | j                   }‰|v r|‰   r|‰   d   S t        ˆfd„|D «       «      }|D ]  }||   sŒ	||   d   c S  t        ˆfd„|D «       d¬«      }|D ]  }||   sŒ	||   d   c S  | j                  j                  r| j                  j                  S t	        d‰› d�«      ‚)u3  
        Resolve a quality tier to a concrete model name.

        Strategy:
            1. Exact tier match â†’ first model registered at that tier.
            2. Round UP to the next higher tier that has a model (closer to a
               request we might lack capacity for).
            3. Round DOWN to the closest lower tier that has a model (degrade
               gracefully instead of jumping straight to `default_model`,
               which may be off-tier).
            4. Fall back to `config.default_model`.
            5. Otherwise raise.
        r   c              3   ó.   •K  — | ]  }|‰kD  sŒ	|–— Œ y ­wrA   r   ©Ú.0Útrt   s     €r#   ú	<genexpr>z@QualityRouter._resolve_model_for_quality_tier.<locals>.<genexpr>!  ó   øè ø€ Ò$G¨1¸aÀ$»h¤QÑ$Gùó   ƒ
Žc              3   ó.   •K  — | ]  }|‰k  sŒ	|–— Œ y ­wrA   r   rw   s     €r#   rz   z@QualityRouter._resolve_model_for_quality_tier.<locals>.<genexpr>'  r{   r|   T)Úreversez3QualityRouter: no model available for quality tier z  and no default_model configured)r)   Úsortedr   r   r8   )r"   rt   Ú
tier_indexÚhigher_tiersry   Úlower_tierss    `    r#   Ú_resolve_model_for_quality_tierz-QualityRouter._resolve_model_for_quality_tier  sÕ   ø€ ð !×0Ñ0ˆ
Ø�:Ñ *¨TÒ"2Ø˜dÑ# AÑ&Ð&ô %Ó$G°
Ô$GÓGˆØò 	(ˆAØ˜!‹}Ø! !‘} QÑ'Ò'ð	(ô
 $Ó$G°
Ô$GÐQUÔVˆØò 	(ˆAØ˜!‹}Ø! !‘} QÑ'Ò'ð	(ð �;‰;×$Ò$Ø—;‘;×,Ñ,Ð,äÐNÈtÈfÐTtÐuÓvÐvr%   Úrequest_kwargsÚdecisionc                 óZ   — |€y|j                  di «      }t        |t        «      r||d<   yy)zù
        Stash the routing decision in request_kwargs.metadata so the Router can
        lift it into response headers (`x-litellm-quality-router-*`). The same
        dict object flows from here through to `make_call.set_response_headers`.
        NÚmetadataÚquality_router_decision)rM   r/   r0   )r"   r„   r…   r‡   s       r#   Ú_stash_decisionzQualityRouter._stash_decision1  s9   € ð Ð!ØØ(×3Ñ3°JÀÓCˆÜ�h¤Ô%Ø2:ˆHÐ.Ò/ð &r%   ÚmodelÚmessagesÚinputÚspecific_deploymentr   c              ƒ   ór  K  — ddl m} |�t        |«      dk(  rt        j                  d«       yd}d}t        |«      D ]Æ  }	|	j                  dd«      }
|	j                  d«      xs d}t        |t        «      rd|D �cg c]:  }t        |t        «      sŒ|j                  d«      d	k(  sŒ)|j                  d	d«      ‘Œ< }}d
j                  |«      j                  «       }t        |t        «      sŒ¯|sŒ²|
dk(  r|€|}Œ¼|
dk(  sŒÂ|�ŒÅ|}ŒÈ |€€t        j                  d«       | j                  j                  st        d«      ‚ || j                  j                  |t!        | j"                  d| j                  j                  d¬«      ¬«      S | j%                  |«      }|�Ü|\  }}t        j&                  d||| j(                  j                  |«      | j*                  j                  |«      «       | j-                  || j"                  |d|| j(                  j                  |«      ddœ«       t!        | j"                  d|d|¬«      }| j(                  j                  |«      }|�t        |«      |d<    ||||¬«      S | j.                  j1                  ||«      \  }}}t3        |d«      r|j4                  n
t        |«      }| j                  j6                  j                  |«      }|€%t        d|› d| j                  j6                  › �«      ‚| j9                  t;        |«      «      }t        j&                  d|› d|d›d|› d|› d |› �
«       | j-                  || j"                  |d!dt;        |«      |dœ«        |||t!        | j"                  d|d!t        t;        |«      «      |t        |«      ¬"«      ¬«      S c c}w ­w)#zATry keyword override first; fall back to complexity-tier routing.r   r   Nz5QualityRouter: No messages provided, skipping routingÚroleÚ ÚcontentÚtyperp   ú ÚuserÚsystemz>QualityRouter: No user message found, routing to default modelz>QualityRouter: no user message and no default_model configuredrj   Údefault_fallback)Úrouter_model_nameÚrouter_typeÚrouted_modelÚcause)rŠ   r‹   Úrouting_decisionzgQualityRouter: keyword override matched='%s' routed_model=%s (quality_tier=%s, input_cost_per_token=%s)Úkeyword)r—   r™   Ú
routed_viaÚmatched_keywordrL   Úcomplexity_tier)r—   r˜   r™   rš   rž   rt   Úvaluez QualityRouter: complexity tier 'z/' not present in complexity_to_quality mapping zQualityRouter: complexity=z, score=z.3fz
, signals=z, quality_tier=z, routed_model=rL   )r—   r˜   r™   rš   rt   ÚscoreÚsignals)Úlitellm.types.routerr   Úlenr   r    Úreversedr1   r/   Úlistr0   ÚjoinÚstriprP   r   r   r8   r
   r   rs   Úinfor   r   r‰   r   ÚclassifyrI   r    Úcomplexity_to_qualityrƒ   rK   )r"   rŠ   r„   r‹   rŒ   r�   r   rf   Úsystem_promptÚmsgr�   r‘   ÚpartÚ
text_partsÚkeyword_matchr™   rž   r›   Úkeyword_quality_tierrŸ   r¡   r¢   Úcomplexity_namerL   s                           r#   Úasync_pre_routing_hookz$QualityRouter.async_pre_routing_hookA  sÞ  è ø€ õ 	@àÐœs 8›}°Ò1Ü!×'Ñ'Ð(_Ô`Øð $(ˆØ$(ˆä˜HÓ%ò 	,ˆCØ—7‘7˜6 2Ó&ˆDØ—g‘g˜iÓ(Ò.¨BˆGÜ˜'¤4Ô(à5<öØ-1Ä
È4ÔQUÕ@VÐ[_×[cÑ[cÐdjÓ[kÐouÓ[u�D—H‘H˜V RÕ(ð�
ð ð Ÿ(™( :Ó.×4Ñ4Ó6�Ü˜'¤3Õ'ªGØ˜6’> lÐ&:Ø#*‘LØ˜XÓ%¨-Ñ*?Ø$+‘Mð	,ð ÐÜ!×'Ñ'Ð(hÔiØ—;‘;×,Ò,Ü Ð!aÓbÐbÙ)Ø—k‘k×/Ñ/Ø!Ü!?Ø&*§o¡oØ )Ø!%§¡×!:Ñ!:Ø,ô	"ô	ð 	ð  $×5Ñ5°lÓCˆØÐ$Ø,9Ñ)ˆL˜/Ü!×&Ñ&ØyØØØ×#Ñ#×'Ñ'¨Ó5Ø× Ñ ×$Ñ$ \Ó2ôð × Ñ Øà)-¯©Ø$0Ø"+Ø'6Ø$(×$7Ñ$7×$;Ñ$;¸LÓ$IØ'+ñô
ô 'EØ"&§/¡/Ø%Ø)ØØ /ô'Ðð +/×*=Ñ*=×*AÑ*AÀ,Ó*OÐ Ø#Ð/Ü+.Ð/CÓ+DÐ  Ñ(Ù)Ø"Ø!Ø!1ôð ð +/¯,©,×*?Ñ*?ÀÈmÓ*\Ñ'ˆ˜ Ü:AÀ/ÐSZÔ:[ ×!6Ò!6ÔadÐetÓauˆà"Ÿk™k×?Ñ?×CÑCÀOÓTˆØÐÜØ2°?Ð2Cð D4Ø48·K±K×4UÑ4UÐ3VðXóð ð
 ×;Ñ;¼CÀÓ<MÓNˆä×"Ñ"Ø(¨Ð(9¸À%ÈÀð MØ�i˜¨|¨nð =Ø(˜>ð+ô	
ð 	×ÑØà%)§_¡_Ø ,Ø,Ø#'Ü # LÓ 1Ø#2ñô
	
ñ &ØØÜ;Ø"&§/¡/Ø%Ø)Ø$Üœ˜\Ó*Ó+ØÜ˜W›ôô
ð 	
ùò}ùs7   ‚A:N7Á<N2ÂN2Â'N2Â;1N7Ã-N7Ã0N7Ä N7ÄJ4N7)NN)NNF)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rP   r0   r   r$   ÚpropertyrK   r¦   r)   r3   r6   r:   r<   r(   rB   rC   rn   rs   rƒ   r‰   Úboolr   r³   r   r%   r#   r   r   &   së  „ ñð %)Ø7;ñ0
àð0
ð "*ð0
ð ˜T‘zð	0
ð
  $ C¨ H™~°Ñ4ó0
ðd ð*  c¨4°©9 nÑ!5ò *ó ð*ðH°3ð H¸4ÀÀSÀ¹>ÈDÑ;Pó Hð*°Sð ¸UÀT¹\ó ð27°Sð 7¸SÀ4¹Zó 7ðA 4¨¨T°#©Y¨Ñ#7ó AðF? Sð ?¨Uó ?ð
= Cð =¨Eó =ð
&¨cð &°e¸CÀ¸H±oÈÑ6Ló &ðP!w°Cð !w¸Có !wðF;à˜S #˜X™¨Ñ-ð;ð �s˜C�x‘.ð;ð 
ó	;ð( 15Ø#'Ø+0ñB
àðB
ð ðB
ð �t˜C ˜H‘~Ñ&¨Ñ-ð	B
ð
 �T‰z˜DÑ ðB
ð " D™[ðB
ð 
Ð*Ñ	+ôB
r%   r   )r·   rc   Útypingr   r   r   r   Úlitellm._loggingr   Ú"litellm.integrations.custom_loggerr   Ú;litellm.router_strategy.complexity_router.complexity_routerr	   Úlitellm.types.utilsr
   r   r   r   Úlitellm.routerr   r£   r   r   r   r%   r#   ú<module>rÀ      sJ   ðñó" ß 6Ó 6å 2Ý ;õõ ?ç ;áÝ%Þ;à€FØ Ðô]
�Lõ ]
r%   