Ë
    tPêjþ  ã                  ó  — d Z ddlmZ ddlZddlZddlmZ ddlmZ ddl	m	Z	m
Z
 ddlmZ ddlmZmZmZ dd	lmZ erdd
lmZ  edd¬«       G d„ d«      «       Zdd„Z	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Z	 d	 	 	 	 	 	 	 dd„Zy)a  
Tool usage tracking for the dashboard.

At request time the spend writer builds one ToolUsageTransaction per request that
invoked tools (MCP namespaced tool name plus response tool_calls; declared-but-not-
invoked tools are excluded) and queues it on the prisma client. The spend-log flush
job drains the queue into LiteLLM_SpendLogToolIndex (per-request drill-down) and
LiteLLM_DailyToolSpend (the per-day rollup the Cost Optimization card reads) in a
single transaction, so a failed flush never leaves a partial rollup increment.
é    )ÚannotationsN)ÚSequence)Ú	dataclass)ÚdatetimeÚtimezone)Úgroupby)ÚTYPE_CHECKINGÚAnyÚFinal)ÚDB_RETRY_SAFE_ERROR_TYPES)ÚPrismaClientT)ÚfrozenÚslotsc                  óJ   — e Zd ZU ded<   ded<   ded<   ded<   ded	<   d
ed<   y)ÚToolUsageTransactionÚstrÚ
request_idÚdater   Ú
start_timeútuple[str, ...]Ú
tool_namesÚfloatÚspendÚintÚtotal_tokensN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    új/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/db/spend_log_tool_index.pyr   r      s#   … àƒOØ
ƒIØÓØÓØƒLØÔr!   r   c                ór   ‡‡— | �t        | t        «      ryddlm} t	        ˆˆfd„ || d¬«      D «       «      S )a<  Tool names invoked in a completion response, in call order, for any response
    surface get_tool_calls_from_response understands (chat completions, Responses
    API output items, Anthropic Messages tool_use blocks). Reads every choice of
    an ``n>1`` chat response: each choice cost money and its tool calls ran.r    r   )Úget_tool_calls_from_responsec              3  óˆ   •K  — | ]9  }t        |j                  d «      xŠt        «      r‰j                  «       xŠr‰–— Œ; y­w)ÚnameN)Ú
isinstanceÚgetr   Ústrip)Ú.0Ú	tool_callr&   Ústrippeds     €€r"   ú	<genexpr>z+response_tool_call_names.<locals>.<genexpr>1   sA   øè ø€ ò àÜ˜iŸm™m¨FÓ3Ð3�d´SÔ9È4Ï:É:Ë<Ð?W¸xÐ?Wô 	ñùs   ƒ?AT)Úinclude_all_choices)r'   Ú	ExceptionÚ3litellm.litellm_core_utils.prompt_templates.factoryr$   Útuple)Úcompletion_responser$   r&   r,   s     @@r"   Úresponse_tool_call_namesr3   &   sB   ù€ ð
 Ð"¤jÐ1DÄiÔ&PØõô ô á5Ð6IÐ_cÔdôó ð r!   c                óà  — |r!|j                  «       r|j                  «       fnd}|rt        ddd|iigi«      nd}t        t        j	                  |t        |«      z   |z   «      «      }	|	sy	 t        j                  |j                  dd«      «      }
t        | |j                  d«      d	   |
j                  r|
n|
j                  t        j                  ¬
«      |	||¬«      S # t        $ r Y yw xY w)aµ  None when the request invoked no tools. Realtime sessions carry invoked
    tools in kwargs["realtime_tool_calls"] (OpenAI tool_calls shape) rather than
    on a response object, so they are normalized through the same owner by
    wrapping them in the chat-completion shape. Date derivation must match the
    daily spend writer's ``startTime.split("T")[0]`` so rollup rows land in the
    same UTC day bucket as LiteLLM_DailyUserSpend.r    ÚchoicesÚmessageÚ
