Ë
    uPêj“õ  ã            
       óÈ  — U d 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
 ddlmZmZmZmZmZmZmZ ddlmZmZmZ  G d„ d	ee«      Z G d
„ dee«      Zej4                  Ze	e   ed<    eddh«      Ze	ee      ed<   ej>                  ej@                  ejB                  ejD                  fZ#e	e$edf      ed<   dZ%e	e&   ed<   dZ'e	e(   ed<   dZ)e	e(   ed<    G d„ de«      Z*dZ+e	e(   ed<   dZ,e	e(   ed<   dZ-e	e(   ed<   d Z.e	e(   ed!<   d"ed#z  d$ed#z  fd%„Z/ G d&„ d'e«      Z0 G d(„ d)e«      Z1 G d*„ d+e«      Z2d,e3d-ed$e$ee4e   z  e$e2df   f   fd.„Z5g d/¢Z6e	e4e      ed0<   g d1¢Z7e	e4e      ed2<   g d3¢Z8e	e4e      ed4<   d5gZ9e	e4e      ed6<   d7Z:e	e$edf      ed8<   d9Z;e	e$edf      ed:<   d;Z<e	e$edf      ed<<   d=Z=e	e   ed><   g d?¢Z>e	e4e      ed@<   dAdBdCdCdDdEdFdGœZ?e	e@ee&f      edH<   dIdJdKdLœZAe	e@ee&f      edM<   dNdOdPœZBe	e@ee(f      edQ<   dRdSdTdTdUœZCe	e@eef      edV<    G dW„ dXe«      ZD G dY„ dZe«      ZE eeEjŒ                  «      ZGe	ee      ed[<   	  eE«       ZHe	ed\<   y#)]z³
Configuration for the Complexity Router.

Contains default keyword lists, weights, tier boundaries, and configuration classes.
All values are configurable via proxy config.yaml.
é    )ÚMapping)ÚEnum©ÚMappingProxyType)Ú	AnnotatedÚFinalÚLiteral)Ú	BaseModelÚ
ConfigDictÚFieldÚSkipValidationÚfield_serializerÚfield_validatorÚmodel_validator)ÚAdaptiveRouterWeightsÚClassifierPluginÚRoutingPluginc                   ó    — e Zd ZdZdZdZdZdZy)ÚComplexityTierz'Complexity tiers for routing decisions.ÚSIMPLEÚMEDIUMÚCOMPLEXÚ	REASONINGN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   © ó    úu/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/router_strategy/complexity_router/config.pyr   r      s   „ Ù1à€FØ€FØ€GØ�Ir   r   c                   ó    — e Zd ZdZdZdZdZdZy)ÚClassificationRubricziWhich calibration examples, and for BUSINESS which tier criteria, the built-in classifier rubric carries.ÚlegacyÚagenticÚchatÚbusinessN)r   r   r   r   ÚLEGACYÚAGENTICÚCHATÚBUSINESSr   r   r    r"   r"      s   „ Ùsà€FØ€GØ€DØ�Hr   r"   ÚDEFAULT_CLASSIFICATION_RUBRICÚllmÚheuristic_firstÚLLM_CLASSIFIER_TYPES.ÚTIER_SEVERITY_ORDERç      à?ÚDEFAULT_TIER_DISTANCE_PENALTYé   Ú&DEFAULT_CLASSIFIER_CONTEXT_WINDOW_SIZEi@  Ú'DEFAULT_CLASSIFIER_CONTEXT_BUDGET_CHARSc                   ó¦   — e Zd ZU dZ edd¬«      Zee   ed<    ed¬«      Z	eed<    e
dd	¬
«      ededefd„«       «       Z ed¬
«      dd„«       Zy)ÚKeywordTierRulezEA deterministic override: if any keyword matches, route to this tier.é   zCKeywords/phrases that trigger this rule (lexical or semantic match))Ú
min_lengthÚdescriptionÚkeywordszzTier to route to when this rule matches: a built-in tier name, or with tier_definitions set, one of the defined tier names©r9   ÚtierÚbefore©ÚmodeÚvalueÚreturnc                 ó~   — t        |t        «      r|j                  S t        |t        «      r|j	                  «       S |S ©N©Ú
isinstancer   r@   ÚstrÚstrip©Úclsr@   s     r    Ú_coerce_tierzKeywordTierRule._coerce_tierJ   ó3   € ô �eœ^Ô,Ø—;‘;ÐÜ�eœSÔ!Ø—;‘;“=Ð Øˆr   Úafterc                 ó�   — | j                   D �cg c]  }|j                  «       x}sŒ|‘Œ }}|st        d«      ‚|| _         | S c c}w )NzFkeyword_tier_rules entries must contain at least one non-empty keyword)r:   rG   Ú
ValueError)ÚselfÚkeywordÚstrippedÚcleaneds       r    Ú_normalize_keywordsz#KeywordTierRule._normalize_keywordsS   sP   € ð 37·-±-Öa wÐPW×P]ÑP]ÓP_ÐD_ÀHÑD_š(ÐaˆÐaÙÜÐeÓfÐfØˆŒØˆùò	 bs
   �A§AN)rA   r6   )r   r   r   r   r   r:   ÚlistrF   Ú__annotations__r<   r   ÚclassmethodÚobjectrJ   r   rS   r   r   r    r6   r6   <   sƒ   … ÙOáØØYô€Hˆd�3‰ió ñ ðBô€Dˆ#ó ñ �V (Ô+Øð ð ¨Fò ó ó ,ðñ ˜'Ô"ò	ó #ñ	r   r6   é   ÚMAX_TIER_DEFINITIONSé@   ÚMAX_TIER_NAME_CHARSiô  ÚMAX_TIER_DESCRIPTION_CHARSiÐ  ÚMAX_CLASSIFICATION_PROMPT_CHARSr@   NrA   c                 ó�   — | €y| j                  «       }|st        d«      ‚t        |«      t        kD  rt        dt        › d�«      ‚|S )aA  Strip, reject blank, and cap an operator-written classifier preamble.

    The single owner of the rule, so the dashboard's prompt preview normalizes exactly what the
    write gate stores: previewing the raw value would render leading whitespace the router strips,
    or an over-long prompt the write then rejects.
    Nú)must be non-empty; omit the field insteadzclassification_prompt exceeds ú characters)rG   rN   Úlenr]   )r@   rQ   s     r    Únormalize_classification_promptrb   f   sP   € ð €}ØØ—k‘k“m€HÙÜÐDÓEÐEÜ
ˆ8ƒ}Ô6Ò6ÜÐ9Ô:YÐ9ZÐZeÐfÓgÐgØ€Or   c                   ór   — e Zd ZU dZ ed¬«      Zeed<    edd¬«      Zedz  ed<    e	d	¬
«      dd„«       Z
y)ÚTierDefinitionz]An operator-defined tier: the name the LLM classifier must return and its rubric description.zMTier name; becomes a value the LLM classifier can return and a key of `tiers`r;   ÚnameNzÔWhat belongs in this tier; rendered as this tier's bullet in the classifier rubric. Required unless the name is a built-in tier (SIMPLE/MEDIUM/COMPLEX/REASONING), which inherits the built-in criteria when omitted©Údefaultr9   r9   rL   r>   c                 ó.  — | j                   j                  «       }| j                  �| j                  j                  «       xs d nd }|st        d«      ‚t	        |«      t
        kD  rt        d|d t
         ›dt
        › d�«      ‚|�(t	        |«      t        kD  rt        d|›dt        › d�«      ‚|€/|j                  «       t        j                  vrt        d|›d�«      ‚||xs d	f}t        d
