§
    ‰eîitl  ã                   ó®  — U d 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mZm	Z	m
Z
mZ ddlmZmZ ddlmZmZ  ej        e¦  «        Zda ej        ¦   «         Z ej        ¦   «         Zd„ Zd„ Zd„ Z e¦   «          	 dd	lmZ  e¦   «          n(# e$ r Z e !                    d
e ¦  «         Y dZ [ ndZ [ ww xY w	 ddl"m#Z#  e#¦   «          n(# e$ r Z e !                    de ¦  «         Y dZ [ ndZ [ ww xY w ej$        ¦   «         Z%ee&e&f         e'd<    ej(        ¦   «         Z)ee&e*f         e'd<   g a+e	e&         e'd<   ddgdgdgdgdgg d¢g d¢dgg d¢g d¢dgdœZ,	 	 	 d?de	e&         de	e&         d e-d!e	ee&ef                  fd"„Z.h d#£Z/d$d%hZ0d&e&d'ee&ef         d!ee&ef         fd(„Z1d)e&fd*„Z2d)e&d+e3fd,„Z4d@d)e&d-e-fd.„Z5d)e&fd/„Z6	 	 	 	 	 	 dAd0e&d1ee&ef         d2e
e&         d3e
e&         d4e
e&         d5e
e&         d6e
e	e&                  d7e-d!e&fd8„Z7d!e	e&         fd9„Z8d&e&d!e
e&         fd:„Z9d!ee&e*f         fd;„Z:d!ee&e-f         fd<„Z;d@d=e-d!ee	e&         e	e*         f         fd>„Z<dS )Baƒ  
Model Tools Module

Thin orchestration layer over the tool registry. Each tool file in tools/
self-registers its schema, handler, and metadata via tools.registry.register().
This module triggers discovery (by importing all tool modules), then provides
the public API that run_agent.py, cli.py, batch_runner.py, and the RL
environments consume.

Public API (signatures preserved from the original 2,400-line version):
    get_tool_definitions(enabled_toolsets, disabled_toolsets, quiet_mode) -> list
    handle_function_call(function_name, function_args, task_id, user_task) -> str
    TOOL_TO_TOOLSET_MAP: dict          (for batch_runner.py)
    TOOLSET_REQUIREMENTS: dict         (for cli.py, doctor.py)
    get_all_tool_names() -> list
    get_toolset_for_tool(name) -> str
    get_available_toolsets() -> dict
    check_toolset_requirements() -> dict
    check_tool_availability(quiet) -> tuple
é    N)ÚDictÚAnyÚListÚOptionalÚTuple)Údiscover_builtin_toolsÚregistry)Úresolve_toolsetÚvalidate_toolsetc                  ó¸   — t           5  t          �t                               ¦   «         rt          j        ¦   «         at          cddd¦  «         S # 1 swxY w Y   dS )a^  Return a long-lived event loop for running async tool handlers.

    Using a persistent loop (instead of asyncio.run() which creates and
    *closes* a fresh loop every time) prevents "Event loop is closed"
    errors that occur when cached httpx/AsyncOpenAI clients attempt to
    close their transport on a dead loop during garbage collection.
    N)Ú_tool_loop_lockÚ
_tool_loopÚ	is_closedÚasyncioÚnew_event_loop© ó    ú-/home/div/.hermes/hermes-agent/model_tools.pyÚ_get_tool_loopr   -   s–   € õ 
ð ð ÝÐ¥×!5Ò!5Ñ!7Ô!7ÐÝ Ô/Ñ1Ô1ˆJÝðð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   ˆ:AÁAÁAc                  óÄ   — t          t          dd¦  «        } | �|                      ¦   «         r3t          j        ¦   «         } t          j        | ¦  «         | t          _        | S )uŸ  Return a persistent event loop for the current worker thread.

    Each worker thread (e.g., delegate_task's ThreadPoolExecutor threads)
    gets its own long-lived loop stored in thread-local storage.  This
    prevents the "Event loop is closed" errors that occurred when
    asyncio.run() was used per-call: asyncio.run() creates a loop, runs
    the coroutine, then *closes* the loop â€” but cached httpx/AsyncOpenAI
    clients remain bound to that now-dead loop and raise RuntimeError
    during garbage collection or subsequent use.

    By keeping the loop alive for the thread's lifetime, cached clients
    stay valid and their cleanup runs on a live loop.
    ÚloopN)ÚgetattrÚ_worker_thread_localr   r   r   Úset_event_loopr   )r   s    r   Ú_get_worker_loopr   <   sV   € õ Õ'¨°Ñ6Ô6€DØ€|�t—~’~Ñ'Ô'€|ÝÔ%Ñ'Ô'ˆÝÔ˜tÑ$Ô$Ð$Ø$(ÕÔ!Ø€Kr   c                 ó¶  — 	 t          j        ¦   «         }n# t          $ r d}Y nw xY w|rÅ|                     ¦   «         r±ddl}|j                             d¬¦  «        }|                     t           j        | ¦  «        }	 | 	                    d¬¦  «        | 
                    dd¬	¦  «         S # |j        j        $ r |                     ¦   «          ‚ w xY w# | 
                    dd¬	¦  «         w xY wt          j        ¦   «         t          j        ¦   «         ur#t!          ¦   «         }|                     | ¦  «        S t%          ¦   «         }|                     | ¦  «        S )
