
    sj!                       U d Z ddlmZ ddlZddlZddlmZmZmZ ddl	m
Z
 ddlmZ  ej        e          Zi Zded<   i Zd	ed
<    ej                    Zddd dZddd!dZddd"dZddd"dZddd#dZd$dZd%dZdS )&u  
Image Generation Provider Registry
==================================

Central map of registered providers. Populated by plugins at import-time via
``PluginContext.register_image_gen_provider()``; consumed by the
``image_generate`` tool to dispatch each call to the active backend.

Active selection
----------------
The active provider is chosen by ``image_gen.provider`` in ``config.yaml``.
If unset, :func:`get_active_provider` applies fallback logic:

1. If exactly one provider is registered, use it.
2. Otherwise if a provider named ``fal`` is registered, use it (legacy
   default — matches pre-plugin behavior).
3. Otherwise return ``None`` (the tool surfaces a helpful error pointing
   the user at ``hermes tools``).
    )annotationsN)DictListOptional)ImageGenProvider)hermes_home_keyzDict[str, ImageGenProvider]
_providersz&Dict[str, Dict[str, ImageGenProvider]]_scoped_providers)scopeproviderr   r   Optional[str]returnNonec                  t          | t                    s$t          dt          |           j                   | j        }t          |t                    r|                                st          d          |                                }t          5  |t          nt                              |i           }|                    |          }| ||<   ddd           n# 1 swxY w Y   |0t                              d|t          |          j                   dS t                              d|t          |           j                   dS )u   Register an image generation provider.

    Re-registration (same ``name``) overwrites the previous entry and logs
    a debug message — this makes hot-reload scenarios (tests, dev loops)
    behave predictably.
    z>register_provider() expects an ImageGenProvider instance, got z3Image gen provider .name must be a non-empty stringNz.Image gen provider '%s' re-registered (was %r)z'Registered image gen provider '%s' (%s))
isinstancer   	TypeErrortype__name__namestrstrip
ValueError_lockr	   r
   
setdefaultgetloggerdebug)r   r   raw_namer   targetexistings         </home/agent/.hermes/hermes-agent/agent/image_gen_registry.pyregister_providerr"   &   sy    h 011 
->>*- -
 
 	
 }Hh$$ PHNN,<,< PNOOO>>D	    $}2C2N2NuVX2Y2Y::d##t                              EtTRZ^^Mdeeeee>d8nnF]^^^^^s   ?CC#&C#List[ImageGenProvider]c                F   t           5  t          t                    }|                    t                              | pt                      i                      t          |                                          }ddd           n# 1 swxY w Y   t          |d           S )z0Return all registered providers, sorted by name.Nc                    | j         S N)r   )ps    r!   <lambda>z list_providers.<locals>.<lambda>F   s    qv     )key)
r   dictr	   updater
   r   r   listvaluessorted)r   mergeditemss      r!   list_providersr2   @   s    	 & &j!!'++E,F_5F5FKKLLLV]]__%%& & & & & & & & & & & & & & & %--....s   A2BB
