
    9ih                       d dl mZ d dlZd dlZd dlZd dlZd dlmZ d dlm	Z	m
Z
mZmZmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZmZmZ e	rd d
lmZ  edede
f         Z ej<                  e      Z ddZ!ddZ"ddZ#d dZ$d!dZ%d"dZ&d#dZ'	 	 d$	 	 	 	 	 	 	 	 	 d%dZ( G d ded      Z)eddd	 	 	 	 	 	 	 d&d       Z*y)'    )annotationsN)Mapping)TYPE_CHECKINGAnyCallableOptionalTypeVarUnion)	TypedDict)client)run_helpers)	warn_beta)InputTokenDetailsOutputTokenDetailsUsageMetadata)genaiCzgenai.Client)boundc                \    | j                         D ci c]  \  }}|	|| c}}S c c}}w )z%Remove `None` values from dictionary.)items)dkvs      d/var/www/html/backtest/airagagent/rag_env/lib/python3.12/site-packages/langsmith/wrappers/_gemini.py_strip_noner      s(    WWY8TQ!-AqD888s   
((c                X    d| v r&t        | d   t              st        | d         | d<   yyy)zFConvert `GenerateContentConfig` to `dict` for LangSmith compatibility.configN)
isinstancedictvars)kwargss    r   _convert_config_for_tracingr"   $   s5    6*VH-=t"Dx 01x #E    c                *   | j                  d      }|s| S t        |t              rAd|dg| j                  d      d| j                         D ci c]  \  }}|dvs|| c}}S t        |t              rt        d |D              rN|D cg c]  }d|d	 c}| j                  d      d| j                         D ci c]  \  }}|dvs|| c}}S g }|D ]_  }t        |t              s|j                  dd      }|j                  d	g       }g }	g }
|D ]  }t        |t              rd
|v r1|d
   r,|	j                  |d
          |
j                  d
|d
   d       Jd|v r~|d   }|j                  dd      }|j                  dd      }t        |t              r%t        j                  |      j                  d      }n|}|
j                  dd| d| ddd       d|v r=|d   }|
j                  d|j                  d      |j                  di       dd       d|v sd|v s|j                  d      xs |j                  d      }|?t        |t              s|j                         }|
j                  d|j                  d       |j                  d      |j                  d!i       d"d#       t        |t              s|	j                  |       |
j                  d
|d        |
r$t        d$ |
D              rd%j                  |	      }n|
r|
nd&}|j                  ||d       b || j                  d      d| j                         D ci c]  \  }}|dvs|| c}}S | S c c}}w c c}w c c}}w c c}}w )'u  Process Gemini inputs to normalize them for LangSmith tracing.

    Example:
        ```txt
        {"contents": "Hello", "model": "gemini-pro"}
        → {"messages": [{"role": "user", "content": "Hello"}], "model": "gemini-pro"}
        {"contents": [{"role": "user", "parts": [{"text": "What is AI?"}]}], "model": "gemini-pro"}
        → {"messages": [{"role": "user", "content": "What is AI?"}], "model": "gemini-pro"}
        ```
    contentsuser)rolecontentmodel)messagesr)   )r%   r)   c              3  <   K   | ]  }t        |t                y w)N)r   str).0items     r   	<genexpr>z)_process_gemini_inputs.<locals>.<genexpr>E   s     :z$$:s   r'   partstexttyper1   inline_data	mime_type