aù  Run an async coroutine from a sync context.

    If the current thread already has a running event loop (e.g., inside
    the gateway's async stack or Atropos's event loop), we spin up a
    disposable thread so asyncio.run() can create its own loop without
    conflicting.

    For the common CLI path (no running loop), we use a persistent event
    loop so that cached async clients (httpx / AsyncOpenAI) remain bound
    to a live loop and don't trigger "Event loop is closed" on GC.

    When called from a worker thread (parallel tool execution), we use a
    per-thread persistent loop to avoid both contention with the main
    thread's shared loop AND the "Event loop is closed" errors caused by
    asyncio.run()'s create-and-destroy lifecycle.

    This is the single source of truth for sync->async bridging in tool
    handlers. The RL paths (agent_loop.py, tool_context.py) also provide
    outer thread-pool wrapping as defense-in-depth, but each handler is
    self-protecting via this function.
    Nr   é   )Úmax_workersi,  )ÚtimeoutFT)ÚwaitÚcancel_futures)r   Úget_running_loopÚRuntimeErrorÚ
is_runningÚconcurrent.futuresÚfuturesÚThreadPoolExecutorÚsubmitÚrunÚresultÚshutdownÚTimeoutErrorÚcancelÚ	threadingÚcurrent_threadÚmain_threadr   Úrun_until_completer   )Úcoror   Ú
concurrentÚpoolÚfutureÚworker_loopÚ	tool_loops          r   Ú
_run_asyncr8   R   sp  € ð,ÝÔ'Ñ)Ô)ˆˆøÝð ð ð Øˆˆˆðøøøð ð ;�—’Ñ!Ô!ð ;à!Ð!Ð!Ð!ØÔ!×4Ò4ÀÐ4ÑCÔCˆØ—’�Wœ[¨$Ñ/Ô/ˆð	;Ø—=’=¨�=Ñ-Ô-ð
 �MŠM˜u°TˆMÑ:Ô:Ð:Ð:øð	 Ô!Ô.ð 	ð 	ð 	Ø�MŠM‰OŒOˆOØð	øøøøð �MŠM˜u°TˆMÑ:Ô:Ð:Ð:øøøõ ÔÑ!Ô!­Ô)>Ñ)@Ô)@Ð@Ð@Ý&Ñ(Ô(ˆØ×-Ò-¨dÑ3Ô3Ð3åÑ Ô €IØ×'Ò'¨Ñ-Ô-Ð-s$   ‚ –%¤%Á>B+ Â+%CÃC ÃC,)Údiscover_mcp_toolszMCP tool discovery failed: %s)Údiscover_pluginszPlugin discovery failed: %sÚTOOL_TO_TOOLSET_MAPÚTOOLSET_REQUIREMENTSÚ_last_resolved_tool_namesÚ
