
    i                       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Zddlm	Z	 ddl
mZmZmZmZmZ  ej        e          ZdZded<   d	Z G d
 dej                  Zd)dZd*dZdddd+dZddd,d"Zd#d$d$d$ed%d-d(ZdS ).au  
Image Generation Provider ABC
=============================

Defines the pluggable-backend interface for image generation. Providers register
instances via ``PluginContext.register_image_gen_provider()``; the active one
(selected via ``image_gen.provider`` in ``config.yaml``) services every
``image_generate`` tool call.

Providers live in ``<repo>/plugins/image_gen/<name>/`` (built-in, auto-loaded
as ``kind: backend``) or ``~/.hermes/plugins/image_gen/<name>/`` (user, opt-in
via ``plugins.enabled``).

Response shape
--------------
All providers return a dict that :func:`success_response` / :func:`error_response`
produce. The tool wrapper JSON-serializes it. Keys:

    success        bool
    image          str | None       URL or absolute file path
    model          str              provider-specific model identifier
    prompt         str              echoed prompt
    aspect_ratio   str              "landscape" | "square" | "portrait"
    provider       str              provider name (for diagnostics)
    error          str              only when success=False
    error_type     str              only when success=False
    )annotationsN)Path)AnyDictListOptionalTuple)	landscapesquareportraitzTuple[str, ...]VALID_ASPECT_RATIOSr
   c                      e Zd ZdZeej        dd                        Zedd            ZddZ	dd	Z
ddZddZej        efdd            ZdS )ImageGenProvideru   Abstract base class for an image generation backend.

    Subclasses must implement :meth:`generate`. Everything else has sane
    defaults — override only what your provider needs.
    returnstrc                    dS )zStable short identifier used in ``image_gen.provider`` config.

        Lowercase, no spaces. Examples: ``fal``, ``openai``, ``replicate``.
        N selfs    =/home/ubuntu/.hermes/hermes-agent/agent/image_gen_provider.pynamezImageGenProvider.name:             c                4    | j                                         S )zMHuman-readable label shown in ``hermes tools``. Defaults to ``name.title()``.)r   titler   s    r   display_namezImageGenProvider.display_nameB   s     y   r   boolc                    dS )zReturn True when this provider can service calls.

        Typically checks for a required API key. Default: True
        (providers with no external dependencies are always available).
        Tr   r   s    r   is_availablezImageGenProvider.is_availableG   s	     tr   List[Dict[str, Any]]c                    g S )a  Return catalog entries for ``hermes tools`` model picker.

        Each entry::

            {
                "id": "gpt-image-1.5",               # required
                "display": "GPT Image 1.5",          # optional; defaults to id
                "speed": "~10s",                     # optional
                "strengths": "...",                  # optional
                "price": "$...",                     # optional
            }

        Default: empty list (provider has no user-selectable models).
        r   r   s    r   list_modelszImageGenProvider.list_modelsO   s	     	r   Dict[str, Any]c                    | j         ddg dS )a5  Return provider metadata for the ``hermes tools`` picker.

        Used by ``tools_config.py`` to inject this provider as a row in
        the Image Generation provider list. Shape::

            {
                "name": "OpenAI",                     # picker label
                "badge": "paid",                      # optional short tag
                "tag": "One-line description...",     # optional subtitle
                "env_vars": [                         # keys to prompt for
                    {"key": "OPENAI_API_KEY",
                     "prompt": "OpenAI API key",
                     "url": "https://platform.openai.com/api-keys"},
                ],
            }

        Default: minimal entry derived from ``display_name``. Override to
        expose API key prompts and custom badges.
         )r   badgetagenv_vars)r   r   s    r   get_setup_schemaz!ImageGenProvider.get_setup_schema`   s"    * %	
 
 	
r   Optional[str]c                h    |                                  }|r|d                             d          S dS )z7Return the default model id, or None if not applicable.r   idN)r"   get)r   modelss     r   default_modelzImageGenProvider.default_model{   s6    !!## 	'!9==&&&tr   promptaspect_ratiokwargsr   c                    dS )u'  Generate an image.

        Implementations should return the dict from :func:`success_response`
        or :func:`error_response`. ``kwargs`` may contain forward-compat
        parameters future versions of the schema will expose — implementations
        should ignore unknown keys.
        Nr   )r   r0   r1   r2   s       r   generatezImageGenProvider.generate   r   r   N)r   r   )r   r   )r   r    )r   r#   )r   r*   )r0   r   r1   r   r2   r   r   r#   )__name__
__module____qualname____doc__propertyabcabstractmethodr   r   r   r"   r)   r/   DEFAULT_ASPECT_RATIOr4   r   r   r   r   r   3   s              X ! ! ! X!      "
 
 
 
6    	 1      r   r   valuer*   r   r   c                    t          | t                    st          S |                                                                 }|t
          v r|S t          S )zClamp an aspect_ratio value to the valid set, defaulting to landscape.

    Invalid values are coerced rather than rejected so the tool surface is
    forgiving of agent mistakes.
    )
isinstancer   r<   striplowerr   )r=   vs     r   resolve_aspect_ratiorC      sL     eS!! $##Ar   r   c                 `    ddl m}   |             dz  dz  }|                    dd           |S )zBReturn ``$HERMES_HOME/cache/images/``, creating parents as needed.r   )get_hermes_homecacheimagesT)parentsexist_ok)hermes_constantsrE   mkdir)rE   paths     r   _images_cache_dirrM      sF    000000?w&1DJJtdJ+++Kr   imagepng)prefix	extensionb64_datarP   rQ   c               2   t          j        |           }t          j                                                            d          }t          j                    j        dd         }t                      | d| d| d| z  }|	                    |           |S )zDecode base64 image data and write it under ``$HERMES_HOME/cache/images/``.

    Returns the absolute :class:`Path` to the saved file.

    Filename format: ``<prefix>_<YYYYMMDD_HHMMSS>_<short-uuid>.<ext>``.
    z%Y%m%d_%H%M%SN   _.)