image/jpegdatar#   utf-8	image_urldata:;base64,highurldetailr3   r9   functionResponsefunction_responsenameresponse)rC   rD   )r3   rB   function_callfunctionCallidargsrG   rC   	argumentsr3   rE   c              3  D   K   | ]  }|j                  d       dk(    yw)r3   r1   N)get)r-   ps     r   r/   z)_process_gemini_inputs.<locals>.<genexpr>   s"      )01AEE&MV+)s    
 )rM   r   r,   r   listallr   appendbytesbase64	b64encodedecodeto_dictjoin)inputsr%   r   r   r.   r*   r(   r'   r0   
text_partscontent_partspartr4   r5   r7   data_b64rB   rE   message_contents                      r   _process_gemini_inputsr`   *   s    zz*%H (C "(X>?ZZ(
 "(RA1<Q3Q1R
 	
 (D!::: LTT4f>TG, &,\\^VTQq@U7UAqDV   V	LG'4({{662GR0  
 "! AMD!$-!T>d6l&--d6l;)00&$v,1WX*d2*.}*=K(3\(RI#.??63#?D  *$6+1+;+;D+A+H+H+Q+/)00,716yk(/T282&!" 047045G0H-)00,?0A0E0Ef0M4E4I4I,65*:&!"
 -4$8N,0HH_,E - .JM  -8'1-'F4A4I4I4KM - 4 40?2?2C2CD2I4A4E4Ef4M9F9J9J6SU9V:*%&	!" $D#."))$/%,,fd-KLCAMH !S )5B) & IM		"IO 8Em"O/ JKmV	Lp !ZZ(
 "(RA1<Q3Q1R
 	
 M[ S UV| Ss*   M>M>NN	N	%N2Nc                8   t        |       }|j                  di       }t        |d      r'|j                  }t	        |dd      }t	        |dd      }n3|j                  d      }|j                  d      }|j                  d      }dd|j                  d      |||d	S )
z*Extract invocation parameters for tracing.r   temperaturemax_output_tokensNstop_sequencesgooglechatr)   )ls_providerls_model_typels_model_namels_temperaturels_max_tokensls_stop)r   rM   hasattrrb   getattr)r!   strippedr   rb   
max_tokensstops         r   _infer_invocation_paramsrr      s    6"H\\(B'F v}%((V%8$?
v/6jj/ZZ 34
zz*+  !g.%# r#   c                   | j                  d      xs d}| j                  d      xs d}| j                  d      xs d}| j                  d      xs d}| j                  d      xs ||z   }i }|r||d<   i }|r||d<   t        |||t        d
i |j                         D 	ci c]  \  }}	|		||	 c}	}t	        d
i |j                         D 	ci c]  \  }}	|		||	 c}	}	      S c c}	}w c c}	}w )z2Convert Gemini usage metadata to LangSmith format.prompt_token_countr   candidates_token_countcached_content_token_countthoughts_token_counttotal_token_count
cache_read	reasoning)input_tokensoutput_tokenstotal_tokensinput_token_detailsoutput_token_details )rM   r   r   r   r   )
gemini_usage_metadatart   ru   rv   rw   rx   r~   r   r   r   s
             r   _create_usage_metadatar      s4   .223GHMA2667OPUTU!!">?D1  1445KLQPQ!!"56 	7 66 
 !#!,FL)!#,@[)',&- 
 3 9 9 ;M1q}q!tM
 0 
 4 : : <N1q!tN

 

 N Os   !
C+,C+
C1C1c                   	 t        | d      r| j                         }n5t        | d      r| j                         }ndt        | dt	        |             i}d}g }d}d|v r|d   r~|d   d   }d|v r|d   }d	|v rX|d	   rR|d	   D ]I  }d|v r%|d   r ||d   z  }|j                  d|d   d
       -d|v r|d   ~|d   }|j                  dd      }	|j                  dd      }
t        |
t              r%t        j                  |
      j                  d      }n|
}|j                  dd|	 d| ddd       d|v sd|v s|j                  d      xs |j                  d      }|t        |t              s|j                         }|j                  d|j                  d      |j                  d      |j                  di       dd       L d|v r(|d   r#|d   }nd|v r|d   }|j                  d|d
       |D cg c]  }|j                  d      dk(  s| }}|rh|xs dd |t        |      D cg c]G  \  }}|d   j                  d      xs d!| d"||d   d   t        j                  |d   d#         d$d%I c}}d&}n(t!        |      d'kD  s|r|d   d   dk7  r|d |d(}n|d |d(}|j                  d)      }t#        ddd*      }|rot%        |      }t'        j(                         }|rN	 |j*                  j-                  d+i       j-                  d)i       }|j/                  |       |j1                          |j                  d-      r|d   d ||d-   |d.S t        |d   t              r
|d   d ||d/S |d   d ||d/S c c}w c c}}w # t2        $ r"}t4        j7                  d,|        Y d}~wd}~ww xY w# t2        $ r&}t4        j9                  d0|        d1| icY d}~S d}~ww xY w)2z$Process Gemini response for tracing.rX   
model_dumpr1   rP   N
candidatesr   r(   r0   r2   r4   r5   r6   r7   r#   r8   r9   r:   r;   r<   r=   r@   rE   rF   rG   rC   rH   rI   rK   finish_reasonr3   	assistantcall_functionrJ   )rC   rJ   )rG   r3   indexr   )r(   r'   r   
tool_calls   )r(   r'   r   usage_metadatar{   r|   r}   metadata!Failed to update usage metadata: r   )r(   r'   r   r   r   )r(   r'   r   r   z"Error processing Gemini response: output)rm   rX   r   rn   r,   rS   rM   r   rT   rU   rV   rW   r   	enumeratejsondumpslenr   r   r   get_current_run_treeextra
setdefaultupdatepatch	Exceptionloggerwarningdebug)rD   rdictcontent_resultr\   r   	candidater(   r]   r4   r5   r7   r^   rE   rN   r   itcresultr   
usage_dictcurrent_runmetaes                          r   "_process_generate_content_responser      s   ]$8Y'$$&EX|,'')EWXvs8}EFE '+5 U<%8l+A.II%#I.g%''*: ' 0 ."!T>d6l*d6l:N)00&$v,1WX*d2tM7J7V*.}*=K(3\(RI#.??63#?D  *$6+1+;+;D+A+H+H+Q+/)00,716yk(/T282&!" -4$8N,0HH_,E - .JM  -8'1-'F4A4I4I4KM - 4 40?2?2C2CD2I4A4E4Ef4M9F9J9J6SU9V:*%&	!"K."^ #i/Io4N$-o$>Mu_"6]N  &.!IJ "/SA!%%-?2RaS
S *1T#!. "+:!6 2 !155d;Jqc{ *!"$&$7$?)-B4G4T)U%		F" !#mA.v6&@ )#!.F *#!.F #34$1!!%

 /?J%::<KL&,,77
BGRR("D KK
+%%'
 ::l# "),#!.$\2",  &+S1%i0'%2&0	   &i0'%2&0	 [ T\ ! LNN%Fqc#JKKL<  $9!=>(##$s   EO &O +BO NN"O ;ANA1O 9AN O %O 	O O 	O N=8O =OO 	O4O/)O4/O4c           	        | sdt        ddd      dS d}d}| D ],  }	 t        |d      r|j                  r||j                  z  }|}. t        ddd      }|r]	 t        |d      rO|j                  rBt        |j                  d	      r|j                  j                         }nt        |j                  d
      r|j                  j                         }nqt        |j                  dd      t        |j                  dd      t        |j                  dd      t        |j                  dd      t        |j                  dd      d}t        |      }t        j                         }|rN	 |j                  j                  di       j                  di       }|j                  |       |j!                          ||dS # t        $ r#}t        j                  d|        Y d}~d}~ww xY w# t        $ r"}t        j#                  d|        Y d}~Zd}~ww xY w# t        $ r"}t        j                  d|        Y d}~d}~ww xY w)z/Reduce streaming chunks into a single response.rP   r   r   )r(   r   Nr1   zError processing chunk: r   rX   r   rt   ru   rv   rw   rx   )rt   ru   rv   rw   rx   r   r   z+Error extracting metadata from last chunk: )r   rm   r1   r   r   r   r   rX   r   rn   r   r   r   r   r   r   r   r   )	
all_chunks	full_text
last_chunkchunkr   r   r   r   r   s	            r   _reduce_generate_content_chunksr     sR   +aa
 	
 IJ 9	9uf%%**UZZ'	J	9 %2aa%N %	Lz#349R9R:44i@!+!:!:!B!B!DJZ66E!+!:!:!E!E!GJ /6&557KQ/ 3:&557OQR3 7>&557SUV7 18&557Mq1 .5&557JA."J$ "8
!C)>>@P*00;;JKVV,b  N3#))+ ( a  	9LL3A3788	9T % P)J1#'NOOP 	LLLFqcJKK	LsU   )F<DH *AG+ <	G(G##G(+	H4HH HH 	I"H??IFc                     |xs i t        j                          fd       }t        j                          fd       }t        j                         r|S |S )z9Create a wrapper for Gemini's `generate_content` methods.c            
         t        |       t        j                  ddrt        nd t        st
        nd t        d}  |      | i |S Nllm)rC   run_type	reduce_fnprocess_inputsprocess_outputs_invocation_params_fnr   r"   r   	traceabler   r`   r   rr   rH   r!   	decoratoris_streamingrC   original_generatetextras      r   generatez_get_wrapper.<locals>.generate  sb     	$F+)) 

