§
    —i»jƒ2  ã                   óB  — d Z ddlmZ ddlmZmZmZ ddlmZm	Z	 ddl
Z
ddlZddlZddlZddlZ ej        d¦  «        Z G d„ dee¦  «        Z G d	„ d
ee¦  «        Ze G d„ d¦  «        ¦   «         Z edd¬¦  «         G d„ d¦  «        ¦   «         Z G d„ d¦  «        ZdS )a:  
FreeExile Multi-LLM Provider Client Engine.
Authoritative bridge for routing tactical prompts to OpenRouter, OpenAI (GPT),
Anthropic (Claude), Google (Gemini), DeepSeek, Moonshot (Kimi), and Local Tactical Fallback.
Adheres to strict async timeouts, schema parsing, and automatic zero-latency heuristic fallback.
é    )ÚEnum)ÚDictÚAnyÚOptional)Ú	dataclassÚfieldNzfreeexile.agent.llmc                   ó*   — e Zd ZdZdZdZdZdZdZdZ	dS )	ÚLLMProviderTypeÚ
OPENROUTERÚOPENAIÚ	ANTHROPICÚGEMINIÚDEEPSEEKÚKIMIÚLOCAL_TACTICALN)
Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   r   r   © ó    ú9C:\Projects\FreeExile\server\agent\llm_provider_client.pyr
   r
      s1   € € € € € Ø€JØ€FØ€IØ€FØ€HØ€DØ%€N€N€Nr   r
   c                   ó.   — e Zd ZdZdZdZdZdZdZdZ	dZ
d	S )
ÚAgentActionTypeÚIDLEÚMOVE_TOWARDSÚ	MOVE_AWAYÚATTACK_SKILLÚDODGEÚLOOTÚ
USE_POTIONÚSWAP_WEAPONN)r   r   r   r   r   r   r   r   r   r    r!   r   r   r   r   r      s6   € € € € € Ø€DØ!€LØ€IØ!€LØ€EØ€DØ€JØ€K€K€Kr   r   c                   óv   — e Zd ZU eed<   dZeed<   dZeed<   dZeed<   dZ	e
ed<   dZeed	<   d
Ze
ed<   dd„ZdS )ÚLLMProviderConfigÚproviderÚ Úapi_keyÚmodelÚbase_urlgš™™™™™É?Útemperatureé   Ú
max_tokensg       @Útimeout_secÚreturnNc                 óp  — | j         sÊ| j        t          j        k    rd| _         n­| j        t          j        k    rd| _         n�| j        t          j        k    rd| _         ns| j        t          j        k    rd| _         nV| j        t          j        k    rd| _         n9| j        t          j        k    rd| _         n| j        t          j	        k    rd| _         | j
        sÛ| j        t          j        k    r	d| _
        d S | j        t          j        k    r	d	| _
        d S | j        t          j        k    r	d
| _
        d S | j        t          j        k    rd| j         › d�| _
        d S | j        t          j        k    r	d| _
        d S | j        t          j        k    r	d| _
        d S | j        t          j	        k    rd| _
        d S d S d S )Nz!meta-llama/llama-3.3-70b-instructzgpt-4o-minizclaude-3-5-haiku-20241022zgemini-1.5-flashzdeepseek-chatzmoonshot-v1-8kzheuristic-reflex-v1z-https://openrouter.ai/api/v1/chat/completionsz*https://api.openai.com/v1/chat/completionsz%https://api.anthropic.com/v1/messagesz8https://generativelanguage.googleapis.com/v1beta/models/z:generateContentz)https://api.deepseek.com/chat/completionsz+https://api.moonshot.cn/v1/chat/completionszlocal://heuristic)r'   r$   r
   r   r   r   r   r   r   r   r(   )Úselfs    r   Ú__post_init__zLLMProviderConfig.__post_init__3   s¢  € ØŒzð 	3ØŒ}¥Ô :Ò:Ð:Ø@�”
