
    oq'j                        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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 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dgd
Z,i Z-e	e.ee	e&e
f                  f         e'd<   dZ/dXdZ0	 	 	 	 dYdeee&                  d eee&                  d!e1d"e1dee	e&e
f                  f
d#Z2	 	 	 	 dYdeee&                  d eee&                  d!e1d"e1dee	e&e
f                  f
d$Z3de4fd%Z5h d&Z6d'd(hZ7 ej8        d)ej9                  Z: ej8        d*ej;                  Z< ej8        d+ej;                  Z= ej8        d,ej>                  Z?d-Z@d.e&de&fd/ZAd0e&d1e	e&e
f         de	e&e
f         fd2ZBdZd3e&d4e*dz  fd5ZCd4e*dz  de1fd6ZDd3e&d7eEfd8ZFd[d3e&d9e1fd:ZGd3e&fd;ZHd<e
de.e&ee&         ee&         f         fd=ZIddddddddddd>
d?e&d@e	e&e
f         d<e
dAee&         dBee&         dCee&         dDee&         dEee&         dFe4dGee&         dHee&         dIee&         dJeee	e&e
f                           ddfdKZJ	 	 	 	 	 	 	 	 	 	 	 	 d\d?e&d@e	e&e
f         dAee&         dCee&         dBee&         dDee&         dEee&         dLee&         dMeee&                  dNe1dOe1dPeee	e&e
f                           deee&                  d eee&                  de&fdQZKdee&         fdRZLd0e&dee&         fdSZMde	e&e*f         fdTZNde	e&e1f         fdUZOd[dVe1deee&         ee*         f         fdWZPdS )]a  
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     0/home/ubuntu/.hermes/hermes-agent/model_tools.py_get_tool_loopr   /   s     
  !5!5!7!7 /11J                 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6D|t~~''|%''t$$$$(!Kr   c                 l   	 	 t          j                    }n# t          $ r d}Y nw xY w|r|                                rddl}d	t          j                     	fd}|j                            d          }|	                    |          }	 |
                    d          |                    d	           S # |j        j        $ r]                     d
          rE	C	 t          j        	          D ]}	                    |j                   n# t          $ r Y nw xY w w xY w# |                    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. Each handler is self-protecting via this function.
    Nr   c            	         t          j                                                     	 t          j                                                 	 t          j                  } | D ]}|                                 | r$                    t          j        | ddi           n# t          $ r Y nw xY w	                                 S # 	 t          j                  } | D ]}|                                 | r$                    t          j        | ddi           n# t          $ r Y nw xY w	                                 w xY w)Nreturn_exceptionsT)
r   r   setr   run_until_complete	all_taskscancelgather	Exceptionclose)pendingtcoro
loop_readyworker_loops     r   _run_in_workerz"_run_async.<locals>._run_in_workerx   s   !022KNN$&{333"55d;; &/<<G$ # #



 #66#NGLtLL   !   D!!#### &/<<G$ # #



 #66#NGLtLL   !   D!!####sC   (C AB''
