+
    iHàjƒ,  ã                  óø   € R t ^ RIHt ^ RIt^ RIt^ RIHt ^ RIHtH	t	H
t
Ht ^ RIHt ^ RIHtHtHt ^ RIHtHt ^ RIHt ]P.                  ! R	4      t] ! R
 R4      4       tR R ltR R ltR R ltR R ltR# )a½  Tool-call validation for the conversation turn loop: unknown tool names (with
auto-repair and the 3-strike partial exit) and malformed JSON arguments (retry, then
recovery tool results).

Role alternation is preserved on every path: an invalid batch is answered with tool-role
error results (never a user message), and the exits close any open tool-result tail
(#48879). Nothing here imports ``agent.conversation_loop`` at module level (cycle).
)ÚannotationsN)Ú	dataclass)ÚAnyÚDictÚListÚOptional)Úappend_message)Úclose_interrupted_tool_sequenceÚcoalesce_tool_call_idÚ normalize_provider_tool_call_ids)Ú	site_copyÚstamp_failure)ÚFINISH_REASON_LENGTHzagent.conversation_loopc                  ó:   € ] tR t^t$ RtR]R&   R]R&   R]R&   RtR	# )
ÚToolValidationVerdictuv  Outcome of ``validate_tool_calls``.

``action``: ``"ok"`` (dispatch the calls), ``"continue"`` (re-issue the API call â€”
error results / retry state were recorded) or ``"return"`` (terminal partial
result in ``result``). ``mixed_invalid_batch`` is True when the batch contains BOTH
valid and unknown tool names: only the invalid calls get error results, the valid
ones run.ÚstrÚactionúOptional[dict[str, Any]]ÚresultÚboolÚmixed_invalid_batch© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__Ú__static_attributes__r   ó    Ú?/home/ubuntu/.hermes/hermes-agent/agent/turn_tool_validation.pyr   r      s   ‡ ñð ƒKØ$Ó$Ø×r   r   c               ó    € V ^8„  d   QhRRRR/# )é   Únamer   Úreturnr   )Úformats   "r    Ú__annotate__r&   )   s   € ÷ 9ñ 9˜ð 9 ñ 9r   c                óF   € \        V 4      ^P8”  d   V R,          R,           # T # )éP   :Nr(   Nz...)Úlen)r#   s   &r    Ú_preview_namer*   )   s    € Ü # D£	¨B¤ˆ4��9�uÕÐ8°DÐ8r   c               ó   € V ^8„  d   QhRR/# )r"   r$   ÚNoner   )r%   s   "r    r&   r&   -   s   € ÷ ñ ÀTñ r   c                ó†   € V F:  p\        V RRRVP                  P                  R\        V4      RV! V4      /4       K<  	  R# )zIOne tool-role result per call so every tool_call keeps a matching result.ÚroleÚtoolr#   Útool_call_idÚcontentN)r   Úfunctionr#   r
   )ÚmessagesÚ