web_searchÚweb_extractÚterminalÚvision_analyzeÚmixture_of_agentsÚimage_generate)Úskills_listÚ
skill_viewÚskill_manage)
Úbrowser_navigateÚbrowser_snapshotÚbrowser_clickÚbrowser_typeÚbrowser_scrollÚbrowser_backÚbrowser_pressÚbrowser_get_imagesÚbrowser_visionÚbrowser_consoleÚcronjob)
Úrl_list_environmentsÚrl_select_environmentÚrl_get_current_configÚrl_edit_configÚrl_start_trainingÚrl_check_statusÚrl_stop_trainingÚrl_get_resultsÚrl_list_runsÚrl_test_inference)Ú	read_fileÚ
write_fileÚpatchÚsearch_filesÚtext_to_speech)Ú	web_toolsÚterminal_toolsÚvision_toolsÚ	moa_toolsÚimage_toolsÚskills_toolsÚbrowser_toolsÚcronjob_toolsÚrl_toolsÚ
file_toolsÚ	tts_toolsFÚenabled_toolsetsÚdisabled_toolsetsÚ
quiet_modeÚreturnc           	      óf	  ‡— t          ¦   «         }| �Ó| D ]Î}t          |¦  «        rSt          |¦  «        }|                     |¦  «         |s,t	          d|› d|rd                     |¦  «        nd› �¦  «         Œd|t          v rMt          |         }|                     |¦  «         |s(t	          d|› dd                     |¦  «        › �¦  «         Œº|st	          d|› �¦  «         ŒÏ�n?|�rdd	lm}  |¦   «         D ]$}|                     t          |¦  «        ¦  «         Œ%|D ]Î}t          |¦  «        rSt          |¦  «        }| 	                    |¦  «         |s,t	          d
|› d|rd                     |¦  «        nd› �¦  «         Œd|t          v rMt          |         }| 	                    |¦  «         |s(t	          d|› dd                     |¦  «        › �¦  «         Œº|st	          d|› �¦  «         ŒÏn5dd	lm}  |¦   «         D ]$}|                     t          |¦  «        ¦  «         Œ%t          j        ||¬¦  «        }	d„ |	D ¦   «         }
d|
v rpddlm}m}m} ||
z  } || |¦   «         ¬¦  «        }t!          |	¦  «        D ]<\  }}|                     di ¦  «                             d¦  «        dk    r
d|dœ|	|<    nŒ=dddœ}|D ]²Š‰|
v r¬	 ddlm} t)          ||‰         ¦  «        } |¦   «         }n# t*          $ r d}Y nw xY w|€$ˆfd„|	D ¦   «         }	|
                     ‰¦  «         Œft!          |	¦  «        D ]<\  }}|                     di ¦  «                             d¦  «        ‰k    r
d|dœ|	|<    nŒ=Œ³d|
v r“ddh|
z  }|sŠt!          |	¦  «        D ]z\  }}|                     di ¦  «                             d¦  «        dk    rH|d                              dd¦  «        }|                     dd¦  «        }di |d         ¥d|i¥dœ|	|<    nŒ{|sS|	rBd„ |	D ¦   «         }t	          d t1          |	¦  «        › d!d                     |¦  «        › �¦  «         nt	          d"¦  «         d#„ |	D ¦   «         a	 dd$lm}  ||	¦  «        }	n2# t*          $ r%}t8                               d%|¦  «         Y d}~nd}~ww xY w|	S )&a§  
    Get tool definitions for model API calls with toolset-based filtering.

    All tools must be part of a toolset to be accessible.

    Args:
        enabled_toolsets: Only include tools from these toolsets.
        disabled_toolsets: Exclude tools from these toolsets (if enabled_toolsets is None).
        quiet_mode: Suppress status prints.

    Returns:
        Filtered list of OpenAI-format tool definitions.
    Nu   âœ… Enabled toolset 'z': z, zno toolsu   âœ… Enabled legacy toolset 'u   âš ï¸�  Unknown toolset: r   )Úget_all_toolsetsu   ðŸš« Disabled toolset 'u   ðŸš« Disabled legacy toolset '©Úquietc                 ó*   — h | ]}|d          d         ’ŒS ©ÚfunctionÚnamer   ©Ú.0Úts     r   ú	<setcomp>z'get_tool_definitions.<locals>.<setcomp>  s!   € ÐJÐJÐJ°a˜A˜jœM¨&Ô1ÐJÐJÐJr   Úexecute_code)ÚSANDBOX_ALLOWED_TOOLSÚbuild_execute_code_schemaÚ_get_execution_mode)Úmoderv   rw   )Útyperv   Úget_dynamic_schema_coreÚget_dynamic_schema_admin)ÚdiscordÚdiscord_admin)Údiscord_toolc                 ón   •— g | ]1}|                      d i ¦  «                              d¦  «        ‰k    ¯/|‘Œ2S ru   )Úget)ry   rz   Údiscord_tool_names     €r   ú