B43B4EAD"!E"
D/,E.D//E   )max_workersi,  )timeoutF)waitg      ?)r   get_running_loopRuntimeError
is_runningconcurrent.futures	threadingEventfuturesThreadPoolExecutorsubmitresultshutdownTimeoutErrorr/   r!   call_soon_threadsafer"   current_threadmain_threadr   r    r   )
r(   r   
concurrentr+   poolfuturer'   	tool_loopr)   r*   s
   `       @@r   
_run_asyncrC   T   s   ('))     4&!! 4& 	"!!!;?_&&
	$ 	$ 	$ 	$ 	$ 	$ 	$, !444CC^,,	&===--  MMuM%%%% !. 
	 
	 
	 s++ 0G$.{;; C C#88BBBBC#   D 
	 MMuM%%%% !!)>)@)@@@&((--d333  I''---sH    ((C   'D,(1DD,
D'$D,&D''D,,D/ /E)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)	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
file_tools	tts_tools_tool_defs_cache   returnc                  8    t                                            dS )zDrop memoized get_tool_definitions() results. Called when dynamic
    schema dependencies change (e.g. discord capability cache reset,
    execute_code sandbox reconfigured).N)rk   clearr   r   r   _clear_tool_defs_cacherp   	  s     r   Fenabled_toolsetsdisabled_toolsets
quiet_modeskip_tool_search_assemblyc           	         |r	 ddl m}  |            }|                                }|j        |j        f}n# t
          t          t          f$ r d}Y nw xY w| t          |           nd|rt          |          ndt          j
        |t          t          j                            d                    t          |          f}t                              |          }	|	d |	D             at#          |	          S t%          | |||          }
|rot'          t                    t(          k    r9t                              t-          t/          t                                         |
t          |<   t#          |
          S |
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.
        skip_tool_search_assembly: When True, return the pre-assembly tool list
            (raw schemas for every enabled tool). Used internally by the
            tool_search / tool_describe bridge handlers so they can read the
            real catalog, not the already-collapsed one. Public callers should
            leave this False.

    Returns:
        Filtered list of OpenAI-format tool definitions.
    r   )get_config_pathNHERMES_KANBAN_TASKc                 *    g | ]}|d          d         S functionnamer   .0r'   s     r   
<listcomp>z(get_tool_definitions.<locals>.<listcomp>E  s!    (O(O(O1:v)>(O(O(Or   )rt   )hermes_cli.configrv   statst_mtime_nsst_sizeFileNotFoundErrorOSErrorImportError	frozensetr	   _generationboolosenvirongetrk   rG   list_compute_tool_definitionslen_TOOL_DEFS_CACHE_MAXpopnextiter)rq   rr   rs   rt   rv   cfg_pathcfg_statcfg_fp	cache_keycachedr9   s              r   get_tool_definitionsr     s   @   	999999&((H}}H*H,<=FF!7K8 	 	 	FFF	 ,<+GI&'''T,=GI'(((4  45566*++
	 "%%i00 )P(O(O(O(O% <<&'79JJAZ\ \ \F    $888  d+;&<&<!=!=>>>&,#F||Ms   27 AAc           	      
  " t                      }| t          |           }t          j                            d          rd|vr|                    d           |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          |
                     %|r|D ]}t          |          rSt          |          }|                    |           |s,t          d| d|rd
                    |          nd            d|t          v rMt          |         }|                    |           |s(t          d| dd
                    |                      |st          d	|            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} t1          ||"                   } |            }n# t2          $ r d}Y nw xY w|$"fd|D             }|                    "           ft+          |          D ]<\  }}|                    di                               d          "k    r
d|d||<    n=d|v rddh|z  }|st+          |          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"t9          |           d#d
                    |                      nt          d$           d% |D             a	 d
d&lm}  ||          }n2# t2          $ r%}t@          !                    d'|           Y d}~nd}~ww xY w	 d
d(l"m#}m$}  |            }|s_|j%        d)k    rTtM                      }  ||| |*          }!|!j'        r*|s(t          d+|!j(         d,|!j)         d-|!j*         d.           |!j+        }n2# t2          $ r%}t@          !                    d/|           Y d}~nd}~ww xY w|S )0z8Uncached implementation of :func:`get_tool_definitions`.Nrw   kanbanu   ✅ 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 ry   r   r|   s     r   	<setcomp>z,_compute_tool_definitions.<locals>.<setcomp>  s!    JJJaAjM&1JJJr   execute_code)SANDBOX_ALLOWED_TOOLSbuild_execute_code_schema_get_execution_mode)moderz   r{   )typerz   get_dynamic_schema_coreget_dynamic_schema_admin)discorddiscord_admin)discord_toolc                 n    g | ]1}|                     d i                                d          k    /|2S ry   )r   )r}   r'   discord_tool_names     r   r~   z-_compute_tool_definitions.<locals>.<listcomp>  sK     " " "uuZ,,0088<MMM MMMr   rQ   rH   rI   description zV For simple information retrieval, prefer web_search or web_extract (faster, cheaper).c                 *    g | ]}|d          d         S ry   r   r|   s     r   r~   z-_compute_tool_definitions.<locals>.<listcomp>  s!    HHHA!J-/HHHr   u   🛠️  Final tool selection (z	 tools): u<   🛠️  No tools selected (all filtered out or unavailable)c                 *    g | ]}|d          d         S ry   r   r|   s     r   r~   z-_compute_tool_definitions.<locals>.<listcomp>  s!     O O O1:v!6 O O Or   )sanitize_tool_schemaszSchema sanitization skipped: %s)assemble_tool_defsload_configoff)context_lengthconfigu   🔎 Tool Search: z MCP/plugin tools deferred (~z6 tokens) behind tool_search/describe/call. Threshold ~z tokens.z Tool search assembly skipped: %s),r   r   r   r   r   appendr   r
   updateprintjoin_LEGACY_TOOLSET_MAPtoolsetsr   difference_updater	   get_definitionstools.code_execution_toolr   r   r   	enumeratetoolsr   r   r$   discardreplacer   rG   tools.schema_sanitizerr   loggerwarningtools.tool_searchr   r   enabled_resolve_active_context_length	activateddeferred_countdeferred_tokensthreshold_tokens	tool_defs)#rq   rr   rs   rt   tools_to_includeeffective_enabled_toolsetstoolset_nameresolvedlegacy_toolsr   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   _load_ts_configts_cfgr   assemblyr   s#                                     @r   r   r   ^  s     EE#%)*:%;%;":>>.// 	8HD^4^4^ '--h7776 	B 	BL-- B*<88 ''111! vt,ttZbCr499XCVCVCVhrttuuu!4442<@ ''555! eccc$))T`JaJaccddd B@,@@AAA	B 	.-----'')) 	> 	>G##OG$<$<====  B- 	B 	BL-- B*<88 228<<<! xvLvv\dEtTYYxEXEXEXjtvvwww!4442<@ 22<@@@! ge<eeDIIVbLcLceefff B@,@@AAA -.>jQQQN KJ>JJJ ---ssssssssss/2FF22?I\I\I^I^___~.. 	 	EArvvj"%%))&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  EArvvj"--11&99=NNN5?W,U,Uq) O 111+];>RR" 	">22  266*b))--f559KKKj>--mR@@D<<p D
 !+$Kr*~$K}d$K$K) )N1% E L  R 	RHHHHHJiC4G4GiiRVR[R[\fRgRgiijjjjPQQQ !P O O O O=@@@@@@..~>> = = =8!<<<<<<<<=>XXXXXXXX ""( 	0V^u-D-D;==N))-  H
 ! * F)@ F F!1F F"*";F F F  
 &/N > > >91========> sC   &K??LL=R 