tool_callsÚcontent_forÚtcs   &&& r    Ú_append_tool_error_resultsr7   -   sC   € ãˆÜ�xØ�FØ�B—K‘K×$Ñ$ØÔ1°"Ó5Ø‘{ 2“ð	"
ö 	ó r   c               ó    € V ^8„  d   QhRRRR/# )r"   Úfinal_responser   r$   zdict[str, Any]r   )r%   s   "r    r&   r&   8   s   € ÷ ñ ÐY\ð Ðaoñ r   c                ól   € \        W4       V P                  W4       \        RVRVRVRRRRRV/R	R4      # )
uß   Terminal partial result. Prior retries or an earlier tool batch leave a tool-result
tail; close it as interrupt aborts do so the next turn is not toolâ†’user (#48879).
This path never reaches finalize_turn, so persist here.r9   r3   Ú	api_callsÚ	completedFÚpartialTÚerrorÚ	truncated)r	   Ú_persist_sessionr   )Úagentr3   Úconversation_historyÚapi_call_countr9   s   &&&&&r    Ú_partial_exitrD   8   sQ   € ô $ HÔ=Ø	×Ñ˜8Ô:ÜØ˜.Ø�HØ�^Ø�UØ�4Ø�ðð �Dóð r   c               ó8   € V ^8„  d   QhRRRRRRRRRRR	R
RRRR/# )r"   rA   r   Úassistant_messageÚfinish_reasonr   r3   zlist[dict[str, Any]]rB   rC   ÚintÚeffective_task_idr$   r   r   )r%   s   "r    r&   r&   H   sX   € ÷ dñ dØðdØ#&ðdØ7:ðdØI]ðdàðdà/2ðdàGJðdð ñdr   c               ó¬  aaaaa€ ^ RI Ho VP                  pV P                  oR*R V3R lllpV U	U
u0 uFG  q™P	                  R4      R8X  g   K  V	P	                  R4      ;'       g    R+ F  p
\        V
4      kK  	  KI  	  pp	p
V P                  W{R7       \        V4       \        4       pV F´  p
V
P                  P                  S9  g   K   V P                  V
P                  P                  4      pV'       g   KO  V P                  V P                   R	V
P                  P                   R
V R2RRR7       WÚP                  n
        VP                  \        V
4      4       K¶  	  ^ RIHp V! WV4       V U
u. uF5  qªP                  P                  S9  g   K  V
P                  P                  NK7  	  pp
\%        V4      ;'       d;    \&        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      oS'       dF   ^ V n        \+        V3R lV 4       4      pV P-                  R\/        V^ ,          4       RV R24       MèV'       dá   V ;P(                  ^,          un        \/        V^ ,          4      pV P-                  RV RV P(                   R24       V P(                  ^8¼  dP   V P1                  4        V P                  V P                   R2RRR7       ^ V n        V! R\3        WWERV 24      4      # \5        W0P7                  W4      4       \9        W7VV3R l4       V! R4      # ^ V n        . oV FÚ  p
V
P                  P:                  p\=        V\>        \@        34      '       d(   \B        PD                  ! V4      V
P                  n        K\  Ve3   \=        V\F        4      '       g   \G        V4      ;V
P                  n        pV'       d   VPI                  4       '       g   RV
P                  n        KÃ   \B        PJ                  ! V4       KÜ  	  S'       Ed�   S UUu0 uF  w  ppVkK
  	  uppo\&        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      pV'       ds   V P                  V P                   RV: R2RRR7       ^ V n(        V PS                  V4       V\T        8X  d   \W        R 4      M
\W        R!4      pV! R\3        WWEV4      4      # V ;PP                  ^,          un(        S^ ,          w  ppV P-                  R"V R#V 24       V PP                  ^8  d(   V P-                  R$V PP                   R%24       V! R4      # V P-                  R&4       ^ V n(        \5        W0P7                  W4      4       R' VV3R( llp\9        W7V4       V! R4      # ^ V n(        V! R)4      # u up
p	i u up
i   \B        PL                   dg   pS'       d   T
P                  P                  S9  g8   SPO                  T
P                  P                  \G        T4      34        Rp?EKÿ   Rp?EK  Rp?ii ; iu uppi ),u`  Validate ``assistant_message.tool_calls`` in place (ids uniquified, names
repaired, dict/empty args normalized to JSON strings). Strikes for invalid names
advance only when a turn has NO valid call, so a degenerate model still halts at
3; args cut off mid-stream (routers rewrite ``length`` â†’ ``tool_calls``) are refused
outright rather than retried.)Ú _invalid_tool_name_error_contentNc               ó$   € V ^8„  d   QhRRRRRR/# )r"   r   r   r   r   r$   r   r   )r%   s   "r    r&   Ú)validate_tool_calls.<locals>.__annotate__V   s(   € ÷ mñ m˜ð mÐ&>ð mÐJ_ñ mr   c                ó   <€ \        WSR 7      # ))r   r   r   )r   )r   r   Ú_mixed_invalid_batchs   &&€r    Ú_verdictÚ%validate_tool_calls.<locals>._verdictV   s   ø€ Ü$¨FÐWkÔlÐlr   r.   Ú	assistantr4   )Útakenu   ðŸ”§ Auto-repaired tool name: 'z' -> 'Ú'T)ÚforceÚ
diagnostic)Úrecord_tool_call_qualityc              3  óT   <"  € T F  qP                   P                  S9   x € K  	  R # 5i©N©r2   r#   ©Ú.0r6   Úvalid_namess   & €r    Ú	<genexpr>Ú&validate_tool_calls.<locals>.<genexpr>v   s!   øé € ð <Ù2<¨B�‰×Ñ˜KÖ'³*ùs   ƒ%(Fc              3  ó`   <"  € T F#  qP                   P                  S9   g   K  ^x € K%  	  R# 5i)é   NrZ   r[   s   & €r    r^   r_   {   s"   øé € ÐQ¡:˜R·±×1AÑ1AÀ[Ñ1P—q’q£:ùs   ƒ.¤
.u   âš ï¸�  Unknown tool 'u-   ' in batch â€” erroring that call, executing z valid call(s)u3   ' â€” sending error to model for agent-correction (z/3)uI   â�Œ Max retries (3) for invalid tool calls exceeded. Stopping as partial.r$   z#Model generated invalid tool call: c                óx   <€ V P                   P                  S9  d   S! V P                   P                  S4      # R # )zZSkipped: another tool call in this turn used an invalid name. Please retry this tool call.rZ   )r6   rK   r]   s   &€€r    Ú<lambda>Ú%validate_tool_calls.<locals>.<lambda>“   s:   ø€ à—;‘;×#Ñ#¨;Ô6ñ 1°·±×1AÑ1AÀ;ÓOð ràqðrr   Úcontinuez{}c              3  óà   <"  € T Fc  qP                   P                  S9   g   K  VP                   P                  ;'       g    R P                  4       P	                  R4      '       * x € Ke  	  R# 5i)Ú N)Ú}Ú])r2   r#   Ú	argumentsÚrstripÚendswith)r\   r6   Úinvalid_namess   & €r    r^   r_   ·   sV   øé € ð 
á �§K¡K×$4Ñ$4¸Ñ$Eô L�—‘×&Ñ&×,Ð,¨"×4Ñ4Ó6×?Ñ?À
ÓK×KÑKÛ ùs   ƒA.¤A.Á-A.u>   âš ï¸�  Truncated tool call arguments detected (finish_reason=u   ) â€” refusing to execute.r?   Útruncated_unreportedu1   âš ï¸�  Invalid JSON in tool call arguments for 'z': u   ðŸ”„ Retrying API call (z/3)...u;   âš ï¸�  Injecting recovery tool results for invalid JSON...c               ó   € V ^8„  d   QhRR/# )r"   r$   r   r   )r%   s   "r    r&   rM   Ý   s   € ÷ 	ñ 	 cñ 	r   c                óv   <a € S P                   P                  S9  d   R # \        V 3R lS 4       4      pRV R2# )z;Skipped: other tool call in this response had invalid JSON.c              3  óf   <"  € T F&  w  rVSP                   P                  8X  g   K"  Vx € K(  	  R # 5irY   rZ   )r\   ÚnÚer6   s   &  €r    r^   ÚBvalidate_tool_calls.<locals>._json_error_result.<locals>.<genexpr>à   s(   øé € ÐPÑ%6™T˜Q¸!¸r¿{¹{×?OÑ?OÑ:O—q’qÓ%6ùs   ƒ1§
1zError: Invalid JSON arguments. z_. For tools with no required parameters, use an empty object: {}. Please retry with valid JSON.)r2   r#   Únext)r6   ÚerrÚinvalid_json_argsrm   s   f €€r    Ú_json_error_resultÚ/validate_tool_calls.<locals>._json_error_resultÝ   s?   ù€ Ø�{‰{×Ñ }Ô4ÙTÜÔPÑ%6ÓPÓPˆCà1°#°ð 70ð 1ðr   ÚokrY   r   ),Úagent.conversation_looprK   r4   Úvalid_tool_namesÚgetr
   Ú_uniquify_tool_call_idsr   Úsetr2   r#   Ú_repair_tool_callÚ_vprintÚ