<listcomp>z(get_tool_definitions.<locals>.<listcomp>6  sK   ø€ ð "ð "ð "ØØ—u’u˜Z¨Ñ,Ô,×0Ò0°Ñ8Ô8Ð<MÒMÐMð ØMÐMÐMr   rG   r>   r?   ÚdescriptionÚ zV For simple information retrieval, prefer web_search or web_extract (faster, cheaper).c                 ó*   — g | ]}|d          d         ‘ŒS ru   r   rx   s     r   rŠ   z(get_tool_definitions.<locals>.<listcomp>W  s!   € ÐHÐHÐH°A˜!˜Jœ-¨Ô/ÐHÐHÐHr   u   ðŸ› ï¸�  Final tool selection (z	 tools): u<   ðŸ› ï¸�  No tools selected (all filtered out or unavailable)c                 ó*   — g | ]}|d          d         ‘ŒS ru   r   rx   s     r   rŠ   z(get_tool_definitions.<locals>.<listcomp>]  s!   € Ð OÐ OÐ O¸1  :¤¨vÔ!6Ð OÐ OÐ Or   )Úsanitize_tool_schemaszSchema sanitization skipped: %s)Úsetr   r
   ÚupdateÚprintÚjoinÚ_LEGACY_TOOLSET_MAPÚtoolsetsrq   Údifference_updater	   Úget_definitionsÚtools.code_execution_toolr}   r~   r   Ú	enumeraterˆ   Útoolsr†   r   Ú	ExceptionÚdiscardÚreplaceÚlenr=   Útools.schema_sanitizerr�   ÚloggerÚwarning)rl   rm   rn   Útools_to_includeÚtoolset_nameÚresolvedÚlegacy_toolsrq   Úts_nameÚfiltered_toolsÚavailable_tool_namesr}   r~   r   Úsandbox_enabledÚdynamic_schemaÚiÚtdÚ_discord_schema_fnsÚ_dtÚ	schema_fnÚdynamicÚweb_tools_availableÚdescÚ