�
Ø”¥/Ô"8Ò8Ð8Ø*�”
�
Ø”¥/Ô";Ò;Ð;Ø8�”
�
Ø”¥/Ô"8Ò8Ð8Ø/�”
�
Ø”¥/Ô":Ò:Ð:Ø,�”
�
Ø”¥/Ô"6Ò6Ð6Ø-�”
�
Ø”¥/Ô"@Ò@Ð@Ø2�”
àŒ}ð 	4ØŒ}¥Ô :Ò:Ð:Ø O�”��Ø”¥/Ô"8Ò8Ð8Ø L�”��Ø”¥/Ô";Ò;Ð;Ø G�”��Ø”¥/Ô"8Ò8Ð8Ø wÐ[_Ô[eÐ wÐ wÐ w�”��Ø”¥/Ô":Ò:Ð:Ø K�”��Ø”¥/Ô"6Ò6Ð6Ø M�”��Ø”¥/Ô"@Ò@Ð@Ø 3�”��ð	4ð 	4ð AÐ@r   )r-   N)r   r   r   r
   Ú__annotations__r&   Ústrr'   r(   r)   Úfloatr+   Úintr,   r0   r   r   r   r#   r#   )   s“   € € € € € € àÐÐÑØ€GˆSÐÐÑØ€Eˆ3€O€O�OØ€HˆcÐÐÑØ€K�ÐÐÑØ€J�ÐÐÑØ€K�ÐÐÑð4ð 4ð 4ð 4ð 4ð 4r   r#   T)ÚslotsÚfrozenc                   ó¸   — e Zd ZU eed<   dZee         ed<   dZee         ed<   dZ	ee
         ed<   dZee
         ed<   dZee         ed<   dZeed	<   d
Zeed<   dS )ÚTacticalActionDecisionÚaction_typeNÚ	target_idÚskill_idÚtarget_xÚtarget_yÚtarget_drop_idr%   Ú	reasoningr   Ú
token_cost)r   r   r   r   r1   r:   r   r4   r;   r<   r3   r=   r>   r2   r?   r@   r   r   r   r8   r8   U   s¢   € € € € € € à Ð Ð Ñ Ø#€Iˆx˜Œ}Ð#Ð#Ñ#Ø"€Hˆh�sŒmÐ"Ð"Ñ"Ø $€Hˆh�uŒoÐ$Ð$Ñ$Ø $€Hˆh�uŒoÐ$Ð$Ñ$Ø$(€N�H˜S”MÐ(Ð(Ñ(Ø€IˆsÐÐÑØ€J�ÐÐÑÐÐr   r8   c                   óº   — e Zd ZdZdedeeef         fd„Zdedeeef         deeef         fd„Z	dede
fd„Zd	eeef         de
fd
„Zded	eeef         de
fd„ZdS )ÚLLMProviderClientRouterzs
    Unified Router connecting to multiple Cloud LLMs with seamless fallback
    to local deterministic rules.
    Úconfigr-   c                 ó(  — ddi}|j         t          j        k    r|j        |d<   d|d<   nh|j         t          j        k    rd|j        › �|d<   d|d	<   d
|d<   n;|j         t          j        k    r|j        r
|j        |d<   n|j        rd|j        › �|d<   |S )NzContent-Typeúapplication/jsonz	x-api-keyz
2023-06-01zanthropic-versionzBearer ÚAuthorizationzhttps://freeexile.gamezHTTP-RefererzFreeExile Dark Martial MMORPGzX-Titlezx-goog-api-key)r$   r
   r   r&   r   r   )r/   rC   Úheaderss      r   Úbuild_request_headersz-LLMProviderClientRouter.build_request_headersg   sÂ   € àÐ.ð#
ˆð Œ?�oÔ7Ò7Ð7Ø#)¤>ˆG�KÑ Ø+7ˆGÐ'Ñ(Ð(ØŒ_¥Ô :Ò:Ð:Ø'A°´Ð'AÐ'AˆG�OÑ$Ø&>ˆG�NÑ#Ø!@ˆG�IÑÐØŒ_¥Ô 6Ò6Ð6ØŒ~ð ;Ø,2¬N�Ð(Ñ)øàŒ~ð FØ+E°V´^Ð+EÐ+E�˜Ñ(àˆr   Úprompt_datac                 ó~  — d}t          j        |d¬¦  «        }|j        t          j        k    r|j        |j        |d|dœg|j        dœS |j        t          j        k    rdd|› d|› �igd	œg|j        |j        d
dœdœS |j        d|dœd|dœg|j        |j        |j        t          j	        t          j
        fv rddind dœS )Na¦  You are an elite tactical AI agent piloting a martial arts character in FreeExile 2.5D MMORPG. Analyze current perception and respond ONLY with a raw JSON object containing: action_type (ATTACK_SKILL | MOVE_TOWARDS | MOVE_AWAY | DODGE | LOOT | USE_POTION), target_id (int or null), skill_id (int or null), target_x (float or null), target_y (float or null), target_drop_id (string or null), reasoning (string explanation).F)Úensure_asciiÚuser)ÚroleÚcontent)r'   r+   ÚsystemÚmessagesr)   Útextz