R>R99R>A3T6 6
U% U  U%c                     	 ddl m}   |             pi }t          |                    d          t                    r|                    d          ni }t          |t                    si }|                    d          p|                    d          pd                                }|sdS ddlm} t           ||          pd          S # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)	u   Look up the active model's context length for the tool-search gate.

    Returns 0 when the model can't be resolved — ``should_activate`` falls
    back to a fixed token cutoff in that case.
    r   )r   modeldefaultr   )get_model_context_lengthz+Could not resolve active context length: %sN)r   r   
isinstancer   dictstripagent.model_metadatar   intr$   r   debug)_loadcfg	model_cfgmodel_idr   r   s         r   r   r     s#   ::::::eggm(237773C3CT(J(JRCGGG$$$PR	)T** 	IMM'**LimmI.F.FL"SSUU 	1AAAAAA++H55:;;;   BAFFFqqqqqs   B(C ,C 
C<C77C<>   todomemorydelegate_tasksession_searchr\   r_   zR</?(?:tool_call|function_call|result|response|output|input|system|assistant|user)>z%^\s*```(?:json|xml|html|markdown)?\s*z
\s*```\s*$z<!\[CDATA\[.*?\]\]>i  	error_msgc                 F   | sdS t                               d|           }t                              d|          }t                              d|          }t                              d|          }t          |          t          k    r|dt          dz
           dz   }d| S )zStrip structural framing tokens from a tool error before showing it to the model.

    See _TOOL_ERROR_ROLE_TAG_RE docstring above for rationale.
    z[TOOL_ERROR] r   N   z...)_TOOL_ERROR_ROLE_TAG_REsub_TOOL_ERROR_FENCE_OPEN_RE_TOOL_ERROR_FENCE_CLOSE_RE_TOOL_ERROR_CDATA_REr   _TOOL_ERROR_MAX_LEN)r   	sanitizeds     r   _sanitize_tool_errorr  W  s    
  '++B	::I)--b)<<I*..r9==I$((Y77I