tool_namesr�   Úer‰   s                              @r   Úget_tool_definitionsrµ   Ë   s¶  ø€ õ&  ™EœEÐàÐ#Ø,ð 	Fð 	FˆLÝ Ñ-Ô-ð FÝ*¨<Ñ8Ô8�Ø ×'Ò'¨Ñ1Ô1Ð1Ø!ð vÝÐt°,ÐtÐtÐZbÐCrÀ4Ç9Â9ÈXÑCVÔCVÐCVÐhrÐtÐtÑuÔuÐuøØÕ!4Ð4Ð4Ý2°<Ô@�Ø ×'Ò'¨Ñ5Ô5Ð5Ø!ð eÝÐc¸ÐcÐcÈ$Ï)Ê)ÐT`ÑJaÔJaÐcÐcÑdÔdÐdøà!ð FÝÐD°lÐDÐDÑEÔEÐEøñ	Fð 
ñ >Ø-Ð-Ð-Ð-Ð-Ð-Ø'Ð'Ñ)Ô)ð 	>ð 	>ˆGØ×#Ò#¥O°GÑ$<Ô$<Ñ=Ô=Ð=Ð=à-ð 	Fð 	FˆLÝ Ñ-Ô-ð FÝ*¨<Ñ8Ô8�Ø ×2Ò2°8Ñ<Ô<Ð<Ø!ð xÝÐv°LÐvÐvÐ\dÐEtÀTÇYÂYÈxÑEXÔEXÐEXÐjtÐvÐvÑwÔwÐwøØÕ!4Ð4Ð4Ý2°<Ô@�Ø ×2Ò2°<Ñ@Ô@Ð@Ø!ð gÝÐe¸<ÐeÐeÈDÏIÊIÐVbÑLcÔLcÐeÐeÑfÔfÐføà!ð FÝÐD°lÐDÐDÑEÔEÐEøð	Fð 	.Ð-Ð-Ð-Ð-Ð-Ø'Ð'Ñ)Ô)ð 	>ð 	>ˆGØ×#Ò#¥O°GÑ$<Ô$<Ñ=Ô=Ð=Ð=õ Ô-Ð.>ÀjÐQÑQÔQ€Nð KÐJ¸>ÐJÑJÔJÐð Ð-Ð-Ð-ØsÐsÐsÐsÐsÐsÐsÐsÐsÐsØ/Ð2FÑFˆØ2Ð2°?ÐI\ÐI\ÑI^ÔI^Ð_Ñ_Ô_ˆÝ˜~Ñ.Ô.ð 	ð 	‰EˆAˆrØ�vŠv�j "Ñ%Ô%×)Ò)¨&Ñ1Ô1°^ÒCÐCØ-7À^Ð$TÐ$T�˜qÑ!Ø�ð Dð -Ø3ðð Ðð 1ð ð ÐØÐ 4Ð4Ð4ðØ5Ð5Ð5Ð5Ð5Ð5Ý# CÐ)<Ð=NÔ)OÑPÔP�	Ø#˜)™+œ+��øÝð ð ð Ø���ðøøøàˆð"ð "ð "ð "Ø-ð"ñ "ô "�ð %×,Ò,Ð->Ñ?Ô?Ð?Ð?å& ~Ñ6Ô6ð ð ‘E�A�rØ—v’v˜j¨"Ñ-Ô-×1Ò1°&Ñ9Ô9Ð=NÒNÐNØ5?ÈWÐ,UÐ,U˜ qÑ)Ø˜ð Oøð Ð1Ð1Ð1Ø+¨]Ð;Ð>RÑRÐØ"ð 	Ý" >Ñ2Ô2ð ð ‘��2Ø—6’6˜* bÑ)Ô)×-Ò-¨fÑ5Ô5Ð9KÒKÐKØ˜jœ>×-Ò-¨m¸RÑ@Ô@�DØŸ<š<ØpØñô �Dð
 !+Ø$K r¨*¤~Ð$K°}ÀdÐ$KÐ$Kð)ð )�N 1Ñ%ð �Eð Lð ð RØð 	RØHÐH¸ÐHÑHÔHˆJÝÐiµC¸Ñ4GÔ4GÐiÐiÐRV×R[ÒR[Ð\fÑRgÔRgÐiÐiÑjÔjÐjÐjåÐPÑQÔQÐQð !PÐ OÀÐ OÑ OÔ OÐð=Ø@Ð@Ð@Ð@Ð@Ð@Ø.Ð.¨~Ñ>Ô>ˆˆøÝð =ð =ð =Ý�ŠÐ8¸!Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<øøøøð=øøøð Ðs*   Ë&K/Ë/K>Ë=K>Ñ-Q? Ñ?
R.Ò	R)Ò)R.>   ÚtodoÚmemoryÚdelegate_taskÚsession_searchr\   r_   Ú	tool_nameÚargsc                 ó¶  — |rt          |t          ¦  «        s|S t          j        | ¦  «        }|s|S |                     d¦  «        pi                      d¦  «        }|s|S |                     ¦   «         D ]d\  }}t          |t          ¦  «        sŒ|                     |¦  «        }|sŒ3|                     d¦  «        }|sŒKt          ||¦  «        }||ur|||<   Œe|S )aA  Coerce tool call arguments to match their JSON Schema types.

    LLMs frequently return numbers as strings (``"42"`` instead of ``42``)
    and booleans as strings (``"true"`` instead of ``true``).  This compares
    each argument value against the tool's registered JSON Schema and attempts
    safe coercion when the value is a string but the schema expects a different
    type.  Original values are preserved when coercion fails.

    Handles ``"type": "integer"``, ``"type": "number"``, ``"type": "boolean"``,
    and union types (``"type": ["integer", "string"]``).
    Ú
parametersÚ
propertiesr�   )Ú
isinstanceÚdictr	   Ú
get_schemarˆ   ÚitemsÚstrÚ_coerce_value)	rº   r»   Úschemar¾   ÚkeyÚvalueÚprop_schemaÚexpectedÚcoerceds	            r   Úcoerce_tool_argsrË   ~  s  € ð ð •z $­Ñ-Ô-ð ØˆåÔ  Ñ+Ô+€FØð Øˆà—*’*˜\Ñ*Ô*Ð0¨b×5Ò5°lÑCÔC€JØð Øˆà—j’j‘l”lð  ð  ‰
ˆˆUÝ˜%¥Ñ%Ô%ð 	ØØ —n’n SÑ)Ô)ˆØð 	ØØ—?’? 6Ñ*Ô*ˆØð 	ØÝ  xÑ0Ô0ˆØ˜%ÐÐØˆD�‰Iøà€Kr   rÇ   c                 ó6  — t          |t          ¦  «        r|D ]}t          | |¦  «        }|| ur|c S Œ| S |dv rt          | |dk    ¬¦  «        S |dk    rt	          | ¦  «        S |dk    rt          | t          ¦  «        S |dk    rt          | t          ¦  «        S | S )z†Attempt to coerce a string *value* to *expected_type*.

    Returns the original string when coercion is not applicable or fails.
    )ÚintegerÚnumberrÍ   )Úinteger_onlyÚbooleanÚarrayÚobject)r¿   ÚlistrÄ   Ú_coerce_numberÚ_coerce_booleanÚ_coerce_jsonrÀ   )rÇ   Úexpected_typerz   r*   s       r   rÄ   rÄ   ¥  sÊ   € õ
 �-¥Ñ&Ô&ð àð 	ð 	ˆAÝ" 5¨!Ñ,Ô,ˆFØ˜UÐ"Ð"Ø���ð #àˆàÐ-Ð-Ð-Ý˜e°=ÀIÒ3MÐOÑOÔOÐOØ˜	Ò!Ð!Ý˜uÑ%Ô%Ð%Ø˜ÒÐÝ˜E¥4Ñ(Ô(Ð(Ø˜Ò Ð Ý˜E¥4Ñ(Ô(Ð(Ø€Lr   Úexpected_python_typec                 óÈ   — 	 t          j        | ¦  «        }n# t          t          f$ r | cY S w xY wt	          ||¦  «        r"t
                               d|j        ¦  «         |S | S )aJ  Parse *value* as JSON when the schema expects an array or object.

    Handles model output drift where a complex oneOf/discriminated-union schema
    causes the LLM to emit the array/object as a JSON string instead of a native
    structure.  Returns the original string if parsing fails or yields the wrong
    Python type.
    z5coerce_tool_args: coerced string to %s via json.loads)ÚjsonÚloadsÚ