Current Game State:
)rM   ÚpartsrE   )r)   ÚmaxOutputTokensÚresponseMimeType)ÚcontentsÚgenerationConfigrO   ÚtypeÚjson_object)r'   rP   r)   r+   Úresponse_format)ÚjsonÚdumpsr$   r
   r   r'   r+   r)   r   r   r   )r/   rC   rI   Úsystem_promptÚuser_contents        r   Úbuild_payloadz%LLMProviderClientRouter.build_payload{   sF  € ðOð 	õ ”z +¸EÐBÑBÔBˆàŒ?�oÔ7Ò7Ð7àœØ$Ô/Ø'Ø&,¸ÐFÐFÐGØ%Ô1ðð ð ð Œ_¥Ô 6Ò6Ð6ð #Ø%¨-Ð'`Ð'`ÐR^Ð'`Ð'`ÐaÐbðð ð ð
 $*Ô#5Ø'-Ô'8Ø(:ð%ð %ð
ð 
ð 
ð  œà%°-Ð@Ð@Ø#°Ð=Ð=ðð  &Ô1Ø$Ô/Ø>D¼oÕRaÔRhÕjyô  kCð  RDð  ?Dð  ?D F¨MÐ#:Ð#:ð  JNð	ð 	ð 	r   Úraw_responsec                 óè  — 	 t          j        d|t           j        ¦  «        }|r|                     d¦  «        n|}t	          j        |¦  «        }t          |                     dd¦  «        ¦  «                             ¦   «         }t          j
        }	 t          |         }n# t          $ r t          j
        }Y nw xY wt          ||                     d¦  «        |                     d¦  «        |                     d¦  «        �t          |d         ¦  «        nd|                     d	¦  «        �t          |d	         ¦  «        nd|                     d
¦  «        t          |                     dd¦  «        ¦  «        t          |                     dd¦  «        ¦  «        ¬¦  «        S # t          $ rF}t                                d|› d�¦  «         t          t          j
        d|› �¬¦  «        cY d}~S d}~ww xY w)z:Parses LLM output into a validated TacticalActionDecision.z\{.*\}r   r9   r   r:   r;   r<   Nr=   r>   r?   r%   r@   )r9   r:   r;   r<   r=   r>   r?   r@   z'Failed to parse LLM tactical decision: z. Fallback to IDLE.zParsing error: ©r9   r?   )ÚreÚsearchÚDOTALLÚgrouprZ   Úloadsr2   ÚgetÚupperr   r   ÚKeyErrorr8   r3   r4   Ú	ExceptionÚloggerÚwarning)r/   r_   ÚmatchÚjson_strÚdataÚ
action_strr9   Úes           r   Úparse_response_to_decisionz2LLMProviderClientRouter.parse_response_to_decision¦   sô  € ð	å”I˜i¨µr´yÑAÔAˆEØ).Ð@�u—{’{ 1‘~”~�~°LˆHÝ”:˜hÑ'Ô'ˆDå˜TŸXšX m°VÑ<Ô<Ñ=Ô=×CÒCÑEÔEˆJÝ)Ô.ˆKð3Ý-¨jÔ9��øÝð 3ð 3ð 3Ý-Ô2���ð3øøøõ *Ø'ØŸ(š( ;Ñ/Ô/ØŸš *Ñ-Ô-Ø48·H²H¸ZÑ4HÔ4HÐ4T�˜t JÔ/Ñ0Ô0Ð0ÐZ^Ø48·H²H¸ZÑ4HÔ4HÐ4T�˜t JÔ/Ñ0Ô0Ð0ÐZ^Ø#ŸxšxÐ(8Ñ9Ô9Ý˜dŸhšh {°BÑ7Ô7Ñ8Ô8Ý˜tŸxšx¨°aÑ8Ô8Ñ9Ô9ð	ñ 	ô 	ð 	øõ ð 	ð 	ð 	Ý�NŠNÐ[ÀQÐ[Ð[Ð[Ñ\Ô\Ð\Ý)Ý+Ô0Ø/¨AÐ/Ð/ðñ ô ð ð ð ð ð ð øøøøð	øøøsC   ‚BF! ÂB ÂF! ÂB8Â5F! Â7B8Â8C(F! Æ!
G1Æ+;G,Ç&G1Ç,G1Úworld_promptc           	      ót  — t          |                     dd¦  «        ¦  «        }|                     dg ¦  «        }|                     dg ¦  «        }|dk     r8|rt          t          j        d¬¦  «        S t          t          j        d¬¦  «        S |ra|d	k    r[|d
         }t          t          j        t          |                     d¦  «        ¦  «        d|                     d¦  «        › d�¬¦  «        S |r¬|d
         }t          |                     dd¦  «        ¦  «        }|dk    r=t          t          j        t          |                     dd