„ |D «       «      rt        d|›d�«      ‚|| _         || _        | S )Nz3tier_definitions entries must have a non-empty nameztier_definitions name z... exceeds r`   z!tier_definitions description for z	 exceeds ztier_definitions entry zw must have a description: only the built-in tiers (SIMPLE, MEDIUM, COMPLEX, REASONING) carry one the rubric can inheritÚ c              3   ó0   K  — | ]  }d |v xs d|v –— Œ y­w)ú
úNr   )Ú.0Úparts     r    ú	<genexpr>z,TierDefinition._normalize.<locals>.<genexpr>š   s    è ø€ ÒM°ˆt�tˆ|Ò+˜t t˜|Ó+ÑMùs   ‚z@ must not contain newlines; the rubric renders one line per tier)re   rG   r9   rN   ra   r[   r\   Úupperr   Ú__members__Úany)rO   re   r9   Úrendered_on_one_lines       r    Ú
_normalizezTierDefinition._normalize†   sD  € à—i‘i—o‘oÓ'ˆØCG×CSÑCSÐC_˜d×.Ñ.×4Ñ4Ó6Ò>¹$ÐeiˆÙÜÐRÓSÐSÜˆt‹9Ô*Ò*ÜØ(¨Ð.BÔ/BÐ)CÐ(FÀlÔSfÐRgÐgrÐsóð ð Ð"¤s¨;Ó'7Ô:TÒ'TÜØ3°D°8¸9ÔE_ÐD`Ð`kÐlóð ð Ð 4§:¡:£<´~×7QÑ7QÑ#QÜØ)¨$¨ð 2Xð Xóð ð (,¨[Ò->¸BÐ&?ÐÜÑMÐ8LÔMÔMÜØ)¨$¨Ð1qÐróð ð ˆŒ	Ø&ˆÔØˆr   )rA   rd   )r   r   r   r   r   re   rF   rU   r9   r   rt   r   r   r    rd   rd   w   sQ   … ÙgáØcô€Dˆ#ó ñ $Øð:ô€K��t‘ó ñ ˜'Ô"òó #ñr   rd   c                   ój   — e Zd ZU dZ ed¬«      Zeed<    ed¬«      Zeed<    e	d¬«      dd	„«       Z
y
)ÚReminderMarkerPairaY  One open/close delimiter pair a harness wraps injected context in.

    Normalizing here rather than at the scan is what makes matching case-insensitive: markers reach
    the scan already lowered, so it lowercases only the haystack and never the needles. Stripping
    keeps YAML indentation whitespace from becoming part of the delimiter.
    z+Opening delimiter, e.g. '<system-reminder>'r;   Úopenz,Closing delimiter, e.g. '</system-reminder>'ÚcloserL   r>   c                 ó   — | j                   j                  «       j                  «       }| j                  j                  «       j                  «       }|r|st	        d«      ‚||k(  rt	        d«      ‚|| _         || _        | S )Nz*reminder_markers entries must not be blankz9reminder_markers open and close must be different strings)rw   rG   Úlowerrx   rN   )rO   Úopen_markerÚclose_markers      r    rt   zReminderMarkerPair._normalize®   sn   € à!ŸY™YŸ_™_Ó.×4Ñ4Ó6ˆØ"Ÿj™j×.Ñ.Ó0×6Ñ6Ó8ˆÙ¡,ÜÐIÓJÐJØ˜,Ò&ÜÐXÓYÐYØˆŒ	Ø!ˆŒ
Øˆr   N)rA   rv   )r   r   r   r   r   rw   rF   rU   rx   r   rt   r   r   r    rv   rv   £   s@   … ññ Ð"OÔP€Dˆ#ÓPÙÐ#QÔR€Eˆ3ÓRá˜'Ô"ò	ó #ñ	r   rv   c                   óè   — e Zd ZU  ed¬«      Zeed<    ed„ ¬«      Ze	e
eef    e«       f   ed<    edd¬«      ed	e
eef   d
e
eef   fd„«       «       Z ed«      d	e
eef   d
e
eef   fd„«       Zy)ÚComplexityTierModelT)ÚfrozenÚ
model_namec                  ó   — t        i «      S rC   r   r   r   r    ú<lambda>zComplexityTierModel.<lambda>À   s   € Ô 0°Ó 4€ r   ©Údefault_factoryÚlitellm_paramsr=   r>   r@   rA   c                 ó*   — t        t        |«      «      S rC   )r   ÚdictrH   s     r    Ú_freeze_litellm_paramsz*ComplexityTierModel._freeze_litellm_paramsÃ   s   € ô  ¤ U£Ó,Ð,r   c                 ó   — t        |«      S rC   )r‡   )rO   r@   s     r    Ú_serialize_litellm_paramsz-ComplexityTierModel._serialize_litellm_paramsÈ   s   € ä�E‹{Ðr   N)r   r   r   r   Úmodel_configrF   rU   r   r…   r   r   rW   r   r   rV   rˆ   r   rŠ   r   r   r    r~   r~   »   s¾   … Ù TÔ*€LàƒOÙHMÙ4ôI€N�I˜g c¨6 kÑ2±NÓ4DÐDÑEó ñ Ð%¨HÔ5Øð-¨7°3¸°;Ñ+?ð -ÀGÈCÐQWÈKÑDXò -ó ó 6ð-ñ Ð&Ó'ð¨w°s¸F°{Ñ/Cð ÈÐPSÐU[ÐP[ÑH\ò ó (ñr   r~   Ú	raw_valuer<   c                 óF  — t        | t        t        f«      r| n| f}t        d„ |D «       «      }t        d„ |D «       «      }t        |«      t        t	        |«      «      k7  rt        d|› d�«      ‚t        | t        t        f«      s|d   j                  n
t        |«      }||fS )Nc              3   ó~   K  — | ]5  }t        |t        «      rt        |¬ «      nt        j                  |«      –— Œ7 y­w)©r€   N)rE   rF   r~   Úmodel_validate©rm   Úentrys     r    ro   z*_normalize_tier_entries.<locals>.<genexpr>Ò   s9   è ø€ ò àô 2<¸EÄ3Ô1GÔ uÕ-ÔM`×MoÑMoÐpuÓMvÓvñùs   ‚;=c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrC   r�   r‘   s     r    ro   z*_normalize_tier_entries.<locals>.<genexpr>Ö   s   è ø€ ÒE°E˜u×/Õ/ÑEùó   ‚ztier zP contains duplicate model_name values; each pool entry needs distinct parametersr   )rE   rT   Útuplera   Ú	frozensetrN   r€   )rŒ   r<   Úraw_entriesÚentriesÚmodel_namesÚ
normalizeds         r    Ú_normalize_tier_entriesr›   Í   sª   € ô '1°¼TÄ5¸MÔ&J™ÐQZÐP\€KÜñ à ôó €Gô ÑE¸WÔEÓE€KÜ
ˆ;Óœ3œy¨Ó5Ó6Ò6Ü˜5  Ð&vÐwÓxÐxô ˜)¤d¬E ]Ô3ð 	�‰
×Òä�+Óð ð
 �wÐÐr   )-ÚfunctionÚclassÚdefÚconstÚletÚvarÚimportÚexportrA   ÚasyncÚawaitÚtryÚcatchÚ	exceptionÚerrorÚdebugÚapiÚendpointÚrequestÚresponseÚdatabaseÚsqlÚqueryÚschemaÚ	algorithmÚ	implementÚrefactorÚoptimizeÚpythonÚ
javascriptÚ
typescriptÚjavaÚrustÚgolangÚreactÚvueÚangularÚnodeÚdockerÚ
kubernetesÚgitÚcommitÚmergeÚbranchzpull requestÚDEFAULT_CODE_KEYWORDS)zstep by stepzthink throughzlet's thinkzreason throughzanalyze thisz
break downzexplain your reasoningzshow your workzchain of thoughtzthink carefullyzconsider allÚevaluatezpros and conszcompare and contrastzweigh the optionsÚlogicalÚdeduceÚinferÚconcludeÚDEFAULT_REASONING_KEYWORDS)ÚarchitectureÚdistributedÚscalableÚmicroservicezmachine learningzneural networkzdeep learningÚ
encryptionÚauthenticationÚauthorizationÚperformanceÚlatencyÚ
throughputÚ	benchmarkÚconcurrencyÚparallelÚ	threadingÚmemoryÚcpuÚgpuÚoptimizationÚprotocolÚtcpÚhttpÚgrpcÚ	websocketÚ	containerÚorchestrationÚDEFAULT_TECHNICAL_KEYWORDSzLITELLM ESCALATEÚDEFAULT_ESCALATION_KEYWORDS)zPlan mode is activezPlan mode still activeÚPLAN_MODE_TAIL_SENTINELS)z)You are currently running in "Plan" mode.ÚPLAN_MODE_SYSTEM_SENTINELS)z:Write the title in the predominant language of the sessionz<You are coming up with a succinct title for a coding sessionÚHOUSEKEEPING_ASK_SENTINELSÚexit_plan_modeÚPLAN_MODE_TOOL_NAME)zwhat iszwhat'sÚdefinezdefinition ofzwho iszwho waszwhen didzwhen waszwhere isz	where waszhow manyzhow muchz	yes or noztrue or falseÚsimpleÚbriefÚshortÚquickÚhelloÚhiÚheyÚthanksz	thank youÚgoodbyeÚbyeÚokayÚDEFAULT_SIMPLE_KEYWORDSgš™™™™™¹?ç333333Ó?g      Ð?gš™™™™™©?g¸…ëQ¸ž?g{®Gáz”?)Ú
tokenCountÚcodePresenceÚreasoningMarkersÚtechnicalTermsÚsimpleIndicatorsÚmultiStepPatternsÚquestionComplexityÚDEFAULT_DIMENSION_WEIGHTSg333333Ã?gffffffÖ?g333333ã?)Úsimple_mediumÚmedium_complexÚcomplex_reasoningÚDEFAULT_TIER_BOUNDARIESé   i�  )rï   ÚcomplexÚDEFAULT_TOKEN_THRESHOLDSzgpt-4o-minizgpt-4ozclaude-sonnet-4-20250514)r   r   r   r   ÚDEFAULT_TIER_MODELSc                   óð   — e Zd ZU dZ ed¬«      Zeed<    edd¬«      Ze	ed<    ed	d
¬«      Z
ed	z  ed<    ed	d¬«      Zed	z  ed<    ed«      eded	z  ded	z  fd„«       «       Z ed¬«      dd„«       Zy	)ÚClassifierLLMConfigz6Configuration for the LLM-based complexity classifier.zDModel name (from the router's model_list) to call for classificationr;   Úmodelé¸  z;Timeout budget for the classification call, in millisecondsrf   Ú
timeout_msNa!  Which calibration examples the built-in rubric carries. 'agentic' anchors routine installs, builds, multi-file edits, and standard debugging at MEDIUM, so ordinary engineering does not route to the most expensive tier; it suits agent, terminal, and coding-assistant traffic as well as mixed traffic. 'chat' omits those engineering anchors, for a deployment serving only conversational traffic. 'business' carries business/sales anchors and business-flavored tier criteria that keep routine drafting and summarizing off the expensive tiers and reserve the top tier for committing to decisions under tradeoffs; it suits sales, support, and go-to-market traffic. Every preset keeps the same four tiers, so this moves where the boundary sits without changing the taxonomy. Leave unset for 'legacy', the rubric as it shipped before calibration examples existed, so an existing router's tier decisions and spend do not move on upgrade. Mutually exclusive with system_prompt, which replaces the rubric this would select. Only applies when classifier_type is 'llm'.Úclassification_rubricax  Replaces the built-in complexity rubric as the classifier's entire system role. When set, neither the default rubric nor the context-window closing line is appended, so the prompt owns the whole taxonomy and the tier names SIMPLE/MEDIUM/COMPLEX/REASONING become whatever buckets it defines: a prompt that classifies data sensitivity routes on that instead of on difficulty. Two consequences of full replacement. The default rubric's closing paragraph is the classifier's prompt-injection defense, telling it that the caller's quoted system prompt and prior turns are material to judge and never instructions; a replacement that omits it lets a caller ask for a tier and get it. And the heuristic fallback still scores complexity, so a router on some other taxonomy wants classifier_fallback='default_model'. Leave unset for the built-in rubric. Only applies when classifier_type is 'llm'.Úsystem_promptr@   rA   c                 ó@   — |�|j                  «       st        d«      ‚|S )NzXclassifier_llm_config.system_prompt must be non-empty; omit it to use the default rubric©rG   rN   rH   s     r    Ú_reject_blank_system_promptz/ClassifierLLMConfig._reject_blank_system_promptÖ  s#   € ð
 Ð U§[¡[¤]ÜÐwÓxÐxØˆr   rL   r>   c                 óL   — | j                   �| j                  �t        d«      ‚| S )Nz£classifier_llm_config.classification_rubric and system_prompt are mutually exclusive: system_prompt replaces the built-in rubric the preset would select. Drop one.)r  r  rN   ©rO   s    r    Ú!_reject_rubric_with_system_promptz5ClassifierLLMConfig._reject_rubric_with_system_promptß  s5   € ð ×ÑÐ)¨d×.HÑ.HÐ.TÜðIóð ð ˆr   )rA   r  )r   r   r   r   r   r  rF   rU   r  Úintr  r"   r  r   rV   r  r   r  r   r   r    r  r  «  sÄ   … Ù@áØZô€Eˆ3ó ñ ØØQô€J�ó ñ :?Øðô:ÐÐ/°$Ñ6ó ñ" !&Øð	Sô!€M�3˜‘:ó ñ  �_Ó%Øð°°d±
