
    
Bj|                    &   U 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  ej                  e      Zi Zded<   i Zded	<   d
a ee      j)                         j*                  j*                  dz  dz  ZddZddZddZddZddZddZy)u  Provider module registry.

Provider profiles can live in two places:

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

Each plugin directory contains:
  - ``__init__.py`` — calls ``register_provider(profile)`` at import
  - ``plugin.yaml`` — manifest (name, kind: model-provider, version, description)

Discovery is lazy: the first call to ``get_provider_profile()`` or
``list_providers()`` scans both locations and imports every plugin. User
plugins override bundled plugins on name collision (last-writer-wins), so
third parties can monkey-patch or replace any built-in profile without
editing the repo.

For backward compatibility, ``providers/*.py`` files (other than ``base.py``
and ``__init__.py``) are still discovered via ``pkgutil.iter_modules``.
This lets out-of-tree users drop a single-file profile into an editable
install without the plugin dir structure. New profiles should prefer the
plugin layout.

Usage::

    from providers import get_provider_profile
    profile = get_provider_profile("nvidia")   # ProviderProfile or None
    profile = get_provider_profile("kimi")     # checks name + aliases
    )annotationsN)Path)OMIT_TEMPERATUREProviderProfilezdict[str, ProviderProfile]	_REGISTRYzdict[str, str]_ALIASESFpluginsmodel-providersc                r    | t         | j                  <   | j                  D ]  }| j                  t        |<    y)u   Register a provider profile by name and aliases.

    Later registrations with the same name replace earlier ones — so user
    plugins under ``$HERMES_HOME/plugins/model-providers/`` can override
    bundled profiles without editing repo code.
    N)r   namealiasesr   )profilealiass     7/home/ubuntu/.hermes/hermes-agent/providers/__init__.pyregister_providerr   5   s2     &Igll '!,,'    c                x    t         s
t                t        j                  | |       }t        j                  |      S )z{Look up a provider profile by name or alias.

    Returns None if the provider has no profile (falls back to generic).
    )_discovered_discover_providersr   getr   )r   	canonicals     r   get_provider_profiler   A   s,    
 T4(I==##r   c                     t         s
t                t               } g }t        j	                         D ]4  }t        |      }|| vs| j                  |       |j                  |       6 |S )zAReturn all registered provider profiles (one per canonical name).)r   r   setr   valuesidaddappend)seenresultr   pids       r   list_providersr"   L   s]    UD$&F##% #kd?HHSMMM'"	#
 Mr   c                 p    	 ddl m}   |        dz  dz  }|j                         r|S dS # t        $ r Y yw xY w)z>Return ``$HERMES_HOME/plugins/model-providers/`` if it exists.r   )get_hermes_homer	   r
   N)hermes_constantsr$   is_dir	Exception)r$   ds     r   _user_plugins_dirr)   [   sB    4	),==HHJq(D( s   $) ) 	55c                p   | dz  }|j                         sy| j                  j                  dd      }|dk(  rd| }nd| }|t        j                  v ry	 t
        j                  j                  ||t        |       g      }||j                  yt
        j                  j                  |      }|t        j                  |<   |j                  j                  |       y# t        $ rL}t        j                  d	|| j                  |       t        j                  j                  |d       Y d}~yd}~ww xY w)
zImport a single plugin directory so it self-registers.

    ``source`` is "bundled" or "user", used only for log messages.
    z__init__.pyN-_bundledzplugins.model_providers._hermes_user_provider_)submodule_search_locationsz(Failed to load %s provider plugin %s: %s)existsr   replacesysmodules	importlibutilspec_from_file_locationstrloadermodule_from_specexec_moduler'   loggerwarningpop)
plugin_dirsource	init_file	safe_namemodule_namespecmoduleexcs           r   _import_plugin_dirrF   f   s   
 ]*I ''S1I0<.yk:ckk!+~~55J?P 6 
 <4;;.006#)K ' +6
QT	
 	T**	+s    :C  AC   	D5)AD00D5c                    t         ryda t        j                         rZt        t        j	                               D ]:  } | j                         r| j
                  j                  d      r/t        | d       < t               }|Vt        |j	                               D ]:  } | j                         r| j
                  j                  d      r/t        | d       < 	 ddl	}ddl
}|j                  |j                        D ]6  \  }}}|j                  d      s|dk(  r	 t        j                  d	|        8 y# t        $ r!}t         j#                  d
||       Y d}~_d}~ww xY w# t$        $ r Y yw xY w)a  Populate the registry by importing every provider plugin.

    Order:
      1. Bundled plugins at ``<repo>/plugins/model-providers/<name>/``
      2. User plugins at ``$HERMES_HOME/plugins/model-providers/<name>/``
      3. Legacy per-file modules at ``providers/<name>.py`` (back-compat)

    Each step imports its plugins, which call ``register_provider()`` at
    module-level. Later steps win on name collision.
    NT)r,   .r-   userr   r,   basez
providers.z.Failed to import legacy provider module %s: %s)r   _BUNDLED_PLUGINS_DIRr&   sortediterdirr   
startswithrF   r)   pkgutil	providersiter_modules__path__r4   import_moduleImportErrorr;   r<   r'   )childuser_dirrO   _pkg	_importermodname_ispkgrE   s           r   r   r      sU    K ""$088:; 	1E<<>UZZ%:%::%Fui0	1 !"HH,,./ 	.E<<>UZZ%:%::%Fuf-	. *1*>*>t}}*M 	&Iw!!#&'V*;''*WI(>?		
  Dgs   s=   AE% D85E% 8	E"EE% E""E% %	E10E1)r   r   returnNone)r   r7   r[   zProviderProfile | None)r[   zlist[ProviderProfile])r[   zPath | None)r>   r   r?   r7   r[   r\   )r[   r\   )__doc__
__future__r   r4   importlib.utilloggingr2   pathlibr   providers.baser   r   	getLogger__name__r;   r   __annotations__r   r   __file__resolveparentrK   r   r   r"   r)   rF   r    r   r   <module>rj      s   < #    
  <			8	$(*	% *.  	N##**Y69JJ 
	'$#+L3r   