9E541:F2D":

 

	 ,y*+T<V<<r#   c            
        K   t        |       t        j                  ddrt        nd t        st
        nd t        d}  |      | i | d {   S 7 wr   r   r   s      r   	ageneratez_get_wrapper.<locals>.agenerate  sl      	$F+)) 

9E541:F2D":

 

	 2Y014B6BBBBs   AAAA)	functoolswrapsr   is_async)r   rC   tracing_extrar   r   r   r   s   `` `  @r   _get_wrapperr     sf      bF__&'= (=$ __&'C (C$ $,,->?9MXMr#   c                  ,    e Zd ZU ded<   ded<   ded<   y)TracingExtrazOptional[Mapping[str, Any]]r   zOptional[list[str]]tagszOptional[ls_client.Client]r   N)__name__
__module____qualname____annotations__r   r#   r   r   r     s    ))
&&r#   r   )totalChatGoogleGenerativeAI)r   	chat_namec                  |xs i }t        | d      rAt        | j                  d      r+t        | j                  j                  d      rt        d      t        | d      rHt        | j                  d      r2t	        | j                  j                  ||d      | j                  _        t        | d      rHt        | j                  d      r2t	        | j                  j
                  ||d      | j                  _        t        | d	      r|t        | j                  d      rft        | j                  j                  d      rFt	        | j                  j                  j                  ||d      | j                  j                  _        t        | d	      r|t        | j                  d      rft        | j                  j                  d      rFt	        | j                  j                  j
                  ||d      | j                  j                  _        | S )
a  Patch the Google Gen AI client to make it traceable.

    !!! warning

        **BETA**: This wrapper is in beta.

    Supports:
        - `generate_content` and `generate_content_stream` methods
        - Sync and async clients
        - Streaming and non-streaming responses
        - Tool/function calling with proper UI rendering
        - Multimodal inputs (text + images)
        - Image generation with `inline_data` support
        - Token usage tracking including reasoning tokens

    Args:
        client: The Google Gen AI client to patch.
        tracing_extra: Extra tracing information.
        chat_name: The run name for the chat endpoint.

    Returns:
        The patched client.

    Example:
        ```python
        from google import genai
        from google.genai import types
        from langsmith import wrappers

        # Use Google Gen AI client same as you normally would.
        client = wrappers.wrap_gemini(genai.Client(api_key="your-api-key"))

        # Basic text generation:
        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents="Why is the sky blue?",
        )
        print(response.text)

        # Streaming:
        for chunk in client.models.generate_content_stream(
            model="gemini-2.5-flash",
            contents="Tell me a story",
        ):
            print(chunk.text, end="")

        # Tool/Function calling:
        schedule_meeting_function = {
            "name": "schedule_meeting",
            "description": "Schedules a meeting with specified attendees.",
            "parameters": {
                "type": "object",
                "properties": {
                    "attendees": {"type": "array", "items": {"type": "string"}},
                    "date": {"type": "string"},
                    "time": {"type": "string"},
                    "topic": {"type": "string"},
                },
                "required": ["attendees", "date", "time", "topic"],
            },
        }

        tools = types.Tool(function_declarations=[schedule_meeting_function])
        config = types.GenerateContentConfig(tools=[tools])

        response = client.models.generate_content(
            model="gemini-2.5-flash",
            contents="Schedule a meeting with Bob and Alice tomorrow at 2 PM.",
            config=config,
        )

        # Image generation:
        response = client.models.generate_content(
            model="gemini-2.5-flash-image",
            contents=["Create a picture of a futuristic city"],
        )

        # Save generated image
        from io import BytesIO
        from PIL import Image

        for part in response.candidates[0].content.parts:
            if part.inline_data is not None:
                image = Image.open(BytesIO(part.inline_data.data))
                image.save("generated_image.png")
        ```

    !!! version-added "Added in `langsmith` 0.4.33"

        Initial beta release of Google Gemini wrapper.

    modelsgenerate_content__wrapped__zfThis Google Gen AI client has already been wrapped. Wrapping a client multiple times is not supported.F)r   r   generate_content_streamTaio)rm   r   r   
ValueErrorr   r   r   )r   r   r   s      r   wrap_geminir     s   F "'RM 	!FMM#56FMM22MBA
 	
 vx WV]]<N%O)5MM**'	*
& vx WV]]<U%V0<MM11'	1
- 	FJJ)FJJ%%'9:-9JJ..'	.


* 	FJJ)FJJ%%'@A4@JJ55'	5


1 Mr#   )r   r   returnr   )r!   r   r   None)rZ   r   r   r   )r!   r   r   r   )r   r   r   r   )rD   r   r   r   )r   rQ   r   r   )NF)
r   r   rC   r,   r   Optional[TracingExtra]r   boolr   r   )r   r   r   r   r   r,   r   r   )+
__future__r   rU   r   r   loggingcollections.abcr   typingr   r   r   r   r	   r
   typing_extensionsr   	langsmithr   	ls_clientr   #langsmith._internal._beta_decoratorr   langsmith.schemasr   r   r   re   r   r   	getLoggerr   r   r   r"   r`   rr   r   r   r   r   r   r   r   r#   r   <module>r      s%   "     #  ( ) ! 9 R RCu^S012			8	$9
2BJ2D_$DFX -1	/N/N
/N */N 	/N
 /Nd'9E '  -1-	YY *Y 	Y
 Y Yr#   