
    sj@              	          d Z ddlmZ ddlZddlZddl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 ddlZddlmZ ddlmZ  ej        e          Z	 ddlZ eej                  Zn# e$ r dZY nw xY wd	Z d
Z!dsdZ"dtdZ#dudZ$dvdZ%e fddddwdZ&dxdZ'dZ(	 dydzd#Z)d$Z* G d% d&e          Z+d{d)Z,d|d+Z-d}d/Z.d0Z/	 d~dd3Z0	 	 ddd7Z1	 d~dd;Z2dd=Z3dd@Z4ddBZ5ddDZ6ddFZ7dddddddddGddLZ8ddMZ9ddOZ:ddQZ;ddSZ< G dT dUe          Z=dddddVddZZ>dd^Z?ddcZ@dddddfZA G dg dh          ZB G di dj          ZC G dk dl          ZD G dm dn          ZE G do dp          ZF G dq dr          ZGdS )a  OpenAI-compatible facade over Google AI Studio's native Gemini API.

Hermes keeps ``api_mode='chat_completions'`` for the ``gemini`` provider so the
main agent loop can keep using its existing OpenAI-shaped message flow.
This adapter is the transport shim that converts those OpenAI-style
``messages[]`` / ``tools[]`` requests into Gemini's native
``models/{model}:generateContent`` schema and converts the responses back.

Why this exists
---------------
Google's OpenAI-compatible endpoint has been brittle for Hermes's multi-turn
agent/tool loop (auth churn, tool-call replay quirks, thought-signature
requirements).  The native Gemini API is the canonical path and avoids the
OpenAI-compat layer entirely.
    )annotationsN)SimpleNamespace)AnyDictIteratorListOptional)read_streaming_error_body)sanitize_gemini_tool_parametersz0.0.0z0https://generativelanguage.googleapis.com/v1betai  modelstrreturnc                    | pd                                 }|                                }dD ]D}|                    |          r-|t          |          d                                          p|c S E|S )zEStrip Gemini's own provider prefix from an aggregator-style model id. )zgoogle/zgemini/N)striplower
startswithlen)r   nameloweredprefixs       ?/home/agent/.hermes/hermes-agent/agent/gemini_native_adapter.pybare_gemini_model_idr   5   s    KR  DjjllG( 6 6f%% 	6F%++--5555	6K    Optional[int]c                    t          |                                           }t          j        d|          }|sdS 	 t	          |                    d                    S # t          $ r Y dS w xY w)uN   Extract the major version from a Gemini model id (``gemini-3.6-flash`` → 3).zgemini-(\d+)N   )r   r   rematchintgroup
ValueError)r   r   r   s      r   _gemini_major_versionr#   ?   sx    &&,,..DH_d++E t5;;q>>"""   tts   !A 
A,+A,boolc                4    t          |           }|duo|dk    S )u  Whether functionCall/functionResponse parts must carry explicit ids.

    Gemini 3+ models require explicit tool call IDs in replayed history —
    without them, multi-tool turns can be rejected or mismatched. Older
    Gemini models (2.x) reject unexpected ``id`` fields, so this is gated on
    the major version. Mirrors earendil-works/pi#7494 (their fix for the same
    class of bug in the google-shared converter).
    N   )r#   )r   versions     r   gemini_requires_tool_call_idsr(   K   s%     $E**G$/7a</r   base_urlc                    t          | pd                                                              d                                          }|sdS d|vrdS |                    d           S )z>Return True when the endpoint speaks Gemini's native REST API.r   /Fz!generativelanguage.googleapis.com/openai)r   r   rstripr   endswith)r)   
normalizeds     r   is_native_gemini_base_urlr0   X   sm    X^$$**,,33C88>>@@J u**<<u""9----r   gemini-3.6-flashg      $@)r   timeoutapi_keyr2   floatc          	     "   | pd                                 }|sdS t          |pt                                                                         d          }|st          }|                                                    d          r|dt          d                    }| d| d}dd	d
igdgddid}	 t          j        |          5 }|	                    |d|i|ddt           d          }	ddd           n# 1 swxY w Y   n3# t          $ r&}
t                              d|
           Y d}
~
dS d}
~
ww xY wd |	j                                        D             }|                    d          }|r>	 t#          |          }n# t$          t&          f$ r d}Y nw xY w||dk    rdS ||dk    rdS |	j        dk    r9d}	 |	j        pd}n# t          $ r d}Y nw xY wd|                                v rdS dS d|	j        cxk    rdk     rn ndS dS )a  Probe a Google AI Studio API key and return its tier.

    Returns one of:

    - ``"free"``    -- key is on the free tier (unusable with Hermes)
    - ``"paid"``    -- key is on a paid tier
    - ``"unknown"`` -- probe failed; callers should proceed without blocking.
    r   unknownr+   r,   N/models/:generateContentusertexthirolepartsmaxOutputTokensr   )contentsgenerationConfigr2   keyapplication/jsonhermes-agent/)Content-TypeX-Goog-Api-Client)paramsjsonheadersz$probe_gemini_tier: network error: %sc                >    i | ]\  }}|                                 |S  r   ).0kvs      r   
<dictcomp>z%probe_gemini_tier.<locals>.<dictcomp>   s&    CCCdaQWWYYCCCr   z"x-ratelimit-limit-requests-per-dayi  freepaid  	free_tier   i,  )r   r   DEFAULT_GEMINI_BASE_URLr-   r   r.   r   httpxClientpost_HERMES_VERSION	ExceptionloggerdebugrJ   itemsgetr    	TypeErrorr"   status_coder:   )r3   r)   r   r2   rC   normalized_baseurlpayloadclientrespexcheaders_lower
rpd_headerrpd_val	body_texts                  r   probe_gemini_tierrm   b   s    =b


