
    i&8                       d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
mZmZ ddlmZ  ej        e          Z ee          j        Zdd	Zd dZd!dZd"dZd#dZd$dZd%dZ G d d          Zd&dZd'dZdS )(a  Memory provider plugin discovery.

Scans two directories for memory provider plugins:

1. Bundled providers: ``plugins/memory/<name>/`` (shipped with hermes-agent)
2. User-installed providers: ``$HERMES_HOME/plugins/<name>/``

Each subdirectory must contain ``__init__.py`` with a class implementing
the MemoryProvider ABC.  On name collisions, bundled providers take
precedence.

Only ONE provider can be active at a time, selected via
``memory.provider`` in config.yaml.

Usage:
    from plugins.memory import discover_memory_providers, load_memory_provider

    available = discover_memory_providers()   # [(name, desc, available), ...]
    provider = load_memory_provider("mnemosyne")  # MemoryProvider instance
    )annotationsN)Path)ListOptionalTuple)cfg_getreturnOptional[Path]c                 |    	 ddl m}   |             dz  }|                                r|ndS # t          $ r Y dS w xY w)z8Return ``$HERMES_HOME/plugins/`` or None if unavailable.r   )get_hermes_homepluginsN)hermes_constantsr   is_dir	Exception)r   ds     </home/ubuntu/.hermes/hermes-agent/plugins/memory/__init__.py_get_user_plugins_dirr   )   sd    444444O	)HHJJ(qqD(   tts   *- 
;;pathr   boolc                    | dz  }|                                 sdS 	 |                    d          dd         }d|v pd|v S # t          $ r Y dS w xY w)	u   Heuristic: does *path* look like a memory provider plugin?

    Checks for ``register_memory_provider`` or ``MemoryProvider`` in the
    ``__init__.py`` source.  Cheap text scan — no import needed.
    __init__.pyFreplace)errorsNi    register_memory_providerMemoryProvider)exists	read_textr   )r   	init_filesources      r   _is_memory_provider_dirr    3   s     }$I u$$I$66uu=)V3Q7G67QQ   uus   %A 
AAList[Tuple[str, Path]]c                    t                      } g }t                                          rt          t                                                    D ]}|                                r|j                            d          r1|dz                                  sI|                     |j                   |	                    |j        |f           t                      }|rt          |                                          D ]g}|                                r|j                            d          r1|j        | v r;t          |          sK|	                    |j        |f           h|S )zYield ``(name, path)`` for all discovered provider directories.

    Scans bundled first, then user-installed.  Bundled takes precedence
    on name collisions (first-seen wins via ``seen`` set).
    )_.r   )set_MEMORY_PLUGINS_DIRr   sortediterdirname
startswithr   addappendr   r    )seendirschilduser_dirs       r   _iter_provider_dirsr1   C   sh    D#%D !!## -/7799:: 	- 	-E<<>> UZ%:%::%F%F M)1133 HHUZ   KKU+,,,, %&&H -H,,..// 	- 	-E<<>> UZ%:%::%F%F zT!!*511 KKU+,,,,K    r)   strc                    t           | z  }|                                r|dz                                  r|S t                      }|r*|| z  }|                                rt	          |          r|S dS )z^Resolve a provider name to its directory.

    Checks bundled first, then user-installed.
    r   N)r&   r   r   r   r    )r)   bundledr0   users       r   find_provider_dirr7   e   s     "D(G~~ W}4<<>> $&&H $;;== 	4T:: 	K4r2   List[Tuple[str, str, bool]]c                    g } t                      D ]\  }}d}|dz  }|                                rj	 ddl}t          |          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    dd          }n# t          $ r Y nw xY wd}	 t          |          }	|	r|	                                }nd}n# t          $ r d}Y nw xY w| 	                    |||f           | S )zScan bundled and user-installed directories for available providers.

    Returns list of (name, description, is_available) tuples.
    Bundled providers take precedence on name collisions.
     plugin.yamlr   NdescriptionTF)
r1   r   yamlopen	safe_loadgetr   _load_provider_from_diris_availabler,   )
resultsr)   r/   desc	yaml_filer=   fmeta	availableproviders
             r   discover_memory_providersrJ   {   s}    G*,, 0 0eM)	 	)__ 3>>!,,2D3 3 3 3 3 3 3 3 3 3 3 3 3 3 3xxr22    		.u55H "$1133		!	 	 	 	III	 	dI.////NsG   BA)B)A-	-B0A-	1B
