
    *"hj                    L    d Z ddlmZ ddlZddlZddlmZ ddZ G d d      Zy)	u>   
Async LLM client — thin wrapper around the ``openai`` SDK.
    )annotationsN)Anyc                f    t        | xs d      j                         j                         }|dv ry|S )N >   	kimi-k2.5ccr/kimi-k2.5   )strstriplower)model	requested
normalizeds      8/root/.hermes/SkillClaw/evolve_server/core/llm_client.py_normalize_temperaturer      s4    U[b!'')//1J33    c                  J    e Zd ZdZ	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 ddZddZd	dZy)
AsyncLLMClientzOpenAI-compatible async chat client.

    All calls are dispatched to a background thread so the event loop stays
    free while the synchronous ``openai`` SDK performs the HTTP round-trip.
    c                P   dd l }ddlm}  ||xs  t        j                  j                  dd      |xs  t        j                  j                  dd      |j                  dd	      
      | _        |xs  t        j                  j                  dd      | _        || _	        || _
        y )Nr   )OpenAIOPENAI_API_KEYr   OPENAI_BASE_URLhttps://api.openai.com/v1g     @g      >@)connect)api_keybase_urltimeoutEVOLVE_MODELgpt-4o)httpxopenair   osenvirongetTimeout_clientr   
max_tokenstemperature)selfr   r   r   r'   r(   r    r   s           r   __init__zAsyncLLMClient.__init__   s     	!Crzz~~.>C_0AC^!_MM%M6

 Fbjjnn^XF
$&r   c           	       K   |j                  d| j                        }| j                  ||j                  d| j                        t	        | j                  |      d|}d}t        |      D ]q  }	 t        j                  | j                  j                  j                  j                  fi | d{   }|j                  d   j                  j                  xs dc S  y7 /# t        $ r}t!        t!        |dd      d	d      xs d}	t!        t!        |dd      d
d      }
|
dk(  rd|	v r|j                  dd       Y d}~|
dk(  r%d|	v r!| j#                  |       d{  7  cY d}~c S ||dz
  k  rJddl}t'        d|z  |j)                  dd      z   d      }t        j*                  |       d{  7   Y d}~P d}~ww xY ww)z@Send a chat completion request and return the assistant content.r(   r'   )r   messagesmax_completion_tokensr(      Nr   r   responsetextstatus_codei  z'temperature' is not supportedzStream must be set to truer	         )popr(   r   r'   r   rangeasyncio	to_threadr&   chatcompletionscreatechoicesmessagecontent	Exceptiongetattr_chat_via_streamrandomminuniformsleep)r)   r,   kwargsrequested_temperaturemergedmax_retriesattemptrespexc	body_textr1   rA   waits                r   r8   zAsyncLLMClient.chat.   s     &

=$:J:J KZZ %+ZZdoo%N1$**>ST	

 
 [) 	G$..LL%%1188  ||A..66<"<	
  #GCT$BFBOUSU	%gc:t&DmUYZ#%*Ji*WJJ}d3#%*F)*S!%!6!6v!>>>>[1_,!q'zFNN1a,@@"ED!-----s   A.G1AC$2C"3*C$G"C$$	G-AF><GF>E!F>#G$G+AF>1F42F>7G=F>>GGc                6  K   dd l }dd l}i }t        | j                  dd       xs  t        j
                  j                  dd      }|rd| |d<   t        |      }d|d<   t        t        | j                  d	d            j                  d
      }g }|j                  d      4 d {   }	|	j                  d| d||      4 d {   }
|
j                          |
j                         2 3 d {   }|r|j                  d      s|dd  j                         }|r|dk(  r8	 |j!                  |      }|j                  dg       xs g D ]M  }|j                  d      xs i }|j                  d      }t%        |t              s:|s=|j'                  |       O 7 7 7 # |j"                  $ r Y w xY w6 d d d       d {  7   n# 1 d {  7  sw Y   nxY wd d d       d {  7   n# 1 d {  7  sw Y   nxY wdj)                  |      S w)Nr   r   r   r   zBearer AuthorizationTstreamr   /g      ^@)r   POSTz/chat/completions)jsonheaderszdata:   z[DONE]r;   deltar=   )rS   r    r?   r&   r"   r#   r$   dictr
   rstripAsyncClientrP   raise_for_statusaiter_lines
startswithr   loadsJSONDecodeError
isinstanceappendjoin)r)   bodyrS   r    rT   r   request_bodyr   content_partsclientrJ   linepayloadeventchoicerV   r0   s                    r   r@   zAsyncLLMClient._chat_via_streamQ   s    "$$,,	48`BJJNNK[]_<`)0	':GO$Dz!%Xwt||Z<=DDSI#%$$U$3 	7 	7v}}*-.!	 %  7 7
 %%'"&"2"2"4 7 7$tw'? "12hnn.G"g&9 ! $

7 3 #())Ir":"@b 7 &

7 3 9r$yy3%dC0T)006	7%	777  // ! ! #57 7 7 7 7	7 	7 	7 	7 	7. ww}%%s   B%H'F(H+G3F 	G3!G-F91F"
2F950G&F$7AGG
GH G3"F9$F6	3G5F6	6G:G3GG3G	GG	G3!H,G/-H3H9G<:HHN)r   r   r   i g?)r   r
   r   r
   r   r
   r'   intr(   floatreturnNone)r,   zlist[dict[str, str]]rE   r   rl   r
   )rb   zdict[str, Any]rl   r
   )__name__
__module____qualname____doc__r*   r8   r@    r   r   r   r      sb     3  '' ' 	'
 ' ' 
'(!F&&r   r   )r   r
   r   rk   rl   rk   )	rq   
__future__r   r6   r"   typingr   r   r   rr   r   r   <module>ru      s)    #  	 d& d&r   