
    Vi%                        d dl mZ d dlmZmZmZmZ d dlZd dlZd dl	m
Z
 d dlmZmZmZ d dlZd dlZddlmZmZ  G d d	e      Ze G d
 d             Z G d d      Zy)    )annotations)asdict	dataclassfieldis_dataclassN)Path)AnyDictOptional   )load_schemaSCHEMA_PATHc                      e Zd Zy)LLMClientErrorN)__name__
__module____qualname__     src/planner/llm_client.pyr   r      s    r   r   c                      e Zd ZU dZded<   dZded<   dZded<   d	Zd
ed<   dZded<   dZ	ded<    e
e      Zded<   dZded<   dZded<   dZded<   dZded<   dZded<   y)	LLMConfigz.https://modelapi.klass.dev/v1/chat/completionsstrendpointzQwen3-Next-80B-A3B-FP8modelNOptional[str]api_key   int	timeout_sTboolinclude_response_formataccept_language)default_factoryDict[str, str]extra_headerszOptional[int]
max_tokenszOptional[float]top_ptop_kFuse_openai_sdkstream)r   r   r   r   __annotations__r   r   r    r"   r#   r   dictr&   r'   r(   r)   r*   r+   r   r   r   r   r      s    DHcD)E3)!G]!Is$(T(%)O])$)$$?M>? $J$!E?!E= ND FDr   r   c                      e Zd Z	 	 d	 	 	 	 	 ddZ	 	 	 d	 	 	 	 	 	 	 	 	 ddZddZ	 	 	 	 	 	 	 	 ddZddZddZddZ	dd	Z
edd
       Zedd       Zy)	LLMClientNc                   |xs
 t               | _        | j                  j                  4| j                  | j                  j                        | j                  _        | j                  j
                  $t        j                  d      | j                  _        | j                  j                  sCt        j                  dd      j                         j                         dv | j                  _        | j                  j                  sCt        j                  dd      j                         j                         dv | j                  _        t        |xs t              | _        y )NLLM_ACCEPT_LANGUAGELLM_USE_OPENAI_SDK >   1onyestrue
LLM_STREAM)r   configr   _resolve_api_keyr   r#   osgetenvr*   striplowerr+   r   r   schema)selfr9   schema_paths      r   __init__zLLMClient.__init__#   s    
 +	;;&"&"7"78L8L"MDKK;;&&.*,))4I*JDKK'{{))		.399;AACGaa KK& {{!!		,+11399;?YY KK "+"<=r   c                   | j                  |      }| j                  |      }| j                  |||      }| j                  j                  d|dd|dg|d}| j                  j
                  rddi|d<   | j                  j                  | j                  j                  |d<   | j                  j                  | j                  j                  |d	<   | j                  j                  | j                  j                  |d
<   | j                  |      }		 |	d   d   d   d   }
t        |
t              rt!        j"                  |
      S t        |
t$              st        d      |
S # t        t        t        f$ r}t        d|       |d }~ww xY w)Nsystem)rolecontentuser)r   messagestemperaturetypejson_objectresponse_formatr'   r(   r)   choicesr   messagerF   z Unexpected LLM response format: z/LLM response content is not a string or object.)_resolve_actions_build_system_prompt_build_user_promptr9   r   r"   r'   r(   r)   _postKeyError
IndexError	TypeErrorr   
isinstancer-   jsondumpsr   )r@   intentcontextfeedbackrI   available_actionssystem_promptuser_promptpayloadresponserF   excs               r   generatezLLMClient.generate7   s    !11':112CD--fgxH [[&&!m<K8 '#
 ;;..*0-)@G%&;;!!-$(KK$:$:GL!;;(#{{00GG;;(#{{00GG::g&	Ty)!,Y7	BG gt$::g&&'3' !RSS *i0 	T #CC5!IJPSS	Ts   E$ $F8FFc                    d}|rddj                  t        |             d}t        j                  | j                  d      }d| d| d	S )
Nr3   zAllowed actions: z, .   )indentzZYou are a robotic action planner.
Return a JSON object that strictly matches this schema:
z8
Use the exact user intent string for the intent field.
z+
Return only JSON. Do not include markdown.)joinsortedrW   rX   r?   )r@   r\   actions_textschema_texts       r   rP   zLLMClient._build_system_prompt_   sb    .tyy@Q9R/S.TTUVLjjQ7Hm Gn 9	9	
r   c                    | j                  |      }t        j                  |dd      }d| d|g}|r"|j                  d       |j                  |       dj	                  |      S )Nre   T)rf   	sort_keyszIntent: zContext:zFeedback from previous attempt:
)_serialize_contextrW   rX   appendrg   )r@   rY   rZ   r[   context_payloadcontext_textsectionss          r   rQ   zLLMClient._build_user_promptn   sd     11':zz/!tLvh'\BOO=>OOH%yy""r   c                    |i S t        |t              r|S t        |      rt        |      S t	        |d      rt        |j
                        S dt        |      iS )N__dict__value)rV   r-   r   r   hasattrrt   r   )r@   rZ   s     r   rn   zLLMClient._serialize_context}   sW    ?Igt$N '?"7J'(())W&&r   c                    |y t        |t              r|j                  d      rt        |d         S t	        |dd       }|rt        |      S y )Nr\   )rV   r-   getsetgetattr)r@   rZ   actionss      r   rO   zLLMClient._resolve_actions   sP    ?gt$5H)Iw2344'#6=w<r   c                Z   ddi}| j                   j                  rd| j                   j                   |d<   | j                   j                  r| j                   j                  |d<   | j                   j                  r%|j	                  | j                   j                         | j                   j
                  r| j                  ||      S t        j                  |      j                  d      }	 dd l
}|j                  | j                   j                  ||| j                   j                        }|j                          |j                         S # t        $ r Y nt         $ r}t#        d	|       |d }~ww xY wt$        j&                  j)                  | j                   j                  ||d
      }	 t$        j&                  j+                  || j                   j                        5 }|j-                         j/                  d      }	t        j0                  |	      cd d d        S # 1 sw Y   y xY w# t$        j2                  j4                  $ rB}|j-                         j/                  dd      }