base64	b64decodedatetimenowstrftimeuuiduuid4hexrM   write_bytes)rR   rP   rQ   rawtsshortrL   s          r   save_b64_imagerc      s     
8
$
$C					 	 	)	)/	:	:BJLLRaR EF!E!ER!E!E%!E!E)!E!EEDSKr   )extramodelr0   r1   providerrd   Optional[Dict[str, Any]]r#   c                |    d| ||||d}|r0|                                 D ]\  }}|                    ||           |S )zBuild a uniform success response dict.

    ``image`` may be an HTTP URL or an absolute filesystem path (for b64
    providers like OpenAI). Callers that need to pass through additional
    backend-specific fields can supply ``extra``.
    T)successrN   re   r0   r1   rf   )items
setdefault)	rN   re   r0   r1   rf   rd   payloadkrB   s	            r   success_responsern      se      $ G  %KKMM 	% 	%DAqq!$$$$Nr   provider_errorr%   )
error_typerf   re   r0   r1   errorrp   c           	         dd| |||||dS )z$Build a uniform error response dict.FN)ri   rN   rq   rp   re   r0   r1   rf   r   )rq   rp   rf   re   r0   r1   s         r   error_responsers      s+      $	 	 	r   )r=   r*   r   r   )r   r   )rR   r   rP   r   rQ   r   r   r   )rN   r   re   r   r0   r   r1   r   rf   r   rd   rg   r   r#   )rq   r   rp   r   rf   r   re   r   r0   r   r1   r   r   r#   )r8   
__future__r   r:   rW   rY   loggingr\   pathlibr   typingr   r   r   r   r	   	getLoggerr5   loggerr   __annotations__r<   ABCr   rC   rM   rc   rn   rs   r   r   r   <module>r|      s    8 # " " " " " 



           3 3 3 3 3 3 3 3 3 3 3 3 3 3		8	$	$ (K  J J J J" \ \ \ \ \sw \ \ \H           	     6 '+     @ ',       r   