BB(CCCOptional['MemoryProvider']c                (   t          |           }|st                              d|            dS 	 t          |          }|r|S t                              d|            dS # t
          $ r'}t                              d| |           Y d}~dS d}~ww xY w)a'  Load and return a MemoryProvider instance by name.

    Checks both bundled (``plugins/memory/<name>/``) and user-installed
    (``$HERMES_HOME/plugins/<name>/``) directories.  Bundled takes
    precedence on name collisions.

    Returns None if the provider is not found or fails to load.
    z9Memory provider '%s' not found in bundled or user pluginsNz:Memory provider '%s' loaded but no provider instance foundz'Failed to load memory provider '%s': %s)r7   loggerdebugrA   warningr   )r)   provider_dirrI   es       r   load_memory_providerrR      s     %T**L PRVWWWt*<88 	OSUYZZZt   @$JJJttttts   A  A   
B*BBrP   c                   | j         }t          | j        v p| j        t          k    }|rd| nd| }| dz  }|                                sdS |t
          j        v rt
          j        |         }ndD ]}|t
          j        vrt          t                    j        }|dk    r|j        }|dz  }|                                rt          j
                            |t          |          t          |          g          }	|	rZt          j
                            |	          }
|
t
          j        |<   	 |	j                            |
           # t           $ r Y w xY wt          j
                            |t          |          t          |           g          }	|	sdS t          j
                            |	          }|t
          j        |<   |                     d          D ]}|j         dk    r|j        }| d	| }|t
          j        vrt          j
                            |t          |                    }|r}t          j
                            |          }|t
          j        |<   	 |j                            |           # t           $ r&}t&                              d
||           Y d}~d}~ww xY w	 |	j                            |           nT# t           $ rG}t&                              d||           t
          j                            |d           Y d}~dS d}~ww xY wt-          |d          rft/                      }	 |                    |           |j        r|j        S n3# t           $ r&}t&                              d||           Y d}~nd}~ww xY wddlm} t9          |          D ]Y}t;          ||d          }t=          |t>                    r1tA          ||          r!||ur	  |            c S # t           $ r Y Uw xY wZdS )u   Import a provider module and extract the MemoryProvider instance.

    The module must have either:
    - A register(ctx) function (plugin-style) — we simulate a ctx
    - A top-level class that extends MemoryProvider — we instantiate it
    plugins.memory._hermes_user_memory.r   N)r   zplugins.memoryr   )submodule_search_locationsz*.pyr$   zFailed to load submodule %s: %szFailed to exec_module %s: %sregisterzregister() failed for %s: %sr   )r   )!r)   r&   parentsparentr   sysmodulesr   __file__	importlibutilspec_from_file_locationr3   module_from_specloaderexec_moduler   globstemrM   rN   pophasattr_ProviderCollectorrW   rI   agent.memory_providerr   dirgetattr
isinstancetype
issubclass)rP   r)   _is_bundledmodule_namer   modrY   parent_pathparent_initspec
parent_modsub_filesub_namefull_sub_namesub_specsub_modrQ   	collectorr   	attr_nameattrs                        r   rA   rA      s    D &)==kATXkAkK.9\*D***?\VZ?\?\K},I t ck!!k+& 4 	! 	!FS[(("8nn3Y&&"-"4K)M9%%'' !$>AAK 0 0474D4D3E B  D  !%.^%D%DT%J%J
.8F+! K33J????( ! ! ! D! ~55Y(+L(9(9': 6 
 
  	4n--d33#&K  %))&11 	Z 	ZH}--}H*77X77MCK//$>AA!3x==   Z'n==hGGG18CK.Z 33G<<<<$ Z Z Z%FWXYYYYYYYYZ	K##C(((( 	 	 	LL7aHHHKOOK...44444	 sJ B&((		BLL###! * ))* 	B 	B 	BLL7qAAAAAAAA	B 544444XX  	sIt,,tT"" 	z$'G'G 	..tvv    4sl   .E		
EE&J
J1J,,J16K 
L"<LL""M( (
N2NN-	O99
PPc                  0    e Zd ZdZd Zd Zd Zd Zd ZdS )rg   zAFake plugin context that captures register_memory_provider calls.c                    d | _         d S NrI   )selfs    r   __init__z_ProviderCollector.__init__#  s    r2   c                    || _         d S r   r   )r   rI   s     r   r   z+_ProviderCollector.register_memory_provider&  s     r2   c                    d S r    r   argskwargss      r   register_toolz _ProviderCollector.register_tool*      r2   c                    d S r   r   r   s      r   register_hookz _ProviderCollector.register_hook-  r   r2   c                    d S r   r   r   s      r   register_cli_commandz'_ProviderCollector.register_cli_command0  r   r2   N)	__name__
__module____qualname____doc__r   r   r   r   r   r   r2   r   rg   rg      se        KK  ! ! !        r2   rg   Optional[str]c                 l    	 ddl m}   |             }t          |dd          pdS # t          $ r Y dS w xY w)u   Read the active memory provider name from config.yaml.

    Returns the provider name (e.g. ``"honcho"``) or None if no
    external provider is configured.  Lightweight — only reads config,
    no plugin loading.
    r   )load_configmemoryrI   N)hermes_cli.configr   r   r   )r   configs     r   _get_active_memory_providerr   4  s]    111111vx44<<   tts   "% 