B
r   r   Optional[ImageGenProvider]c               F   t          | t                    sdS t          5  |                                 }t                              |pt                      i                               |          pt                              |          cddd           S # 1 swxY w Y   dS )z5Return the provider registered under *name*, or None.N)r   r   r   r   r
   r   r   r	   )r   r   r*   s      r!   get_providerr5   I   s    dC   t	 e ejjll $$U%?o.?.?DDHHMMdQ[Q_Q_`cQdQde e e e e e e e e e e e e e e e e es   A*BBBc                   t           5  |t          nt                              |i           }|                    |                                           cd d d            S # 1 swxY w Y   d S r&   )r   r	   r
   r   r   )r   r   r   s      r!   snapshot_registrationr7   R   s     
 ( ($}2C2G2Gr2R2Rzz$**,,''( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (s   AA  A$'A$currentpreviousboolc               x   |                                  }t          5  |t          nt                              |i           }|                    |          |ur	 ddd           dS ||                    |d           n|||<   ||st                              |d           ddd           n# 1 swxY w Y   dS )zERestore a plugin registration only when *current* is still installed.NFT)r   r   r	   r
   r   r   pop)r   r8   r9   r   r*   r   s         r!   restore_registrationr=   Z   s    **,,C	 	/ 	/$}2C2N2NuVX2Y2Y::c??'))	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ JJsD!!!!"F3KV!!%...	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 4s   =B/&=B//B36B3c                 .   d} 	 ddl m}  |            }t          |t                    r|                    d          nd}t          |t                    rR|                    d          }t          |t
                    r(|                                r|                                } n2# t          $ r%}t          	                    d|           Y d}~nd}~ww xY w| r2	 ddl
m} |                                 |k    rd} n# t          $ r Y nw xY wt          5  t          t                    }|                    t                               t#                      i                      ddd           n# 1 swxY w Y   dd| r4|                    |           }||S t          	                    d|            fd|                                D             }	t'          |	          dk    r|	d         S |                    d          }
|
 |
          r|
S dS )u  Resolve the currently-active provider.

    Reads ``image_gen.provider`` from config.yaml; falls back per the
    module docstring.

    **Availability semantics** (mirrors :mod:`agent.web_search_registry`):

    - When ``image_gen.provider`` is explicitly set, the configured
      provider is returned even if :meth:`ImageGenProvider.is_available`
      reports False — the dispatcher surfaces a precise "X_API_KEY is not
      set" error rather than silently switching backends.
    - When ``image_gen.provider`` is unset, the fallback path (single-
      provider shortcut and the FAL legacy preference) is filtered by
      ``is_available()`` so we don't pick a provider the user has no
      credentials for.
    Nr   )load_config_readonly	image_genr   z1Could not read image_gen.provider from config: %s)NOUS_MANAGED_PROVIDERfalr'   r   r   r:   c                    	 t          |                                           S # t          $ r,}t                              d| j        |           Y d}~dS d}~ww xY w)zDWrap ``is_available()`` so a buggy provider doesn't kill resolution.z.image_gen provider %s.is_available() raised %sNF)r:   is_available	Exceptionr   r   r   )r'   excs     r!   _is_available_safez/get_active_provider.<locals>._is_available_safe   se    	(())) 	 	 	LLI16SVWWW55555	s    # 
A!AAzCimage_gen.provider='%s' configured but not registered; falling backc                *    g | ]} |          |S  rI   ).0r'   rG   s     r!   
<listcomp>z'get_active_provider.<locals>.<listcomp>   s*    GGGq1C1CA1F1FGGGGr)      )r'   r   r   r:   )hermes_cli.configr?   r   r+   r   r   r   rE   r   r   tools.tool_backend_helpersrA   lowerr   r	   r,   r
   r   r.   len)
configuredr?   cfgsectionrawrF   rA   snapshotr   	availablerB   rG   s              @r!   get_active_providerrW   p   s   " !%J
O::::::""$$*4S$*?*?I#''+&&&Tgt$$ 	)++j))C#s## )		 ) YY[[
 O O OH#NNNNNNNNO  	HHHHHH!!%:::"
 	 	 	D	 
 F F
##)--o.?.?DDEEEF F F F F F F F F F F F F F F     
<<
++OQ	
 	
 	
 HGGGHOO--GGGI
9~~| ,,u

C
--c22
4s=   B#B) )
C3CC C? ?
DDAE11E58E5c                     t           5  t                                           t                                           ddd           dS # 1 swxY w Y   dS )z"Clear the registry. **Test-only.**N)r   r	   clearr
   rI   r)   r!   _reset_for_testsrZ      s    	 " "!!!" " " " " " " " " " " " " " " " " "s   3AAA)r   r   r   r   r   r   )r   r   r   r#   )r   r   r   r   r   r3   )
r   r   r8   r   r9   r3   r   r   r   r:   )r   r3   )r   r   )__doc__
__future__r   logging	threadingtypingr   r   r   agent.image_gen_providerr   hermes_constantsr   	getLoggerr   r   r	   __annotations__r
   Lockr   r"   r2   r5   r7   r=   rW   rZ   rI   r)   r!   <module>re      s    ( # " " " " "      ' ' ' ' ' ' ' ' ' ' 5 5 5 5 5 5 , , , , , ,		8	$	$ +-
 , , , ,<>  > > > >	 MQ _ _ _ _ _ _4 .2 / / / / / / 7; e e e e e e *.( ( ( ( ( (       ,M M M M`" " " " " "r)   