ð ¸sÀT¹zò ó ó &ðñ ˜'Ô"òó #ñr   r  c                   ó  — e Zd ZU dZ ed„ d¬«      Zeeeee   z  f   e	d<    ee¬«      Z
eeeedf   f   e	d<    ed	d
¬«      Zeedf   d	z  e	d<    ed	d¬«      Zed	z  e	d<    ed	d¬«      Zed	z  e	d<    eed¬«      Zeeef   e	d<    ed„ d¬«      Zeeef   e	d<    ed	d¬«      Zed	z  e	d<    ed„ d¬«      Zeeef   e	d<    ed„ d¬«      Zeeef   e	d<    ed	d¬«      Zee   d	z  e	d<    ed	d ¬«      Zee   d	z  e	d!<    ed	d"¬«      Zee   d	z  e	d#<    ed	d$¬«      Zee   d	z  e	d%<    ed	d&¬«      Zee   d	z  e	d'<    ed	d(¬«      Zed	z  e	d)<    ed*d+¬«      Z e!e	d,<    ed-d.¬«      Z"e#d/   e	d0<    ed	d1¬«      Z$e%d	z  e	d2<    ed	d3¬«      Z&ed	z  e	d4<    ed	d5¬«      Z'e(d	z  e	d6<    ed7d8d9¬:«      Z)ee	d;<    ed-d<¬«      Z*e#d=   e	d><    ee+d8d?¬@«      Z,ee	dA<    ee-d8dB¬@«      Z.ee	dC<    ed	d8dD¬:«      Z/ed	z  e	dE<    ed*dF¬«      Z0e!e	dG<    ed*dH¬«      Z1e!e	dI<    edJ„ dK¬«      Z2e3e	dL<    ee4dMdN¬@«      Z5ee	dO<    edPdQ¬«      Z6e#dR   e	dS<    ed	dT¬«      Z7ee   d	z  e	dU<    ed	dV¬«      Z8ee9   d	z  e	dW<    ed	dX¬«      Z:ed	z  e	dY<    ed	dZ¬«      Z;eedf   d	z  e	d[<    ed\d]¬«      Z<e!e	d^<    ed	d_¬«      Z=eedf   d	z  e	d`<    ed*da¬«      Z>e!e	db<    ed	dc¬«      Z?ed	z  e	dd<    ededMdfdg¬h«      Z@ee	di<    ed*dj¬«      ZAe!e	dk<    ed\dl¬«      ZBe!e	dm<    ednd8do¬:«      ZCee	dp<    ed	dq¬«      ZDeeE   d	z  e	dr<    ed	dsdt¬u«      ZFeeGdf   d	z  e	dv<    eHdwd\¬x«      ZI eJddy¬z«      eKd{eLd|eLfd}„«       «       ZM eNdy¬z«      eKd{eLd|eLfd~„«       «       ZO eJdU«      eKd{ee   d	z  d|ee   d	z  fd„«       «       ZP eJdYdy¬z«      eKd{eLd|eLfd€„«       «       ZQ eJd[«      eKd{eedf   d	z  d|eedf   d	z  fd�„«       «       ZR eJd`«      eKd{eedf   d	z  d|eedf   d	z  fd‚„«       «       ZS eNdƒ¬z«      dœd„„«       ZT eNdƒ¬z«      dœd…„«       ZU eJd4dy¬z«      eKd{eLd|eLfd†„«       «       ZV eNdƒ¬z«      dœd‡„«       ZW eJd«      eKd{ed	z  d|ed	z  fdˆ„«       «       ZX eJd«      eKd{ed	z  d|ed	z  fd‰„«       «       ZYeZd|e!fdŠ„«       Z[eZd|e!fd‹„«       Z\d|eedf   fdŒ„Z]d|eedf   fd�„Z^dŽed|eez  d	z  fd�„Z_d|eedf   fd�„Z` eNdƒ¬z«      dœd‘„«       Za eNdƒ¬z«      dœd’„«       Zb eNdƒ¬z«      dœd“„«       Zc eNdƒ¬z«      dœd”„«       Zd eNdƒ¬z«      dœd•„«       Ze eNdƒ¬z«      dœd–„«       Zf eNdƒ¬z«      dœd—„«       Zgd˜ed|efd™„Zhd|eeeef   df   fdš„ZidŽed|ed	z  fd›„Zjy	)�ÚComplexityRouterConfigz'Configuration for the ComplexityRouter.c                  ó*   — t         j                  «       S rC   )r  Úcopyr   r   r    r‚   zComplexityRouterConfig.<lambda>ô  s   € Ô 3× 8Ñ 8Ó :€ r   zŸMapping of complexity tiers to a model or model pool. A list is randomly picked from when adaptive=False, and used as a soft-floor home pool when adaptive=True)r„   r9   Útiersrƒ   .Útier_model_configsNa  Operator-defined tier set replacing the built-in SIMPLE/MEDIUM/COMPLEX/REASONING. Each entry's name becomes a value the LLM classifier can return and its description becomes that tier's rubric bullet; entries named after a built-in tier may omit the description and inherit the built-in criteria. List order is ascending severity and decides which tier wins when several keyword_tier_rules match. Requires classifier_type 'llm' or 'custom', a fallback_tier, and `tiers` keys matching the defined names exactly. Escalation, adaptive selection, session affinity, plugins, tier_labels, and the calibration-example rubric presets are unavailable with a custom tier set: the first four are built on the built-in tier ladder, and the last two rename or exemplify tiers the set replaces.rf   Útier_definitionsa  Tier routed to when the LLM classifier fails (timeout, provider error, or an unparseable reply). Required with tier_definitions and must name a defined tier; the heuristic scorer cannot produce custom tiers, so this replaces the heuristic fallback for custom tier sets.Úfallback_tiera¿  Replaces the opening instructions of the LLM classifier rubric (the judging-criteria prose) for a custom tier set. The per-tier bullets and the trust-boundary paragraph telling the classifier to ignore tier requests embedded in quoted caller text are always appended after it and cannot be overridden. Requires tier_definitions; a built-in-tier router customizes its prompt via classifier_llm_config.system_prompt or classification_rubric instead.Úclassification_prompta¬  Display names for the complexity tiers, so a deployment can use its own vocabulary (e.g. Cheap/Standard/Premium/Deep) in the dashboard, spend logs, and the LLM classifier rubric. Purely operator-facing: config keys stay canonical (tiers, keyword_tier_rules[].tier, tier_boundaries), API callers never see these names, and the heuristic scorer never reads them. Unlisted tiers keep their canonical name. Partial maps are allowed.Útier_labelsc                  ó*   — t         j                  «       S rC   )r  r  r   r   r    r‚   zComplexityRouterConfig.<lambda>-  s   € Ô 7× <Ñ <Ó >€ r   zóScore boundaries between tiers. These keys (simple_medium, medium_complex, complex_reasoning) name the gaps between the default tier names and are not renameable by tier_labels; they are scorer knobs persisted by name on every routing decisionÚtier_boundariesa  Minimum weighted score a request must reach before 2+ reasoning markers may promote it to the reasoning tier. Unset tracks tier_boundaries.simple_medium, so the override never rescues a request the scorer placed in the cheapest tier; 0 restores the unconditional overrideÚreasoning_override_min_scorec                  ó*   — t         j                  «       S rC   )r
  r  r   r   r    r‚   zComplexityRouterConfig.<lambda>@  s   € Ô 8× =Ñ =Ó ?€ r   z8Token count thresholds for simple/complex classificationÚtoken_thresholdsc                  ó*   — t         j                  «       S rC   )r  r  r   r   r    r‚   zComplexityRouterConfig.<lambda>F  s   € Ô 9× >Ñ >Ó @€ r   z"Weights for each scoring dimensionÚdimension_weightsz(Keywords indicating code-related contentÚcode_keywordsz.Keywords indicating reasoning-required contentÚreasoning_keywordsz%Keywords indicating technical contentÚtechnical_keywordszóDomain-specific technical keywords appended to the effective base list (technical_keywords if set, otherwise DEFAULT_TECHNICAL_KEYWORDS). Order is preserved; duplicates are removed case-insensitively against the base list and within this list.Úcustom_technical_keywordsz(Keywords indicating simple/basic queriesÚsimple_keywordsz1Default model to use if tier cannot be determinedÚdefault_modelFzvReturn the resolved raw model name in the response model field instead of the client-requested complexity-router aliasÚreturn_raw_model_nameÚ	heuristiczëClassification strategy: local regex/keyword scoring, an LLM call, a custom classifier plugin, or 'heuristic_first', which scores locally and only pays for the LLM classifier when the local scorer does not confidently land a cheap tier)r2  r,   Úcustomr-   Úclassifier_typezaConfiguration for the LLM classifier; required when classifier_type is 'llm' or 'heuristic_first'Úclassifier_llm_configaÌ  The highest tier the local scorer may decide on its own; required when classifier_type is 'heuristic_first' and rejected otherwise. A request whose heuristic tier is at or below this one skips the LLM classifier and routes straight to that heuristic tier, so the classifier call is only paid for on traffic the scorer could not place cheaply. The scorer must also have produced at least one signal: a prompt where no dimension fired scores 0.0 and would otherwise land SIMPLE by default rather than by evidence, which is how a chained router would silently send unclassified traffic to the cheapest model. Names a built-in tier, and may not name the highest one, since that would make the LLM classifier unreachable.Úheuristic_first_max_tieraw  Custom classifier deciding the tier; required when classifier_type is 'custom'. In the proxy config, a dotted path to a ClassifierPlugin instance (resolved at startup, like plugins). Its classify(context) receives the request messages and metadata (caller identity included) and returns the name of the tier to route to, or None to decline and let classifier_fallback decide.Úclassifier_pluginr  r   zœTimeout budget for the classifier plugin call, in milliseconds. On expiry the fallback path decides the tier. Only applies when classifier_type is 'custom'.)rg   Úgtr9   Úclassifier_plugin_timeout_msaZ  What classifies the request when the LLM classifier errors, times out, or returns an unparseable response. 'heuristic' runs the local complexity scorer, which is right when the classifier grades complexity too. 'default_model' skips scoring and routes to default_model, which is what a classifier on some other taxonomy wants: a prompt that grades data sensitivity has no use for a complexity score, and scoring one produces a tier unrelated to what the operator configured. Requires default_model when set to 'default_model'. Only applies when classifier_type is 'llm', 'custom', or 'heuristic_first'.)r2  r0  Úclassifier_fallbacka•  Number of prior user turns (tool output and harness reminders excluded) to include as context in the LLM classifier prompt, so a follow-up like 'now do the same for the streaming path' is classified against what it refers to. Counts turns of both roles when classifier_context_include_assistant_turns is enabled. These turns are sent to the classifier model, which may be a different deployment or provider than the routed completion model; that call already carries the current user ask and the caller's system prompt in full. Set to 0 to send neither prior turns nor any conversation context beyond the current ask. Only applies when classifier_type is 'llm'.)rg   Úger9   Úclassifier_context_window_sizeaà  Maximum characters of prior-turn text quoted to the LLM classifier, across the whole context window, per classification call. Turns are taken newest first and quoted whole while they fit, so a conversation small enough to quote entirely is never cut; once the budget runs out the older turns are dropped whole and only the turn straddling the boundary is truncated, into whatever space is left. The current ask and the caller's system prompt sit outside this budget and are always sent in full, as does the numbering each quoted turn carries. A budget under 120 leaves no room to quote a turn and suppresses the block; set classifier_context_window_size to 0 to turn context off deliberately. Only applies when classifier_type is 'llm'.Úclassifier_context_budget_charsaš  Optional cap on each individual prior turn's text, applied before classifier_context_budget_chars bounds the block. Unset by default, so one long turn may spend the whole budget, which is usually what a follow-up needs; set it when no single turn should dominate the context the classifier sees. A capped turn keeps its opening and its ending with the middle elided. Only applies when classifier_type is 'llm'.Ú!classifier_context_per_turn_charsa^  Include assistant turns in the classifier context window, so difficulty stated by the model rather than by the user stays visible: a plan the assistant calls complex, which the user approves with 'yes', is classified on the work being approved instead of on the word 'yes'. When enabled, classifier_context_window_size counts the last N turns of the conversation across both roles rather than the last N user turns, and assistant text is sent to the classifier model, which may be a different deployment or provider than the routed completion model. Assistant replies spend classifier_context_budget_chars alongside user turns, so raise it if the oldest turns stop being quoted once replies join the window. Off by default because enabling it shifts tier decisions, and therefore spend, for an already-deployed router. Only applies when classifier_type is 'llm'.Ú*classifier_context_include_assistant_turnsz<Enable adaptive bandit selection with soft complexity floorsÚadaptivec                  ó   — t        dd¬«      S )Nrû   gffffffæ?)ÚqualityÚcost)r   r   r   r    r‚   zComplexityRouterConfig.<lambda>ê  s   € Ô 5¸cÈÔ L€ r   zHQuality vs cost weights for adaptive selection (used when adaptive=True)Úadaptive_weightsg        zLScore penalty per tier-step away from the classified tier when adaptive=TrueÚtier_distance_penaltyÚallz§When adaptive=True: 'all' scores every pool model with a tier-distance penalty (soft floors); 'classified_tier' Thompson-samples only inside the classified tier's pool)rF  Úclassified_tierÚadaptive_eligiblea  Case-sensitive phrases a user can include to force a bump to the next-higher complexity tier when they aren't satisfied with results (they can force a stronger model, but not choose which one). Defaults to ['LITELLM ESCALATE'] when unset; set to an empty list to disable.Úescalation_keywordszERules that force a specific tier when their keywords match the promptÚkeyword_tier_rulesa#  When set, requests carrying a coding-agent plan-mode sentinel (Claude Code plan mode, VS Code Copilot Plan mode, Copilot CLI's exit_plan_mode tool) are routed to at least this tier: the classified tier still wins when it is higher, and the floor also overrides a session-affinity pin to a lower tier for exactly the turns carrying the sentinel, without rewriting the pin -- the first turn after plan mode exits routes as if plan mode had never happened. Names a built-in tier, or with tier_definitions set, one of the defined tier names (list order is ascending severity, same as keyword_tier_rules). Unset disables detection entirely. The sentinels ride in client-injected prompt text, so a caller who pastes one can spend up to this tier's models -- never down, and never outside the configured pools.Úplan_mode_min_tierzðAdditional case-sensitive literal sentinels that mark a request as plan mode, on top of the built-in Claude Code and Copilot ones. For clients whose plan-mode wording the built-ins don't cover, or after a client release changes its strings.Úplan_mode_patternsTa  Route a coding agent's own housekeeping calls to the cheapest configured tier without classifying them. A client names the conversation by quoting the whole session and asking for a title, so the ask reads as the session's engineering work and lands on the most expensive tier, which is the reverse of what the call is worth. Detection is a literal match against client-owned sentinels on the newest ask only, so it cannot fire on an earlier turn, and it never lowers what anyone else asked for: a keyword_tier_rule or a session pin still decides instead, and an escalation keyword or the plan-mode floor still raises the tier from here. Only the classifier is displaced, and its call is skipped, so a matched request costs nothing to route. Set false to classify these calls like any other.Ú#route_housekeeping_to_cheapest_tierzëAdditional case-sensitive literal sentinels that mark a request as client housekeeping, on top of the built-in conversation-title ones. For clients whose wording the built-ins don't cover, or after a client release changes its strings.Úhousekeeping_patternszHMatch keyword_tier_rules by embedding similarity instead of literal textÚsemantic_keyword_matchingzSEmbedding model (LiteLLM model name) used when semantic_keyword_matching is enabledÚembedding_modelr0   g      ð?z6Minimum cosine similarity for a semantic keyword match)rg   r;  Úler9   Úmatch_thresholdat  When True and a session_id is resolvable on the request, pin the model chosen on the session's first turn and reuse it for every later turn, skipping re-classification. Off by default so every turn is classified on its own merits and routed to the cheapest adequate tier. Set True to keep a multi-turn session on one model, which preserves provider prompt caches and avoids cross-model conversation-history errors. Always implies the deployment pin regardless of deployment_affinity: the session sticks to one deployment of the pinned model, since freezing the model while re-shuffling its deployments would still go cache-cold.Úsession_affinityaW  When True and a session_id is resolvable on the request, pin the deployment chosen inside each routed model group and reuse it whenever the session returns to that group, without pinning which group the session routes to. Independent of session_affinity, which pins the model group instead (and always carries this deployment pin with it): with session_affinity off, every turn is still classified on its own merits while a session that escalates to a stronger tier and comes back still lands on the deployment it used before, which is what keeps a provider prompt cache warm. Pins are held per model group, so switching tiers does not disturb the pin left behind in the previous group. On by default because re-shuffling a conversation across deployments of the same model discards that cache for no benefit; set False to keep every turn load-balanced across the group, which is what a deployment set with tight per-deployment rate limits wants. Inert when no session_id is resolvable, since there is nothing to key a pin on, and suppressed when plugins are configured, for the same reason session_affinity is.Údeployment_affinityi  zôTTL for the session affinity pin; refreshed on every cache hit. Bounds both the session_affinity model pin and the deployment_affinity deployment pin, so it measures idle time for the session's routing decisions rather than total session lengthÚsession_affinity_ttl_secondsz[RoutingPlugin instances that narrow the classified tier's candidate models before selectionÚpluginsr7   aš  Override the delimiter pairs used to recognize and strip harness-injected reminder blocks before classification. A harness that wraps injected context differently per agent type (main, subagent, cron) lists every pair it emits. Replaces, rather than adds to, the built-in default of ('<system-reminder>', '</system-reminder>'), so a harness that also emits that pair lists it too. Matching is case-insensitive.)rg   r8   r9   Úreminder_markersÚallow)ÚextraÚarbitrary_types_allowedr=   r>   r@   rA   c                 óÞ   — t        |t        «      s|S i }|j                  «       D ]E  \  }}t        |t        «      r|||<   Œt        |t        t
        f«      rt	        |«      ||<   ŒA|||<   ŒG |S rC   )rE   r‡   ÚitemsrF   rT   r•   )rI   r@   ÚcoercedÚkeyÚitems        r    Ú_coerce_tier_valuesz*ComplexityRouterConfig._coerce_tier_valuesˆ  so   € ô ˜%¤Ô&ØˆLØ,.ˆØŸ™›ò 	$‰IˆC�Ü˜$¤Ô$Ø#�˜’Ü˜D¤4¬ -Ô0Ü# D›z�˜’à#�˜’ð	$ð ˆr   c                 ó`  ‡‡— t        |t        «      s|S |j                  d«      }t        |t        «      s|S |j                  d«      }t        |j	                  «       D ��ci c]  \  }}|t        ||«      “Œ c}}«      }t        |j	                  «       D ���ci c]  \  }\  }}||“Œ c}}}«      }	t        |t        «      rSt        |j	                  «       D ��
�ci c],  \  }}
d„ |
D «       D ]  }||j                  f|j                  “Œ Œ. c}}
}«      n
t        i «      Št        |j	                  «       D �‡��
ci c]D  \  Š\  }}
t        d„ |
D «       «      st        |t        «      r‰|v r‰t        ˆˆfd„|
D «       «      “ŒF c}
}}«      }i |¥|	|dœ¥S c c}}w c c}}}w c c}}
}w c c}
}}w )Nr  r  c              3   óF   K  — | ]  }t         j                  |«      –— Œ y ­wrC   )r~   r�   )rm   r_  s     r    ro   zGComplexityRouterConfig._normalize_tier_model_configs.<locals>.<genexpr>«  s   è ø€ Ò!_ÈtÔ"5×"DÑ"DÀT×"JÑ!_ùs   ‚!c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrC   )r…   r‘   s     r    ro   zGComplexityRouterConfig._normalize_tier_model_configs.<locals>.<genexpr>¾  s   è ø€ ÒA°�u×+Õ+ÑAùr”   c           
   3   ó¤   •K  — | ]G  }|j                  t        d ‰j                  ‰|j                  f|j                  «      i«      ¬«      –— ŒI y­w)r…   )ÚupdateN)Ú
model_copyr   Úgetr€   r…   )rm   r’   Úincoming_paramsr<   s     €€r    ro   zGComplexityRouterConfig._normalize_tier_model_configs.<locals>.<genexpr>³  s\   øè ø€ ò 	ð ð ×$Ñ$Ü/à 0°/×2EÑ2EÀtÈU×M]ÑM]ÐF^Ð`e×`tÑ`tÓ2uðó ð %÷ ñ	ùs   ƒAA)r  r  )
rE   r‡   rg  r   r\  r›   r€   r…   rr   r•   )rI   r@   Ú	raw_tiersÚexisting_configsr<   rŒ   Únormalized_entriesrš   Ú_Únormalized_tiersr˜   r’   r  rh  s       `        @r    Ú_normalize_tier_model_configsz4ComplexityRouterConfig._normalize_tier_model_configs—  s×  ù€ ô ˜%¤Ô&ØˆLØ Ÿ9™9 WÓ-ˆ	Ü˜)¤TÔ*ØˆLØ"'§)¡)Ð,@Ó"AÐÜ$4ØS\×SbÑSbÓSd×eÁÀÀiˆTÔ*¨9°dÓ;Ñ;Óeó%
Ðô #3Ø;M×;SÑ;SÓ;U×VÐVÑ"7 $©¨°QˆT�:ÑÔVó#
Ðô Ð*¬DÔ1ô ð *:×)?Ñ)?Ó)A÷ð á%˜˜gÙ!_ÐW^Ô!_òð ð ˜5×+Ñ+Ð,¨e×.BÑ.BÑBðØ,ôôô " "Ó%ð 	ô %5ð +=×*BÑ*BÓ*D÷ñ ñ '�D™,˜1˜gÜÑA¸ÔAÔAÜÐ/´Ô6¸4ÐCSÑ;Sð ”eô 	ð ")ô	ó 	ñ 	ôó%
Ðð"
Øð
à%Ø"4ò
ð 	
ùóC fùô Wùôùôs   Á!F
ÂFÃ1F"Ä:A	F)c                 óX   — |€y |D �cg c]  }|j                  «       x}sŒ|‘Œ c}S c c}w rC   ©rG   )rI   r@   rP   rQ   s       r    Ú_normalize_escalation_keywordsz5ComplexityRouterConfig._normalize_escalation_keywordsÈ  s0   € ð ˆ=ØØ(-ÖO˜W¸g¿m¹m»oÐ2M°(Ñ2M’ÒOÐOùÒOs   ˆ' 'c                 ó~   — t        |t        «      r|j                  S t        |t        «      r|j	                  «       S |S rC   rD   rH   s     r    Ú_coerce_plan_mode_min_tierz1ComplexityRouterConfig._coerce_plan_mode_min_tierÏ  rK   r   c                 ó2   ‡— |€yt        ˆfd„|D «       «      S )zÄBlank patterns are dropped rather than kept: an empty string substring-matches every
        request, which would silently floor all traffic (same failure mode keyword_tier_rules
        rejects).Nc              3   óH   •K  — | ]  }|j                  «       xŠsŒ‰–— Œ y ­wrC   rp  ©rm   ÚpatternrQ   s     €r    ro   zGComplexityRouterConfig._normalize_plan_mode_patterns.<locals>.<genexpr>à  ó!   øè ø€ ÒT 'À7Ç=Á=Ã?Ð7R°xÑ7R”XÑTùó   ƒ"›"©r•   ©rI   r@   rQ   s     @r    Ú_normalize_plan_mode_patternsz4ComplexityRouterConfig._normalize_plan_mode_patternsØ  s   ø€ ð ˆ=ØÜÓT¨UÔTÓTÐTr   c                 ó2   ‡— |€yt        ˆfd„|D «       «      S )z‘Blank patterns are dropped: an empty string substring-matches every request, which would
        silently route all traffic to the cheapest tier.Nc              3   óH   •K  — | ]  }|j                  «       xŠsŒ‰–— Œ y ­wrC   rp  rv  s     €r    ro   zJComplexityRouterConfig._normalize_housekeeping_patterns.<locals>.<genexpr>é  rx  ry  rz  r{  s     @r    Ú _normalize_housekeeping_patternsz7ComplexityRouterConfig._normalize_housekeeping_patternsâ  s   ø€ ð
 ˆ=ØÜÓT¨UÔTÓTÐTr   rL   c           	      ó,  — | j                   €| S | j                   | j                  «       vr8t        d| j                   ›ddj                  | j                  «       «      › �«      ‚| j                   | j                  vrt        d| j                   › d�«      ‚| S )Nzplan_mode_min_tier ú, is not an active tier: it must name one of ú, z¹ has no model configured in tiers; a floor pointing at an unconfigured tier would route every plan-mode request to the default fallback instead of the premium pool the operator intended)rK  Ú
