Ë
    tPêjd8  ã                  ó<  — U d Z ddlmZ ddlZddlmZ ddlmZmZ ddl	m
Z
 ddlmZmZmZ ddlmZ dd	lmZmZmZ d
dlmZmZ dZded<   dZded<    G d„ de«      Z G d„ de«      Z G d„ de«      Z G d„ de«      Zd d„Zd!d„Z d"d„Z!d#d„Z"d$d„Z# G d„ de«      Z$y)%uè   Mavvrik GCS destination for FOCUS export.

Flow:
  1. GET /metrics/agent/ai/{connection_id}/upload-url â†’ GCS signed URL
  2. PUT <signed_url> with CSV content
  3. PATCH /metrics/agent/ai/{connection_id} â†’ advance metricsMarker
é    )ÚannotationsN)ÚMapping)ÚFinalÚProtocol)Úurlparse)ÚNotRequiredÚReadOnlyÚ	TypedDict)Úverbose_logger)ÚAsyncHTTPHandlerÚget_async_httpx_clientÚhttpxSpecialProvideré   )ÚFocusDestinationÚFocusTimeWindow)z.mavvrik.devz.mavvrik.aiz.mavvrik.appr   Ú_MAVVRIK_ALLOWED_SUFFIXESi  € Ú_GCS_CHUNK_SIZEc                  ó   — e Zd ZU ded<   y)ÚMavvrikRegisterBodyz ReadOnly[NotRequired[int | str]]ÚmetricsMarkerN©Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    ú€/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/focus/destinations/mavvrik_destination.pyr   r   "   s   … Ø3Ô3r   r   c                  ó   — e Zd ZU ded<   y)ÚMavvrikUploadUrlBodyzReadOnly[NotRequired[str]]ÚurlNr   r   r   r   r    r    &   s   … Ø	#Ô#r   r    c                  ó   — e Zd Zdd„Zy)Ú_RegisterResponsec                 ó   — y ©Nr   ©Úselfs    r   Újsonz_RegisterResponse.json+   ó   � r   N)Úreturnr   ©r   r   r   r(   r   r   r   r#   r#   *   s   „ Ü.r   r#   c                  ó   — e Zd Zdd„Zy)Ú_UploadUrlResponsec                 ó   — y r%   r   r&   s    r   r(   z_UploadUrlResponse.json/   r)   r   N)r*   r    r+   r   r   r   r-   r-   .   s   „ Ü/r   r-   c                ó"   — | j                  «       S r%   ©r(   ©Úresponses    r   Ú_register_bodyr3   2   ó   € Ø�=‰=‹?Ðr   c                ó"   — | j                  «       S r%   r0   r1   s    r   Ú_upload_url_bodyr6   6   r4   r   c                ó$   — | j                  |«      S r%   )Úget)ÚheadersÚnames     r   Ú_header_valuer;   :   s   € Ø�;‰;�tÓÐr   c                óÒ   ‡— | j                  d«      st        d«      ‚t        | «      j                  xs dj	                  «       Št        ˆfd„t        D «       «      st        d«      ‚y )Nzhttps://z)MAVVRIK_API_ENDPOINT must be an HTTPS URLÚ c              3  ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wr%   )Úendswith)Ú.0ÚsuffixÚhostnames     €r   ú	<genexpr>z)_validate_api_endpoint.<locals>.<genexpr>B   s   øè ø€ ÒQ¨Vˆx× Ñ  ×(ÑQùs   ƒz]MAVVRIK_API_ENDPOINT host must be a Mavvrik domain (e.g. https://api.mavvrik.dev/<tenant_id>))Ú
startswithÚ
ValueErrorr   rB   ÚlowerÚanyr   )Úapi_endpointrB   s    @r   Ú_validate_api_endpointrI   >   s`   ø€ Ø×"Ñ" :Ô.ÜÐDÓEÐEÜ Ó-×6Ñ6Ò<¸"×CÑCÓE€HÜÓQÔ7PÔQÔQÜØkó
ð 	
ð Rr   c                óþ   — t        | «      }|j                  dk7  rt        d|› d|j                  › d�«      ‚|j                  xs dj	                  «       }|dk(  s$|j                  d«      st        d|› d|› d�«      ‚y y )	NÚhttpszMavvrik FOCUS destination: z must be HTTPS, got scheme 'ú'r=   zstorage.googleapis.comz.storage.googleapis.comz7 must be a GCS endpoint (storage.googleapis.com), got ')r   ÚschemerE   rB   rF   r?   )r!   ÚlabelÚparsedrB   s       r   Ú_validate_gcs_urlrP   H   s–   € Ü˜S“M€FØ‡}�}˜ÒÜÐ6°u°gÐ=YÐZ`×ZgÑZgÐYhÐhiÐjÓkÐkØ—‘Ò,¨"×3Ñ3Ó5€HØÐ0Ò0°H×4EÑ4EÐF_Ô4`ÜØ)¨%¨Ð0gÐhpÐgqÐqrÐsó
ð 	
ð 5aÐ0r   c                  óž   — e Zd ZdZddœ	 	 	 	 	 dd„Zedd„«       Zedd„«       Zedd„«       Zdd„Z	dd	„Z
dd
„Zdd„Zdd„Z	 	 	 	 	 	 	 	 dd„Zy)ÚFocusMavvrikDestinationz7Upload FOCUS CSV exports to Mavvrik via GCS signed URL.N)Úconfigc               ó|  — |xs i }|j                  d«      }|j                  d«      }|j                  d«      }|st        d«      ‚|st        d«      ‚|st        d«      ‚t        |«       || _        |j	                  d«      | _        || _        || _        t        t        j                  ¬«      | _        d	| _        y )
NÚapi_keyrH   Úconnection_idzzMAVVRIK_API_KEY must be provided for Mavvrik FOCUS destination (set MAVVRIK_API_KEY env var or pass in destination_config)z„MAVVRIK_API_ENDPOINT must be provided for Mavvrik FOCUS destination (set MAVVRIK_API_ENDPOINT env var or pass in destination_config)z†MAVVRIK_CONNECTION_ID must be provided for Mavvrik FOCUS destination (set MAVVRIK_CONNECTION_ID env var or pass in destination_config)ú/)Úllm_providerF)r8   rE   rI   rU   ÚrstriprH   rV   Úprefixr   r   ÚLoggingCallbackÚ_httpÚ_registered)r'   rZ   rS   Úresolved_configrU   rH   rV   s          r   Ú__init__z FocusMavvrikDestination.__init__V   sÑ   € ð 5;²L¸bˆØ(×,Ñ,¨YÓ7ˆØ-×1Ñ1°.ÓAˆØ.×2Ñ2°?ÓCˆáÜðNóð ñ ÜðSóð ñ ÜðTóð ô
 	˜|Ô,àˆŒØ(×/Ñ/°Ó4ˆÔØ*ˆÔØˆŒÜ'=ÔK_×KoÑKoÔ'pˆŒ
Ø ˆÕr   c                ó8   — | j                   › d| j                  › �S )Nú/metrics/agent/ai/©rH   rV   r&   s    r   Ú
_agent_urlz"FocusMavvrikDestination._agent_urlz   s"   € à×#Ñ#Ð$Ð$6°t×7IÑ7IÐ6JÐKÐKr   c                ó:   — | j                   › d| j                  › d�S )Nra   z/upload-urlrb   r&   s    r   Ú_upload_url_endpointz,FocusMavvrikDestination._upload_url_endpoint~   s$   € à×#Ñ#Ð$Ð$6°t×7IÑ7IÐ6JÈ+ÐVÐVr   c                ó    — d| j                   dœS )Nzapplication/json)úContent-Typez	x-api-key)rU   r&   s    r   Ú_auth_headersz%FocusMavvrikDestination._auth_headers‚   s   € à 2ÀÇÁÑNÐNr   c              ƒ  óð  K  — | j                   ry| j                  j                  j                  d| j                  | j
                  d| j                  id¬«      ƒ d{  –—† }|j                  dk(  rd| _         t        d«      ‚|j                  d	k\  r(t        d
|j                  › d|j                  dd › �«      ‚d| _         t        |«      j                  dd«      }t        j                  d|«       |S 7 Œ–­w)u~  POST agent endpoint to register/initialize the connector (once per instance).

        Returns metricsMarker from the Mavvrik response â€” the last date index
        Mavvrik has successfully processed. Used by the logger to catch up any
        dates that were missed due to previous export failures.

        Returns None if the connector was already registered (cached).
        NÚPOSTr:   ç      >@©Úmethodr!   r9   r(   Útimeoutéš  FúnMavvrik FOCUS destination: connector is disconnected (410). Re-enable the connection in the Mavvrik dashboard.é�  ú,Mavvrik FOCUS destination: register failed (ú): éÈ   Tr   r   zBMavvrik FOCUS destination: connector registered (metricsMarker=%s))r]   r\   ÚclientÚrequestrc   rh   rV   Ústatus_codeÚRuntimeErrorÚtextr3   r8   r   Údebug©r'   ÚrespÚmetrics_markers      r   Ú_ensure_registeredz*FocusMavvrikDestination._ensure_registered†   s	  è ø€ ð ×ÒØØ ŸJ™J×-Ñ-×5Ñ5ØØ—‘Ø×&Ñ&Ø˜$×,Ñ,Ð-Øð 6ó 