log_prefixÚaddÚidÚ-hermes_cli.observability.shared_metrics_modelrW   r   ÚanyÚ_invalid_tool_retriesÚsumÚ_buffer_vprintr*   Ú_flush_status_bufferrD   r   Ú_build_assistant_messager7   rj   Ú
isinstanceÚdictÚlistÚjsonÚdumpsr   ÚstripÚloadsÚJSONDecodeErrorÚappendÚ_invalid_json_retriesÚ_cleanup_task_resourcesr   r   ) rA   rF   rG   r3   rB   rC   rI   r4   rP   Úmsgr6   rS   Úrepaired_idsÚrepairedrW   Úinvalid_tool_callsÚ_n_validÚinvalid_previewÚargsrs   rr   Ú_Ú
_truncatedÚ_copyÚ	tool_nameÚ	error_msgrx   rK   rO   rw   rm   r]   s    &&&$$$$                    @@@@@r    Úvalidate_tool_callsr£   H   sþ  ü€ õ Ià"×-Ñ-€JØ×(Ñ(€K÷mò mñ ôáˆCŸw™w v›°+Ñ=ô 	"à—'‘'˜,Ó'×-Ð-¨2Ò-ˆBô 	˜bÖ!á-ñ 	"Ùð 
ñ ð
 