tier_namesrN   Újoinr  r  s    r    Ú_validate_plan_mode_min_tierz3ComplexityRouterConfig._validate_plan_mode_min_tierë  s¦   € à×"Ñ"Ð*ØˆKØ×"Ñ"¨$¯/©/Ó*;Ñ;ÜØ% d×&=Ñ&=Ð%@ð AØŸ)™) D§O¡OÓ$5Ó6Ð7ð9óð ð ×"Ñ"¨$¯*©*Ñ4ÜØ% d×&=Ñ&=Ð%>ð ?Uð Uóð ð
 ˆr   c                 ó  — | j                   r$| j                  €t        d| j                  ›�«      ‚| j                  dk(  r| j                  €t        d«      ‚| j                  �(| j                  dk7  rt        d| j                  ›d�«      ‚| S )Nz:classifier_llm_config is required when classifier_type is r3  z>classifier_plugin is required when classifier_type is 'custom'z0classifier_plugin is set but classifier_type is zV; the plugin would never run. Set classifier_type 'custom' or remove classifier_plugin)Úuses_llm_classifierr5  rN   r4  r7  r  s    r    Ú_validate_classifier_configz2ComplexityRouterConfig._validate_classifier_configü  sž   € à×#Ò#¨×(BÑ(BÐ(JÜÐYÐZ^×ZnÑZnÐYqÐrÓsÐsØ×Ñ 8Ò+°×0FÑ0FÐ0NÜÐ]Ó^Ð^Ø×!Ñ!Ð-°$×2FÑ2FÈ(Ò2RÜØBÀ4×CWÑCWÐBZð [gð góð ð ˆr   c                 ó~   — t        |t        «      r|j                  S t        |t        «      r|j	                  «       S |S rC   rD   rH   s     r    Ú _coerce_heuristic_first_max_tierz7ComplexityRouterConfig._coerce_heuristic_first_max_tier	  rK   r   c                 ót  — | j                   dk7  r'| j                  �t        d| j                   ›d�«      ‚| S | j                  }|€t        d«      ‚| j                  «       }||vr t        d|›ddj	                  |«      › �«      ‚||d   k(  rt        d|› d	�«      ‚|| j
                  vrt        d|› d
�«      ‚| S )Nr-   z7heuristic_first_max_tier is set but classifier_type is z|; the local scorer would never gate the classifier. Set classifier_type 'heuristic_first' or remove heuristic_first_max_tierz°heuristic_first_max_tier is required when classifier_type is 'heuristic_first': without a threshold there is nothing to decide whether a request escalates to the LLM classifierzheuristic_first_max_tier r�  r‚  éÿÿÿÿz— is the highest tier, so every request would short-circuit and the LLM classifier would never run; name a lower tier or use classifier_type 'heuristic'z¶ has no model configured in tiers; a threshold pointing at an unconfigured tier would route short-circuited requests to the default fallback instead of the pool the operator intended)r4  r6  rN   rƒ  r„  r  )rO   Ú	thresholdÚnamess      r    Ú"_validate_heuristic_first_max_tierz9ComplexityRouterConfig._validate_heuristic_first_max_tier  s  € à×ÑÐ#4Ò4Ø×,Ñ,Ð8Ü ØMÈd×NbÑNbÐMeð fKð Kóð ð
 ˆKØ×8Ñ8ˆ	ØÐÜðióð ð —‘Ó(ˆØ˜EÑ!ÜØ+¨I¨=Ð8dÐei×enÑenÐotÓeuÐdvÐwóð ð ˜˜b™	Ò!ÜØ+¨I¨;ð 7oð oóð ð ˜DŸJ™JÑ&ÜØ+¨I¨;ð 7-ð -óð ð
 ˆr   c                 óF   — |€y |j                  «       }|st        d«      ‚|S )Nr_   r  r{  s      r    Ú_reject_blank_optional_textz2ComplexityRouterConfig._reject_blank_optional_text4  s+   € ð ˆ=ØØŸ+™+›-ˆÙÜÐHÓIÐIØˆr   c                 ó   — t        |«      S rC   )rb   rH   s     r    Ú&_normalize_classification_prompt_fieldz=ComplexityRouterConfig._normalize_classification_prompt_field>  s   € ô /¨uÓ5Ð5r   c                 ó   — | j                   duS )zKTrue when the operator replaced the built-in tier set via tier_definitions.N)r   r  s    r    Úhas_custom_tiersz'ComplexityRouterConfig.has_custom_tiersC  s   € ð ×$Ñ$¨DÐ0Ð0r   c                 ó&   — | j                   t        v S )a_  True when this router can call classifier_llm_config.model, so the model is a real
        dependency: authorized against the caller's key, counted in the health graph, and given a
        prebuilt rubric. 'heuristic_first' only calls it for traffic the local scorer escalates,
        which still makes it a dependency on every one of those requests.)r4  r.   r  s    r    r‡  z*ComplexityRouterConfig.uses_llm_classifierH  s   € ð ×#Ñ#Ô';Ð;Ð;r   c                 ó~   — | j                   �t        d„ | j                   D «       «      S t        d„ t        D «       «      S )zPThe active tier names: the defined names, or the built-in set in severity order.c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrC   ©re   ©rm   Ú