ValueErrorÚ	TypeErrorr¿   r    ÚdebugÚ__name__)rÇ   rØ   Úparseds      r   rÖ   rÖ   ½  s   € ðÝ”˜EÑ"Ô"ˆˆøÝ�	Ð"ð ð ð Øˆˆˆðøøøå�&Ð.Ñ/Ô/ð Ý�ŠØCØ Ô)ñ	
ô 	
ð 	
ð ˆØ€Ls   ‚ —-¬-rÏ   c                 ó  — 	 t          | ¦  «        }n# t          t          f$ r | cY S w xY w||k    s&|t          d¦  «        k    s|t          d¦  «        k    r| S |t          |¦  «        k    rt          |¦  «        S |r| S |S )zFTry to parse *value* as a number.  Returns original string on failure.Úinfz-inf)ÚfloatrÜ   ÚOverflowErrorÚint)rÇ   rÏ   Úfs      r   rÔ   rÔ   Ò  s™   € ðÝ�%‰LŒLˆˆøÝ�Ð&ð ð ð Øˆˆˆðøøøð 	ˆA‚v€v�•e˜E‘l”lÒ"Ð" a­5°©=¬=Ò&8Ð&8Øˆà�C�‰FŒF‚{€{Ý�1‰vŒvˆØð àˆØ€Hs   ‚ ’(§(c                 ór   — |                       ¦   «                              ¦   «         }|dk    rdS |dk    rdS | S )zGTry to parse *value* as a boolean.  Returns original string on failure.ÚtrueTÚfalseF)ÚstripÚlower)rÇ   Úlows     r   rÕ   rÕ   ä  s<   € à
�+Š+‰-Œ-×
Ò
Ñ
Ô
€CØ
ˆf‚}€}ØˆtØ
ˆg‚~€~ØˆuØ€Lr   Úfunction_nameÚfunction_argsÚtask_idÚtool_call_idÚ
session_idÚ	user_taskÚenabled_toolsÚskip_pre_tool_call_hookc           
      ór  — t          | |¦  «        }	 | t          v rt          j        d| › d�i¦  «        S |sKd}	 ddlm}	  |	| ||pd|pd|pd¬¦  «        }n# t          $ r Y nw xY w|�t          j        d|id¬	¦  «        S n/	 dd
lm}
  |
d| ||pd|pd|pd¬¦  «         n# t          $ r Y nw xY w| t          vr%	 ddl	m
}  ||pd¦  «         n# t          $ r Y nw xY wt          j        ¦   «         }| dk    r$|�|nt          }t          j        | |||¬¦  «        }nt          j        | |||¬¦  «        }t!          t          j        ¦   «         |z
  dz  ¦  «        }	 dd
lm}
  |
d| |||pd|pd|pd|¬¦  «         n# t          $ r Y nw xY w	 dd
lm}
  |