÷ 
ˆð ×Ñ˜sÒ"Ø$ˆDÔÜðEóð ð ×Ñ˜sÒ"ÜÐ!MÈd×N^ÑN^ÐM_Ð_bÐcg×clÑclÐmqÐnqÐcrÐbsÐtÓuÐuØˆÔÜ .¨tÓ 4× 8Ñ 8¸È!Ó LˆÜ×ÑØPØô	
ð Ðð+
ús   ‚AC6ÁC4ÁBC6c              ƒ  óÌ  K  — |d|dœ}| j                   j                  j                  d| j                  | j                  |d¬«      ƒ d{  –—† }|j
                  dk\  r(t        d|j
                  › d	|j                  dd
 › �«      ‚t        |«      j                  d«      }|st        d|j                  «       › �«      ‚t        |d«       t        j                  d|«       |S 7 Œ—­w)u>   GET upload-url endpoint â†’ GCS signed URL for the given date.Úmetrics)r:   ÚtypeÚdatetimeÚGETrk   )rm   r!   r9   Úparamsrn   Nrq   z5Mavvrik FOCUS destination: failed to get signed URL (rs   rt   r!   z9Mavvrik FOCUS destination: response missing 'url' field: z
signed URLz5Mavvrik FOCUS destination: got signed URL for date %s)r\   ru   rv   re   rh   rw   rx   ry   r6   r8   r(   rP   r   rz   )r'   Údate_strr„   r|   Ú
signed_urls        r   Ú_get_signed_urlz'FocusMavvrikDestination._get_signed_url¨   sö   è ø€ à!)°9È(ÑSˆØ ŸJ™J×-Ñ-×5Ñ5ØØ×)Ñ)Ø×&Ñ&ØØð 6ó 
÷ 
ˆð ×Ñ˜sÒ"ÜØGÈ×HXÑHXÐGYÐY\Ð]a×]fÑ]fÐgkÐhkÐ]lÐ\mÐnóð ô -¨TÓ2×6Ñ6°uÓ=ˆ
ÙÜÐ!ZÐ[_×[dÑ[dÓ[fÐZgÐhÓiÐiÜ˜* lÔ3Ü×ÑÐTÐV^Ô_ØÐð!
ús   ‚AC$Á
C"ÁBC$c              ƒ  óŽ  K  — t        j                  |«      }t        |«      }d}| j                  j                  j                  d|dddœ|d¬«      ƒ d{  –—† }|j                  d	vr(t        d
|j                  › d|j                  dd › �«      ‚t        |j                  d«      }|st        d«      ‚t        |d«       t        j                  d|t        d| t        z   «      «       d}	 ||k  rê|||t        z    }	|t        |	«      z   dz
  }
