Ë
    tPêjëq  ã                   ól  — U d Z ddlZddlZddlmZ ddlmZmZ ddlmZm	Z	m
Z
mZ ddlmZmZmZmZ ddl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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+ erddl,m-Z-  e«       Z.e
e/d<    ee0e1e2f   «      Z3e
e/d<    G d„ de«      Z4 G d„ de«      Z5ddde5fd„Z6h d£Z7e
e8e1      e/d<    e9d„ e)D «       «      Z:e
e9e1      e/d<    e«       Z;e
e/d <   d!Z<e
e/d"<    e9h d#£«      Z=e
e9e1      e/d$<   d%ee1e2f   de0e1e	f   fd&„Z>d'e2de0e1e2f   fd(„Z?d)ee1e2f   de0e1e2f   fd*„Z@d%ee1e2f   de0e1e2f   fd+„ZAd,e1deBfd-„ZCd.e2deBfd/„ZDd0ZEe
eFe1d1f      e/d2<   d.e2de1fd3„ZGd4ee1e2f   d5ee1e2f   deBfd6„ZHd4ee1e2f   d5ee1e2f   dee1e2f   fd7„ZId%ee1e2f   dz  de0e1e2f   fd8„ZJdUd9„ZKd:ed;ee1e2f   dz  d<ee1e2f   dz  d=e!d>e1dz  ddfd?„ZL G d@„ dA«      ZM G dB„ dCe«      ZN G dD„ dEe«      ZO G dF„ dGe«      ZP G dH„ dIe«      ZQe.j¥                  dJdKg ee#«      geN¬L«       ee#«      fd=e!fdM„«       ZSe.j©                  dNdKg ee#«      geP¬L«       ee#«      fdOeOd=e!fdP„«       ZUe.j©                  dJdKg ee#«      g¬Q«       ee#«       eddR¬S«      fdOeQd=e!d>e1dz  fdT„«       ZVy)Va  
CACHE SETTINGS MANAGEMENT

Endpoints for managing cache configuration

GET /cache/settings - Get cache configuration including available settings
POST /cache/settings/test - Test cache connection with provided credentials
POST /cache/settings - Save cache settings to database
é    N)ÚMapping)ÚdatetimeÚtimezone)ÚTYPE_CHECKINGÚAnyÚFinalÚProtocol)Ú	APIRouterÚDependsÚHeaderÚHTTPException)Ú	BaseModelÚFieldÚTypeAdapter)Úverbose_proxy_logger)Ú_redis_kwargs_from_environment)Úuuid)ÚSensitiveDataMasker)ÚAUDIT_ACTIONSÚLiteLLM_AuditLogsÚLitellmTableNamesÚUserAPIKeyAuth)Úuser_api_key_auth)Úcall_with_db_reconnect_retry)ÚCacheConfigRepository)ÚCACHE_SETTINGS_FIELDSÚREDIS_TYPE_DESCRIPTIONSÚCacheSettingsField)ÚPrismaClientÚrouterÚ_STORED_CACHE_SETTINGS_ADAPTERc                   ó8   — e Zd Zedeeeef   z  dz  fd„«       Zy)Ú_CacheConfigRowÚreturnNc                  ó   — y ©N© )Úselfs    ú€/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/management_endpoints/cache_settings_endpoints.pyÚcache_settingsz_CacheConfigRow.cache_settings0   s   € ØCFó    )Ú__name__Ú
__module__Ú__qualname__ÚpropertyÚstrr   Úobjectr*   r'   r+   r)   r#   r#   /   s(   „ ØØF  g¨c°6¨kÑ&:Ñ :¸TÑ AÒFó ÙFr+   r#   c                   ó^   — e Zd Zdeeef   dedz  fd„Zdeeef   deeeeef   f   defd„Zy)Ú_CacheConfigTableÚwherer$   Nc              ƒ   ó   K  — y ­wr&   r'   )r(   r4   s     r)   Úfind_uniquez_CacheConfigTable.find_unique5   ó   è ø� ùó   ‚Údatac              ƒ   ó   K  — y ­wr&   r'   )r(   r4   r9   s      r)   Úupsertz_CacheConfigTable.upsert7   r7   r8   )r,   r-   r.   r   r0   r#   r6   r;   r'   r+   r)   r3   r3   4   sO   „ ØX w¨s°C¨xÑ'8ÐX¸_ÈtÑ=SÓXàs '¨#¨s¨(Ñ"3Ðs¸7À3ÈÐPSÐUXÐPXÑHYÐCYÑ;ZÐsÐ_nÔsr+   r3   Úprisma_clientr   r$   c                 ó,   — t        | «      j                  S r&   )r   Útable©r<   s    r)   Ú_cache_config_tabler@   :   s   € Ü  Ó/×5Ñ5Ð5r+   >   ÚurlÚpasswordÚsentinel_passwordÚ_CACHE_SENSITIVE_FIELDSc              #   ó4   K  — | ]  }|j                   –— Œ y ­wr&   )Ú
field_name)Ú.0Úfields     r)   ú	<genexpr>rI   H   s   è ø€ Ò>sÐTY¸u×?OÕ?OÑ>sùs   ‚Ú_CACHE_SETTINGS_FIELD_NAMESÚ_CREDENTIAL_CLASSIFIERz***REDACTED***Ú_REDACTED_VALUE>   ÚdbÚhostÚportrB   ÚusernameÚ!_URL_OVERRIDDEN_CONNECTION_FIELDSÚsettingsc                 ó  — | j                  d«      }t        |t        «      xr |j                  «       dk7  }|r| j                  d«      rt	        | «      S | j                  «       D ��ci c]  \  }}|t        vsŒ||“Œ c}}S c c}}w )aÉ  Return cache settings with the url-vs-discrete-fields ambiguity resolved.

    When a full ``url`` is supplied it wins: the discrete
    host/port/db/password/username fields are dropped so the persisted config
    is unambiguous and matches runtime resolution in ``litellm._redis``
    (``redis.Redis.from_url`` ignores them). Cluster mode
    (``redis_startup_nodes``) is exempt because it authenticates via the
    discrete fields rather than a url.
    rA   Ú Úredis_startup_nodes)ÚgetÚ