9~~+++62Q667%?	&9&&&r   	tool_nameargsc                    |rt          |t                    s|S t          j        |           }|s|S |                    d          pi                     d          }|s|S t          |                                          D ]j\  }}|                    |          }|s|                    d          }|dk    r|t          |t
          t          f          st          |t                    rt          |||          }||ur|||<   |
                                                    d          rt                              d| |           |g||<   t                              d	| |           |g||<   t                              d
t          |          j        | |           %t          |t                    s<|st#          |          sOt          |||          }||ur|||<   l|S )a  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"]``).

    Also wraps bare scalar values in a single-element list when the schema
    declares ``"type": "array"``.  Open-weight models (DeepSeek, Qwen, GLM)
    sometimes emit ``{"urls": "https://a.com"}`` when the tool expects
    ``{"urls": ["https://a.com"]}``; wrapping here avoids a confusing tool
    failure on what is otherwise a well-formed call.
    
parameters
propertiesr   arrayNschema[u   coerce_tool_args: %s.%s looks like a JSON array string but could not be parsed — model may have emitted a JSON-encoded string instead of a native array. Falling back to single-element list.z7coerce_tool_args: wrapped bare string in list for %s.%sz3coerce_tool_args: wrapped bare %s in list for %s.%s)r   r   r	   
get_schemar   r   itemstuplestr_coerce_valuer   
startswithr   r   infor   __name___schema_allows_null)	r  r  r
  r  keyvalueprop_schemaexpectedcoerceds	            r   coerce_tool_argsr  k  s/   $  z$--  ++F **\**0b55lCCJ 4::<<(( 2  2 
U nnS)) 	??6** w5#4ZPTV[}=]=]#4%%% 'xLLL%'' !(DI ;;==++C00 NN? "3   #GS	Ms   DIKKEU$i   %%% 	 	 3K @ @ 	xDDD%DIKr   r  r
  c                    t          |          r,|                                                                 dk    rdS 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 |dk    r,|                                                                 dk    rdS | S )
zAttempt to coerce a string *value* to *expected_type*.

    Returns the original string when coercion is not applicable or fails.
    nullNr	  >   numberintegerr  )integer_onlybooleanr  object)
r  r   lowerr   r   r  _coerce_number_coerce_boolean_coerce_jsonr   )r  expected_typer
  r'   r9   s        r   r  r    s0   
 6"" u{{}}':':'<'<'F'Ft-&&  	 	A"5!F;;;FU"" #---e=I3MOOOO	!!u%%%E4(((  E4(((5;;==#6#6#8#8F#B#BtLr   c                    t          | t                    sdS |                     d          }|dk    rdS t          |t                    rd|v rdS |                     d          du rdS dD ]d}|                     |          }t          |t                    s-|D ]4}t          |t                    r|                    d          dk    r  dS 5edS )z@Return True when a JSON Schema fragment explicitly permits null.Fr   r  Tnullable)anyOfoneOf)r   r   r   r   )r
  schema_type	union_keyvariantsvariants        r   r  r    s    fd## u**V$$Kft+t$$ ;)>)>tzz*%%t'  	::i(((D)) 	 	 	G'4(( W[[-@-@F-J-Jttt	 5r   expected_python_typec                 ~   	 t          j        |           }nA# t          t          f$ r-}t                              d|j        |           | cY d}~S d}~ww xY wt          ||          r"t                              d|j                   |S t                              dt          |          j        |j                   | 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.
    zIcoerce_tool_args: failed to parse string as JSON for expected type %s: %sNz5coerce_tool_args: coerced string to %s via json.loadsuL   coerce_tool_args: JSON-parsed value is %s, expected %s — skipping coercion)
jsonloads
ValueError	TypeErrorr   r   r  r   r   r   )r  r/  parsedexcs       r   r%  r%    s    E""	"   W )	
 	
 	

  &.// C )	
 	
 	
 
NNVV%  
 Ls    A"A
AA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)floatr3  OverflowErrorr   )r  r  fs      r   r#  r#    s    %LL&    	AvveEll""a5==&8&8CFF{{1vv 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)r   r"  )r  lows     r   r$  r$  %  s<    
++--