×!Ñ! *Ð!Ô:Ü$ ZÔ0ô “5€LÛˆØ�;‰;×Ñ ;Ö.Ø×.Ñ.¨r¯{©{×/?Ñ/?Ó@ˆHß‰xØ—‘ ×!1Ñ!1Ð 2Ð2QÐRT×R]ÑR]×RbÑRbÐQcÐciÐjrÐisÐstÐuØ$(°Tð ô ;à#+—‘Ô Ø× Ñ ¤ B£Ö(ñ õ WÙ˜U°Ô=Ù5?Óg±Z¨rÇ;Á;×CSÑCSÐ[fÑCfÔ*˜"Ÿ+™+×*Ô*±ZÐÐgô  Ð 2Ó3÷ ð ¿»ô <Ù2<ó<¿¿ºô <Ù2<ó<ó 9Ð÷ Ø&'ˆÔ#ÜÔQ¡:ÓQÓQˆØ×ÑØ$¤]Ð3EÀaÕ3HÓ%IÐ$Jð KØ!˜
 .ð2õ	
÷ 
Ø×#Ò# qÕ(Õ#ä'Ð(:¸1Õ(=Ó>ˆØ×ÑÐ5°oÐ5FÐFyÐz÷  {Vñ  {Vð  zWð  WZð  [ô  	\à×&Ñ&¨!Ô+Ø×&Ñ&Ô(Ø�M‰M˜U×-Ñ-Ð.Ð.wÐxð  AEð  RVˆMô  WØ*+ˆEÔ'Ù˜H¤mØÐ!5Ø5°oÐ5FÐGó'ó ð ô
 	�x×!?Ñ!?Ð@QÓ!aÔbä"Øõô	
ñ ˜
Ó#Ð#à"#€EÔð ÐÛˆØ�{‰{×$Ñ$ˆÜ�dœT¤4˜L×)Ò)Ü$(§J¢J¨tÓ$4ˆB�K‰KÔ!ÙØÒ¤J¨t´S×$9Ò$9Ü+.¨t«9Ð4ˆB�K‰KÔ! Dß˜4Ÿ:™:Ÿ<š<Ø$(ˆB�K‰KÔ!Ùð	EÜ�JŠJ�tÖñ ÷$ ÐÙ'8Ô9Ñ'8™t˜q !›Ñ'8Ò9ˆ÷ “Sô 
á ó
—S—S’Sô 
á ó
ó 
ˆ
÷ Ø�M‰MØ×#Ñ#Ð$ð %"Ø"/Ñ!2Ð2LðNà tð ô ð
 +,ˆEÔ'Ø×)Ñ)Ð*;Ô<ð +8Ô;OÔ*O”	˜+Ô&ÜÐ5Ó6ð ñ ˜H¤mØÐ!5Àuó'ó ð ð 	×#Ò# qÕ(Õ#Ø0°Õ3Ñˆ	�9Ø×ÑÐPÐQZÐP[Ð[^Ð_hÐ^iÐjÔkà×&Ñ&¨Ô*Ø× Ñ Ð#;¸E×<WÑ<WÐ;XÐX^Ð!_Ô`á˜JÓ'Ð'ð 	×ÑÐZÔ[Ø&'ˆÔ#ô 	�x×!?Ñ!?Ð@QÓ!aÔb÷	ñ 	ô 	# 8Ð9KÔLÙ˜
Ó#Ð#ð #$€EÔÙ�D‹>Ðùó_ùò* høôt ×#Ñ#ô 	E÷ )¨R¯[©[×-=Ñ-=À[Ô-PØ!×(Ñ(¨"¯+©+×*:Ñ*:¼CÀ»FÐ)C×DÓDö .Qûð	Eüó :s<   ´WÁWÁ(WÅ8WÆWÐWÐ.Y×Y×'AYÙY)r   Ú
__future__r   r�   ÚloggingÚdataclassesr   Útypingr   r   r   r   Úagent.message_metadatar   Úagent.message_sanitizationr	   r
   r   Úagent.turn_failure_copyr   r   Úhermes_constantsr   Ú	getLoggerÚloggerr   r*   r7   rD   r£   r   r   r    Ú<module>r®      sr   ðñõ #ã Û Ý !ß ,Ó ,å 1÷Lñ Lç <Ý 1à	×	Ò	Ð4Ó	5€ð ÷ð ó ðõ9õõ÷ dr   