¦  «        ¦  «        d¬¦  «        S t          t          j
        t          |                     dd
¦  «        ¦  «        dd¬¦  «        S t          t          j        d¬¦  «        S )z”
        Instant 0ms tactical heuristic rule-based engine.
        Ensures player character survives even if network is completely severed.
        Úplayer_hp_pctg      ð?Únearby_enemiesÚnearby_dropsg      Ð?uW   [Tactical Heuristic] Critical HP (<25%). Activating Huyá»…n áº¢nh Bá»™ i-frame evasion.ra   z>[Tactical Heuristic] Low HP (<25%). Consuming recovery elixir.g      à?r   Úidz2[Tactical Heuristic] Collecting rare ground loot: Úitemú.)r9   r>   r?   Údistanceg      $@g      @z4[Tactical Heuristic] Moving into melee attack range.)r9   r:   r?   é   z>[Tactical Heuristic] Executing elemental counter attack skill.)r9   r:   r;   r?   zI[Tactical Heuristic] No immediate threat or loot in vicinity. Patrolling.)r3   rg   r8   r   r   r    r   r2   r   r4   r   r   )r/   rs   Úhp_pctrv   rw   Ú	best_dropÚtargetÚdists           r   Ú_heuristic_fallbackz+LLMProviderClientRouter._heuristic_fallbackÆ   sÜ  € õ
 �|×'Ò'¨¸Ñ=Ô=Ñ>Ô>ˆØ%×)Ò)Ð*:¸BÑ?Ô?ˆØ#×'Ò'¨¸Ñ;Ô;ˆð �DŠ=ˆ=Øð Ý-Ý /Ô 5Øwðñ ô ð õ *Ý+Ô6ØZðñ ô ð ð ð 	˜F dšN˜NØ$ QœˆIÝ)Ý+Ô0Ý" 9§=¢=°Ñ#6Ô#6Ñ7Ô7ØgÈyÏ}Ê}Ð]cÑOdÔOdÐgÐgÐgðñ ô ð ð ð 	Ø# AÔ&ˆFÝ˜Ÿš J°Ñ5Ô5Ñ6Ô6ˆDØ�cŠzˆzÝ-Ý /Ô <Ý! &§*¢*¨T°1Ñ"5Ô"5Ñ6Ô6ØTðñ ô ð õ .Ý /Ô <Ý! &§*¢*¨T°1Ñ"5Ô"5Ñ6Ô6ØØ^ð	ñ ô ð õ &Ý'Ô,Øað
ñ 
ô 
ð 	
r   c              ƒ   óÔ  ‡‡‡K  — ‰j         t          j        k    r|                      |¦  «        S ‰j        s|                      |¦  «        S |                      ‰¦  «        Š|                      ‰|¦  «        }t          j        |¦  «         	                    d¦  «        Šddl
}dt          fˆˆˆfd„}	 |                     ¦   «         }|                     d|¦  «        ƒ d{V —†}t          j        |¦  «        }d}	‰j         t          j        k    r2|                     di g¦  «        d                              dd¦  «        }	nÄ‰j         t          j        k    rg|                     d	g ¦  «        }
|
rN|
d                              di ¦  «                             d
g ¦  «        }|r|d                              dd¦  «        }	nH|                     dg ¦  «        }|r0|d                              di ¦  «                             dd¦  «        }	|                      |	¦  «        S # t&          $ rE}t(                               d‰j         › d|› d�¦  «         |                      |¦  «        cY d}~S d}~ww xY w)zž
        Submits request to configured provider.
        If LOCAL_TACTICAL or on network timeout/error, immediately resolves via _heuristic_fallback.
        úutf-8r   Nr-   c                  ó&  •— t           j                             ‰j        ‰‰d¬¦  «        } t           j                             | ‰j        ¬¦  «        5 }|                     ¦   «                              d¦  «        }|cd d d ¦  «         S # 1 swxY w Y   d S )NÚPOST)Úurlro   rG   Úmethod)Útimeoutrƒ   )ÚurllibÚrequestÚRequestr(   Úurlopenr,   ÚreadÚdecode)ÚreqÚrespÚbodyrC   rG   Úpayload_bytess      €€€r   Ú_do_http_callzHLLMProviderClientRouter.request_tactical_decision.<locals>._do_http_call  sÌ   ø€ Ý”.×(Ò(Ø”OØ"ØØð	 )ñ ô ˆCõ ”×'Ò'¨°VÔ5GÐ'ÑHÔHð ÈDØ—y’y‘{”{×)Ò)¨'Ñ2Ô2�Øðð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   Á)BÂB