C
f}}t
g~~uLr   r9   c                    	 t          | t                    rt          j        |           n| }t          |t                    r:|                    d          r%ddt          |                    d                    fS n# t          $ r Y nw xY wdS )Nerror
tool_error)okNN)r   r  r1  r2  r   r   r$   )r9   parsed_results     r   _tool_result_observer_fieldsrE  /  s    .8.E.EQ
6***6mT** 	J}/@/@/I/I 	JL#m.?.?.H.H*I*III   s   A9A= =
B
	B
)
task_id
session_idtool_call_idturn_idapi_request_idduration_msstatus
error_typeerror_messagemiddleware_tracefunction_namefunction_argsrF  rG  rH  rI  rJ  rK  rL  rM  rN  rO  c                 &   	 ddl m}m}  |d          sdS |	t          |          \  }	}
} |d| |||pd|pd|pd|pd|pd||	|
|t	          |pg                      dS # t
          $ r&}t                              d|           Y d}~dS d}~ww xY w)u  Emit the ``post_tool_call`` observer hook.

    No-ops cheaply when no plugin has registered for ``post_tool_call`` —
    the ``has_hook`` gate skips both the result-field derivation and the
    payload dispatch so the no-listener path costs one dict lookup.  When
    ``status`` is not supplied, the ok/error fields are derived from the
    result *after* the gate (parsing the result is only worth it when a
    listener will actually consume it).
    r   has_hookinvoke_hookpost_tool_callNr   )r  r  r9   rF  rG  rH  rI  rJ  rK  rL  rM  rN  rO  zpost_tool_call hook error: %s)hermes_cli.pluginsrT  rU  rE  r   r$   r   r   )rP  rQ  r9   rF  rG  rH  rI  rJ  rK  rL  rM  rN  rO  rT  rU  	_hook_errs                   r   _emit_post_tool_call_hookrY  9  s   2A<<<<<<<<x()) 	F>0LV0T0T-FJ#Mr!'R%+Mr)/R#!'!"2"8b99	
 	
 	
 	
 	
 	
   A A A4i@@@@@@@@@As   A  AA   
B*BB	user_taskenabled_toolsskip_pre_tool_call_hookskip_tool_request_middlewaretool_request_middleware_tracec                    1 t           |          }t          |t                    si }t          |pg           }d}	 ddlm} n# t          $ r d}Y nw xY w|(|                               r	 t          ||dd          pg }n# t          $ r g }Y nw xY w |j	        k    r|
                    |pi |          S  |j        k    r|                    |pi |          S  |j        k    r|                    |pi           \  }}}|s|st          j        d|pdid	
          S |                    |          }||vrt          j        dd| did	
          S t%          ||||||	|
