
    i=1                       U d Z ddlmZ ddlZddlmZmZmZmZm	Z	 ddl
mZmZmZmZmZmZ  ej        e          ZdZddd	d
ddddddddddddZded<   dZddddZdZdZdZd2d!Zd3d#Zd4d%Zd& Zd5d-Z  G d. d/e          Z!d6d1Z"dS )7u3  OpenAI image generation backend — ChatGPT/Codex OAuth variant.

Identical model catalog and tier semantics to the ``openai`` image-gen plugin
(``gpt-image-2`` at low/medium/high quality), but routes the request through
the Codex Responses API ``image_generation`` tool instead of the
``images.generate`` REST endpoint. This lets users who are already
authenticated with Codex/ChatGPT generate images without configuring a
separate ``OPENAI_API_KEY``.

Selection precedence for the tier (first hit wins):

1. ``OPENAI_IMAGE_MODEL`` env var (escape hatch for scripts / tests)
2. ``image_gen.openai-codex.model`` in ``config.yaml``
3. ``image_gen.model`` in ``config.yaml`` (when it's one of our tier IDs)
4. :data:`DEFAULT_MODEL` — ``gpt-image-2-medium``

Output is saved as PNG under ``$HERMES_HOME/cache/images/``.
    )annotationsN)AnyDictListOptionalTuple)DEFAULT_ASPECT_RATIOImageGenProvidererror_responseresolve_aspect_ratiosave_b64_imagesuccess_responsezgpt-image-2zGPT Image 2 (Low)z~15szFast iteration, lowest costlow)displayspeed	strengthsqualityzGPT Image 2 (Medium)z~40su   Balanced — defaultmediumzGPT Image 2 (High)z~2minz,Highest fidelity, strongest prompt adherencehigh)zgpt-image-2-lowgpt-image-2-mediumzgpt-image-2-highzDict[str, Dict[str, Any]]_MODELSr   	1536x1024	1024x1024	1024x1536)	landscapesquareportraitzgpt-5.4z%https://chatgpt.com/backend-api/codexzrYou are an assistant that must fulfill image generation requests by using the image_generation tool when provided.returnDict[str, Any]c                    	 ddl m}   |             }t          |t                    r|                    d          nd}t          |t                    r|ni S # t
          $ r'}t                              d|           i cY d}~S d}~ww xY w)z@Read ``image_gen`` from config.yaml (returns {} on any failure).r   )load_config	image_genNz#Could not load image_gen config: %s)hermes_cli.configr!   
isinstancedictget	Exceptionloggerdebug)r!   cfgsectionexcs       L/home/ubuntu/.hermes/hermes-agent/plugins/image_gen/openai-codex/__init__.py_load_image_gen_configr.   X   s    111111kmm*4S$*?*?I#''+&&&T$Wd33;ww;   :C@@@						s   AA 
B!B=BBTuple[str, Dict[str, Any]]c                 f   ddl } | j                            d          }|r|t          v r|t          |         fS t	                      }t          |                    d          t                    r|                    d          ni }d}t          |t                    r5|                    d          }t          |t                    r|t          v r|}|5|                    d          }t          |t                    r|t          v r|}||t          |         fS t          t          t                   fS )z9Decide which tier to use and return ``(model_id, meta)``.r   NOPENAI_IMAGE_MODELopenai-codexmodel)	osenvironr&   r   r.   r$   r%   strDEFAULT_MODEL)r4   env_overrider*   sub	candidatevaluetops          r-   _resolve_modelr=   e   s#   III:>>"677L 3//W\222
 
"
"C%/0G0G%N%N
V#''.
!
!
!TVC#I#t   eS!! 	ew&6&6Igggc3 	C7NNI'),,,'-000    Optional[str]c                    	 ddl m}   |             }t          |t                    r(|                                r|                                S dS # t
          $ r&}t                              d|           Y d}~dS d}~ww xY w)zReturn a usable Codex OAuth token, or None.

    Delegates to the canonical reader in ``agent.auxiliary_client`` so token
    expiry, credential pool selection, and JWT decoding stay in one place.
    r   )_read_codex_access_tokenNz(Could not resolve Codex access token: %s)agent.auxiliary_clientrA   r$   r6   stripr'   r(   r)   )_readertokenr,   s      r-   rA   rA      s    	NNNNNN		eS!! 	!ekkmm 	!;;== t   ?EEEttttts   AA 