isinstancer0   ÚstripÚdictÚitemsrQ   )rR   rA   Úhas_urlÚkÚvs        r)   Ú_resolve_cache_url_precedencer^   V   sr   € ð —‘˜eÓ$€CÜ ¤SÓ)Ò?¨c¯i©i«k¸RÑ.?€GÙ�h—l‘lÐ#8Ô9Ü�H‹~ÐØ%Ÿ^™^Ó-×\‘T�Q˜°Ô:[Ò1[ˆAˆq‰DÓ\Ð\ùÓ\s   Á(BÁ9BÚcache_settings_valuec                 óx   — t        | t        «      rt        j                  | «      n| }t        |t        «      r|S i S )a  Normalize a stored cache_settings blob to a dict.

    The prisma column comes back as either a JSON string or an already-parsed
    dict depending on the client, so callers that json.loads unconditionally
    silently drop the whole (still-encrypted) row on the dict path.
    )rW   r0   ÚjsonÚloadsrY   )r_   Úparseds     r)   Ú_parse_stored_settingsrd   g   s6   € ô 9CÐCWÔY\Ô8]”D—J‘JÐ3Ô4Ðcw€FÜ ¬Ô-ˆ6Ð5°2Ð5r+   Ústoredc                 óÄ   — t        «       j                  «       D ��ci c]  \  }}|t        v sŒ||“Œ }}}|st        | «      S i |¥| ¥}|j	                  dd«       |S c c}}w )a#  Fill connection fields from the REDIS_* environment the cache actually reads.

    A response cache pointed at Redis resolves host/port/password/etc. from the
    REDIS_* env vars when the stored config leaves them unset, so a cache
    configured purely through the environment works while its settings page,
    which reads only the database row, shows blank. Overlaying the same env
    kwargs the runtime uses makes the page reflect the effective connection.
    Stored values win; the environment only fills what the stored config omits.
    ÚtypeÚredis)r   rZ   rJ   rY   Ú