d| |||pd|pd|pd|¬¦  «        }|D ]}t#          |t$          ¦  «        r|} nŒn# t          $ r Y nw xY w|S # t          $ rQ}d| › dt%          |¦  «        › �}t&                               |¦  «         t          j        d|id¬	¦  «        cY d}~S d}~ww xY w)aÁ  
    Main function call dispatcher that routes calls to the tool registry.

    Args:
        function_name: Name of the function to call.
        function_args: Arguments for the function.
        task_id: Unique identifier for terminal/browser session isolation.
        user_task: The user's original task (for browser_snapshot context).
        enabled_tools: Tool names enabled for this session.  When provided,
                       execute_code uses this list to determine which sandbox
                       tools to generate.  Falls back to the process-global
                       ``_last_resolved_tool_names`` for backward compat.

    Returns:
        Function result as a JSON string.
    Úerrorz" must be handled by the agent loopNr   )Úget_pre_tool_call_block_messagerŒ   )rï   rñ   rð   F)Úensure_ascii)Úinvoke_hookÚpre_tool_call)rº   r»   rï   rñ   rð   )Únotify_other_tool_callÚdefaultr|   )rï   ró   )rï   rò   iè  Úpost_tool_call)rº   r»   r*   rï   rñ   rð   Úduration_msÚtransform_tool_resultzError executing z: )rË   Ú_AGENT_LOOP_TOOLSrÚ   ÚdumpsÚhermes_cli.pluginsr÷   r›   rù   Ú_READ_SEARCH_TOOLSÚtools.file_toolsrû   ÚtimeÚ	monotonicr=   r	   Údispatchrå   r¿   rÃ   r    rö   )rí   rî   rï   rð   rñ   rò   ró   rô   Úblock_messager÷   rù   rû   Ú_dispatch_startr©   r*   rþ   Úhook_resultsÚhook_resultr´   Ú	error_msgs                       r   Úhandle_function_callr  î  s÷  € õ6 % ]°MÑBÔB€MðvDØÕ-Ð-Ð-Ý”:˜w¨=Ð(\Ð(\Ð(\Ð]Ñ^Ô^Ð^ð
 'ð 	Ø+/ˆMð
ØNÐNÐNÐNÐNÐNØ ?Ð ?Ø!Ø!Ø#˜M rØ)Ð/¨RØ!-Ð!3°ð!ñ !ô !��øõ ð ð ð Ø�ðøøøð Ð(Ý”z 7¨MÐ":ÈÐOÑOÔOÐOð )ð
Ø:Ð:Ð:Ð:Ð:Ð:Ø�Ø#Ø+Ø&Ø#˜M rØ)Ð/¨RØ!-Ð!3°ðñ ô ð ð øõ ð ð ð Ø�ðøøøð
 Õ 2Ð2Ð2ðØCÐCÐCÐCÐCÐCØ&Ð& wÐ';°)Ñ<Ô<Ð<Ð<øÝð ð ð Ø�ðøøøõ œ.Ñ*Ô*ˆØ˜NÒ*Ð*ð 0=Ð/H˜m˜mÕNgˆOÝÔ&Ø˜}ØØ-ðñ ô ˆFˆFõ Ô&Ø˜}ØØ#ðñ ô ˆFõ
 �4œ>Ñ+Ô+¨oÑ=ÀÑEÑFÔFˆð	Ø6Ð6Ð6Ð6Ð6Ð6ØˆKØ Ø'Ø"ØØ˜ 2Ø%Ð+¨Ø)Ð/¨RØ'ð	ñ 	ô 	ð 	ð 	øõ ð 	ð 	ð 	ØˆDð	øøøð	Ø6Ð6Ð6Ð6Ð6Ð6Ø&˜;Ø'Ø'Ø"ØØ˜ 2Ø%Ð+¨Ø)Ð/¨RØ'ð	ñ 	ô 	ˆLð  ,ð ð �Ý˜k­3Ñ/Ô/ð Ø(�FØ�Eðøøõ ð 	ð 	ð 	ØˆDð	øøøð ˆøåð Dð Dð DØ@ }Ð@Ð@½¸A¹¼Ð@Ð@ˆ	Ý�Š�YÑÔÐÝŒz˜7 IÐ.¸UÐCÑCÔCÐCÐCÐCÐCÐCÐCøøøøðDøøøsÝ   ’!G ´G ¹A ÁG Á
