
    L0&jH9                    4   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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d6d!Zd7d#Zd8d%Zd9d*Z d:d-Z!d;d/Z"d<d1Z# G d2 d3e          Z$d=d5Z%dS )>u3  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.5z%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.   Y   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=   f   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promptr6   sizer   c                f    t           dt          ddd| dgdgdt          ||dd	d
dgddddigdddS )zDBuild the Codex Responses request body for an image_generation call.Fmessageuser
input_text)typetext)rL   rolecontentimage_generationpngopaque   )rL   r3   rG   r   output_format
backgroundpartial_imagesallowed_toolsrequiredrL   )rL   modetoolsT)r3   storeinstructionsinputrZ   tool_choicestream)_CODEX_CHAT_MODEL_CODEX_INSTRUCTIONS	API_MODELrF   rG   r   s      r-   _build_responses_payloadrd      s     #+!-v>>?
 
  '""
 
  $123
 

 /  r>   r;   r   c                   d}t          | t                    r|                     d          dk    r.|                     d          }t          |t                    r|r|}|                     d          }t          |t                    r|r|}|                                 D ]}t          |          }|r|}n-t          | t                    r| D ]}t          |          }|r|}|S )zBReturn the newest image b64 embedded in a Responses event payload.NrL   image_generation_callresultpartial_image_b64)r$   r%   r&   r6   values_extract_image_b64list)r;   foundrg   partialchildnesteds         r-   rj   rj      s
   E% 99V 777YYx((F&#&& 6 ))/00gs## 	 	E\\^^ 	 	E'..F 	 
E4	 	   	 	E'..F Lr>   responsec              #  d  K   dg fd}|                                  D ]}t          |t                    r|                    dd          }t	          |          }|dk    r |            }||V  T|                    d          rj|                    d          r*|t          d          d                                         |                    d	          r<                    |t          d	          d         	                                            |            }||V  dS dS )
a
  Yield JSON payloads from an SSE response without OpenAI SDK parsing.

    The ChatGPT/Codex backend can emit image-generation events newer than the
    pinned Python SDK understands. Parsing raw SSE keeps this provider tolerant
    of those event-shape changes.
    Nc                     sd d S d                                                               } }d g | r| dk    rd S t          j        |           }t	          |t
                    r|r	d|vr||d<   |S )N
z[DONE]rL   )joinrC   jsonloadsr$   r%   )raweventpayload
data_lines
event_names      r-   flushz_iter_sse_json.<locals>.flush   s     	J4ii
##))++

 	cXoo4*S//gt$$ 	$ 	$63H3H#GFOr>   zutf-8replace)errors :zevent:zdata:)

iter_linesr$   bytesdecoder6   
startswithlenrC   appendlstrip)rp   r|   linery   rz   r{   s       @@r-   _iter_sse_jsonr      s^      !%JJ       ##%% < <dE"" 	:;;wy;99D4yy2::eggG"??3 	??8$$ 	<c(mmnn-3355JJ__W%% 	<d3w<<==188::;;;eggG r>   rE   c          	        ddl }ddlm}  ||           }|                    dd|  dd           t	          |||          }|                    d	d
d	d
d
          }d}	|                    ||          5 }
|
                    dt           d|          5 }	 |	                                 n_# |j
        $ rR}|j                                         |j        j        dd         }t          d|j        j         d|           |d}~ww xY wt!          |          D ]}t#          |          }|r|}		 ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |	S )zHStream a Codex Responses image_generation call and return the b64 image.r   N)_codex_cloudflare_headersztext/event-streamzBearer zapplication/json)AcceptAuthorizationzContent-Typerc   g     r@g      >@)connectreadwritepool)timeoutheadersPOSTz
/responses)ru   i  z"Codex Responses API returned HTTP z: )httpxrB   r   updaterd   TimeoutClientr_   _CODEX_BASE_URLraise_for_statusHTTPStatusErrorrp   r   rM   RuntimeErrorstatus_coder   rj   )rE   rF   rG   r   r   r   r   ry   r   	image_b64httprp   r,   bodyrx   rl   s                   r-   _collect_image_b64r      sB   LLL@@@@@@''..GNN%*5***    
 'f4QQQGmmE4e4dmSSG#I	gw	7	7 &4[[O!?!?!?g[NN 	&RZ))++++(   !!###|(#."[9Q[[UY[[  (11 & &*511 & %I&	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	&& & & & & & & & & & & & & & & s[   7!EE B/.E /
D9ADD(E 4E E	EE	EEE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   r   ImportError)r   r   s     r-   is_availablez(OpenAICodexImageGenProvider.is_available&  sL    ')) 	5	LLLL 	 	 	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>0  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>   rF   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                      }	|	s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 )Nr   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   z6httpx Python package not installed (pip install httpx)missing_dependencyr   )r   r   r   r3   rF   r   r   rc   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)rG   r   )imager3   rF   r   r   extra)rC   r   r   rA   r   r   r=   _SIZESr&   r   r'   r(   r)   r   r   r6   )r   rF   r   r   aspectr   tier_idr   rG   rE   b64r,   
saved_paths                r-   generatez$OpenAICodexImageGenProvider.generateJ  s    ,B%%''%l33 	!I-'#	    ()) 		!T +'#   	LLLL 	 	 	!N/'#	     	 '((zz&&"233(** 	!T +'#
 
 
 
	$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   )rF   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f
 f
 f
 f
 f
 f
 f
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     s#    ##$?$A$ABBBBBr>   r   )r   r/   r   )rF   r6   rG   r6   r   r6   r   r   )r;   r   r   r?   )rp   r   )
rE   r6   rF   r6   rG   r6   r   r6   r   r?   )r   r   )&r   
__future__r   ru   loggingtypingr   r   r   r   r   agent.image_gen_providerr	   r
   r   r   r   r   	getLoggerr   r(   rb   r   __annotations__r7   r   r`   r   ra   r.   r=   rA   rd   rj   r   r   r   r   r   r>   r-   <module>r      sR    & # " " " " "   3 3 3 3 3 3 3 3 3 3 3 3 3 3                
	8	$	$ 	 '2	  *+	  (C	 & &    * % 
 
  95 
 
 
 
1 1 1 14   $   :   ., , , ,^   LU
 U
 U
 U
 U
"2 U
 U
 U
zC C C C C Cr>   