setdefault)re   ÚkeyÚvalueÚ
env_kwargsÚ	effectives        r)   Ú_overlay_environmentrn   r   sw   € ô &DÓ%E×%KÑ%KÓ%M÷Ù!�s˜EÐQTÔXsÒQsˆˆU‰
ð€Jñ ñ Ü�F‹|ÐØ/˜*Ð/¨Ð/€Ið ×Ñ˜ Ô)ØÐùós
   œA­Ac                 ó|   — | j                  «       D ��ci c]  \  }}||�t        |«      rt        n|“Œ c}}S c c}}w )a[  Replace credential-bearing values with a fixed marker, keeping the rest.

    The marker is unambiguous on the way back in: an admin who edits an
    unrelated field and re-submits sends the marker for the untouched secret,
    which the update path maps back to the stored value rather than persisting
    the marker over a working password.
    )rZ   Ú_is_credential_fieldrL   )rR   rj   rk   s      r)   Ú_redact_credentialsrq   ˆ   sD   € ð #Ÿ.™.Ó*÷áˆC�ð 	 Ð!2Ô7KÈCÔ7P�oÐV[Ñ[óð ùó s   ” 8rj   c                 ó@   — | t         v xs t        j                  | «      S )zJWhether a cache setting carries a credential and must be redacted on read.)rD   rK   Úis_sensitive_key)rj   s    r)   rp   rp   –   s    € àÔ)Ð)ÒYÔ-C×-TÑ-TÐUXÓ-YÐYr+   rk   c                 ól   — t        | t        «      r| j                  «       dk7  xr	 | t        k7  S | dg i fvS )z@Whether a payload value names a live discrete connection target.rT   N)rW   r0   rX   rL   ©rk   s    r)   Ú_has_connection_targetrv   ›   s8   € ä�%œÔØ�{‰{‹} Ñ"Ò? u´Ñ'?Ð?Ø˜˜r 2˜Ð&Ð&r+   )rN   rO   rA   rU   Úsentinel_nodesÚservice_name.Ú_CONNECTION_TARGET_FIELDSc                 ó|   — t        | t        t        f«      rt        j                  | dt
        ¬«      S t        | «      S )aD  Canonical string form of a connection-target value for equality checks.

    The client may serialize the same target differently from storage (a port as
    "6379" vs 6379, node lists round-tripped through JSON), so compare normalized
    forms rather than raw values to avoid treating an unchanged target as a change.
    T)Ú	sort_keysÚdefault)rW   ÚlistrY   ra   Údumpsr0   ru   s    r)   Ú_target_reprr   ¯   s/   € ô �%œ$¤˜Ô&Ü�z‰z˜%¨4¼Ô=Ð=Üˆu‹:Ðr+   ÚincomingÚsavedc                 óø   — t         D ]q  }|j                  |«      }|ddg i fv rŒ| j                  |«      }|dk(  r&|ddt        fv rŒ?t        |«      t        |«      k7  r yŒYt        |«      t        |«      k7  sŒq y y)a¯  Whether a stored credential may be restored for this request.

    A stored secret belongs to the stored connection target, so it is reused only
    when the request describes that same target on every dimension the stored
    config pins (host/port, url, cluster nodes, sentinel nodes/service). This
    prevents credential replay: a caller cannot omit the credential, point at a
    different (or incomplete) target, and have the proxy send the stored secret
    to a Redis of their choosing.

    Non-secret target fields (host/port/nodes/service) must be supplied and match
    in normalized form, so equivalent representations (port "6379" vs 6379) are
    not seen as a change while an omitted or different value is. ``url`` is the
    exception: it is itself the secret and the form never re-prefills it, so a
    redacted or omitted url means "keep the stored url" (same target) and only a
    different supplied url blocks reuse.
    NrT   rA   FT)ry   rV   rL   r   )r€   r�   rH   Úsaved_valueÚincoming_values        r)   Ú_saved_secret_is_reusabler…   »   sŽ   € ô" +ò ˆØ—i‘i Ó&ˆØ˜4  R¨Ð,Ñ,ØØ!Ÿ™ eÓ,ˆØ�EŠ>Ø $¨¬OÐ!<Ñ<ØÜ˜NÓ+¬|¸KÓ/HÒHÙØÜ˜Ó'¬<¸Ó+DÓDÙðð r+   c                 ó†  — t        | j                  d«      «      xs6 t        | j                  d«      «      xs t        | j                  d«      «      }t        | |«      }t        | «      }t        D ]N  }|| v r| |   t
        k7  rŒ|dk(  r|r|j                  |d«       Œ.||v r|r	||   ||<   Œ=|j                  |d«       ŒP |S )a×  Keep the stored secret behind any credential the caller echoed back redacted or omitted.

    GET returns credentials as the marker and the form never re-prefills a
    secret, so a save that does not touch a credential arrives with the marker
    or with the field absent. Either way the real secret must survive: it is
    restored from the stored row, or dropped when there is no stored row (the
    value is env-sourced and the marker must never be persisted). Non-secret
    fields are taken from the incoming payload as-is, so clearing one still works.

    ``url`` is the exception: it is credential-bearing (redacted) yet also a
    connection-mode selector that url-precedence resolves against host/port. If
    the caller supplies a discrete target (host, cluster, or sentinel nodes), a
    stored url is a stale mode the caller is leaving, so it is dropped rather
    than restored, otherwise url-precedence would resurrect it and discard the
    submitted host/port.
    rN   rU   rw   rA   N)rv   rV   r…   rY   rD   rL   Úpop)r€   r�   Úswitching_to_discrete_targetÚreuse_saved_secretÚmergedrH   s         r)   Ú_merge_over_savedr‹   Ü   sÒ   € ô$ 	˜xŸ|™|¨FÓ3Ó4ò 	BÜ! (§,¡,Ð/DÓ"EÓFò	Bä! (§,¡,Ð/?Ó"@ÓAð !ô
 !:¸(ÀEÓ JÐÜ˜“N€FÜ(ò $ˆð �HÑ ¨%¡´OÒ!CØØ�EŠ>Ñ:Ø�J‰J�u˜dÔ#ØØ�E‰>Ñ0Ø! %™LˆF�5ŠMð �J‰J�u˜dÕ#ð$ð €Mr+   c                 ó>   — | si S | D �ci c]	  }|t         “Œ c}S c c}w )aJ  Replace every value in a settings map with a fixed marker.

    Cache config carries Redis credentials (passwords, connection strings).
    The audit-log row preserves the field names so a reader can see *which*
    fields changed, but values are stripped so the audit table can't itself
    become a credential-harvest sink.
    )rL   )rR   r\   s     r)   Ú_redact_settingsr�     s%   € ñ Øˆ	Ø(0Ö1 1ˆAŒÑÒ1Ð1ùÒ1s   ‰c                 óx   — | j                  «       ry| j                  «       }|�t        j                  d|«       yy)uÎ   Surface a fire-and-forget audit-log task failure as a warning.

    ``asyncio.create_task`` swallows exceptions silently â€” if the audit
    write fails we'd otherwise lose the row without any signal.
    Nz,Failed to write cache-settings audit log: %s)Ú	cancelledÚ	exceptionr   Úwarning)ÚtaskÚexcs     r)   Ú_log_audit_task_exceptionr”     s9   € ð ‡~�~ÔØØ—‘Ó!€CØ