!
!C y(=&=>>DDFFMMcRRO 21''	22 =)*;S^^O*;<
=
=e
=
=
=C$/?@@A.2 G
\'*** 		f;;s|$6)J)J)J 	   D		 		 		 		 		 		 		 		 		 		 		 		 		 		 		    ;SAAAyyyyy DCdl.@.@.B.BCCCM""#GHHJ 	*ooGG:& 	 	 	GGG	
 7d??67T>>63			RII 	 	 	III	)//++++6v
d$$$$$$$$$v9s`   5D	 
'C=1D	 =DD	 DD	 	
D9D44D97F FF	G GGerror_messagec                6    | sdS d|                                  v S )zEReturn True when a Gemini 429 message indicates free-tier exhaustion.FrU   rM   )rn   s    r   is_free_tier_quota_errorrp      s&     u---////r   at  

Your Google API key is on the free tier (a few hundred requests/day for Gemini Flash models). Hermes typically makes 3-10 API calls per user turn, so the free tier is exhausted in a handful of messages and cannot sustain an agent session. Enable billing on your Google Cloud project and regenerate the key in a billing-enabled project: https://aistudio.google.com/apikeyr   statusr    reasonc                R    | dk    rdS |dk    rdS d|pd                                 v S )a  Return True when a Gemini 401 indicates Google rejected the key TYPE.

    Google began rejecting unrestricted legacy "Standard" Google Cloud API
    keys on the Gemini API on June 19, 2026, and ALL Standard keys stop
    working in September 2026. The rejection surfaces as a misleading 401
    telling the user to supply an OAuth 2 access token ("Request had invalid
    authentication credentials. Expected OAuth 2 access token, login cookie
    or other valid authentication credential."), optionally carrying
    ``google.rpc.ErrorInfo`` reason ``ACCESS_TOKEN_TYPE_UNSUPPORTED``.

    Scoped narrowly so a plain bad key (reason ``API_KEY_INVALID``,
    "API key not valid") keeps its existing message.
      FACCESS_TOKEN_TYPE_UNSUPPORTEDTzexpected oauth 2 access tokenr   rM   )rq   rn   rr   s      r   is_standard_key_auth_errorrv      s?      }}u000t*}/B.I.I.K.KKKr   u=  

Google Gemini rejected this API key's type — you do NOT need OAuth. Google began rejecting legacy 'Standard' Google Cloud keys for the Gemini API on June 19, 2026, and all Standard keys stop working in September 2026. Open https://aistudio.google.com/api-keys, check the key's type and status, and create a replacement Gemini API key (or, as a temporary bridge, restrict the Standard key to generativelanguage.googleapis.com). Then update GEMINI_API_KEY / GOOGLE_API_KEY in ~/.hermes/.env and restart your session. Details: https://ai.google.dev/gemini-api/docs/api-keyc                  2     e Zd ZdZddddddd fdZ xZS )GeminiAPIErrorz>Error shape compatible with Hermes retry/error classification.gemini_api_errorNcoderb   responseretry_afterdetailsmessager   r{   rb   r   r|   Optional[httpx.Response]r}   Optional[float]r~   Optional[Dict[str, Any]]r   Nonec                   t                                          |           || _        || _        || _        || _        |pi | _        d S N)super__init__r{   rb   r|   r}   r~   )selfr   r{   rb   r|   r}   r~   	__class__s          r   r   zGeminiAPIError.__init__   sJ     	!!!	& &}"r   )r   r   r{   r   rb   r   r|   r   r}   r   r~   r   r   r   )__name__
__module____qualname____doc__r   __classcell__)r   s   @r   rx   rx      s^        HH '%)-1'+,0% % % % % % % % % % % %r   rx   contentr   c                   | dS t          | t                    r| S t          | t                    rg }| D ]}t          |t                    r|                    |           -t          |t                    rX|                    d          dk    r?|                    d          }t          |t                    r|                    |           d                    |          S t          |           S )Nr   typer:   
)
isinstancer   listappenddictr`   join)r   piecespartr:   s       r   _coerce_content_to_textr      s    r'3 '4   	! 	( 	(D$$$ (d####D$'' (DHHV,<,<,F,Fxx''dC(( (MM$'''yy   w<<r   List[Dict[str, Any]]c                   t          | t                    st          |           }|rd|igng S g }| D ]}t          |t                    r|                    d|i           0t          |t
                    sF|                    d          }|dk    rD|                    d          }t          |t                    r|r|                    d|i           |dk    r|                    d          pi                     d          pd}t          |t                    r|                    d          s	 |                    dd          \  }}|                    d	d          d                             d
d          d         }t          j
        |          }	n# t          $ r Y vw xY w|                    d|t          j        |	                              d          di           |S )Nr:   r   	image_urlrd   r   zdata:,r   :;r   
