
    `gj'                    *   U d Z ddlmZ ddlZddlZddlmZ ddlmZ  ej                  e
      ZdZddd	d
ddZded<   d!dZ G d de      Z ed       G d d             Zd"dZdddd#dZd$dZd%dZd&dZdddddd	 	 	 	 	 	 	 	 	 	 	 	 	 d'd Zy)(un  Thin image-generation layer for pet sprites.

Wraps the active :class:`~agent.image_gen_provider.ImageGenProvider` with the
two things sprite generation needs that the agent-facing ``image_generate`` tool
doesn't expose: **N variants** (loop) and **reference-image grounding** (so each
animation row stays the same character as the chosen base).

Reference grounding only works on providers that support it — currently OpenAI
``gpt-image-2`` (image edits) and Krea (style references). We resolve to one of
those and surface a clear, actionable error otherwise rather than silently
producing an ungrounded, drifting pet.
    )annotationsN)	dataclass)Path)nousopenaiopenai-codex
openrouterkreazNous Portal
OpenRouterOpenAIzOpenAI (Codex)Krea)r   r	   r   r   r
   zdict[str, str]_PROVIDER_LABELSc                     t         j                  j                  dd      j                         j	                         } | t
        v r| S dS )a  Optional QA override to force a pet-gen backend.

    `HERMES_PET_IMAGE_PROVIDER=<name>` (e.g. `openrouter`) bypasses the normal
    active/default provider resolution for pet generation only. Unknown values are
    ignored so existing users are unaffected.
    HERMES_PET_IMAGE_PROVIDER N)osenvirongetstriplower_REF_CAPABLE)forceds    N/root/.hermes/venv/lib/python3.12/site-packages/agent/pet/generate/imagegen.py_forced_provider_from_envr   (   s=     ZZ^^7<BBDJJLF|+655    c                      e Zd ZdZy)GenerationErrorzDRaised on any image-generation failure (no provider, API error, IO).N)__name__
__module____qualname____doc__ r   r   r   r   3   s    Nr   r   T)frozenc                  0    e Zd ZU dZded<   ded<   ded<   y)	SpriteProviderz<Resolved provider plus whether it can take reference images.strnameobjectproviderboolsupports_referencesN)r   r   r    r!   __annotations__r"   r   r   r%   r%   7   s    F
Ir   r%   c                 x    	 ddl m}   |         y # t        $ r }t        j	                  d|       Y d }~y d }~ww xY w)Nr   )_ensure_plugins_discoveredz%image-gen plugin discovery failed: %s)hermes_cli.pluginsr.   	Exceptionloggerdebug)r.   excs     r   	_discoverr4   @   s5    CA"$ C<cBBCs    	949)require_referencespreferc                n   t                ddlm}m} t	               }|r( ||      }||j                         rt        ||d      S |r0 ||      }|t        v r ||j                         rt        ||d      S d}	  |       }|3t        |dd      }|t        v r|j                         rt        ||d      S t        D ]-  } ||      }||j                         st        ||d      c S  | s+|)|j                         rt        t        |dd      |d	      S t        d
      # t        $ r d}Y w xY w)a  Pick the image provider to use for sprite work.

    Preference: an explicit *prefer* choice (the desktop pet-gen picker) when it's
    reference-capable and configured, then the configured/active provider when
    it's reference-capable, else the first available reference-capable provider.
    With *require_references* off we fall back to any available provider (used for
    prompt-only base drafts).
    r   )get_active_providerget_providerNT)r'   r)   r+   r'   r   unknownFu   Pet generation needs an image backend that supports reference images. Open `hermes tools` → Image Generation and configure Nous Portal, OpenRouter, or OpenAI (gpt-image-2) with an API key.)r4   agent.image_gen_registryr8   r9   r   is_availabler%   r   r0   getattrr   )	r5   r6   r8   r9   r   chosenactiver'   r)   s	            r   resolve_providerr@   I   sc    KJ '(Ff%&"5"5"7!vTXYY f%\!f&8V=P=P=R!vTXYY F$& vvr*<F$7$7$9!tfRVWW  Z%H$9$9$;!thTXYYZ
 &"49L9L9N3fZ_
 	
 	? %  s   <D& &D43D4c                    t                ddlm}  	 t        d      j                  }g }t        D ]I  } | |      }||j                         s|j                  |t        j                  ||      ||k(  d       K |S # t
        $ r d}Y cw xY w)a  The reference-capable providers available to pick for pet generation.

    Returns ``[{name, label, default}]`` for every ref-capable provider the user
    actually has credentials for, in preference order, marking the one
    :func:`resolve_provider` would choose with no explicit preference. Empty when
    none is configured (the picker hides itself). Best-effort: discovery hiccups
    yield an empty list.
    r   )r9   Tr5   r   )r'   labeldefault)r4   r;   r9   r@   r'   r   r   r<   appendr   r   )r9   default_nameoutr'   r)   s        r   list_sprite_providersrH      s     K5'4@EE C 

%8#8#8#:

)--dD9</	
	

 J  s   A> >BBc               l    | j                  d      rddlm} t         || |            S t        |       S )zBReturn a local path for *image_ref*, downloading it if it's a URL.)zhttp://zhttps://r   )save_url_imageprefix)
startswithagent.image_gen_providerrJ   r   )	image_refrL   rJ   s      r   _save_localrP      s0    34;N9V<==	?r   c                J    | xs dj                         }d|v xr
 d|v xs d|v S )u|  True when a provider error is specifically about the ``background`` param.

    Transparent backgrounds are a per-model capability (e.g. some gpt-image tiers
    reject ``background=transparent`` outright). We detect that one rejection so
    we can retry without the flag rather than failing the whole pet — our chroma
    key pass makes the result transparent regardless.
    r   
backgroundznot supportedtransparent)r   )errorlowereds     r   _rejected_backgroundrV      s6     {!!#G7"_7(B(^mW^F^_r      pet_gensquare)nreference_imagesr)   rL   aspect_ratioc                   |xs t        t        |            |r%j                  st        dj                   d      |xs g D cg c]  }t        |       c}d fd}g }d}	d}
t        t        d|            D ]E  } ||
rdd	ini       \  }}||
rt        |      rd
}
 |i       \  }}||j                  |       D|}	G |st        |	xs d      |S c c}w )a  Generate *n* sprite images and return their local paths.

    *reference_images* grounds the output on a base image (required for rows).
    *aspect_ratio* picks the canvas: ``"square"`` for single-character base
    drafts, ``"landscape"`` for multi-frame row strips (the wider 1536px canvas
    gives every frame real horizontal room so winged poses don't have to be
    shrunk to avoid touching their neighbors).
    We *ask* for a transparent background, but fall back to an opaque generation
    (cleaned up downstream by the chroma-key pass) on models that reject the
    flag. Raises :class:`GenerationError` if nothing usable comes back.
    rB   zimage backend 'zV' cannot use reference images; configure OpenAI gpt-image-2 or Krea for pet generationc                   di| }r
|d<   |d<   	  	j                   j                  fi |}t        |t              r|j                  d      s+d t        |t              r|xs i j                  dd      fS dfS |j                  d	      }|sy
	 t        t        |            dfS # t        $ r-}t        j	                  d|       d t        |      fcY d }~S d }~ww xY w# t        $ r}d d| fcY d }~S d }~ww xY w)Nr\   r[   reference_image_urlszprovider.generate crashed: %ssuccessrT   zunknown errorz	no resultimage)Nzprovider returned no imagerK   r   z could not save generated image: )
r)   generater0   r1   r2   r&   
isinstancedictr   rP   )
extrakwargsresultr3   rO   r\   rL   promptrefssprites
        r   _runzgenerate.<locals>._run   s   &>> *.F%&-1F)*	"-V__--f??F &$'vzz)/DTZ\`Ia&,B++G_ErrgrrrJJw'	5	Bs9~f=rAA  	"LL8#>S>!	"  	B;C5AAA	Bs;   B+ C$ +	C!4"CC!C!$	C>-C93C>9C>r   TrW   rR   rS   Fz#image generation produced no output)re   rd   returnztuple[Path | None, str])
r@   r*   r+   r   r'   r&   rangemaxrV   rE   )rh   rZ   r[   r)   rL   r\   prk   rG   
last_errorallow_transparent_patherrri   rj   s   `   ``        @@r   rb   rb      s   ( T)TBR=STF : :fkk] +F F
 	

 .35qCF5DB B. CJ3q!9 
:K,6QST	c <-2Fs2K %RID#JJtJ
 jQ,QRRJU 6s   C#)rl   
str | None)rl   None)r5   r*   r6   ru   rl   r%   )rl   z
list[dict])rO   r&   rL   r&   rl   r   )rT   r&   rl   r*   )rh   r&   rZ   intr[   zlist[Path] | Noner)   zSpriteProvider | NonerL   r&   r\   r&   rl   z
list[Path])r!   
__future__r   loggingr   dataclassesr   pathlibr   	getLoggerr   r1   r   r   r,   r   RuntimeErrorr   r%   r4   r@   rH   rP   rV   rb   r"   r   r   <module>r~      s   #  	 ! 			8	$ H
 $$ . 6Ol O $  C 48d 5p@	` *.&* EE E (	E
 $E E E Er   