€Ü×$Ñ$Ð%SÐUXÕYð r+   ÚactionÚbefore_settingsÚafter_settingsÚuser_api_key_dictÚlitellm_changed_byc              ƒ   ó  K  — ddl m}m} ddlm}  |«       syt        j                   |t        t        t        j                  «       «      t        j                  t        j                  «      |xs |j                  xs ||j                   t"        j$                  d| t'        j(                  dt+        |«      it        ¬«      t'        j(                  dt+        |«      it        ¬«      ¬«	      ¬	«      «      }|j-                  t.        «       y­w)
am  Emit an audit-log row for a /cache/settings mutation.

    Mirrors the ``store_audit_logs``-gated pattern used in
    ``team_callback_endpoints.py``: fire-and-forget, no-op when audit
    logging is disabled, with a done-callback that surfaces any task
    exception.  Captured under ``LiteLLM_CacheConfig`` so the row
    co-locates with the table it mutates.
    r   )Úcreate_audit_log_for_updateÚis_audit_logging_enabled)Úlitellm_proxy_admin_nameNÚcache_configrR   )r|   )	ÚidÚ
updated_atÚ
changed_byÚchanged_by_api_keyÚ
table_nameÚ	object_idr•   Úupdated_valuesÚbefore_value)Úrequest_data)Ú+litellm.proxy.management_helpers.audit_logsr›   rœ   Úlitellm.proxy.proxy_serverr�   ÚasyncioÚcreate_taskr   r0   r   Úuuid4r   Únowr   ÚutcÚuser_idÚapi_keyr   ÚCACHE_CONFIG_TABLE_NAMEra   r~   r�   Úadd_done_callbackr”   )	r•   r–   r—   r˜   r™   r›   rœ   r�   r’   s	            r)   Ú_emit_cache_settings_audit_logr³      sÊ   è ø€ ÷ õ Dá#Ô%Øä×%Ñ%Ù#Ü*Ü”t—z‘z“|Ó$Ü#Ÿ<™<¬¯©Ó5Ø-ÒfÐ1B×1JÑ1JÒfÐNfØ#4×#<Ñ#<Ü,×DÑDØ(ØÜ#Ÿz™z¨:Ô7GÈÓ7WÐ*XÔbeÔfÜ!ŸZ™Z¨Ô5EÀoÓ5VÐ(WÔadÔeô
ô	
ó€Dð 	×ÑÔ4Õ5ùs   ‚D	Dc                   ó”   — e Zd ZU dZdZeeef   dz  ed<   e	deeef   deeef   de
fd„«       Ze	dd„«       Ze	d	eeef   fd
„«       Zy)ÚCacheSettingsManagerz€
    Manages cache settings initialization and updates.
    Tracks last cache params to avoid unnecessary reinitialization.
    NÚ_last_cache_paramsÚparams1Úparams2r$   c                 ó€   — dt         t        t        f   dt         t        t        f   fd„} || «      } ||«      }||k(  S )z‚
        Compare two cache parameter dictionaries for equality.
        Normalizes values and filters out UI-only fields.
        Úparamsr$   c                 ó˜   — i }| j                  «       D ]4  \  }}|dk(  rŒ|€Œt        |t        t        f«      st	        |«      n|||<   Œ6 |S )NÚ
redis_type)rZ   rW   r}   rY   r0   )rº   Ú
normalizedr\   r]   s       r)   Ú	normalizez;CacheSettingsManager._cache_params_equal.<locals>.normalize[  sW   € Ø "ˆJØŸ™›ò U‘��1Ø˜Ò$ØØ‘=ä2<¸QÄÄtÀÔ2M¤C¨¤FÐST�J˜q’MðUð Ðr+   )rY   r0   r1   )r·   r¸   r¾   Únormalized1Únormalized2s        r)   Ú_cache_params_equalz(CacheSettingsManager._cache_params_equalS  sH   € ð	œd¤3¬ ;Ñ/ð 	´D¼¼f¸Ñ4Eó 	ñ ' wÓ/ˆÙ& wÓ/ˆà˜kÑ)Ð)r+   c              ƒ   óò  ‡ K  — 	 t        ‰ ˆ fd„d¬«      ƒ d{  –—† }|�� |j                  �r|j                  }t        |t        «      rt        j                  |«      n
t        |«      }|j                  |¬«      }|j                  «       D ��ci c]  \  }}|dk7  sŒ||“Œ }}}t        j                  �:t        j                  t        j                  |«      rt        j                  d«       y|j                  |¬«       |j                  «       t        _
        |j!                  «        t        j"                  d	«       yyy7 �Œ)c c}}w # t$        $ r }	t        j&                  d