BA<<Bc                     t                      } | sdS 	 ddl}ddlm} |                    | t
           ||                     S # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)zFReturn an OpenAI client pointed at the ChatGPT/Codex backend, or None.Nr   )_codex_cloudflare_headers)api_keybase_urldefault_headersz&Could not build Codex image client: %s)	rA   openairB   rG   OpenAI_CODEX_BASE_URLr'   r(   r)   )rE   rK   rG   r,   s       r-   _build_codex_clientrN      s    $&&E tDDDDDD}}$55e<<  
 
 	

    =sCCCttttts   /A 
A4A//A4clientr   promptr6   sizer   c                  d}| j                             t          dt          ddd|dgdgdt          ||d	d
ddgddddigd          5 }|D ]}t          |dd          }|dk    rQt          |dd          }t          |dd          dk    r*t          |dd          }	t          |	t                    r|	r|	}j|dk    r*t          |dd          }
t          |
t                    r|
r|
}|                                }ddd           n# 1 swxY w Y   t          |dd          pg D ]A}t          |dd          dk    r*t          |dd          }	t          |	t                    r|	r|	}B|S )zHStream a Codex Responses image_generation call and return the b64 image.NFmessageuser
input_text)typetext)rV   rolecontentimage_generationpngopaque   )rV   r3   rQ   r   output_format
backgroundpartial_imagesallowed_toolsrequiredrV   )rV   modetools)r3   storeinstructionsinputrd   tool_choice zresponse.output_item.doneitemimage_generation_callresultz,response.image_generation_call.partial_imagepartial_image_b64output)		responsesstream_CODEX_CHAT_MODEL_CODEX_INSTRUCTIONS	API_MODELgetattrr$   r6   get_final_response)rO   rP   rQ   r   	image_b64rp   event
event_typerj   rl   partialfinals               r-   _collect_image_b64r{      s/   #I			 	 (!-v>>?
 
  '""
 
  $123
 
% 
! 
 
 $,. 
 	( 	(E 33J888ufd334..2III$T8T::F!&#.. +6 +$*	MMM!%)<dCCgs++ ( ( 'I))++I$, $, $, $, $, $, $, $, $, $, $, $, $, $, $,P x..4" # #4&&*AAAT8T22F&#&& #6 #"	s   B2D		DDc                  n    e Zd ZdZedd            Zedd            ZddZdd	ZddZ	ddZ
efddZdS )OpenAICodexImageGenProviderzEgpt-image-2 routed through ChatGPT/Codex OAuth instead of an API key.r   r6   c                    dS )Nr2    selfs    r-   namez OpenAICodexImageGenProvider.name   s    ~r>   c                    dS )NOpenAI (Codex auth)r   r   s    r-   display_namez(OpenAICodexImageGenProvider.display_name   s    $$r>   boolc                T    t                      sdS 	 dd l}n# t          $ r Y dS w xY wdS )NFr   T)rA   rK   ImportError)r   rK   s     r-   is_availablez(OpenAICodexImageGenProvider.is_available   sL    ')) 	5	MMMM 	 	 	55	ts    
%%List[Dict[str, Any]]c                H    d t                                           D             S )Nc                H    g | ]\  }}||d          |d         |d         dd S )r   r   r   varies)idr   r   r   pricer   ).0model_idmetas      r-   
<listcomp>z;OpenAICodexImageGenProvider.list_models.<locals>.<listcomp>   sQ     	
 	
 	
 $ 	?g!+.! 	
 	
 	
r>   )r   itemsr   s    r-   list_modelsz'OpenAICodexImageGenProvider.list_models   s-    	
 	
 #*--//	
 	
 	
 		