definitions     r    ro   z4ComplexityRouterConfig.tier_names.<locals>.<genexpr>S  s   è ø€ ÒQ¨Z˜Ÿ�ÑQùr”   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrC   )r@   )rm   r<   s     r    ro   z4ComplexityRouterConfig.tier_names.<locals>.<genexpr>T  s   è ø€ Ò@ D�T—Z•ZÑ@ùr”   )r   r•   r/   r  s    r    rƒ  z!ComplexityRouterConfig.tier_namesP  s7   € à× Ñ Ð,ÜÑQ¸4×;PÑ;PÔQÓQÐQÜÑ@Ô,?Ô@Ó@Ð@r   c                 óz   — | j                   �| j                  «       S t        d„ | j                  «       D «       «      S )zTThe tier names the classifier is told to emit: defined names, or the display labels.c              3   ó&   K  — | ]	  \  }}|–— Œ y ­wrC   r   ©rm   rl  Úlabels      r    ro   z@ComplexityRouterConfig.classifier_wire_labels.<locals>.<genexpr>Z  s   è ø€ Ò@™x˜q %”UÑ@ùs   ‚)r   rƒ  r•   Úlabeled_tiersr  s    r    Úclassifier_wire_labelsz-ComplexityRouterConfig.classifier_wire_labelsV  s5   € à× Ñ Ð,Ø—?‘?Ó$Ð$ÜÑ@¨4×+=Ñ+=Ó+?Ô@Ó@Ð@r   r   c                 óÀ   ‡— | j                   €| j                  |«      S |j                  «       j                  «       Št	        ˆfd„| j                  «       D «       d«      S )zSResolve a classifier reply to the active tier it names, or None when it names none.Nc              3   óJ   •K  — | ]  }|j                  «       ‰k(  sŒ|–— Œ y ­wrC   ©Úcasefold)rm   re   Úfoldeds     €r    ro   zAComplexityRouterConfig.resolve_classified_tier.<locals>.<genexpr>a  s   øè ø€ ÒU˜d¸4¿=¹=»?ÈfÓ;T”TÑUùs   ƒ#œ#)r   Útier_for_labelrG   r¦  Únextrƒ  )rO   r   r§  s     @r    Úresolve_classified_tierz.ComplexityRouterConfig.resolve_classified_tier\  sO   ø€ à× Ñ Ð(Ø×&Ñ& uÓ-Ð-ØŸ™›×.Ñ.Ó0ˆÜÓU d§o¡oÓ&7ÔUÐW[Ó\Ð\r   c           
      óÊ  — | j                   }t        d„ d| j                  fd| j                  fdt	        | j
                  «      fdt	        | j                  «      ffD «       «      }t        d„ t	        |«      dj                  |«      › d�f|d	uxr |j                  d	ud
f|d	uxr |j                  d	udf| j                  dk(  dft	        | j                  «      dffD «       «      S )zNError messages for config features that cannot coexist with a custom tier set.c              3   ó*   K  — | ]  \  }}|r|–— Œ y ­wrC   r   )rm   r   Úenableds      r    ro   zDComplexityRouterConfig._tier_definition_conflicts.<locals>.<genexpr>f  s!   è ø€ ò 	'
á��wñ ô ñ	'
ùó   ‚r@  rS  rI  rV  c              3   ó*   K  — | ]  \  }}|r|–— Œ y ­wrC   r   )rm   ÚpresentÚmessages      r    ro   zDComplexityRouterConfig._tier_definition_conflicts.<locals>.<genexpr>p  s!   è ø€ ò  
á �˜ñ: ô= ñ 
ùr®  r‚  z‹ cannot be combined with tier_definitions: these features rely on the built-in tier severity order, which a custom tier set does not defineNzúclassifier_llm_config.system_prompt cannot be combined with tier_definitions: a wholesale replacement prompt drops the defined-tier bullets and the trust boundary; use classification_prompt, which replaces only the opening instructions and keeps bothz¾classifier_llm_config.classification_rubric cannot be combined with tier_definitions: the preset calibration examples are written against the built-in tiers, which a custom tier set replacesr0  zšclassifier_fallback 'default_model' cannot be combined with tier_definitions: fallback_tier is where a custom-tier router routes when the classifier failsz¥tier_labels cannot be combined with tier_definitions: labels rename the built-in tiers, which a custom tier set replaces; name the tiers directly in tier_definitions)r5  r•   r@  rS  ÚboolrI  rV  r„  r  r  r:  r#  )rO   Ú
llm_configÚorder_dependents      r    Ú_tier_definition_conflictsz1ComplexityRouterConfig._tier_definition_conflictsc  s.  € à ×6Ñ6ˆ
Ü!&ñ 	'
ð ˜TŸ]™]Ð+Ø# T×%:Ñ%:Ð;Ø&¬¨T×-EÑ-EÓ(FÐGØœD §¡Ó.Ð/ð	#ô	'
ó 	"
ˆô ñ  
ô ˜Ó)Ø—y‘y Ó1Ð2ð 3hð hðð  dÐ*ÒS¨z×/GÑ/GÈtÐ/Sðiðð  dÐ*Ò[¨z×/OÑ/OÐW[Ð/[ð#ðð ×,Ñ,°Ñ?ðUðô ˜×)Ñ)Ó*ðdðð/%ô 
ó  
ð  	
r   c                 óä  ‡ ‡	— ‰ j                   €?t        d„ d‰ j                  fd‰ j                  ffD «       d «      }|�t	        |› d�«      ‚‰ S t        d„ ‰ j                   D «       «      }dt        |«      cxk  r	t        k  s n t	        dt        › dt        |«      › �«      ‚t        d	„ |D «       «      Š	t        t        t        ˆ	fd
„t        |‰	«      D «       «      «      «      }|rt	        ddj                  |«      › �«      ‚‰ j                  dv rt	        d«      ‚‰ j                  «       }|rt	        dj                  |«      «      ‚t        |«      }t        t        |t        ‰ j                  «      z
  «      «      }|rt	        ddj                  |«      › �«      ‚t        t        t        ‰ j                  «      |z
  «      «      }|rt	        ddj                  |«      › �«      ‚t        t        ˆ fd„|D «       «      «      }|rt	        ddj                  |«      › �«      ‚‰ j                  €t	        d«      ‚‰ j                  |vr*t	        d‰ j                  ›ddj                  |«      › �«      ‚‰ S )Nc              3   ó*   K  — | ]  \  }}|�|–— Œ y ­wrC   r   )rm   Úfieldr@   s      r    ro   zDComplexityRouterConfig._validate_tier_definitions.<locals>.<genexpr>–  s$   è ø€ ò á$˜˜uð Ð(ô ñùr®  r!  r"  z requires tier_definitionsc              3   ó4   K  — | ]  }|j                   –— Œ y ­wrC   r™  rš  s     r    ro   zDComplexityRouterConfig._validate_tier_definitions.<locals>.<genexpr>£  s   è ø€ ÒU°˜ZŸ_�_ÑUùr”   é   z+tier_definitions must define between 2 and z tiers, got c              3   ó<   K  — | ]  }|j                  «       –— Œ y ­wrC   r¥  )rm   re   s     r    ro   zDComplexityRouterConfig._validate_tier_definitions.<locals>.<genexpr>¨  s   è ø€ Ò@°$˜dŸm™mŸoÑ@ùs   ‚c              3   óR   •K  — | ]  \  }}‰j                  |«      d kD  sŒ|–— Œ  y­w)r7   N)Úcount)rm   re   Úfoldr§  s      €r    ro   zDComplexityRouterConfig._validate_tier_definitions.<locals>.<genexpr>ª  s'   øè ø€ Òa¡j d¨DÈ&Ï,É,ÐW[ÓJ\Ð_`ÓJ`œTÑaùs   ƒ' 'z:tier_definitions names must be unique (case-insensitive): r‚  )r2  r-   zrtier_definitions requires classifier_type 'llm' or 'custom': the heuristic scorer only produces the built-in tiersú; z7tiers must map every defined tier to a model; missing: z9tiers keys must be defined in tier_definitions; unknown: c              3   óZ   •K  — | ]"  }‰j                   j                  |«      rŒ|–— Œ$ y ­wrC   )r  rg  )rm   re   rO   s     €r    ro   zDComplexityRouterConfig._validate_tier_definitions.<locals>.<genexpr>½  s!   øè ø€ Ò)]°4ÈÏ