|	«       Y d}	~	yd}	~	ww xY w­w)zŽ
        Initialize cache settings from database into the router on startup.
        Only reinitializes if cache params have changed.
        c                  ó>   •— t        ‰ «      j                  ddi¬«      S )NrŸ   rž   ©r4   )r@   r6   r?   s   €r)   ú<lambda>z@CacheSettingsManager.init_cache_settings_in_db.<locals>.<lambda>s  s!   ø€ Ô+¨MÓ:×FÑFÈdÐTbÐMcÐFÓd€ r+   Ú(init_cache_settings_in_db_lookup_failure)ÚreasonN©Úvariables_dictr¼   z3Cache settings unchanged, skipping reinitialization©Úcache_paramsz(Cache settings initialized from databaseztlitellm.proxy.management_endpoints.cache_settings_endpoints.py::CacheSettingsManager::init_cache_settings_in_db - %s)r   r*   rW   r0   r!   Úvalidate_jsonrY   Ú_decrypt_db_variablesrZ   rµ   r¶   rÁ   r   ÚdebugÚ_init_cacheÚcopyÚswitch_on_llm_response_cachingÚinfoÚ	Exceptionr�   )
r<   Úproxy_configrž   Úcache_settings_jsonÚcache_settings_dictÚdecrypted_settingsr\   r]   rË   Úes
   `         r)   Úinit_cache_settings_in_dbz.CacheSettingsManager.init_cache_settings_in_dbj  sv  øè ø€ ð+	Ü(DØÛdØAô)÷ #ˆLð
 Ñ'¨L×,GÓ,Gà-9×-HÑ-HÐ#ô "Ð"5´sÔ;ô 3×@Ñ@ÐATÔUäÐ1Ó2ð $ð -9×,NÑ,NÐ^qÐ,NÓ,rÐ"ð 9K×8PÑ8PÓ8R×&h±°°1ÐVWÐ[gÓVg q¨!¡tÐ&h�Ñ&hô (×:Ñ:ÐFÔK_×KsÑKsÜ(×;Ñ;¸\ôLô )×.Ñ.Ð/dÔeØð ×(Ñ(°lÐ(ÔCð ;G×:KÑ:KÓ:MÔ$Ô7ð ×;Ñ;Ô=ä$×)Ñ)Ð*TÕUðA -HÐ'ð#ûó& 'iøô& ò 	Ü ×*Ñ*ð GØ÷ñ ûð	üse   ƒE7…E ™EšA5E ÂEÂEÂ"AE Ã.E7Ã/AE Ä?E7ÅE ÅE Å	E4ÅE/Å*E7Å/E4Å4E7rË   c                 ó6   — | j                  «       t        _        y)z�
        Update the last cache params after initialization.
        Called after cache settings are updated via the API.
        N)rÐ   rµ   r¶   rÊ   s    r)   Úupdate_cache_paramsz(CacheSettingsManager.update_cache_params�  s   € ð 3?×2CÑ2CÓ2EÔÕ/r+   )r<   r   )r,   r-   r.   Ú__doc__r¶   rY   r0   r1   Ú__annotations__ÚstaticmethodÚboolrÁ   rÙ   rÛ   r'   r+   r)   rµ   rµ   K  s˜   … ñð
 48Ð˜˜S &˜[Ñ)¨DÑ0Ó7àð* T¨#¨v¨+Ñ%6ð *ÀÀcÈ6ÀkÑARð *ÐW[ò *ó ð*ð, ò0ó ð0ðd ðF¨$¨s°F¨{Ñ*;ò Fó ñFr+   rµ   c                   ó|   — e Zd ZU  ed¬«      Zee   ed<    ed¬«      Ze	e
ef   ed<    ed¬«      Ze	e
e
f   ed<   y)	ÚCacheSettingsResponsez5List of all configurable cache settings with metadata©ÚdescriptionÚfieldsz Current values of cache settingsÚcurrent_valuesz'Descriptions for each Redis type optionÚredis_type_descriptionsN)r,   r-   r.   r   rä   r}   r   rÝ   rå   rY   r0   r1   ræ   r'   r+   r)   rá   rá   ¦  sJ   … Ù',Ð9pÔ'q€FˆDÐ#Ñ$ÓqÙ(-Ð:\Ô(]€N�D˜˜f˜Ñ%Ó]Ù.3Ð@iÔ.jÐ˜T # s (™^Ôjr+   rá   c                   ó4   — e Zd ZU  ed¬«      Zeeef   ed<   y)ÚCacheTestRequestz&Cache settings to test connection withrâ   r*   N©	r,   r-   r.   r   r*   rY   r0   r1   rÝ   r'   r+   r)   rè   rè   ¬  s   … Ù(-Ð:bÔ(c€N�D˜˜f˜Ñ%Ôcr+   rè   c                   ój   — e Zd ZU  ed¬«      Zeed<    ed¬«      Zeed<    edd¬«      Zedz  ed	<   y)
ÚCacheTestResponsez(Connection status: 'success' or 'failed'râ   ÚstatuszConnection result messageÚmessageNz"Error message if connection failed)r|   rã   Úerror)	r,   r-   r.   r   rì   r0   rÝ   rí   rî   r'   r+   r)   rë   rë   °  s8   … ÙÐ$NÔO€FˆCÓOÙÐ%@ÔA€GˆSÓAÙ dÐ8\Ô]€Eˆ3�‰:Ô]r+   rë   c                   ó4   — e Zd ZU  ed¬«      Zeeef   ed<   y)ÚCacheSettingsUpdateRequestzCache settings to saverâ   r*   Nré   r'   r+   r)   rð   rð   ¶  s   … Ù(-Ð:RÔ(S€N�D˜˜f˜Ñ%ÔSr+   rð   z/cache/settingszCache Settings)ÚtagsÚdependenciesÚresponse_modelc              ƒ   óÚ  K  — ddl m}m} 	 t        D �cg c]  }|j	                  d¬«      ‘Œ }}i }|�Xt        |«      j                  ddi¬«      ƒ d{  –—† }|�1|j                  r%|j                  t        |j                  «      ¬	«      }t        t        |«      «      }|j                  d
«      dk(  r3|j                  d«      rd|d<   n|j                  d«      rd|d<   nd|d<   t        |«      }|D ]%  }|j                  |v sŒ||j                     |_        Œ' t!        ||t"        ¬«      S c c}w 7 ŒÞ# t$        $ r+}	t'        j(                  d|	«       t+        dd|	› �¬«      ‚d}	~	ww xY w­w)zü
    Get cache configuration and available settings.

    Returns:
    - fields: List of all configurable cache settings with their metadata (type, description, default, options)
    - current_values: Current values of cache settings from database
    r   ©r<   rÔ   T)ÚdeepNrŸ   rž   rÄ   rÈ   rg   rh   rU   Úclusterr¼   rw   ÚsentinelÚnode)rä   rå   ræ   z!Error fetching cache settings: %séô  zError fetching cache settings: ©Ústatus_codeÚdetail)r©   r<   rÔ   r   Ú
model_copyr@   r6   r*   rÍ   rd   r^   rn   rV   rq   rF   Úfield_valuerá   r   rÓ   r   rî   r   )
r˜   r<   rÔ   rH   Úcache_fieldsre   rž   rm   rå   rØ   s
             r)   Úget_cache_settingsr  º  s‘  è ø€ ÷  Gð-[äH]Ö^¸u˜u×/Ñ/°TÐ/Õ:Ð^ˆÐ^ð %'ˆØÐ$Ü!4°]Ó!C×!OÑ!OÐW[Ð]kÐVlÐ!OÓ!m×mˆLØÐ'¨L×,GÒ,GØ%×;Ñ;Ü#9¸,×:UÑ:UÓ#Vð <ó �ô 9Ô9MÈfÓ9UÓVˆ	ð �=‰=˜Ó  GÒ+Ø�}‰}Ð2Ô3Ø*3�	˜,Ò'Ø—‘Ð/Ô0Ø*4�	˜,Ò'à*0�	˜,Ñ'ô !4°IÓ >ˆð "ò 	EˆEØ×Ñ >Ò1Ø$2°5×3CÑ3CÑ$D�Õ!ð	Eô %ØØ)Ü$;ô
ð 	
ùòI _ð
 nùôH ò [Ü×"Ñ"Ð#FÈÔJÜ¨Ð6UÐVWÐUXÐ4YÔZÐZûð[üsK   ‚	E+ŒD4 ”D-­&D4 ÁD2ÁB0D4 Ä'D4 Ä,E+Ä-D4 Ä4	E(Ä=&E#Å#E(Å(E+z/cache/settings/testÚrequestc              ƒ   óÀ  K  — ddl m} ddlm}m} 	 i }|�Y	 t        |«      j                  ddi¬«      ƒ d{  –—† }|�1|j                  r%|j                  t        |j                  «      ¬«      }t        t        | j                  |«      «      }t        j                  d	t        |«      «       |j!                  d
«      dk7  rt#        dd¬«      S  |di |¤Ž}|j$                  j'                  «       ƒ d{  –—† }	t#        di |	¤ŽS 7 ŒË# t        $ r i }Y Œ£w xY w7 Œ"# t        $ r:}
t        j(                  d|
«       t#        dd|
› �t+        |
«      ¬«      cY d}
~
S d}
~
ww xY w­w)zÉ
    Test cache connection with provided credentials.

    Creates a temporary cache instance and uses its test_connection method
    to verify the credentials work without affecting global state.
    r   )ÚCacherõ   NrŸ   rž   rÄ   rÈ   z*Testing cache connection with settings: %srg   rh   Úfailedz8Only Redis cache type is currently supported for testing)rì   rí   z"Error testing cache connection: %szCache connection test failed: )rì   rí   rî   r'   )Úlitellmr  r©   r<   rÔ   r@   r6   r*   rÍ   rd   rÓ   r^   r‹   r   rÎ   rq   rV   rë   ÚcacheÚtest_connectionrî   r0   )r  r˜   r  r<   rÔ   Úsaved_settingsÚexisting_rowr*   Ú
temp_cacheÚresultrØ   s              r)   Útest_cache_connectionr  ü  sp  è ø€ õ  ßFð'
ð -/ˆØÐ$ð$Ü,?ÀÓ,N×,ZÑ,ZÐbfÐhvÐawÐ,ZÓ,x×&x�ØÐ+°×0KÒ0KØ%1×%GÑ%GÜ'=¸l×>YÑ>YÓ'Zð &Hó &�Nô
 !>Ô>OÐPW×PfÑPfÐhvÓ>wÓ xˆä×"Ñ"Ð#OÔQdÐesÓQtÔuð ×Ñ˜fÓ%¨Ò0Ü$ØØRôð ñ "Ñ3 NÑ3ˆ
ð )×.Ñ.×>Ñ>Ó@×@ˆä Ñ* 6Ñ*Ð*ð1 'yùô
 ò $Ø!#’ð$úð" Aùô ò 
Ü×"Ñ"Ð#GÈÔKÜ ØØ4°Q°CÐ8Ü�a“&ô
õ 	
ûð
üs€   ‚E’D — D ·D¸7D Á/AD ÃEÃ%D Ã3DÃ4D ÄEÄD ÄDÄD ÄDÄD Ä	EÄ!/EÅEÅEÅEÅE)rñ   rò   z�The litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountabilityrâ   c              ƒ   óô  K  — ddl m}m}m} |€t	        dddi¬«      ‚|durt	        ddd	i¬«      ‚	 t        |«      j                  d
di¬«      ƒ d{  –—† }d}i }|�3|j                  r't        |j                  «      }|j                  |¬«      }|�dnd}	t        t        | j                  |«      «      }
|j                  |
¬«      }t        |«      j                  d
didt        j                  |«      dœdt        j                  |«      idœ¬«      ƒ d{  –—†  |j                  |¬«      }|j!                  «       D ��ci c]  \  }}|dk7  sŒ||“Œ }}}|j#                  |¬«       t$        j'                  |«       |j)                  «        t+        |	||
||¬«      ƒ d{  –—†  ddt-        |
«      dœS 7 �Œb7 Œ c c}}w 7 Œ# t.        $ r+}t1        j2                  d|«       t	        dd|› �¬«      ‚d}~ww xY w­w)zÝ
    Save cache settings to database and initialize cache.

    This endpoint:
    1. Encrypts sensitive fields (passwords, etc.)
    2. Saves to LiteLLM_CacheConfig table
    3. Reinitializes cache with new settings
    r   )r<   rÔ   Ústore_model_in_dbNrú   rî   z2Database not connected. Please connect a database.rû   TzCSet `'STORE_MODEL_IN_DB='True'` in your env to enable this feature.rŸ   rž   rÄ   rÈ   ÚupdatedÚcreated)Úenvironment_variables)rŸ   r*   r*   )ÚcreateÚupdate)r4   r9   r¼   rÊ   )r•   r–   r—   r˜   r™   z#Cache settings updated successfullyÚsuccess)rí   rì   rR   z!Error updating cache settings: %szError updating cache settings: )r©   r<   rÔ   r  r   r@   r6   r*   rd   rÍ   r^   r‹   Ú_encrypt_env_variablesr;   ra   r~   rZ   rÏ   rµ   rÛ   rÑ   r³   rq   rÓ   r   rî   )r  r˜   r™   r<   rÔ   r  r
  r–   r	  r•   r*   Úencrypted_settingsr×   r\   r]   rË   rØ   s                    r)   Úupdate_cache_settingsr  9  s_  è ø€ ÷*ñ ð ÐÜØØÐQÐRô
