
    Ki)                         d Z ddlZddlZddlmZmZmZmZmZ  ej	        e
          Z G d d          Z G d d          Z e            ZdS )aV  Central registry for all hermes-agent tools.

Each tool file calls ``registry.register()`` at module level to declare its
schema, handler, toolset membership, and availability check.  ``model_tools.py``
queries the registry instead of maintaining its own parallel data structures.

Import chain (circular-import safe):
    tools/registry.py  (no imports from model_tools or tool files)
           ^
    tools/*.py  (import from tools.registry at module level)
           ^
    model_tools.py  (imports tools.registry + all tool modules)
           ^
    run_agent.py, cli.py, batch_runner.py, etc.
    N)CallableDictListOptionalSetc                       e Zd ZdZdZd ZdS )	ToolEntryz&Metadata for a single registered tool.	nametoolsetschemahandlercheck_fnrequires_envis_asyncdescriptionemojic
                     || _         || _        || _        || _        || _        || _        || _        || _        |	| _        d S Nr
   )
selfr   r   r   r   r   r   r   r   r   s
             +/home/ubuntu/hermes-agent/tools/registry.py__init__zToolEntry.__init__    sG    	 ( &


    N)__name__
__module____qualname____doc__	__slots__r    r   r   r	   r	      s0        00I

 
 
 
 
r   r	   c                      e Zd ZdZd Z	 	 	 	 	 d#dededed	ed
edede	dedefdZ
deddfdZd$dee         de	dee         fdZdededefdZdee         fdZdedee         fdZdedee         fdZd%dededefdZdeeef         fdZdede	fdZdeee	f         fdZdeeef         fd Zdeeef         fd!Zd$de	fd"ZdS )&ToolRegistryzISingleton registry that collects tool schemas + handlers from tool files.c                 "    i | _         i | _        d S r   )_tools_toolset_checksr   s    r   r   zToolRegistry.__init__0   s    ,.46r   NF r   r   r   r   r   r   r   r   r   c
                 :   | j                             |          }
|
r-|
j        |k    r"t                              d||
j        |           t          ||||||pg ||p|                    dd          |		  	        | j         |<   |r|| j        vr|| j        |<   dS dS dS )zARegister a tool.  Called at module-import time by each tool file.zMTool name collision: '%s' (toolset '%s') is being overwritten by toolset '%s'r   r&   r
   N)r#   getr   loggerwarningr	   r$   )r   r   r   r   r   r   r   r   r   r   existings              r   registerzToolRegistry.register8   s     ;??4(( 	(G33NN.h&  
 &%+#Dvzz-'D'D

 

 

D  	5t';;;,4D )))	5 	5;;r   returnc                 <   | j                             |d          dS j        | j        v rRt	          fd| j                                         D                       s | j                            j        d           t                              d|           dS )a  Remove a tool from the registry.

        Also cleans up the toolset check if no other tools remain in the
        same toolset.  Used by MCP dynamic tool discovery to nuke-and-repave
        when a server sends ``notifications/tools/list_changed``.
        Nc              3   8   K   | ]}|j         j         k    V  d S r   r   ).0eentrys     r   	<genexpr>z*ToolRegistry.deregister.<locals>.<genexpr>e   s=       =
 =
+,AI&=
 =
 =
 =
 =
 =
r   zDeregistered tool: %s)r#   popr   r$   anyvaluesr)   debugr   r   r3   s     @r   
deregisterzToolRegistry.deregisterZ   s     d++=F=D000 =
 =
 =
 =
040B0B0D0D=
 =
 =
 :
 :
0  $$U]D999,d33333r   
tool_namesquietc                    g }i }t          |          D ]}| j                            |          }|s|j        r|j        |vrb	 t	          |                                          ||j        <   n7# t
          $ r* d||j        <   |st                              d|           Y nw xY w||j                 s|st                              d|           i |j        d|j	        i}|
                    d|d           |S )zReturn OpenAI-format tool schemas for the requested tool names.

        Only tools whose ``check_fn()`` returns True (or have no check_fn)
        are included.
        FzTool %s check raised; skippingz"Tool %s unavailable (check failed)r   function)typer>   )sortedr#   r(   r   bool	Exceptionr)   r8   r   r   append)r   r;   r<   resultcheck_resultsr   r3   schema_with_names           r   get_definitionszToolRegistry.get_definitionso   s<    .0:&& 	N 	NDKOOD))E ~ >66Q8<U^^=M=M8N8Nen55$ Q Q Q8=en5$ Q"LL)I4PPPQ %U^4   Q%I4PPPC%,C
CCMM:;KLLMMMMs   )A..1B"!B"argsc                    | j                             |          }|st          j        dd| i          S 	 |j        rddlm}  | |j        |fi |          S  |j        |fi |S # t          $ rT}t          
                    d||           t          j        ddt          |          j         d| i          cY d}~S d}~ww xY w)	zExecute a tool handler by name.

        * Async handlers are bridged automatically via ``_run_async()``.
        * All exceptions are caught and returned as ``{"error": "..."}``
          for consistent error format.
        errorzUnknown tool: r   )
_run_asynczTool %s dispatch error: %szTool execution failed: z: N)r#   r(   jsondumpsr   model_toolsrK   r   rB   r)   	exceptionr?   r   )r   r   rH   kwargsr3   rK   r2   s          r   dispatchzToolRegistry.dispatch   s    %% 	B:w(?(?(?@AAA	\~ A222222!z-%-"?"?"?"?@@@ 5=00000 	\ 	\ 	\94CCC:w(Y$q''BR(Y(YVW(Y(YZ[[[[[[[[	\s$   #A) A) )
C3A	C<CCc                 N    t          | j                                                  S )z0Return sorted list of all registered tool names.)r@   r#   keysr%   s    r   get_all_tool_nameszToolRegistry.get_all_tool_names   s    dk&&(()))r   c                 L    | j                             |          }|r|j        ndS )u   Return a tool's raw schema dict, bypassing check_fn filtering.

        Useful for token estimation and introspection where availability
        doesn't matter — only the schema content does.
        N)r#   r(   r   r9   s      r   
get_schemazToolRegistry.get_schema   s(     %%$.u||$.r   c                 L    | j                             |          }|r|j        ndS )z.Return the toolset a tool belongs to, or None.N)r#   r(   r   r9   s      r   get_toolset_for_toolz!ToolRegistry.get_toolset_for_tool   s&    %% %/u}}4/r      ⚡defaultc                 Z    | j                             |          }|r|j        r|j        n|S )z3Return the emoji for a tool, or *default* if unset.)r#   r(   r   )r   r   rZ   r3   s       r   	get_emojizToolRegistry.get_emoji   s-    %%$AA'Br   c                 H    d | j                                         D             S )z?Return ``{tool_name: toolset_name}`` for every registered tool.c                 $    i | ]\  }}||j         S r   r0   )r1   r   r2   s      r   
<dictcomp>z8ToolRegistry.get_tool_to_toolset_map.<locals>.<dictcomp>   s     CCCGD!aiCCCr   )r#   itemsr%   s    r   get_tool_to_toolset_mapz$ToolRegistry.get_tool_to_toolset_map   s$    CCt{/@/@/B/BCCCCr   c                     | j                             |          }|sdS 	 t           |                      S # t          $ r t                              d|           Y dS w xY w)zCheck if a toolset's requirements are met.

        Returns False (rather than crashing) when the check function raises
        an unexpected exception (e.g. network error, missing import, bad config).
        Tz,Toolset %s check raised; marking unavailableF)r$   r(   rA   rB   r)   r8   )r   r   checks      r   is_toolset_availablez!ToolRegistry.is_toolset_available   su     $((11 	4	==  	 	 	LLGQQQ55	s   7 %A A c                      t          d  j                                        D                       } fdt          |          D             S )z7Return ``{toolset: available_bool}`` for every toolset.c              3   $   K   | ]}|j         V  d S r   r0   )r1   r2   s     r   r4   z:ToolRegistry.check_toolset_requirements.<locals>.<genexpr>   s$      ??Qqy??????r   c                 <    i | ]}|                     |          S r   )rd   )r1   tsr   s     r   r_   z;ToolRegistry.check_toolset_requirements.<locals>.<dictcomp>   s)    MMMbD--b11MMMr   )setr#   r7   r@   )r   toolsetss   ` r   check_toolset_requirementsz'ToolRegistry.check_toolset_requirements   sO    ??$+*<*<*>*>?????MMMMF8<L<LMMMMr   c                 b   i }| j                                         D ]}|j        }||vr|                     |          g dg d||<   ||         d                             |j                   |j        r;|j        D ]3}|||         d         vr!||         d                             |           4|S )z'Return toolset metadata for UI display.r&   )	availabletoolsr   requirementsrn   ro   )r#   r7   r   rd   rC   r   r   )r   rj   r3   rh   envs        r   get_available_toolsetsz#ToolRegistry.get_available_toolsets   s    $&['')) 	A 	AEB!!!%!:!:2!>!>#%$&	    RL!((444! A - A AC(2,~">>> ^4;;C@@@r   c                    i }| j                                         D ]}|j        }||vr#|g | j                            |          dg d||<   |j        ||         d         vr&||         d                             |j                   |j        D ]3}|||         d         vr!||         d                             |           4|S )zABuild a TOOLSET_REQUIREMENTS-compatible dict for backward compat.N)r   env_varsr   	setup_urlrn   rn   rs   )r#   r7   r   r$   r(   r   rC   r   )r   rD   r3   rh   rp   s        r   get_toolset_requirementsz%ToolRegistry.get_toolset_requirements   s    "$['')) 	7 	7EB " $ 4 8 8 < <!% r
 zG!444r
7#**5:666) 7 7fRj4442Jz*11#6667 r   c                    g }g }t                      }| j                                        D ]}|j        |v r|                               |                               r|                               N|                    |j        fd| j                                        D             d           ||fS )zDReturn (available_toolsets, unavailable_info) like the old function.c                 4    g | ]}|j         k    |j        S r   )r   r   )r1   r2   rh   s     r   
<listcomp>z8ToolRegistry.check_tool_availability.<locals>.<listcomp>  s#    VVVaiSUooafooor   )r   rs   rn   )ri   r#   r7   r   addrd   rC   r   )r   r<   rm   unavailableseenr3   rh   s         @r   check_tool_availabilityz$ToolRegistry.check_tool_availability   s    	uu['')) 	 	EBTzzHHRLLL((,,   $$$$"" % 2VVVVdk.@.@.B.BVVV$ $    
 +%%r   )NNFr&   r&   )F)rY   )r   r   r   r   r   strdictr   listrA   r,   r:   r   r   rG   rQ   rT   r   rV   rX   r\   r   ra   rd   rk   rq   ru   r|   r   r   r   r!   r!   -   s       SS7 7 7 "! 5  5 5  5 	 5
  5  5  5  5  5  5  5  5  5D4s 4t 4 4 4 4* #c( 4 DQUJ    B\S \ \3 \ \ \ \.*DI * * * */s /x~ / / / /0 0# 0 0 0 0
C Cc CC CC C C C C
Dc3h D D D DC D    NDdO N N N N
S$Y    &$sDy/    (& &T & & & & & &r   r!   )r   rL   loggingtypingr   r   r   r   r   	getLoggerr   r)   r	   r!   registryr   r   r   <module>r      s        6 6 6 6 6 6 6 6 6 6 6 6 6 6		8	$	$       *b& b& b& b& b& b& b& b&L <>>r   