É
ÏÉÐW[ÕH\¬$Ñ)]ùs   ƒ +¤+z@tiers must map every defined tier to at least one model; empty: zifallback_tier is required with tier_definitions: it is where requests route when the LLM classifier failszfallback_tier z" is not one of the defined tiers: )r   r©  r!  r"  rN   r•   ra   rY   Úsortedr–   Úzipr„  r4  rµ  r  )
rO   ÚorphanedrŽ  Ú
duplicatedÚ	conflictsÚdefinedÚmissingÚunknownÚempty_poolsr§  s
   `        @r    Ú_validate_tier_definitionsz1ComplexityRouterConfig._validate_tier_definitions’  s’  ù€ à× Ñ Ð(Ü"ñð )¨$×*<Ñ*<Ð=Ø0°$×2LÑ2LÐMð)ôð ó
ˆHð Ð#Ü  H :Ð-GÐ!HÓIÐIØˆKÜÑU¸t×?TÑ?TÔUÓUˆØ”C˜“JÔ6Ô"6Ô6ÜØ=Ô>RÐ=SÐS_Ô`cÐdiÓ`jÐ_kÐlóð ô Ñ@¸%Ô@Ó@ˆÜ!Ü”9Óa´C¸¸vÓ4FÔaÓaÓbó
ˆ
ñ ÜÐYÐZ^×ZcÑZcÐdnÓZoÐYpÐqÓrÐrØ×ÑÐ#CÑCÜð.óð ð  ×:Ñ:Ó<ˆ	ÙÜ˜TŸY™Y yÓ1Ó2Ð2Ü" 5Ó)ˆÜœv g´	¸$¿*¹*Ó0EÑ&EÓFÓGˆÙÜÐVÐW[×W`ÑW`ÐahÓWiÐVjÐkÓlÐlÜœv¤i°·
±
Ó&;¸gÑ&EÓFÓGˆÙÜÐXÐY]×YbÑYbÐcjÓYkÐXlÐmÓnÐnÜ"¤6Ó)]¸5Ô)]Ó#]Ó^ˆÙÜØRÐSW×S\ÑS\Ð]hÓSiÐRjÐkóð ð ×ÑÐ%Üð'óð ð ×Ñ WÑ,ÜØ  ×!3Ñ!3Ð 6Ð6XÐY]×YbÑYbÐchÓYiÐXjÐkóð ð ˆr   c           	      ó4  ‡— | j                   s| S t        | j                  «       «      Št        t	        t        ˆfd„| j                   D «       «      «      «      }|r=t        ddj                  |«      › ddj                  | j                  «       «      › �«      ‚| S )Nc              3   óT   •K  — | ]  }|j                   ‰vsŒ|j                   –— Œ! y ­wrC   )r<   )rm   ÚruleÚvalids     €r    ro   zFComplexityRouterConfig._validate_keyword_rule_tiers.<locals>.<genexpr>Ó  s!   øè ø€ Òe¨4ÈdÏiÉiÐ_dÒNd˜TŸY�YÑeùs   ƒ(—(z,keyword_tier_rules reference unknown tiers: r‚  z; valid tiers: )rJ  r–   rƒ  r•   rÁ  rN   r„  )rO   Úunknown_tiersrÎ  s     @r    Ú_validate_keyword_rule_tiersz3ComplexityRouterConfig._validate_keyword_rule_tiersÍ  s�   ø€ à×&Ò&ØˆKÜ  §¡Ó!2Ó3ˆÜ$Ü”9Óe°4×3JÑ3JÔeÓeÓfó 
ˆñ ÜØ>¸t¿y¹yÈÓ?WÐ>Xð Y Ø $§	¡	¨$¯/©/Ó*;Ó <Ð=ð?óð ð ˆr   c           	      óz  — | j                   s| S | j                  j                  «       D ��ci c]  \  }}|t        |t        «      r|n|g“Œ }}}t        |j                  «       «      st        d«      ‚|j                  «       D ��cg c]
  \  }}|rŒ	|‘Œ }}}|rt        d|› �«      ‚|| _        | S c c}}w c c}}w )Nz7adaptive=True requires at least one non-empty tier poolz9adaptive=True tier pools must be non-empty; empty tiers: )r@  r  r\  rE   rT   rr   ÚvaluesrN   )rO   r<   Úmodelsrš   Úemptys        r    Ú_validate_adaptive_poolsz/ComplexityRouterConfig._validate_adaptive_poolsÜ  s¸   € à�}Š}ØˆKØcg×cmÑcm×csÑcsÓcu×vÑS_ÐSWÐY_�d¤z°&¼$Ô'?™VÀfÀXÑMÐvˆ
ÑvÜ�:×$Ñ$Ó&Ô'ÜÐVÓWÐWØ1;×1AÑ1AÓ1C×R¡  vÊ6šÐRˆÑRÙÜÐXÐY^ÐX_Ð`ÓaÐaØˆŒ
Øˆùó wùó Ss   ¬ B1Â
B7ÂB7c                 ó~   — | j                   s| S | j                  st        d«      ‚| j                  st        d«      ‚| S )NzEembedding_model is required when semantic_keyword_matching is enabledzNkeyword_tier_rules must be non-empty when semantic_keyword_matching is enabled)rO  rP  rN   rJ  r  s    r    Ú_validate_semantic_matchingz2ComplexityRouterConfig._validate_semantic_matchingé  s?   € à×-Ò-ØˆKØ×#Ò#ÜÐdÓeÐeØ×&Ò&ÜÐmÓnÐnØˆr   c                 ó,  ‡‡— | j                   s| S t        t        d„ | j                   j                  «       D «       «      «      }|rt	        ddj                  |«      › �«      ‚t        t        d„ | j                   j                  «       D «       «      «      }|rt	        ddj                  |«      › �«      ‚| j                  «       Št        d„ ‰D «       «      Št        ˆˆfd„t        ‰«      D «       «      }|rt	        dd	j                  |«      › �«      ‚| S )
Nc              3   ó\   K  — | ]$  \  }}|j                  «       rŒ|j                  –— Œ& y ­wrC   )rG   r@   ©rm   r<   r   s      r    ro   z?ComplexityRouterConfig._validate_tier_labels.<locals>.<genexpr>÷  s$   è ø€ Ò#p±;°4¸Ðbg×bmÑbmÕbo D§J¥JÑ#pùs   ‚,›,z>tier_labels values must be non-empty; blank labels for tiers: r‚  c              3   ó  K  — | ]  \  }}|j                  «       j                  «       t        j                  v rL|j                  «       j                  «       |j                  k7  r!|j                  › d |j                  «       › �–— Œ� y­w)z -> N)rG   rp   r   rq   r@   rÚ  s      r    ro   z?ComplexityRouterConfig._validate_tier_labels.<locals>.<genexpr>û  sk   è ø€ ò á�D˜%Ø—;‘;“=×&Ñ&Ó(¬N×,FÑ,FÑFÈ5Ï;É;Ë=×K^ÑK^ÓK`Ðdh×dnÑdnÒKnð —:‘:�,˜d 5§;¡;£= /Ô2ñùs   ‚BBz|tier_labels values must not reuse another tier's canonical name, which would make logs and the classifier rubric ambiguous: c              3   óB   K  — | ]  \  }}|j                  «       –— Œ y ­wrC   r¥  rŸ  s      r    ro   z?ComplexityRouterConfig._validate_tier_labels.<locals>.<genexpr>  s   è ø€ Ò$N¹(¸!¸U U§^¡^×%5Ñ$Nùs   ‚c              3   óª   •‡K  — | ]I  \  }Š‰j                  ‰«      d kD  r0‰j                  ‰«      |k(  rdj                  ˆfd„‰D «       «      –— ŒK y­w)r7   z and c              3   ód   •K  — | ]'  \  }}|j                  «       ‰k(  sŒ|j                  –— Œ) y ­wrC   )r¦  r@   )rm   r<   r   r§  s      €r    ro   zIComplexityRouterConfig._validate_tier_labels.<locals>.<genexpr>.<genexpr>	  s(   øè ø€ Ò]©¨¨eÀ%Ç.Á.ÓBRÐV\ÓB\˜Ÿ�Ñ]ùs   ƒ0Ÿ0N)r½  Úindexr„  )rm   Úpositionr§  Úfolded_labelsÚlabeleds     @€€r    ro   z?ComplexityRouterConfig._validate_tier_labels.<locals>.<genexpr>  sR   ùè ø€ ò "
á �˜&Ø×"Ñ" 6Ó*¨QÒ.°=×3FÑ3FÀvÓ3NÐRZÒ3Zð �L‰LÓ]°wÔ]×]ñ"
ùs   „AAzCtier_labels values must be unique across tiers; shared labels for: r¿  )r#  r•   rÁ  r\  rN   r„  r¡  Ú	enumerate)rO   ÚblankÚshadowedrÄ  rá  râ  s       @@r    Ú_validate_tier_labelsz,ComplexityRouterConfig._validate_tier_labelsó  s   ù€ à×ÒØˆKÜœVÑ#pÀ$×BRÑBR×BXÑBXÓBZÔ#pÓpÓqˆÙÜÐ]Ð^b×^gÑ^gÐhmÓ^nÐ]oÐpÓqÐqÜÜñ à#'×#3Ñ#3×#9Ñ#9Ó#;ôó ó
ˆñ Üð8Ø8<¿	¹	À(Ó8KÐ7LðNóð ð ×+Ñ+Ó-ˆÜ$Ñ$NÀgÔ$NÓNˆÜ!ô "
ä$-¨mÓ$<ô"
ó 
ˆ
ñ
 ÜØUÐVZ×V_ÑV_Ð`jÓVkÐUlÐmóð ð ˆr   c                 óL   — | j                   r| j                  rt        d«      ‚| S )Nz¢plugins and adaptive=True cannot both be set: adaptive's bandit selection doesn't yet consume plugin-narrowed candidate pools. Disable adaptive or remove plugins.)rV  r@  rN   r  s    r    Ú _validate_plugins_adaptive_comboz7ComplexityRouterConfig._validate_plugins_adaptive_combo  s)   € à�<Š<˜DŸMšMÜð_óð ð ˆr   c                 óš   — t        d„ | j                  j                  «       D «       «      }|rt        ddj	                  |«      › d�«      ‚| S )aL  Reject a router setting written into a tier entry's request params.

        A tier entry's ``litellm_params`` are request params for that deployment: the
        pre-routing hook spreads them onto the outbound call, so a config key placed
        there configures nothing and reaches the provider as an unknown body field.
        c              3   ó’   K  — | ]?  \  }}|D ]5  }t        t        |j                  «      t        z  «      D ]  }|› d |› �–— Œ Œ7 ŒA y­w)ú.N)rÁ  r–   r…   ÚCOMPLEXITY_ROUTER_CONFIG_KEYS)rm   r<   r˜   r’   r^  s        r    ro   zHComplexityRouterConfig._validate_tier_param_placement.<locals>.<genexpr>$  sf   è ø€ ò !
á��gØ ò!
ð Üœi¨×(<Ñ(<Ó=Ô@]Ñ]Ó^ò	!
ð ð ˆf�A�c�UŒOð!
Øð!
Øñ!
ùs   ‚AAz¿tier entries carry complexity_router_config settings in their litellm_params, where the router never reads them and the outbound request forwards them to the provider as unknown body fields: r‚  z.. Set these on complexity_router_config itself)r•   r  r\  rN   r„  )rO   Ú	misplaceds     r    Ú_validate_tier_param_placementz5ComplexityRouterConfig._validate_tier_param_placement  s`   € ô !ñ !
à!%×!8Ñ!8×!>Ñ!>Ó!@ô!
ó 
ˆ	ñ Üð à $§	¡	¨)Ó 4Ð5Ð5cðeóð ð
 ˆr   r<   c                 ór   — | j                   j                  |d«      j                  «       xs |j                  S )zLOperator-facing display name for a tier, falling back to its canonical name.ri   )r#  rg  rG   r@   )rO   r<   s     r    Ú