tool_callsNÚZz+00:00ÚTr   )Útzinfo)r   r   r   r   r   r   )r)   r3   r1   ÚdictÚfromkeysr   ÚfromisoformatÚreplaceÚ
ValueErrorr   Úsplitr:   r   Úutc)r   Ústart_time_isoÚmcp_namespaced_tool_namer   r   r2   Úrealtime_tool_callsÚ	mcp_namesÚrealtime_namesr   r   s              r"   Úbuild_tool_usage_transactionrG   8   s  € ñ  0HÐLd×LjÑLjÔLlÐ	!×	'Ñ	'Ó	)Ñ+Ðrtð ñ
 ô 	! )¨y¸<ÐI\Ð:]Ð.^Ð-_Ð!`Ôaàð ô
 œdŸm™m¨IÔ8PÐQdÓ8eÑ,eÐhvÑ,vÓwÓx€JÙØðÜ$×2Ñ2°>×3IÑ3IÈ#ÈxÓ3XÓYˆ
ô  ØØ×!Ñ! #Ó& qÑ)Ø!+×!2Ò!2‘:¸
×8JÑ8JÔRZ×R^ÑR^Ð8JÓ8_ØØØ!ôð øô ò Ùðús   Á-%C! Ã!	C-Ã,C-c              ƒ  ót  K  — |sy|D ��cg c]-  }|j                   D ]  }|j                  ||j                  dœ‘Œ Œ/ }}}t        d„ |D «       d„ ¬«      }t	        |dz   «      D ]ã  }	 | j
                  j                  «       4 ƒd{  –—† }|j                  j                  |d¬«       t        |d	„ ¬«      D ]~  \  \  }	}}
t        |
«      }t        d
„ |D «       «      }t        d„ |D «       «      }|j                  j                  d|	|dœi|	|||t        |«      dœd|id|idt        |«      idœdœ¬«       Œ€ ddd«      ƒd{  –—†   y yc c}}w 7 ŒÊ7 Œ# 1 ƒd{  –—†7  sw Y    yxY w# t        $ rB ||k\  r‚ t!        j"                  d|z  t%        j&                  dd«      z   «      ƒ d{  –—†7   Y �ŒQw xY w­w)aE  Write index rows and rollup upserts for a drained queue batch in one
    transaction. Retries only ConnectError, the one failure that proves the
    statements never reached the database. Post-send failures (Read timeouts
    and errors) are ambiguous and are NOT retried: the engine can abandon the
    transaction open on the pooled connection, so a retry's statements stack
    into the same transaction and one commit applies both increment sets.
    Ambiguous failures drop the batch; the caller logs it at error. Callers
    must not add their own retry around this function.N)r   Ú	tool_namer   c              3  ó†   K  — | ]9  }|j                   D ](  }|j                  ||j                  |j                  f–— Œ* Œ; y ­w©N)r   r   r   r   )r*   ÚtxnrI   s      r"   r-   z0flush_tool_usage_transactions.<locals>.<genexpr>v   s<   è ø€ ÒtÀÐeh×esÑesÒtÐXaˆ#�(‰(�I˜sŸy™y¨#×*:Ñ*:Ô	;ÐtÐ	;Ñtùs   ‚?Ac                ó   — | d   | d   fS ©Nr   é   r    ©Úentrys    r"   ú<lambda>z/flush_tool_usage_transactions.<locals>.<lambda>w   s   € ˜5 ™8 U¨1¡XÐ.€ r!   )ÚkeyrO   T)ÚdataÚskip_duplicatesc                ó   — | d   | d   fS rN   r    rP   s    r"   rR   z/flush_tool_usage_transactions.<locals>.<lambda>~   s   € Ð_dÐefÑ_gÐinÐopÑiqÐ^r€ r!   c              3  ó&   K  — | ]	  }|d    –— Œ y­w)é   Nr    ©r*   rQ   s     r"   r-   z0flush_tool_usage_transactions.<locals>.<genexpr>€   s   è ø€ Ò>¨U  a¥Ñ>ùó   ‚c              3  ó&   K  — | ]	  }|d    –— Œ y­w)é   Nr    rY   s     r"   r-   z0flush_tool_usage_transactions.<locals>.<genexpr>�   s   è ø€ Ò&E°E u¨Q¥xÑ&EùrZ   Údate_tool_name)r   rI   )r   rI   r   r   Úrequest_countÚ	increment)r   r   r^   )ÚcreateÚupdate)ÚwhererT   rX   r   )r   r   r   ÚsortedÚrangeÚdbÚbatch_Úlitellm_spendlogtoolindexÚcreate_manyr   r1   ÚsumÚlitellm_dailytoolspendÚupsertÚlenr   ÚasyncioÚsleepÚrandomÚuniform)Úprisma_clientÚtransactionsÚn_retry_timesrL   rI   Ú
index_rowsÚper_tool_dayÚattemptÚbatcherÚdate_keyÚgroupedÚentriesr   r   s                 r"   Úflush_tool_usage_transactionsr{   `   sï  è ø€ ñ Øð  ÷àØŸ™òð ð —~‘~°IÈSÏ^É^Ó\ðØ\ð€Jñ ô
 !ÙtÀ|ÔtÙ.ô€Lô
 ˜¨Ñ*Ó+ò Cˆð	CØ$×'Ñ'×.Ñ.Ó0÷ ð °GØ×1Ñ1×=Ñ=À:Ð_cÐ=ÔdÜ6=¸lÑPrÔ6sò Ñ2Ñ)�X˜y¨7Ü# G›n�GÜÑ>°gÔ>Ó>�EÜ#&Ñ&E¸WÔ&EÓ#E�LØ×2Ñ2×9Ñ9Ø/¸(ÐQZÑ1[Ð\ð )1Ø-6Ø).Ø0<Ü14°W³ñ'ð +6°uÐ)=Ø1<¸lÐ0KØ2=¼sÀ7»|Ð1Lñ'ñð :õ ð	÷÷ ñ. ñ3Cùóðøð ø÷ ÷ ð ñ. ûÜ(ò 	CØ˜-Ò'ØÜ—-‘-  7¡
¬V¯^©^¸A¸qÓ-AÑ AÓB×BÔBð	Cüs•   ‚	F8‹2E
½)F8Á'E*ÂEÂE*Â	B-EÄ6E*ÅEÅE*Å
F8ÅE*ÅE*ÅE'	ÅEÅE'	Å"E*Å%F8Å'E*Å*AF5Æ+F.Æ,F5Æ1F8Æ4F5Æ5F8)r2   ÚobjectÚreturnr   rK   )r   r   rB   r   rC   z
str | Noner   r   r   r   r2   r|   rD   r
   r}   zToolUsageTransaction | None)r\   )rq   r   rr   zSequence[ToolUsageTransaction]rs   r   r}   ÚNone)Ú__doc__Ú
__future__r   rm   ro   Úcollections.abcr   Údataclassesr   r   r   Ú	itertoolsr   Útypingr	   r
   r   Úlitellm.proxy._typesr   Úlitellm.proxy.utilsr   r   r3   rG   r{   r    r!   r"   ú<module>r‡      sß   ðñ	õ #ã Û Ý $Ý !ß 'Ý ß ,Ñ ,å :áÝ0ñ �$˜dÔ#÷ð ó $ðóð2  $ð%Øð%àð%ð )ð%ð ð	%ð
 ð%ð  ð%ð ð%ð !ó%ðV ð7CØð7Cà0ð7Cð ð7Cð 
ô	7Cr!   