ð 	
ð
  Ñ$ÜØØÐbÐcô
ð 	
ð
C[ô %8¸Ó$F×$RÑ$RÐZ^Ð`nÐYoÐ$RÓ$p×pˆØ48ˆØ,.ˆØÐ#¨×(CÒ(CÜ4°\×5PÑ5PÓQˆOØ)×?Ñ?ÈÐ?Ó_ˆNØ4@Ð4L¡yÐR[ˆô !>Ô>OÐPW×PfÑPfÐhvÓ>wÓ xˆð %1×$GÑ$GÐ^lÐ$GÓ$mÐô " -Ó0×7Ñ7Ø˜Ð(ð )Ü&*§j¡jÐ1CÓ&Dñð
 %¤d§j¡jÐ1CÓ&Dðñð 8ó 
÷ 	
ð 	
ð %1×$FÑ$FÐVhÐ$FÓ$iÐð 1C×0HÑ0HÓ0J×`©¨¨1ÈaÐS_ÓN_˜q !™tÐ`ˆÑ`ð 	× Ñ ¨lÐ Ô;ô 	×0Ñ0°Ô>ð 	×3Ñ3Ô5ô -ØØ+Ø)Ø/Ø1ô
÷ 	
ð 	
ð =ØÜ+¨NÓ;ñ
ð 	
ðs qùð 	
úó$ að	
ùô ò [Ü×"Ñ"Ð#FÈÔJÜ¨Ð6UÐVWÐUXÐ4YÔZÐZûð[üsr   ‚/G8² G ÁF4ÁCG ÄF7Ä)G Å F9ÅF9ÅAG Æ F?Æ!G Æ3G8Æ4G Æ7G Æ9G Ç	G5Ç
&G0Ç0G5Ç5G8)r’   zasyncio.Task[None]r$   N)WrÜ   rª   ra   Úcollections.abcr   r   r   Útypingr   r   r   r	   Úfastapir
   r   r   r   Úpydanticr   r   r   Úlitellm._loggingr   Úlitellm._redisr   Úlitellm._uuidr   Ú0litellm.litellm_core_utils.sensitive_data_maskerr   Úlitellm.proxy._typesr   r   r   r   Ú$litellm.proxy.auth.user_api_key_authr   Ú"litellm.proxy.db.exception_handlerr   Ú'litellm.repositories.table_repositoriesr   Ú"litellm.types.management_endpointsr   r   r   Úlitellm.proxy.utilsr   r    rÝ   rY   r0   r1   r!   r#   r3   r@   rD   ÚsetÚ	frozensetrJ   rK   rL   rQ   r^   rd   rn   rq   rß   rp   rv   ry   Útupler   r…   r‹   r�   r”   r³   rµ   rá   rè   rë   rð   rV   r  Úpostr  r  r'   r+   r)   ú<module>r+     sk  ðòó Û Ý #ß 'ß 6Ó 6ç =Ó =ß 2Ñ 2å 1Ý 9Ý Ý P÷ó õ CÝ KÝ I÷ñ ñ Ý0á“€ˆÓ á(3°D¸¸f¸Ñ4EÓ(FÐ  Ó FôG�hô Gô