ÂB
r%   rN   rQ   Ú
candidatesrR   ÚchoicesÚmessagezLLM request to z	 failed: z+. Activating autonomous heuristic fallback.)r$   r
   r   r�   r&   rH   r^   rZ   r[   ÚencodeÚasyncior2   Úget_event_loopÚrun_in_executorrf   r   rg   r   rr   rj   rk   rl   )r/   rC   rs   Úpayloadr˜   r“   ÚloopÚraw_bodyÚ	resp_dataÚcontent_textr”   rR   r•   ÚexcrG   r’   s    `            @@r   Úrequest_tactical_decisionz1LLMProviderClientRouter.request_tactical_decisionû   s›  øøøè è € ð Œ?�oÔ<Ò<Ð<Ø×+Ò+¨LÑ9Ô9Ð9ð Œ~ð 	:Ø×+Ò+¨LÑ9Ô9Ð9à×,Ò,¨VÑ4Ô4ˆØ×$Ò$ V¨\Ñ:Ô:ˆÝœ
 7Ñ+Ô+×2Ò2°7Ñ;Ô;ˆàˆˆˆð		�sð 		ð 		ð 		ð 		ð 		ð 		ð 		ð 		ð	:Ø×)Ò)Ñ+Ô+ˆDØ!×1Ò1°$¸ÑFÔFÐFÐFÐFÐFÐFÐFˆHõ œ
 8Ñ,Ô,ˆIØˆLØŒ¥/Ô";Ò;Ð;Ø(Ÿ}š}¨Y¸¸Ñ=Ô=¸aÔ@×DÒDÀVÈRÑPÔP��Ø”¥OÔ$:Ò:Ð:Ø&Ÿ]š]¨<¸Ñ<Ô<�
Øð @Ø& qœM×-Ò-¨i¸Ñ<Ô<×@Ò@ÀÈ"ÑMÔM�EØð @Ø',¨Q¤x§|¢|°F¸BÑ'?Ô'?˜øà#Ÿ-š-¨	°2Ñ6Ô6�Øð TØ#*¨1¤:§>¢>°)¸RÑ#@Ô#@×#DÒ#DÀYÐPRÑ#SÔ#S�Là×2Ò2°<Ñ@Ô@Ð@øåð 	:ð 	:ð 	:Ý�NŠNØl &¤/ÐlÐl¸CÐlÐlÐlñô ð ð ×+Ò+¨LÑ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9øøøøð		:øøøs   Â2E%H È
I'È":I"ÉI'É"I'N)r   r   r   Ú__doc__r#   r   r2   rH   r   r^   r8   rr   r�   r¡   r   r   r   rB   rB   a   s  € € € € € ðð ð
Ð,=ð À$ÀsÈCÀxÄ.ð ð ð ð ð()Ð$5ð )ÀDÈÈcÈÄNð )ÐW[Ð\_ÐadÐ\dÔWeð )ð )ð )ð )ðV°sð Ð?Uð ð ð ð ð@3
°°S¸#°X´ð 3
ÐCYð 3
ð 3
ð 3
ð 3
ðj;:à!ð;:ð ˜3 ˜8”nð;:ð 
 ð	;:ð ;:ð ;:ð ;:ð ;:ð ;:r   rB   )r¢   Úenumr   Útypingr   r   r   Údataclassesr   r   rZ   Úloggingrb   Úurllib.requestr‰   Úurllib.errorÚ	getLoggerrk   r2   r
   r   r#   r8   rB   r   r   r   ú<module>rª      s¬  ððð ð Ð Ð Ð Ð Ð Ø &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ð &Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø €€€Ø €€€Ø 	€	€	€	Ø Ð Ð Ð Ø Ð Ð Ð à	ˆÔ	Ð0Ñ	1Ô	1€ð&ð &ð &ð &ð &�c˜4ñ &ô &ð &ð ð  ð  ð  ð  �c˜4ñ  ô  ð  ð ð(4ð (4ð (4ð (4ð (4ñ (4ô (4ñ „ð(4ðV €�˜dÐ#Ñ#Ô#ðð ð ð ð ñ ô ñ $Ô#ððU:ð U:ð U:ð U:ð U:ñ U:ô U:ð U:ð U:ð U:r   