33
List[dict]c            	        g } t                                           s| S t                      }|s| S t          |          }|s| S |dz  }|                                s| S t           |j        v p|j        t           k    }|rd| dnd| d}	 |t          j        v rt          j        |         }nt          j
                            |t          |                    }|r|j        s| S t          j
                            |          }|t          j        |<   |j                            |           t!          |dd          }t#          |          s| S d| d}	d	}
|d
z  }|                                rp	 ddl}t'          |          5 }|                    |          pi }ddd           n# 1 swxY w Y   |                    dd	          }|r|}	|}
n# t,          $ r Y nw xY wt!          || dd          pt!          |dd          }|                     ||	|
|||d           n3# t,          $ r&}t0                              d||           Y d}~nd}~ww xY w| S )u  Return CLI commands for the **active** memory plugin only.

    Only one memory provider can be active at a time (set via
    ``memory.provider`` in config.yaml).  This function reads that
    value and only loads CLI registration for the matching plugin.
    If no provider is active, no commands are registered.

    Looks for a ``register_cli(subparser)`` function in the active
    plugin's ``cli.py``.  Returns a list of at most one dict with
    keys: ``name``, ``help``, ``description``, ``setup_fn``,
    ``handler_fn``.

    This is a lightweight scan — it only imports ``cli.py``, not the
    full plugin module.  Safe to call during argparse setup before
    any provider is loaded.
    zcli.pyrT   z.clirU   register_cliNzManage z memory pluginr:   r;   r   r<   _commandhoncho_command)r)   helpr<   setup_fn
handler_fnpluginz-Failed to scan CLI for memory plugin '%s': %s)r&   r   r   r7   r   rX   rY   rZ   r[   r]   r^   r_   r3   ra   r`   rb   rj   callabler=   r>   r?   r@   r   r,   rM   rN   )rC   active_provider
plugin_dircli_filern   ro   cli_modrs   r   	help_textr<   rE   r=   rF   rG   rD   r   rQ   s                     r   discover_plugin_cli_commandsr   C  s/   " G%%'' 133O  #?33J H$H?? %);;gz?PTg?gK=Hz9O9999NzetNzNzNzK.Z#+%%k+.GG>99S]] D  t{ n55d;;G'.CK$K##G,,,w==%% 	N >o===	.	 
		)__ 3>>!,,2D3 3 3 3 3 3 3 3 3 3 3 3 3 3 3xxr22 ' $I"&K    W&B&B&BDII >W&6== 	 	#&$$%
 
 	 	 	 	  Z Z ZDoWXYYYYYYYYZ Nso   AH! $A)H! !H! 0G F'G 'F++G .F+/G H! 
GH! GAH! !
I+II)r	   r
   )r   r   r	   r   )r	   r!   )r)   r3   r	   r
   )r	   r8   )r)   r3   r	   rK   )rP   r   r	   rK   )r	   r   )r	   r   )r   
__future__r   r]   importlib.utilloggingrZ   pathlibr   typingr   r   r   r   r   	getLoggerr   rM   r\   rY   r&   r   r    r1   r7   rJ   rR   rA   rg   r   r   r   r2   r   <module>r      s   * # " " " " "          



       ( ( ( ( ( ( ( ( ( ( % % % % % %		8	$	$d8nn+           D   ," " " "J   2d d d dN       (   T T T T T Tr2   