inlineDataascii)mimeTypedata)r   r   r   r   r   r   r`   r   splitbase64	b64decoder\   	b64encodedecode)
r   r:   r>   itemptyperd   headerencodedmimeraws
             r   _extract_multimodal_partsr     s   gt$$ 0&w//#'/R/"$E  dC   	LL&$((($%% 	  F??88F##D$$$ - -fd^,,,k!!HH[))/R44U;;ArCc3'' s~~g/F/F "%))C"3"3||C++A.44S!<<Q?&w//   LL $( & 0 5 5 < <W E E# #   Ls   7A#F
F)(F)	tool_callDict[str, Any]Optional[str]c                   |                      d          pi }t          |t                    sd S |                     d          p|                     d          }t          |t                    rR|                     d          p|                     d          }t          |t                    r|rt          |          nd S t          |t                    r|r|S d S )Nextra_contentgooglethought_signaturethoughtSignature)r`   r   r   r   )r   extrar   sigs       r   _tool_call_extra_signaturer   1  s    MM/**0bEeT"" tYYx  BEII.A$B$BF&$ Bjj,--O<N1O1O%c3//ACAs3xxxTA&# 6 4r   z<[The previous response was interrupted before it completed.]Finclude_idsc                0   |                      d          pi }|                     dd          }	 t          |t                    r|rt          j        |          ni }n# t          j        $ r d|i}Y nw xY wt          |t                    sd|i}dt          |                     d          pd          |di}|rFt          |                      d	          p|                      d
          pd          }|r||d         d	<   t          |           }|pd|d<   |S )Nfunction	argumentsr   _raw_valuefunctionCallr   )r   argsidcall_id skip_thought_signature_validatorr   )r`   r   r   rI   loadsJSONDecodeErrorr   r   )r   r   fnargs_rawr   r   tool_call_idr   s           r   _translate_tool_call_to_geminir   H  sP    
z	"	"	(bBvvk2&&H"'1(C'@'@UXUtz(###SU " " "!"dD!!  $ 	v,"--
 
D  6 9==..P)--	2J2JPbQQ 	6)5D &29==  1V4VD	Ks   -A A32A3r   tool_name_by_call_idOptional[Dict[str, str]]c                   |pi }t          |                     d          pd          }t          |                    |          p|                     d          p|pd          }t          |                     d                    }	 |                                                    d          rt          j        |          nd }n# t
          j        $ r d }Y nw xY wt          |t                    r|nd|i}||d}|r|r||d	<   d
|iS )Nr   r   r   toolr   ){[output)r   r|   r   functionResponse)
r   r`   r   r   r   rI   r   r   r   r   )	r   r   r   r   r   r   parsedr|   function_responses	            r    _translate_tool_result_to_geminir   k  sF   
 052w{{>228b99L
   .. 	;;v		 	 D &gkk)&<&<==G(/(B(B:(N(NXG$$$TX   #FD11Jvv'7JH) )  /| /".$ 122s   =C CCmessagesinclude_tool_call_ids5tuple[List[Dict[str, Any]], Optional[Dict[str, Any]]]c           	     t   g }g }i }| D ]}t          |t                    st          |                    d          pd          }|dk    r6|                    t          |                    d                               y|dv r*|                    dt          |||          gd           |dk    rd	nd}g }t          |                    d                    }	|                    |	           |                    d
          pg }
t          |
t                    r|
D ]}t          |t                    rt          |                    d          p|                    d          pd          }t          |                    d          pi                     d          pd          }|r|r|||<   |                    t          ||                     |r|                    ||d           g }|D ]}t          |o|d         d         |d         k              }|r|d         dk    rt          d |d                             dg           D                       }t          d |                    dg           D                       }||k    r"d}|                    d	dt          igd           |r(|d         d                             |d                    |                    |           |}d }d                    d |D                                                       }|rdd|igd}||fS )Nr=   r9   systemr   >   r   r   )r   r   r<   	assistantr   
tool_callsr   r   r   r   r   )r   c              3  H   K   | ]}t          |t                    od |v V  dS r   Nr   r   rN   r   s     r   	<genexpr>z)_build_gemini_contents.<locals>.<genexpr>  sK       1 1 4&&E+=+E1 1 1 1 1 1r   r>   c              3  H   K   | ]}t          |t                    od |v V  dS r   r   r   s     r   r   z)_build_gemini_contents.<locals>.<genexpr>  sK       0 0 4&&E+=+E0 0 0 0 0 0r   Fr:   r   c              3     K   | ]}||V  	d S r   rL   r   s     r   r   z)_build_gemini_contents.<locals>.<genexpr>  s'      IItDIdIIIIIIr   )r   r   r   r`   r   r   r   r   extendr   r   r$   any!_INTERRUPTED_RESPONSE_PLACEHOLDERr   r   )r   r   system_text_partsr@   r   msgr=   gemini_roler>   content_partsr   r   r   	tool_namemerged_contentsr   	same_roleprevious_has_function_responsecurrent_has_function_responsesystem_instructionjoined_systems                        r   _build_gemini_contentsr     s    $&%'H+- -C -C#t$$ 	3776??,f--8$$%<SWWY=O=O%P%PQQQ'''OO"81E(=  	 	   !%!4!4gg&&(1#'')2D2DEE]###WW\**0b
j$'' 	' 
 
	i.. 	#&y}}T':':'\immI>V>V'\Z\#]#]L #immJ&?&?&E2%J%J6%R%R%XVX Z ZI# G	 G=F,\:LL6%3H      	COO[5AABBB* -/O , ,N 3F ;wv N
 
	  	F22-0 1 1+B/33GR@@1 1 1 . .* -0 0 0#KK440 0 0 - -) .1NNN!	&& '#)+L"M!N     	,B(//0@AAAA""7++++HIIII/@IIIIIOOQQM T&.6=:Q9RSS'''r   toolsc                <   t          | t                    sg S g }| D ]}t          |t                    s|                    d          pi }t          |t                    sE|                    d          }t          |t                    r|srd|i}|                    d          }t          |t                    r|r||d<   |                    d          }t          |t                    rt          |          |d<   |                    |           |rd|igng S )Nr   r   description
parametersfunctionDeclarations)r   r   r   r`   r   r   r   )r   declarationsr   r   r   declr   r   s           r   _translate_tools_to_geminir     s;   eT"" 	)+L " "$%% 	XXj!!'R"d## 	vvf~~$$$ 	D 	 &~ff]++k3'' 	.K 	."-DVVL))
j$'' 	M!@!L!LDD!!!!7CK#\233Kr   tool_choicer   c                @   | d S t          | t                    r$| dk    rdddiiS | dk    rdddiiS | dk    rdddiiS t          | t                    rK|                     d	          pi }|                    d
          }t          |t                    r
|rdd|gdiS d S )NautofunctionCallingConfigmodeAUTOrequiredANYnoneNONEr   r   )r  allowedFunctionNames)r   r   r   r`   )r   r   r   s      r    _translate_tool_choice_to_geminir	    s    t+s## ?&  +ff-=>>*$$+fe_==&  +ff-=>>+t$$ ^__Z((.Bvvf~~dC   	^T 	^+eVZU[-\-\]]4r   configc                j   t          | t                    r| sd S |                     d|                     d                    }|                     d|                     d                    }|                     d|                     d                    }i }t          |t          t          f          rt          |          |d<   t          |t
                    r||d<   t          |t                    r=|                                r)|                                                                |d<   |pd S )NthinkingBudgetthinking_budgetincludeThoughtsinclude_thoughtsthinkingLevelthinking_level)	r   r   r`   r    r4   r$   r   r   r   )r
  budgetincludelevelr/   s        r   _normalize_thinking_configr  #  s   fd## 6 tZZ(&**5F*G*GHHFjj*FJJ7I,J,JKKGJJ

3C(D(DEEE!#J&3,'' 3'*6{{
#$'4   0(/
$%% <%++-- <&+kkmm&9&9&;&;
?#r   thinking_configc                   t          |           }|sdS |                    d          du r&d|v p!t          |                    d                    S |                    d          }t          |t                    r|dk    rd|vrdS dS )ax  Return True when Gemini will spend output tokens on thinking.

    Gemini bills thought tokens against ``maxOutputTokens``. A global
    Hermes ``max_tokens`` of 4096/16384 is enough for visible text, but
    Ultra/high thinking can consume the entire budget and leave
    ``finishReason=MAX_TOKENS`` with no complete answer. Continuations
    then abort after 4 retries.
    Fr  r  r  r   T)r  r`   r$   r   r    )r  r/   r  s      r   "_thinking_requests_output_headroomr  3  s     ,O<<J u~~'((E11*,VZ^^DT5U5U0V0VV^^,--F&# 6Q;;?*3T3Tu4r   
max_tokensc                    | t           S 	 t          |           }n# t          t          f$ r
 t           cY S w xY w|dk    rt           S t	          |          rt          |t                     S |S )u@  Resolve native ``maxOutputTokens``.

    Gemini's generateContent API does not treat an omitted cap as
    unlimited — it applies a low internal default and truncates. When
    thinking is enabled, also raise a too-small explicit cap to the
    published 65,535 ceiling so thought tokens do not starve the answer.
    Nr   ) GEMINI_DEFAULT_MAX_OUTPUT_TOKENSr    ra   r"   r  max)r  r  	requesteds      r   #_effective_gemini_max_output_tokensr  G  s     //0
OO		z" 0 0 0////0A~~//)/:: @9>???s    66)r   r   temperaturer  top_pstopr  r   r  r   r   r!  c        	           t          | t          |                    \  }	}
d|	i}|
r|
|d<   t          |          }|r||d<   t          |          }|r||d<   i }|||d<   t	          ||          |d<   |||d<   |r*t          |t                    r|nt          |          g|d	<   t          |          }|r||d
<   |r||d<   |S )N)r   r@   systemInstructionr   
toolConfigr  r?   topPstopSequencesthinkingConfigrA   )	r   r(   r   r	  r  r   r   r   r  )r   r   r   r  r  r   r!  r  r   r@   r   requestgemini_toolstool_configgeneration_confignormalized_thinkings                   r   build_gemini_requestr-  ^  s=    $:;EBB$ $ $ H   *84G :'9#$-e44L ('2;??K , +(*+6-(+NO, ,'( $)&! ]5?d5K5K-\TTRUVZR[R[Q\/*4_EE B.A*+ 8&7"#Nr   c                    dddddd}|                     t          | pd                                          d          S )Nr!  lengthcontent_filter)STOP
MAX_TOKENSSAFETY
RECITATIONOTHERr   )r`   r   upper)rr   mappings     r   _map_gemini_finish_reasonr8    sK    "& G ;;s6<R((..00&999r   r   c                j    |                      d          }t          |t                    r|rdd|iiS d S )Nr   r   r   )r`   r   r   )r   r   s     r   _tool_call_extra_from_partr:    sC    
((%
&
&C#s 6 6.4554r   r   c                <   t          ddd d d d           }t          d|d          }t          dddt          d                    }t          d	t          j                    j        d d
          dt	          t          j                              | |g|          S )Nr   r   r=   r   r   	reasoningreasoning_contentreasoning_detailsr   r!  indexr   finish_reasoncached_tokensprompt_tokenscompletion_tokenstotal_tokensprompt_tokens_details	chatcmpl-   chat.completionr   objectcreatedr   choicesusage)r   uuiduuid4hexr    time)r   r   choicerQ  s       r   _empty_responserW    s      G 1gVLLLF-A>>>	  E .tz||',.. DIKK     r   rg   c                	   |                      d          pg }t          |t                    r|st          |          S t          |d         t                    r|d         ni }t          |t                    r|                     d          ni }t          |t                    r|                     d          ng }g }g }g }t          |pg           D ]\  }	}
t          |
t                    s|
                     d          du rDt          |
                     d          t                    r|                    |
d                    wt          |
                     d          t                    r|                    |
d                    |
                     d          }t          |t                    r1|                     d	          r	 t          j	        |                     d
          pi d          }n# t          t          f$ r d}Y nw xY wt          t          |                     d          t                    r*|                     d          rt          |d                   n"dt          j                    j        d d          d|	t          t          |d	                   |                    }t!          |
          }|r||_        |                    |           |rdn0t%          t          |                     d          pd                    }|                      d          pi }t          t'          |                     d          pd          t'          |                     d          pd          t'          |                     d          pd          t          t'          |                     d          pd                              }d                    |          pd }t          d|rd                    |          nd |pd ||d           }t          d||           }t          d!t          j                    j        d d          d"t'          t+          j                              ||g|#          S )$N
candidatesr   r   r>   thoughtTr:   r   r   r   F)ensure_ascii{}r   call_rK  r   r   r   )r   r   rA  r   r   finishReasonr   usageMetadatapromptTokenCountcandidatesTokenCounttotalTokenCountcachedContentTokenCountrC  rE  r   r<  r@  rJ  rL  rM  )r`   r   r   rW  r   	enumerater   r   rI   dumpsra   r"   r   rR  rS  rT  r:  r   r8  r    r   rU  )rg   r   rY  candcontent_objr>   text_piecesreasoning_piecesr   rA  r   fcargs_strr   r   rB  
usage_metarQ  r=  r   rV  s                        r   translate_gemini_responsern    se   ,''-2Jj$'' &z &u%%%&z!}d;;C:a==D)3D$)?)?G$((9%%%RK(2;(E(EMKOOG$$$2EK"$(*J "-- ) )t$%% 	88I$&&:dhhv6F6F+L+L&##DL111dhhv&&,, 	tF|,,,XXn%%b$ 	)BFF6NN 	) :bffVnn&:OOOz*       ' ""&&,,4499;9C4MMM8!1#2#!688(c"V*ooRRR	 	 	I 7t<<M 8*7	'i((($.rLL4McRVRZRZ[iRjRjRpnpNqNq4r4rM/**0bJ*..);<<ABBjnn-CDDIJJ(9::?a@@-jnn-FGGL1MM
 
 
	  E ())1TI(3=$$$%#  G 1g]SSSF.tz||',.. DIKK     s   +G;;HHc                      e Zd ZdS )_GeminiStreamChunkN)r   r   r   rL   r   r   rp  rp    s        Dr   rp  )r   tool_call_deltarB  r=  rq  rB  r=  c                   dd d d d d}|r||d<   |t          |                    dd          |                    d          p"dt          j                    j        d d          d	t          |                    d
          pd|                    d          pd                    }|                    d          }t          |t                    r||_        |g|d<   |r
||d<   ||d<   t          di |}t          d||          }	t          dt          j                    j        d d          dt          t          j
                              | |	gd           S )Nr   )r=   r   r   r=  r>  r   rA  r   r   r]  rK  r   r   r   r   r^  )rA  r   r   r   r   r   r=  r>  )rA  deltarB  rJ  zchat.completion.chunkrM  rL   )r   r`   rR  rS  rT  r   r   r   rp  r    rU  )
r   r   rq  rB  r=  delta_kwargs
tool_deltar   rs  rV  s
             r   _make_stream_chunkrv    s    !$ $L  *")Y"$!%%gq11""4((K,KDJLL4DSbS4I,K,K$$((006B)--k::@b  	
 
 

 (++O<<mT** 	5'4J$&0\\" 6$-[!,5()++l++E1EOOOF.tz||',..&DIKK     r   r|   httpx.ResponseIterator[Dict[str, Any]]c              #    K   d}|                                  D ]}|s||z  }d|v r|                    dd          \  }}|                    d          }|s5|                    d          sK|dd          }|dk    r d S 	 t	          j        |          }n8# t          j        $ r& t                              d|d d	                    Y w xY wt          |t                    r|V  d|v Ōd S )
Nr   r   r   zdata:    z[DONE]zNon-JSON Gemini SSE line: %srV   )	iter_textr   r-   r   rI   r   r   r]   r^   r   r   )r|   bufferchunkliner   re   s         r   _iter_sse_eventsr  4  s5     F##%%   	%fnn!<<a00LD&;;t$$D ??8,, 8Dx*T**'   ;T$3$ZHHH '4(( ! fnn	 s   B2CCeventtool_call_indicesDict[str, Dict[str, Any]]List[_GeminiStreamChunk]c                	   |                      d          pg }|sg S t          |d         t                    r|d         ni }t          |t                    r,|                     d          pi                      d          pg ng }g }t          |          D ]\  }}t          |t                    s|                     d          du rSt          |                     d          t                    r+|                    t          ||d                              t          |                     d          t                    r2|d         r*|                    t          ||d         	                     |                     d
          }	t          |	t                    r|	                     d          rt	          |	d                   }
	 t          j        |	                     d          pi dd          }n# t          t          f$ r d}Y nw xY wt          |                     d          t                    r|                     d          nd}t          j        ||
|dd          }|                     |          }|t          |          t          |	                     d          t                    r*|	                     d          rt	          |	d                   n"dt          j                    j        d d          dd}|||<   |}t	          |                     d          pd          }|r5||k    rd}n,|                    |          r|t          |          d          }||d<   |                    t          ||d         |d         |
|t!          |          d                     t	          |                     d          pd          }|r |rdnt#          |          }t          ||          }|                      d          pi }|rt%          t'          |                     d           pd          t'          |                     d!          pd          t'          |                     d"          pd          t%          t'          |                     d#          pd          $          %          |_        |                    |           |S )&NrY  r   r   r>   rZ  Tr:   )r   r=  )r   r   r   r   r   F)r[  	sort_keysr\  r   r   )
part_indexr   r   )r  r   r]  rK  )rA  r   last_argumentsr  rA  )rA  r   r   r   r   )r   rq  r_  r   )r   rB  r`  ra  rb  rc  rd  rC  rE  )r`   r   r   re  r   r   rv  rI   rf  ra   r"   r   rR  rS  rT  r   r:  r8  r   r    rQ  )r  r   r  rY  rg  r>   chunksr  r   rk  r   rl  r   call_keyslotemitted_argumentsr  finish_reason_rawmappedfinish_chunkrm  s                        r   translate_stream_eventr  M  s   <((.BJ 	&z!}d;;C:a==D@J4QU@V@V^dhhy!!'R,,W55;\^E')F%e,, 7 7
D$%% 	88I$&&:dhhv6F6F+L+L&MM,5DLQQQRRRdhhv&&,, 	Qf 	QMM,5$v,OOOPPPXXn%%b$ .	BFF6NN .	r&z??D :bffVnn&:Z^___z*       @J488TfKgKgil@m@m u); < < <suz", ): 
   H %((22D| !233 &bffTllC88==?VVD\\=BtH<TZ\\%5crc%:<<&(  /3!(+ ( *:!;!;!ArBBN G~--(*%%((88 G(0^1D1D1E1E(F%%-D!"MM"!%g"4j $%6)CD)I)I% %	 	 	   DHH^44:;; $!2d8QRc8d8d)VLLL YY//52
 	!0!*..1C"D"D"IJJ"%jnn5K&L&L&QPQ"R"R 0A!B!B!GaHH&5"%jnn5N&O&O&TST"U"U' ' '	" " "L 	l###Ms   ,G99HHrl   rl   c                  | j         }i }|	 | j        }n# t          $ r d}Y nw xY w|pd}|rF	 t          j        |          }t          |t                    r|}n# t          t          f$ r i }Y nw xY wt          |t                    r|	                    d          nd }t          |t                    si }t          |	                    d          pd                                          }t          |	                    d          pd                                          }|	                    d          }t          |t                    r|ng }	d}
d }i }|	D ]}t          |t                    st          |	                    d          pd          }|
sm|                    d          rX|	                    d          }t          |t                    r|}
|	                    d	          }t          |t                    r|}| j        	                    d
          p| j        	                    d          }|r*	 t          |          }n# t          t          f$ r d }Y nw xY wd| }|dk    rd}n|dk    rd}n|dk    rd}|rd| d|pd d| }nd| d|d d          }|dk    rt!          |p|          r
|t"          z   }t%          ||p||
          r
|t&          z   }t)          |||| |||
||d          S )Nr   errorrq   r   r~   z@typez/google.rpc.ErrorInforr   metadatazRetry-Afterzretry-aftergemini_http_rt   gemini_unauthorizedrT   gemini_rate_limitedi  gemini_model_not_foundzGemini HTTP z (z): zGemini returned HTTP z: i  )rq   rr   r  r   rz   )rb   r:   r\   rI   r   r   r   r"   ra   r`   r   r   r   r.   rJ   r4   rp   _FREE_TIER_GUIDANCErv   _STANDARD_KEY_GUIDANCErx   )r|   rl   rq   	body_jsonr   err_obj
err_statuserr_message_raw_detailsdetails_listrr   r}   r  detailtype_urlreason_valuemdheader_retryr{   r   s                       r   gemini_http_errorr    s    !F "I	 II 	 	 	III	RI 	Z	**F&$'' #"	I& 	 	 	III	 )39d(C(CMimmG$$$Ggt$$ W[[**0b117799Jgkk),,23399;;K;;y))L#-lD#A#AI<<rLF#'K!H 
 
&$'' 	vzz'**0b11 	(++,CDD 	!::h//L,,, &%J''B"d## #''66](:J:N:N}:]:]L 	--KK:& 	 	 	KKK	 #&""D}}$	3$	3' FRRR:+@RR[RRE&EEIdsdOEE
 }}1+2JKK}//
 "&+*BFKK 322  "	
 
   s/    $$+A A0/A0;I I! I!c                      e Zd Zd	dZd
dZdS )_GeminiChatCompletionsrf   'GeminiNativeClient'c                    || _         d S r   _clientr   rf   s     r   r   z_GeminiChatCompletions.__init__      r   kwargsr   r   c                &     | j         j        di |S NrL   r  _create_chat_completionr   r  s     r   createz_GeminiChatCompletions.create  s    3t|3==f===r   Nrf   r  r  r   r   r   r   r   r   r   r  rL   r   r   r  r    s<           > > > > > >r   r  c                      e Zd Zd	dZd
dZdS )_AsyncGeminiChatCompletionsrf   'AsyncGeminiNativeClient'c                    || _         d S r   r  r  s     r   r   z$_AsyncGeminiChatCompletions.__init__  r  r   r  r   r   c                6   K    | j         j        di | d {V S r  r  r  s     r   r  z"_AsyncGeminiChatCompletions.create  s3      9T\9CCFCCCCCCCCCr   Nrf   r  r  r  rL   r   r   r  r    sB           D D D D D Dr   r  c                      e Zd ZddZdS )_GeminiChatNamespacerf   r  c                .    t          |          | _        d S r   )r  completionsr  s     r   r   z_GeminiChatNamespace.__init__  s    1&99r   Nr  r   r   r   r   rL   r   r   r  r    s(        : : : : : :r   r  c                      e Zd ZddZdS )_AsyncGeminiChatNamespacerf   r  c                .    t          |          | _        d S r   )r  r  r  s     r   r   z"_AsyncGeminiChatNamespace.__init__  s    6v>>r   Nr  r  rL   r   r   r  r    s(        ? ? ? ? ? ?r   r  c                      e Zd ZdZdddddd2dZd3dZd Zd Zd4dZe	d5d            Z
ddddddddddddd6d-Zdd.d7d1ZdS )8GeminiNativeClientzCMinimal OpenAI-SDK-compatible facade over Gemini's native REST API.N)r)   default_headersr2   http_clientr3   r   r)   r   r  r   r2   r   r  Optional[httpx.Client]_r   r   c                  |pd                                 st          d          || _        |pt                              d          }|                    d          r|d t          d                    }|| _        t          |pi           | _	        t          |           | _        d| _        |p,t          j        |pt          j        dddd	          
          | _        d S )Nr   zGemini native client requires an API key, but none was provided. Set GOOGLE_API_KEY or GEMINI_API_KEY in your environment / ~/.hermes/.env (get one at https://aistudio.google.com/app/apikey), or run `hermes setup` to configure the Google provider.r+   r,   Fg      .@g     @g      >@)connectreadwritepoolrB   )r   RuntimeErrorr3   rW   r-   r.   r   r)   r   _default_headersr  chat	is_closedrX   rY   Timeout_http)r   r3   r)   r  r2   r  r  rc   s           r   r   zGeminiNativeClient.__init__  s     2$$&& 	4   #>'>FFsKK##I.. 	A-.?Y.?@O' $_%: ; ;(..	  
EL]u}TTX\]]]%
 %
 %



r   c                j    d| _         	 | j                                         d S # t          $ r Y d S w xY w)NT)r  r  closer\   r   s    r   r  zGeminiNativeClient.close5  sJ    	J 	 	 	DD	s   $ 
22c                    | S r   rL   r  s    r   	__enter__zGeminiNativeClient.__enter__<  s    r   c                .    |                                   d S r   )r  )r   exc_typeexc_valexc_tbs       r   __exit__zGeminiNativeClient.__exit__?  s    

r   Dict[str, str]c                v    dd| j         dt           ddt           d}|                    | j                   |S )NrD   rE   z (gemini-native))rF   Acceptzx-goog-api-keyz
User-AgentrG   )r3   r[   updater  )r   rJ   s     r   _headerszGeminiNativeClient._headersB  sQ    .("l L/KKK!B!B!B	
 	
 	t,---r   iteratorIterator[_GeminiStreamChunk])tuple[bool, Optional[_GeminiStreamChunk]]c                H    	 dt          |           fS # t          $ r Y dS w xY w)NF)TN)nextStopIteration)r  s    r   _advance_stream_iteratorz+GeminiNativeClient._advance_stream_iteratorP  s:    	$x..(( 	 	 	::	s    
!!r1   F)r   r   streamr   r   r  r  r   r!  
extra_bodyr2   r   r   Optional[List[Dict[str, Any]]]r  r$   r   r   r  r   r  r   r   r!  r  r   c               b   d }t          |
t                    r*|
                    d          p|
                    d          }t          |pg ||||||	||	  	        }t	          |          }|r|                     |||          S | j         d| d}| j                            ||| 	                                |          }|j
        dk    rt          |          	 |                                }n.# t          $ r!}t          d	| d
|j
        |          |d }~ww xY wt          ||          S )Nr  r'  )	r   r   r   r  r  r   r!  r  r   )r   r(  r2   r7   r8   rI   rJ   r2   rV   z%Invalid JSON from Gemini native API: gemini_invalid_json)r{   rb   r|   )r   )r   r   r`   r-  r   _stream_completionr)   r  rZ   r  rb   r  rI   r"   rx   rn  )r   r   r   r  r   r   r  r  r   r!  r  r2   r  r  r(  rd   r|   re   rh   s                      r   r  z*GeminiNativeClient._create_chat_completionW  sz     j$'' 	d(nn->??c:>>RbCcCcO&^##!+

 

 

 %U++ 	Z**QX*YYY?????:??3WdmmooW^?__3&&#H---	mmooGG 	 	 	 ===*$0!	  
 	 )>>>>s   C2 2
D<DDrB   r(  r   c                     j          d dt                                                     dd<   d fd} |            S )	Nr7   z:streamGenerateContent?alt=sseztext/event-streamr  r   r  c               3    K   	 j                             d	
          5 } | j        dk    r t          |           }t	          | |          i }t          |           D ]}t          ||          D ]}|V  	 d d d            d S # 1 swxY w Y   d S # t          j        $ r}t          d| d          |d }~ww xY w)NPOSTr  rV   r  z!Gemini streaming request failed: gemini_stream_error)r{   )
r  r  rb   r
   r  r  r  rX   	HTTPErrorrx   )r|   rl   r  r  r~  rh   r   r(  r   stream_headersr2   rd   s         r   
_generatorz9GeminiNativeClient._stream_completion.<locals>._generator  sY     Z&&vs.bi&jj (nv+s22$=h$G$G	/INNNNCE%!1(!;!; ( (%;E5J[%\%\ ( (E"'KKKK((( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ?   $===.   s;   B AB
=B 
BB BB C &B;;C )r   r  )r)   r   r  )r   r   r(  r2   r  r  rd   s   ```` @@r   r  z%GeminiNativeClient._stream_completion  s    MMMMMdmmoo..#6x 	 	 	 	 	 	 	 	 	 	 	  z||r   )r3   r   r)   r   r  r   r2   r   r  r  r  r   r   r   r   r   )r   r  )r  r  r   r  )r   r   r   r  r  r$   r   r   r   r   r  r   r  r   r   r   r!  r   r  r   r2   r   r  r   r   r   )r   r   r(  r   r2   r   r   r  )r   r   r   r   r   r  r  r  r  staticmethodr  r  r  rL   r   r   r  r    s       MM #'48.2
 
 
 
 
 
:              \ (37'+$(!%/31? 1? 1? 1? 1? 1?f Y]        r   r  c                  *    e Zd ZdZddZddZdd
ZdS )AsyncGeminiNativeClientz?Async wrapper used by auxiliary_client for native Gemini calls.sync_clientr  c                z    || _         |j        | _        |j        | _        t          |           | _        || _        d S r   )_syncr3   r)   r  r  _real_client)r   r   s     r   r   z AsyncGeminiNativeClient.__init__  s<     
"*#,-d33	 (r   r  r   r   c                    K   t          |                    d                    }t          j         j        j        j        j        fi | d {V |sS d fd} |            S )Nr  r   r   c                n   K   	 t          j        j        j                   d {V \  } }| rd S |W V  2r   )asyncio	to_threadr  r  )doner~  resultr   s     r   _async_streamzFAsyncGeminiNativeClient._create_chat_completion.<locals>._async_stream  sW      $+$5dj6Y[a$b$bbbbbbbe E	r   )r   r   )r$   r`   r  r  r  r  r  r  )r   r  r  r
  r	  s   `   @r   r  z/AsyncGeminiNativeClient._create_chat_completion  s      fjj**++()D)KVVvVVVVVVVV 	M	 	 	 	 	 	 	 }r   r   c                R   K   t          j        | j        j                   d {V  d S r   )r  r  r  r  r  s    r   r  zAsyncGeminiNativeClient.close  s4      
 011111111111r   N)r   r  r  r  )r   r   r   r   r   r  r  rL   r   r   r  r    sV        II
( 
( 
( 
(   2 2 2 2 2 2r   r  )r   r   r   r   )r   r   r   r   )r   r   r   r$   )r)   r   r   r$   )
r3   r   r)   r   r   r   r2   r4   r   r   )rn   r   r   r$   )r   )rq   r    rn   r   rr   r   r   r$   )r   r   r   r   )r   r   r   r   )r   r   r   r   )F)r   r   r   r$   r   r   )NF)r   r   r   r   r   r$   r   r   )r   r   r   r$   r   r   )r   r   r   r   )r   r   r   r   )r
  r   r   r   )r  r   r   r$   )r  r   r  r   r   r    )r   r   r   r   r   r   r  r   r  r   r   r   r!  r   r  r   r   r   r   r   )rr   r   r   r   )r   r   r   r   )r   r   r   r   )rg   r   r   r   r   r   )r   r   r   r   rq  r   rB  r   r=  r   r   rp  )r|   rw  r   rx  )r  r   r   r   r  r  r   r  )r|   rw  rl   r   r   rx   )Hr   
__future__r   r  r   rI   loggingr   rU  rR  typesr   typingr   r   r   r   r	   rX   agent.bounded_responser
   agent.gemini_schemar   	getLoggerr   r]   
hermes_cli_hermes_clir   __version__r[   r\   rW   r  r   r#   r(   r0   rm   rp   r  rv   r  rx   r   r   r   r   r   r   r   r   r	  r  r  r  r-  r8  r:  rW  rn  rp  rv  r  r  r  r  r  r  r  r  r  rL   r   r   <module>r     s     # " " " " "     				   ! ! ! ! ! ! 6 6 6 6 6 6 6 6 6 6 6 6 6 6  < < < < < < ? ? ? ? ? ?		8	$	$$$$$c+122OO   OOO M  $)     	 	 	 	
0 
0 
0 
0. . . . ,J $J J J J J JZ0 0 0 0)  46L L L L L0= % % % % %Y % % %*   $# # # #L
 
 
 
& C "          J 6:3 3 3 3 3D #(k( k( k( k( k(\L L L L0   $       (   4 #' $!, , , , , ,^: : : :      4F F F FR	 	 	 	 	 	 	 	 04#'+ + + + + +\   2S S S Sn =AU U U U U Up> > > > > > > >D D D D D D D D: : : : : : : :
? ? ? ? ? ? ? ?
J J J J J J J JZ2 2 2 2 2 2 2 2 2 2s   A/ /A98A9