t          |          ||          S t          |          }|
sk	 ddlm}  | |pd|pd|pd|pd|pd          }|j        }|j        }|j        }n2# t          $ r%}t0                              d|           Y d}~nd}~ww xY w	  t4          v rt          j        d  di          S |	sd}	 ddlm}  | |pd|pd|pd|pd|pdt          |                    }n2# t          $ r%}t0                              d|           Y d}~nd}~ww xY w|Bt          j        d|id	
          }t;           ||||||dd|t          |                     |S 	 ddlm}  | |          }||S nS# t          $ rF}t0                              d|            dv rt          j        ddid	
          cY d}~S Y d}~nd}~ww xY w t@          vr%	 ddl!m"}   | pd           n# t          $ r Y nw xY wtG          j$                    }!d}"	 ddl%m&}#m'}$  |$|pd|pd           }"n# t          $ r d}#Y nw xY w	  d!k    r4||ntP          1d"tR          tT          tV          f         d#tV          f 1fd$}%n(d"tR          tT          tV          f         d#tV          f fd%}%dd&lm,}&  |& ||%|pd|pd|pd|pd|pd'	  	        }|"|#	  |#|"           n8# t          $ r Y n,w xY wn'# |"|#	  |#|"           w # t          $ r Y w w xY ww w xY wt[          tG          j$                    |!z
  d(z            }'t;           |||||||'t          |          )
  
         	 dd*lm.}(m/})  |(d+          rSta          |          \  }*}+}, |)d+ ||pd|pd|pd|pd|pd|'|*|+|,,          }-|-D ]}.t          |.tT                    r|.} nn2# t          $ r%}t0                              d-|           Y d}~nd}~ww xY w|S # t          $ r^}/d.  d/tU          |/           }0t0          1                    |0           t          j        dte          |0          id	
          cY d}/~/S d}/~/ww xY w)0a  
    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.
        enabled_toolsets: The session's enabled toolsets.  Used to scope the
                       Tool Search bridge catalog so ``tool_search`` /
                       ``tool_describe`` / ``tool_call`` only see and invoke
                       tools the session was actually granted.  ``None`` means
                       "no restriction" (the caller scopes to every toolset),
                       matching ``get_tool_definitions`` semantics.
        disabled_toolsets: The session's disabled toolsets, applied as a
                       subtraction when scoping the bridge catalog.

    Returns:
        Function result as a JSON string.
    Nr   )tool_searchT)rq   rr   rs   rt   )current_tool_defsrA  ztool_call could not be resolvedF)ensure_ascii'zO' is not available in this session. Use tool_search to find tools you can call.)rP  rQ  rF  rH  rG  rZ  r[  r\  r]  r^  rq   rr   )apply_tool_request_middlewarer   )rF  rG  rH  rI  rJ  z!tool_request middleware error: %sz" must be handled by the agent loop)get_pre_tool_call_block_message)rF  rG  rH  rI  rJ  rO  zpre_tool_call hook error: %sblockedplugin_block)rP  rQ  r9   rF  rG  rH  rI  rJ  rL  rM  rN  rO  )maybe_require_edit_approvalz!ACP edit approval guard error: %s>   r^   r]   z+Edit approval denied: approval guard failed)notify_other_tool_callr   )#reset_current_observability_context!set_current_observability_context)rI  rH  r   	next_argsrm   c                 4    t          j        |           S )N)rF  r[  r	   dispatch)rl  rP  r   rF  s    r   	_dispatchz'handle_function_call.<locals>._dispatchZ  s(    #,%y '&5   r   c                 4    t          j        |           S )N)rF  rZ  rn  )rl  rP  rF  rZ  s    r   rp  z'handle_function_call.<locals>._dispatcha  s(    #,%y '"+   r   )run_tool_execution_middleware)original_argsrF  rG  rH  rI  rJ  i  )
rP  rQ  r9   rF  rG  rH  rI  rJ  rK  rO  rS  transform_tool_result)r  r  r9   rF  rG  rH  rI  rJ  rK  rL  rM  rN  z$transform_tool_result hook error: %szError executing z: )3r  r   r   r   r   r`  r$   is_bridge_toolr   TOOL_SEARCH_NAMEdispatch_tool_searchTOOL_DESCRIBE_NAMEdispatch_tool_describeTOOL_CALL_NAMEresolve_underlying_callr1  dumpsscoped_deferrable_nameshandle_function_callhermes_cli.middlewarerd  payloadoriginal_payloadtracer   r   _AGENT_LOOP_TOOLSrW  re  rY  acp_adapter.edit_approvalrh  _READ_SEARCH_TOOLStools.file_toolsri  time	monotonictools.approvalrj  rk  rG   r   r  r   rr  r   rT  rU  rE  	exceptionr  )2rP  rQ  rF  rH  rG  rI  rJ  rZ  r[  r\  r]  r^  rq   rr   _tool_middleware_trace_ts_modcurrent_defsunderlying_nameunderlying_argserr_scoped_deferrable_tool_original_argsrd  _tool_request_mw_mw_errblock_messagere  rX  r9   rh  edit_block_message_edit_approval_errri  _dispatch_start_approval_tokensrj  rk  rp  rr  rK  rT  rU  rL  rM  rN  hook_resultshook_resultr   r   r   s2   ` `    `                                         @r   r~  r~  l  s
   R %]MBBMmT** !"?"E2FF G0000000    w55mDD	 0!1"34    	 L
  	 	 	LLL	G444//0CBN 0 P P PG66611-2E2DP 2 R R RG2224;4S4STaTgeg4h4h1O_c 6/ 6z7C,T3T"U/46 6 6 6 ")!@!@!N!N&888zFO F F F#
 !&' ' ' ' (--)%#+(?-I.23I.J.J!1"3    }--' G	GKKKKKK<<2%+)/R2-3      -4M"2"C%5%;"" 	G 	G 	GLL<gFFFFFFFF	GwZ---:w=(\(\(\]^^^ ' !	+/MHNNNNNN ? ?!!#Mr)/R!-!3#Mr#1#7R%)*@%A%A	! 	! 	!  H H H;YGGGGGGGGH (Wm$<5QQQ)"/"/!#)!-##1$-"/%)*@%A%A    
		pMMMMMM!<!<]M!Z!Z!-)) . 	p 	p 	pLL<>PQQQ 777z7,Y"Zinooooooooo 87777	p  222CCCCCC&&w';)<<<<    .**
	7         A@2)/R       	7 	7 	726///	7$	.. 4A3L--Rkc3h C         c3h C         LKKKKK2212%+)/R2-3
 
 