r>   r?   c                    t           S )N)r7   r   s    r-   default_modelz)OpenAICodexImageGenProvider.default_model   s    r>   r   c                    dddg ddS )Nr   freeu;   gpt-image-2 via ChatGPT/Codex OAuth — no API key requiredui   Sign in with `hermes auth codex` (or `hermes setup` → Codex) if you haven't already. No API key needed.)r   badgetagenv_varspost_setup_hintr   r   s    r-   get_setup_schemaz,OpenAICodexImageGenProvider.get_setup_schema  s"    )P=	
 	
 		
r>   rP   aspect_ratiokwargsr   c           
        |pd                                 }t          |          }|st          ddd|          S t                      st          ddd|          S 	 dd l}n## t
          $ r t          d	d
d|          cY S w xY wt                      \  }}t                              |t          d                   }t                      }	|	t          ddd|||          S 	 t          |	|||d                   }
nK# t          $ r>}t                              dd           t          d| dd|||          cY d }~S d }~ww xY w|
st          ddd|||          S 	 t          |
d|           }n/# t          $ r"}t          d| dd|||          cY d }~S d }~ww xY wt          t!          |          |||d||d         d          S )Nri   z1Prompt is required and must be a non-empty stringinvalid_argumentr2   )error
error_typeproviderr   uo   No Codex/ChatGPT OAuth credentials available. Run `hermes auth codex` (or `hermes setup` → Codex) to sign in.auth_requiredr   z8openai Python package not installed (pip install openai)missing_dependencyr   z'Could not initialize Codex image client)r   r   r   r3   rP   r   r   )rP   rQ   r   zCodex image generation failedT)exc_infoz/OpenAI image generation via Codex auth failed: 	api_errorz8Codex response contained no image_generation_call resultempty_responseopenai_codex_)prefixzCould not save image to cache: io_error)rQ   r   )imager3   rP   r   r   extra)rC   r   r   rA   rK   r   r=   _SIZESr&   rN   r{   r'   r(   r)   r   r   r6   )r   rP   r   r   aspectrK   tier_idr   rQ   rO   b64r,   
saved_paths                r-   generatez$OpenAICodexImageGenProvider.generate  s    ,B%%''%l33 	!I-'#	    ()) 		!T +'#   	MMMM 	 	 	!P/'#	     	 '((zz&&"233$&&>!?*'#   	$Y	  CC  		 		 		LL84LHHH!MMM&'#        		  	!P+'#   
	'4MG4M4MNNNJJ 	 	 	!===%'#        	  j//#DO<<
 
 
 	
sN   A" "BB"C< <
E3D?9E?EE4 4
F >FF F N)r   r6   )r   r   )r   r   r   r?   r   r   )rP   r6   r   r6   r   r   r   r   )__name__
__module____qualname____doc__propertyr   r   r   r   r   r   r	   r   r   r>   r-   r}   r}      s        OO   X % % % X%   

 

 

 

   

 

 

 

 1c
 c
 c
 c
 c
 c
 c
r>   r}   Nonec                H    |                      t                                 dS )uD   Plugin entry point — register the Codex-backed image-gen provider.N)register_image_gen_providerr}   )ctxs    r-   registerr   x  s#    ##$?$A$ABBBBBr>   r   )r   r/   r   )
rO   r   rP   r6   rQ   r6   r   r6   r   r?   )r   r   )#r   
__future__r   loggingtypingr   r   r   r   r   agent.image_gen_providerr	   r
   r   r   r   r   	getLoggerr   r(   rs   r   __annotations__r7   r   rq   rM   rr   r.   r=   rA   rN   r{   r}   r   r   r>   r-   <module>r      s    & # " " " " "  3 3 3 3 3 3 3 3 3 3 3 3 3 3                
	8	$	$ 	 '2	  *+	  (C	 & &    * % 
 
  95 
 
 
 
1 1 1 14   $  &2 2 2 2tR
 R
 R
 R
 R
"2 R
 R
 R
tC C C C C Cr>   