t#        d|j6                   d|
       |d }~wt         $ r}t#        d	|       |d }~ww xY w)NContent-Typezapplication/jsonzBearer AuthorizationzAccept-Languagezutf-8r   )rW   headerstimeoutLLM request failed: POST)datar   method)r   replace)errorszLLM HTTP error z: )r9   r   r#   r&   updater*   _post_openai_sdkrW   rX   encoderequestspostr   r    raise_for_statusImportError	Exceptionr   urllibrequestRequesturlopenreaddecodeloadserror	HTTPErrorcode)r@   r_   r   r   r   r`   ra   r   handlebodydetails              r   rR   zLLMClient._post   sC   !#56;;)01D1D0E'FGO$;;&&)-)D)DG%&;;$$NN4;;445;;%%(('::zz'"))'2	H}}$$--	 % H %%'==?" 	 	H #7u!=>CG	H ..((KK  	 ) 
	H''9N9N'O (SY{{}++G4zz$'( ( ( ||%% 	RXXZ&&wy&AF ?388*Bvh!GHcQ 	H #7u!=>CG	Hsa   .A E 	E6E6"E11E615H0 &4H$	H0 $H-)H0 -H0 0J*=J

J*J%%J*c           
     n   	 ddl m} | j	                  | j
                  j                        } || j
                  j                  || j
                  j                        }|d   |d   |j                  dd      | j
                  j                  |j                         D ci c]  \  }}|d	k7  s|| c}}d
}	d|v r|d   |	d<   d|v r|d   |	d<   d|v r|d   |	d<   d|v r
d|d   i|	d<   	 | j
                  j                  r |j                  j                  j                  di |	}
g }|
D ]K  }t        |dd       xs g }|st        |d   dd       }|rt        |dd       nd }|s;|j!                  |       M dj#                  |      }ddd|iigiS  |j                  j                  j                  di |	}t%        |d      r|j'                         S t)        |t*              r|S t        d      # t        $ r}t        d      |d }~ww xY wc c}}w # t,        $ r}t        d|       |d }~ww xY w)Nr   )OpenAIzAopenai package not installed; disable SDK mode or install openai.)r   base_urlr   r   rH   rI   333333?r}   )r   rH   rI   r+   r&   rL   r'   r(   r)   
extra_bodyrM   deltarF   r3   rN   
model_dumpzUnexpected SDK response type.r   r   )openair   r   r   _to_base_urlr9   r   r   r    rx   r+   itemschatcompletionscreaterz   ro   rg   rv   r   rV   r-   r   )r@   r_   r   r   ra   r   clientkvrequest_kwargsr+   partschunkrM   r   textrF   r`   s                     r   r   zLLMClient._post_openai_sdk   sh   	% $$T[[%9%9: 3 3hPTP[P[PePef W%
+";;}c:kk((/6}}Vtq!!~BUadV*
 '078I0JN,-7"+2<+@N<(g&-g&6N7#g,3WW5E+FN<(	H{{!!70077I.I# +E%eY=CG" #GAJ>E>C75)T:DT*+ ''%.!YG0D$E#FGG5v{{..55GGHx.**,,(D) !@AAY  	 S	 W@  	H #7u!=>CG	HsU   G4 !H/H-A:H (,H AH H )H 4	H=H		H	H4 H//H4c                   | j                         }d|v r,t        j                  d      xs t        j                  d      S t        j                  d      xs, t        j                  d      xs t        j                  d      S )Nzapi.z.aiZ_AI_API_KEYOPENAI_API_KEYMODELAPI_KEYMODEL_API_KEY)r>   r;   r<   )r   hosts     r   r:   zLLMClient._resolve_api_key   sh    ~~99^,K		:J0KKIIn% +yy)+yy)*	
r   c                J    d}| j                  |      r| d t        |        S | S )Nz/chat/completions)endswithlen)r   markers     r   r   zLLMClient._to_base_url   s-    $V$Ns6{l++r   )NN)r9   zOptional[LLMConfig]rA   zOptional[Path]returnNone)NNr   )
rY   r   rZ   Optional[Any]r[   r   rI   floatr   r   )r\   Optional[set]r   r   )rY   r   rZ   r   r[   r   r   r   )rZ   r   r   Dict[str, Any])rZ   r   r   r   )r_   r   r   r   )r_   r   r   r%   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   rB   rb   rP   rQ   rn   rO   rR   r   staticmethodr:   r   r   r   r   r/   r/   "   s     '+&*>#> $> 
	>. "&"& && &  	&
 & 
&P
## #  	#
 
#	',H\1Hf 
 
  r   r/   )
__future__r   dataclassesr   r   r   r   rW   r;   pathlibr   typingr	   r
   r   urllib.errorr   urllib.request
dag_parserr   r   RuntimeErrorr   r   r/   r   r   r   <module>r      sW    " > >  	  & &   0	\ 	   a ar   