F  +0S0_778HIIII    D  +0S0_778HIIII    D ,0_
 4>++o=EFF!''!%)#!"899	
 	
 	
 	
*	L@@@@@@@@x/00 4PQW4X4X1
M*{++&!#Mr)/R!-!3#Mr#1#7R +!)"/      $0  K!+s33 !,  	L 	L 	LLL?KKKKKKKK	L  Z Z Z@}@@A@@	###z7$8$C$CDSXYYYYYYYYYZs   A AA3B	 	BB7G 
G=G88G=!U" #U" (0I U" 
J#J>U" JAU" K' &U" '
L716L2'L7(U" -U" 2L77U" M U" 
M%"U" $M%%U" >N U" N'$U" &N''U" +BQ 1U" 6Q U" 
QU" QU" Q7Q%$Q7%
Q2/Q71Q22Q77AU" A&T. -U" .
U8UU" UU" "
W
,AW?W
W
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   r   c                 ,    t          j        |           S )z.Return (available_toolsets, unavailable_info).r   )r	   check_tool_availabilityr   s    r   r  r    s    +%8888r   )rm   N)NNFF)N)F)NNNNNNNFFNNN)Q__doc__r   r1  rer   loggingr4   r  typingr   r   r   r   r   tools.registryr   r	   r   r
   r   	getLoggerr  r   r   Lockr   localr   r   r   rC   rW  rD   r$   r   r   get_tool_to_toolset_maprE   r  __annotations__get_toolset_requirementsrF   r   rG   r   rk   r  r   rp   r   r   r   r   r   r  r  compile
IGNORECASEr   	MULTILINEr   r   DOTALLr   r   r  r  r  r  r   r%  r#  r$  rE  rY  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((     ,Y. Y. Y.@      3333333 3 3 3
LL.222222223 'Gh&F&H&H T#s(^ H H H(I(I(K(K d39o K K K (* 49 ) ) ) .!l%&%&$%AAA    [FFF"#  D 79 $ud4S>223 8 8 8      -1-1&+	K KtCy)KS	*K K  $	K
 
$sCx.K K K K^ -1-1&+	z ztCy)zS	*z z  $	z
 
$sCx.z z z zz    < JII !>2 & %"*YM   'BJ'OQSQ]^^ 'RZr|DD !rz"8")DD  'C 'C ' ' ' '(Q Q4S> Qd38n Q Q Q Qh  TD[    :t     0 4    > # T    $3     sHSM8TW=7X1Y     " $"&!$(  $#'7;0A 0A 0A0A S>0A 	0A
 c]0A 0A 3-0A c]0A SM0A 0A SM0A 0A C=0A tDcN340A 
0A 0A 0A 0Al ""& $!$(#)-$)).DH,0-1DZ DZDZS>DZ c]DZ 3-	DZ
 DZ c]DZ SMDZ }DZ DI&DZ "DZ #'DZ $,Dc3h,@#ADZ tCy)DZ  S	*DZ 	DZ DZ DZ DZV
)DI ) ) ) )
4C 4HSM 4 4 4 4
-S$Y - - - -
1DdO 1 1 1 1
9 94 9E$s)T$Z:O4P 9 9 9 9 9 9s   B B8B33B8