tier_labelz!ComplexityRouterConfig.tier_label2  s-   € à×Ñ×#Ñ# D¨"Ó-×3Ñ3Ó5ÒC¸¿¹ÐCr   c                 ó4   ‡ — t        ˆ fd„t        D «       «      S )zEEvery tier paired with its display name, in ascending severity order.c              3   óD   •K  — | ]  }|‰j                  |«      f–— Œ y ­wrC   )rð  )rm   r<   rO   s     €r    ro   z7ComplexityRouterConfig.labeled_tiers.<locals>.<genexpr>8  s   øè ø€ ÒS°t�d˜DŸO™O¨DÓ1Ô2ÑSùs   ƒ )r•   r/   r  s   `r    r¡  z$ComplexityRouterConfig.labeled_tiers6  s   ø€ äÓSÔ?RÔSÓSÐSr   c                 ó¸   ‡— |j                  «       j                  «       Š| j                  «       }t        ˆfd„|D «       t        ˆfd„t        D «       d«      «      S )zRResolve a display name back to its tier, case-insensitively, then canonical names.c              3   óP   •K  — | ]  \  }}|j                  «       ‰k(  sŒ|–— Œ y ­wrC   r¥  )rm   r<   rð  r§  s      €r    ro   z8ComplexityRouterConfig.tier_for_label.<locals>.<genexpr>?  s&   øè ø€ ÒUÑ&�d˜J°Z×5HÑ5HÓ5JÈfÓ5TŒTÑUùs   ƒ&Ÿ&c              3   ó^   •K  — | ]$  }|j                   j                  «       ‰k(  sŒ!|–— Œ& y ­wrC   )r@   r¦  )rm   r<   r§  s     €r    ro   z8ComplexityRouterConfig.tier_for_label.<locals>.<genexpr>@  s&   øè ø€ ÒZ˜4¸$¿*¹*×:MÑ:MÓ:OÐSYÓ:Y”$ÑZùs   ƒ"-¦-N)rG   r¦  r¡  r©  r/   )rO   r   râ  r§  s      @r    r¨  z%ComplexityRouterConfig.tier_for_label:  sL   ø€ àŸ™›×.Ñ.Ó0ˆØ×+Ñ+Ó-ˆÜÛU¨'ÔUÜÓZÔ#6ÔZÐ\`Óaó
ð 	
r   )rA   r  )kr   r   r   r   r   r  r‡   rF   rT   rU   r  r   r•   r~   r   rd   r!  r"  r#  r   r%  Úfloatr&  r(  r  r*  r+  r,  r-  r.  r/  r0  r1  r²  r4  r	   r5  r  r6  r7  r   r9  r:  r3   r<  r4   r=  r>  r?  r@  rD  r   r1   rE  rH  rI  rJ  r6   rK  rL  rM  rN  rO  rP  rR  rS  rT  rU  rV  r   rW  rv   r   r‹   r   rV   rW   r`  r   rn  rq  rs  r|  r  r…  rˆ  rŠ  r�  r‘  r“  Úpropertyr•  r‡  rƒ  r¢  rª  rµ  rÊ  rÐ  rÕ  r×  ræ  rè  rî  rð  r¡  r¨  r   r   r    r  r  ï  s
  … Ù1ñ ).Ù:ðxô)€Eˆ4��S˜4 ™9‘_Ð$Ñ%ó ñ INØôIÐ˜  UÐ+>ÀÐ+CÑ%DÐ DÑEó ñ ;@Øðaô;Ð�e˜N¨CÐ/Ñ0°4Ñ7ó ñ !&Øð-ô!€M�3˜‘:ó ñ ).Øð0ô
)Ð˜3 ™:ó 
ñ .3ØðRô	.€K��n cÐ)Ñ*ó 	ñ ).Ù>ðGô)€O�T˜#˜u˜*Ñ%ó ñ 27Øðdô2Ð  %¨$¡,ó ñ (-Ù?ØNô(Ð�d˜3 ˜8‘nó ñ +0Ù@Ø8ô+Ð�t˜C ˜JÑ'ó ñ ',ØØ>ô'€M�4˜‘9˜tÑ#ó ñ ,1ØØDô,Ð˜˜S™	 DÑ(ó ñ ,1ØØ;ô,Ð˜˜S™	 DÑ(ó ñ 38Øð2ô3Ð˜t C™y¨4Ñ/ó ñ ).ØØ>ô)€O�T˜#‘Y Ñ%ó ñ !&ØØGô!€M�3˜‘:ó ñ
 #(Øð;ô#Ð˜4ó ñ QVØðKôQ€O�WÐLÑMó ñ 9>ØØwô9ÐÐ.°Ñ5ó ñ ,1Øðbô,Ð˜c D™jó ñ 27Øðoô2ÐÐ'¨$Ñ.ó ñ ).ØØðTô	)Ð  #ó ñ BGØðUôBÐ˜Ð!=Ñ>ó ñ +0Ø6Øð(ô	+Ð" Có ñ ,1Ø7ØðHô	,Ð# Só ñ 5:ØØðaô	
5Ð% s¨T¡zó 
ñ 8=Øð	aô8Ð.°ó ñ  ØØRô€Hˆdó ñ /4ÙLØ^ô/ÐÐ+ó ñ $)Ø-ØØbô$Ð˜5ó ñ
 <AØðXô<Ð�wÐ7Ñ8ó ñ -2Øð/ô-Ð˜˜c™ TÑ)ó ñ 8=ØØ[ô8Ð˜˜_Ñ-°Ñ4ó ñ
 &+Øð
ô&Ð˜˜d™
ó ñ  27Øð`ô2Ð˜˜c 3˜h™¨$Ñ.ó ñ 16Øð	Rô1Ð'¨ó ñ 5:Øð`ô5Ð˜5  c ™?¨TÑ1ó ñ ',ØØ^ô'Ð˜tó ñ #(ØØiô#€O�S˜4‘Zó ñ #ØØØØLô	€O�Uó ñ #Øð5ôÐ�dó ñ !&Øð_ô!Ð˜ó ñ& ).ØØð]ô	)Ð  #ó ñ +0ØØqô+€GˆT�-Ñ  4Ñ'ó ñ
 ?DØØð\ô	
?Ð�eÐ.°Ð3Ñ4°tÑ;ó 
ñ  GÀTÔJ€Lá�W 8Ô,Øð¨ð °6ò ó ó -ðñ ˜(Ô#Øð-
°&ð -
¸Vò -
ó ó $ð-
ñ^ Ð*Ó+ØðP°4¸±9¸tÑ3Cð PÈÈSÉ	ÐTXÑHXò Pó ó ,ðPñ
 Ð)°Ô9Øð¨vð ¸&ò ó ó :ðñ Ð)Ó*ØðU°%¸¸S¸±/ÀDÑ2Hð UÈUÐSVÐX[ÐS[É_Ð_cÑMcò Uó ó +ðUñ Ð,Ó-ØðU°U¸3À¸8±_ÀtÑ5Kð UÐPUÐVYÐ[^ÐV^ÑP_ÐbfÑPfò Uó ó .ðUñ ˜'Ô"òó #ðñ  ˜'Ô"ò
ó #ð
ñ Ð/°hÔ?Øð°Vð Àò ó ó @ðñ ˜'Ô"òó #ðñB �_Ó%Øð°°d±
ð ¸sÀT¹zò ó ó &ðñ Ð,Ó-Øð6¸3À¹:ð 6È#ÐPTÉ*ò 6ó ó .ð6ð ð1 $ò 1ó ð1ð ð< Tò <ó ð<ðA˜E # s (™Oó AðA¨¨c°3¨h©ó Að]¨Sð ]°^ÀcÑ5IÈDÑ5Pó ]ð-
¨E°#°s°(©Oó -
ñ^ ˜'Ô"ò8ó #ð8ñt ˜'Ô"òó #ðñ ˜'Ô"ò
ó #ð
ñ ˜'Ô"òó #ðñ ˜'Ô"òó #ðñ> ˜'Ô"òó #ðñ ˜'Ô"òó #ðð*D˜~ð D°#ó DðT˜u U¨>¸3Ð+>Ñ%?ÀÐ%DÑEó Tð
 Cð 
¨N¸TÑ,Aô 
r   r  rì  ÚDEFAULT_COMPLEXITY_CONFIG)Ir   Úcollections.abcr   Úenumr   Útypesr   Útypingr   r   r	   Úpydanticr
   r   r   r   r   r   r   Úlitellm.types.routerr   r   r   rF   r   r"   r'   r+   rU   r–   r.   r   r   r   r   r/   r•   r1   rö  r3   r  r4   r6   rY   r[   r\   r]   rb   rd   rv   r~   rW   rT   r›   rÇ   rÍ   rç   rè   ré   rê   rë   rí   rú   r  r‡   r  r
  r  r  r  Úmodel_fieldsrì  rø  r   r   r    ú<module>r      sœ  ðòõ $Ý Ý "ß ,Ñ ,ç u× uÑ uç WÑ Wô�S˜$ô ô˜3 ô ð >R×=XÑ=XÐ ˜uÐ%9Ñ:Ó Xñ
 /8¸Ð@QÐ8RÓ.SÐ �e˜I c™NÑ+Ó Sð ×ÑØ×ÑØ×ÑØ×Ñð	:Ð �U˜5 °Ð!4Ñ5Ñ6ó ð /2Ð ˜u U™|Ó 1à56Ð &¨¨c©
Ó 6Ø6:Ð '¨¨s©Ó :ô!�iô !ðH $%Ð �e˜C‘jÓ $Ø"$Ð �U˜3‘ZÓ $Ø),Ð ˜E #™JÓ ,Ø.2Ð   s¡Ó 2ð¨3°©:ð ¸#À¹*ó ô")�Yô )ôX˜ô ô0˜)ô ð$Øðà
ðð ˆ3��c‘‰?˜EÐ"5°sÐ":Ñ;Ð;Ñ<óò0.+Ð �u˜T #™YÑ'ó .ò`0Ð ˜E $ s¡)Ñ,ó ò,0Ð ˜E $ s¡)Ñ,ó ð@ 2DÐ0DÐ ˜U 4¨¡9Ñ-Ó Dð
4Ð ˜%  c¨3 h¡Ñ0ó ð 6dÐ ˜E %¨¨S¨¡/Ñ2Ó cð6Ð ˜E %¨¨S¨¡/Ñ2ó ð #3Ð �U˜3‘ZÓ 2ò-Ð ˜˜t C™yÑ)ó ðD ØØØØØØñ6Ð ˜5  c¨5 jÑ!1Ñ2ó ð ØØñ4Ð ˜˜t C¨ JÑ/Ñ0ó ð Øñ3Ð ˜%  S¨# X¡Ñ/ó ð ØØ)Ø+ñ	.Ð �U˜4  S ™>Ñ*ó ôA˜)ô AôHR
˜Yô R
ñj 8AÐAW×AdÑAdÓ7eÐ ˜u Y¨s¡^Ñ4Ó eðñ $:Ó#;Ð ˜5Ô ;r   