
    i                     ~    d 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
Z
ddlmZ  e            dz  Z G d d          ZdS )a  
Event Hook System

A lightweight event-driven system that fires handlers at key lifecycle points.
Hooks are discovered from ~/.hermes/hooks/ directories, each containing:
  - HOOK.yaml  (metadata: name, description, events list)
  - handler.py (Python handler with async def handle(event_type, context))

Events:
  - gateway:startup     -- Gateway process starts
  - session:start       -- New session created (first message of a new session)
  - session:end         -- Session ends (user ran /new or /reset)
  - session:reset       -- Session reset completed (new session entry created)
  - agent:start         -- Agent begins processing a message
  - agent:step          -- Each turn in the tool-calling loop
  - agent:end           -- Agent finishes processing
  - command:*           -- Any slash command executed (wildcard match)

Errors in hooks are caught and logged but never block the main pipeline.
    N)AnyCallableDictListOptional)get_hermes_homehooksc                       e Zd ZdZd Zedee         fd            ZddZ	ddZ
dded	eeeef                  ddfd
ZdS )HookRegistryz
    Discovers, loads, and fires event hooks.

    Usage:
        registry = HookRegistry()
        registry.discover_and_load()
        await registry.emit("agent:start", {"platform": "telegram", ...})
    c                 "    i | _         g | _        d S N)	_handlers_loaded_hooksselfs    5/home/agentuser/.hermes/hermes-agent/gateway/hooks.py__init__zHookRegistry.__init__,   s    46)+    returnc                 *    t          | j                  S )z'Return metadata about all loaded hooks.)listr   r   s    r   loaded_hookszHookRegistry.loaded_hooks1   s     D&'''r   Nc                    	 ddl m} | j                            dg                               |           | j                            dddgdd           dS # t          $ r}t          d| d	
           Y d}~dS d}~ww xY w)z/Register built-in hooks that are always active.r   )handlezgateway:startupzboot-mdz(Run ~/.hermes/BOOT.md on gateway startupz	(builtin)namedescriptioneventspathz.[hooks] Could not load built-in boot-md hook: TflushN)gateway.builtin_hooks.boot_mdr   r   
setdefaultappendr   	Exceptionprint)r   boot_md_handlees      r   _register_builtin_hooksz$HookRegistry._register_builtin_hooks6   s    	TNNNNNNN%%&7<<CCNSSS%%!I,-#	' '       	T 	T 	TF1FFdSSSSSSSSSS	Ts   AA 
B"A<<Bc           	      Z   |                                   t                                          sdS t          t                                                    D ]S}|                                s|dz  }|dz  }|                                r|                                sK	 t          j        |                    d                    }|rt          |t                    st          d|j         dd	           |                    d
|j                  }|                    dg           }|st          d| dd	           t          j                            d| |          }||j        t          d| dd	           2t          j                            |          }|j                            |           t)          |dd          }	|	t          d| dd	           |D ]0}
| j                            |
g                               |	           1| j                            ||                    dd          |t3          |          d           t          d| d| d	           !# t4          $ r'}t          d|j         d| d	           Y d}~Md}~ww xY wdS )aI  
        Scan the hooks directory for hook directories and load their handlers.

        Also registers built-in hooks that are always active.

        Each hook directory must contain:
          - HOOK.yaml with at least 'name' and 'events' keys
          - handler.py with a top-level 'handle' function (sync or async)
        Nz	HOOK.yamlz
handler.pyzutf-8)encodingz[hooks] Skipping z: invalid HOOK.yamlTr    r   r   z: no events declaredhermes_hook_z: could not load handler.pyr   z: no 'handle' function foundr    r   z[hooks] Loaded hook 'z' for events: z[hooks] Error loading hook z: )r)   	HOOKS_DIRexistssortediterdiris_diryaml	safe_load	read_text
isinstancedictr&   r   get	importlibutilspec_from_file_locationloadermodule_from_specexec_modulegetattrr   r#   r$   r   strr%   )r   hook_dirmanifest_pathhandler_pathmanifest	hook_namer   specmodule	handle_fneventr(   s               r   discover_and_loadzHookRegistry.discover_and_loadE   s+    	$$&&&!! 	Fy002233 4	V 4	VH??$$ ${2M#l2L '')) 1D1D1F1F *V>-*A*A7*A*S*STT z(D'A'A PhmPPPX\]]]]$LL??	!h33 MiMMMUYZZZZ !~==.9..  <4;#6TiTTT\`aaaa"88>>''///#FHd;;	$UiUUU]abbbb $ K KEN--eR88??	JJJJ"))%#+<<r#B#B$MM	+ +    OiOOvOOW[\\\\\ V V VHHMHHQHHPTUUUUUUUUUVg4	V 4	Vs5   "AI7<AI7AI7A!I7+B
I77
J(J##J(
event_typecontextc                   K   |i }t          | j                            |g                     }d|v rN|                    d          d         }| d}|                    | j                            |g                      |D ]Y}	  |||          }t          j        |          r| d{V  ,# t          $ r!}t          d| d| d           Y d}~Rd}~ww xY wdS )	a  
        Fire all handlers registered for an event.

        Supports wildcard matching: handlers registered for "command:*" will
        fire for any "command:..." event. Handlers registered for a base type
        like "agent" won't fire for "agent:start" -- only exact matches and
        explicit wildcards.

        Args:
            event_type: The event identifier (e.g. "agent:start").
            context:    Optional dict with event-specific data.
        N:r   z:*z[hooks] Error in handler for 'z': Tr    )	r   r   r8   splitextendasyncioiscoroutiner%   r&   )	r   rK   rL   handlersbasewildcard_keyfnresultr(   s	            r   emitzHookRegistry.emit   s7      ?G **:r::;; *##C((+D";;;LOODN..|R@@AAA 	W 	WBWJ00&v.. ! LLLLLLL W W WIzIIaIIQUVVVVVVVVVW	W 	Ws   (B//
C9CC)r   Nr   )__name__
__module____qualname____doc__r   propertyr   r7   r   r)   rJ   r@   r   r   r   rX    r   r   r   r   "   s         , , ,
 (d4j ( ( ( X(T T T TCV CV CV CVJ W  WS  W8DcN3K  WW[  W  W  W  W  W  Wr   r   )r\   rQ   importlib.utilr9   typingr   r   r   r   r   r3   hermes_cli.configr   r.   r   r^   r   r   <module>rb      s    *      6 6 6 6 6 6 6 6 6 6 6 6 6 6  - - - - - - O'	HW HW HW HW HW HW HW HW HW HWr   