A#Á G Á"A#Á#G Â G ÂB  ÂG Â 
B-Â*G Â,B-Â-G Â:C ÃG Ã
CÃG ÃCÃA>G ÅE: Å9G Å:
FÆG ÆFÆG Æ=G	 ÇG Ç	
GÇG ÇGÇG Ç
H6Ç%AH1È+H6È1H6c                  ó(   — t          j        ¦   «         S )z!Return all registered tool names.)r	   Úget_all_tool_namesr   r   r   r  r  ˆ  s   € åÔ&Ñ(Ô(Ð(r   c                 ó*   — t          j        | ¦  «        S )z%Return the toolset a tool belongs to.)r	   Úget_toolset_for_tool)rº   s    r   r  r  �  s   € åÔ(¨Ñ3Ô3Ð3r   c                  ó(   — t          j        ¦   «         S )z0Return toolset availability info for UI display.)r	   Úget_available_toolsetsr   r   r   r  r  ’  s   € åÔ*Ñ,Ô,Ð,r   c                  ó(   — t          j        ¦   «         S )z>Return {toolset: available_bool} for every registered toolset.)r	   Úcheck_toolset_requirementsr   r   r   r  r  —  s   € åÔ.Ñ0Ô0Ð0r   rs   c                 ó,   — t          j        | ¬¦  «        S )z.Return (available_toolsets, unavailable_info).rr   )r	   Úcheck_tool_availabilityrr   s    r   r  r  œ  s   € åÔ+°%Ð8Ñ8Ô8Ð8r   )NNF)F)NNNNNF)=Ú__doc__rÚ   r   Úloggingr.   r  Útypingr   r   r   r   r   Útools.registryr   r	   r•   r
   r   Ú	getLoggerrß   r    r   ÚLockr   Úlocalr   r   r   r8   Útools.mcp_toolr9   r›   r´   rÞ   r  r:   Úget_tool_to_toolset_mapr;   rÃ   Ú__annotations__Úget_toolset_requirementsr<   rÀ   r=   r”   Úboolrµ   r   r  rË   rÄ   r�   rÖ   rÔ   rÕ   r  r  r  r  r  r  r   r   r   ú<module>r$     sˆ  ððð ð ð* €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø €€€Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3à ;Ð ;Ð ;Ð ;Ð ;Ð ;Ð ;Ð ;Ø 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6à	ˆÔ	˜8Ñ	$Ô	$€ð €
Ø �)”.Ñ"Ô"€Ø&�y”Ñ(Ô(Ð ðð ð ðð ð ð,2.ð 2.ð 2.ðr Ð Ñ Ô Ð ð5Ø1Ð1Ð1Ð1Ð1Ð1ØÐÑÔÐÐøØð 5ð 5ð 5Ø
‡L‚LÐ0°!Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4øøøøð5øøøð3Ø3Ð3Ð3Ð3Ð3Ð3ØÐÑÔÐÐøØð 3ð 3ð 3Ø
‡L‚LÐ.°Ñ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2øøøøð3øøøð 'G hÔ&FÑ&HÔ&HÐ �T˜#˜s˜(”^Ð HÐ HÑ Hà(I¨Ô(IÑ(KÔ(KÐ �d˜3 ˜9”oÐ KÐ KÑ Kð (*Ð ˜4 œ9Ð )Ð )Ñ )ð  Ð.Ø!�lØ%Ð&Ø%Ð&Ø$Ð%ØAÐAÐAðð ð ð  �[ðð ð ð GÐFÐFØ"Ð#ð-ð Ð ð> #'Ø#'Øð`ð `Ø˜3”ið`à˜C”yð`ð ð`ð 
ˆ$ˆs�CˆxŒ.Ôð	`ð `ð `ð `ðV JÐIÐIÐ Ø! >Ð2Ð ð$ ð $¨4°°S°¬>ð $¸dÀ3ÈÀ8¼nð $ð $ð $ð $ðN˜ð ð ð ð ð0˜ð °4ð ð ð ð ð*ð ˜#ð ¨Tð ð ð ð ð$˜3ð ð ð ð ð "Ø"&Ø $Ø#Ø)-Ø$)ðSDð SDØðSDà˜˜S˜”>ðSDð �cŒ]ðSDð ˜3”-ð	SDð
 ˜”ðSDð ˜Œ}ðSDð ˜D œIÔ&ðSDð "ðSDð 	ðSDð SDð SDð SDðt)˜D œIð )ð )ð )ð )ð
4 Cð 4¨H°S¬Mð 4ð 4ð 4ð 4ð
-  S¨$ Y¤ð -ð -ð -ð -ð
1 D¨¨d¨¤Oð 1ð 1ð 1ð 1ð
9ð 9 4ð 9°E¸$¸s¼)ÀTÈ$ÄZÐ:OÔ4Pð 9ð 9ð 9ð 9ð 9ð 9s0   Á:B ÂB0ÂB+Â+B0Â4C ÃC*Ã
C%Ã%C*