|t        |	«      z   |k\  }|rd|› d|
› d|› �nd|› d|
› d�}|rddhndh}| j                  j                  j                  d|d|dœ|	d¬«      ƒ d{  –—† }|j                  |vr.t        d|› d|› d|j                  › d|j                  dd › �«      ‚|t        |	«      z  }t        j                  d ||«       ||k  rŒéyy7 �Œ‡7 Œp# t         $ rX 	 | j                  j                  j                  d!|d"¬#«      ƒ d{  –—†7   t        j                  d$«       ‚ # t         $ r Y ‚ w xY ww xY w­w)%uÀ  Upload gzip-compressed CSV to GCS via chunked resumable upload.

        The full CSV is gzip-compressed first, then uploaded in _GCS_CHUNK_SIZE
        chunks using the GCS resumable upload protocol. GCS assembles the chunks
        server-side into a single complete object â€” the bucket receives one file
        regardless of how many chunks were sent.

        Intermediate chunks: Content-Range: bytes X-Y/*   â†’ expect 308
        Final chunk:         Content-Range: bytes X-Y/T   â†’ expect 200/201

        This handles exports larger than available memory for a single PUT while
        keeping the destination code self-contained (no changes to the FOCUS
        pipeline upstream).
        s<   {"contentEncoding":"gzip","contentDisposition":"attachment"}rj   zapplication/gzipÚstart)rg   zx-goog-resumablerk   )rm   r!   r9   Úcontentrn   N)rt   éÉ   z4Mavvrik FOCUS destination: GCS session init failed (rs   rq   ÚLocationzCMavvrik FOCUS destination: GCS session init missing Location headerzsession URIzVMavvrik FOCUS destination: GCS session started, uploading %d gzip bytes in %d chunk(s)r   r   zbytes ú-rW   z/*rt   r‹   i4  ÚPUT)rg   zContent-Rangeg      ^@zAMavvrik FOCUS destination: GCS chunk upload failed (chunk offset=z, expected=z, got=z6Mavvrik FOCUS destination: uploaded chunk offset=%d/%dÚDELETEg      $@)rm   r!   rn   z<Mavvrik FOCUS destination: cancelled GCS session after error)ÚgzipÚcompressÚlenr\   ru   rv   rw   rx   ry   r;   r9   rP   r   rz   Úmaxr   Ú	Exception)r'   r†   rŠ   Ú
gzip_bytesÚtotalÚmetadataÚ	init_respÚsession_uriÚoffsetÚchunkÚ	chunk_endÚis_finalÚcontent_rangeÚexpected_statusesr|   s                  r   Ú_upload_to_gcsz&FocusMavvrikDestination._upload_to_gcs½   sÃ  è ø€ ô !ŸM™M¨'Ó2ˆ
Ü˜:“ˆð ZˆØ!%§¡×!2Ñ!2×!:Ñ!:ØØà 2Ø$+ñð Øð ";ó 	"
÷ 	
ˆ	ð × Ñ ¨
Ñ2ÜØFÀy×G\ÑG\ÐF]Ð]`Ðaj×aoÑaoÐptÐqtÐauÐ`vÐwóð ô +¨9×+<Ñ+<¸jÓIˆÙÜÐdÓeÐeÜ˜+ }Ô5ä×ÑØdØÜ��e�VœÑ.Ð/Ó0ô	
ð ˆð%	Ø˜5’.Ø" 6¨F´_Ñ,DÐE�Ø"¤S¨£ZÑ/°!Ñ3�	Ø"¤S¨£ZÑ/°EÑ9�ÙIQ &¨¨°°)°¸A¸e¸WÑ EÐY_Ð`fÐ_gÐghÐirÐhsÐsuÐWv�Ù2: S¨#¡JÀÀÐ!à!ŸZ™Z×.Ñ.×6Ñ6Ø Ø#à(:Ø)6ñð "Ø!ð 7ó 	÷ 	�ð ×#Ñ#Ð+<Ñ<Ü&ð)Ø)/¨°Ð<MÐ;Nð OØ#×/Ñ/Ð0°°D·I±I¸d¸s°OÐ3DðFóð ð
 œ#˜e›*Ñ$�Ü×$Ñ$ØLØØôð1 ˜5•.ð=	
ùðJ	ùô, ò 	ðØ—j‘j×'Ñ'×/Ñ/°xÀ[ÐZ^Ð/Ó_×_Ñ_Ü×$Ñ$Ð%cÔdð øô ò ØØðúð	üso   ‚AIÁGÁBIÃ,BG! Å.GÅ/A*G! ÇIÇG! Ç!	IÇ++H2ÈHÈH2È1IÈ2	H>È;IÈ=H>È>IÉIc              ƒ  ó|  K  — | j                   j                  j                  d| j                  | j                  d|id¬«      ƒ d{  –—† }|j
                  dk(  rd| _        t        d«      ‚|j
                  d	k\  r(t        d
|j
                  › d|j                  dd › �«      ‚t        j                  d|«       y7 Œs­w)zHPATCH agent endpoint to advance metricsMarker after a successful upload.ÚPATCHr   rk   rl   Nro   Frp   rq   z;Mavvrik FOCUS destination: failed to update metricsMarker (rs   rt   z7Mavvrik FOCUS destination: metricsMarker advanced to %s)r\   ru   rv   rc   rh   rw   r]   rx   ry   r   rz   )r'   Ú
date_epochr|   s      r   Ú_update_metrics_markerz.FocusMavvrikDestination._update_metrics_marker  sÒ   è ø€ à ŸJ™J×-Ñ-×5Ñ5ØØ—‘Ø×&Ñ&Ø! :Ð.Øð 6ó 
÷ 
ˆð ×Ñ˜sÒ"Ø$ˆDÔÜðEóð ð ×Ñ˜sÒ"ÜØMÈd×N^ÑN^ÐM_Ð_bÐcg×clÑclÐmqÐnqÐcrÐbsÐtóð ô 	×ÑÐVÐXbÕcð#
ús   ‚AB<ÁB:ÁA4B<c              ƒ  óÖ  K  — | j                   j                  j                  d| j                  | j                  d| j
                  id¬«      ƒ d{  –—† }|j                  dk(  rd| _        t        d«      ‚|j                  d	k\  r(t        d
|j                  › d|j                  dd › �«      ‚d| _        t        |«      j                  dd«      }t        j                  d|«       |S 7 Œ–­w)u   Register with Mavvrik and return the current metricsMarker.

        Always calls the Mavvrik register API â€” unlike deliver() which skips
        registration once _registered is True, catch-up requires a fresh
        marker value on every run.
        rj   r:   rk   rl   Nro   Frp   rq   rr   rs   rt   Tr   r   z/Mavvrik FOCUS destination: got metricsMarker=%s)r\   ru   rv   rc   rh   rV   rw   r]   rx   ry   r3   r8   r   rz   r{   s      r   Úget_metrics_markerz*FocusMavvrikDestination.get_metrics_marker*  sù   è ø€ ð !ŸJ™J×-Ñ-×5Ñ5ØØ—‘Ø×&Ñ&Ø˜$×,Ñ,Ð-Øð 6ó 
÷ 
ˆð ×Ñ˜sÒ"Ø$ˆDÔÜðEóð ð ×Ñ˜sÒ"ÜÐ!MÈd×N^ÑN^ÐM_Ð_bÐcg×clÑclÐmqÐnqÐcrÐbsÐtÓuÐuØˆÔÜ .¨tÓ 4× 8Ñ 8¸È!Ó LˆÜ×ÑÐNÐP^Ô_ØÐð%
ús   ‚AC)ÁC'ÁBC)c             ƒ  ó6  K  — |j                   j                  d«      }t        |j                   j                  «       «      }| j	                  «       ƒ d{  –—†  |s0t        j                  d|«       | j                  |«      ƒ d{  –—†  yt        j                  dt        |«      ||«       | j                  |«      ƒ d{  –—† }| j                  ||«      ƒ d{  –—†  | j                  |«      ƒ d{  –—†  t        j                  d|«       y7 Œº7 Œ‹7 ŒR7 Œ:7 Œ#­w)z€Upload FOCUS CSV to Mavvrik via GCS signed URL.

        Uses the start date of the time window as the object date key.
        z%Y-%m-%dNzFMavvrik FOCUS destination: empty content for date=%s, advancing markerz>Mavvrik FOCUS destination: uploading %d bytes for date=%s (%s)z6Mavvrik FOCUS destination: upload complete for date=%s)Ú
start_timeÚstrftimeÚintÚ	timestampr~   r   rz   r¤   r’   r‡   r    )r'   rŠ   Útime_windowÚfilenamer…   r£   r†   s          r   ÚdeliverzFocusMavvrikDestination.deliverE  s  è ø€ ð &×0Ñ0×9Ñ9¸*ÓEˆÜ × 6Ñ 6× @Ñ @Ó BÓCˆ
à×%Ñ%Ó'×'Ð'áÜ× Ñ ØXØôð ×-Ñ-¨jÓ9×9Ð9Øä×ÑØLÜ�‹LØØô		
ð #'×"6Ñ"6°xÓ"@×@ˆ
Ø×!Ñ! *¨gÓ6×6Ð6Ø×)Ñ)¨*Ó5×5Ð5ä×ÑÐUÐW_Õ`ð+ 	(øð :øð AøØ6øØ5úsZ   ‚ADÁDÁ0DÂDÂ:DÃ DÃDÃDÃDÃ3DÃ4DÄDÄDÄDÄD)rZ   ÚstrrS   zMapping[str, str] | Noner*   ÚNone)r*   r¯   )r*   zdict[str, str])r*   zint | str | None)r…   r¯   r*   r¯   )r†   r¯   rŠ   Úbytesr*   r°   )r£   rª   r*   r°   )rŠ   r±   r¬   r   r­   r¯   r*   r°   )r   r   r   Ú__doc__r_   Úpropertyrc   re   rh   r~   r‡   r    r¤   r¦   r®   r   r   r   rR   rR   S   s¿   „ ÙAð ,0ñ	"!ð ð"!ð )ð	"!ð
 
ó"!ðH òLó ðLð òWó ðWð òOó ðOó óDó*Vópdó*ð6#að ð#að %ð	#að
 ð#að 
ô#ar   rR   )r2   r#   r*   r   )r2   r-   r*   r    )r9   zMapping[str, str]r:   r¯   r*   z
str | None)rH   r¯   r*   r°   )r!   r¯   rN   r¯   r*   r°   )%r²   Ú
__future__r   r�   Úcollections.abcr   Útypingr   r   Úurllib.parser   Útyping_extensionsr   r	   r
   Úlitellm._loggingr   Ú&litellm.llms.custom_httpx.http_handlerr   r   r   Úbaser   r   r   r   r   r   r    r#   r-   r3   r6   r;   rI   rP   rR   r   r   r   ú<module>r¼      s¤   ðòõ #ã Ý #ß "Ý !ç >Ñ >å +÷ñ ÷ 4à#RÐ ˜5Ó Rð )€�Ó (ô4˜)ô 4ô$˜9ô $ô/˜ô /ô0˜ô 0óóóó
ó
ôUaÐ.õ Uar   