t˜ô tð6 ~ð 6Ð:Kó 6ò ,TÐ ˜˜s 3™x™Ó Sñ 6?Ñ>sÐ]rÔ>sÓ5sÐ ˜U 9¨S¡>Ñ2Ó sñ
 !4Ó 5Ð ˜Ó 5ð *€�Ó )ñ <EÒEsÓ;tÐ ! 5¨°3©Ñ#8Ó tð]¨G°C¸°KÑ,@ð ]ÀTÈ#ÈsÈ(Á^ó ]ð"6°ð 6¸DÀÀfÀÑ<Mó 6ð ¨¨f¨Ñ!5ð ¸$¸sÀF¸{Ñ:Kó ð, '¨#¨v¨+Ñ"6ð ¸4ÀÀVÀÑ;Ló ðZ˜cð Z dó Zð
' &ð '¨Tó 'ð5Ð ˜5  s¨C x¡Ñ1ó ð	˜ð 	 3ó 	ð¨°°V°Ñ(<ð ÀWÈSÐRXÈ[ÑEYð Ð^bó ðB' ¨¨V¨Ñ 4ð '¸WÀSÈ&À[Ñ=Qð 'ÐV]Ð^aÐciÐ^iÑVjó 'ðT
2˜w s¨F {Ñ3°dÑ:ð 
2¸tÀCÈÀKÑ?Pó 
2ó
Zð(6àð(6ð ˜S &˜[Ñ)¨DÑ0ð(6ð ˜C ˜KÑ(¨4Ñ/ð	(6ð
 &ð(6ð ˜d™
ð(6ð 
ó(6÷VXFñ XFôvk˜Iô kôd�yô dô^˜	ô ^ôT ô Tð ‡�ØØ
Ð	ÙÐ+Ó,Ð-Ø(ð	 ó ñ )0Ð0AÓ(Bñ9[Ø%ò9[óð9[ðx ‡�ØØ
Ð	ÙÐ+Ó,Ð-Ø$ð	 ó ñ )0Ð0AÓ(Bñ4
Øð4
à%ò4
óð4
ðn ‡�ØØ
Ð	ÙÐ+Ó,Ð-ð ó ñ )0Ð0AÓ(BÙ%+Øð tô&ñe[Ø'ðe[à%ðe[ð ˜d™
òe[óñ
e[r+   