
    )jp                        d Z ddlm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  ej        e          Zd+d
Zd,dZddd-dZ eh d          Zd.d/dZd0dZdddddd d1d$Zd2d3d(Zd.d3d)Zg d*ZdS )4u  Codex API runtime — App Server and Responses-API streaming paths.

Extracted from :class:`AIAgent` to keep the agent loop file focused.
Each function takes the parent ``AIAgent`` as its first argument
(``agent``).  AIAgent keeps thin forwarder methods for backward
compatibility.

* ``run_codex_app_server_turn`` — drives one turn through the
  ``codex_app_server`` subprocess client (used when a Codex CLI install
  is the active provider).
* ``run_codex_stream`` — streams a Codex Responses API call (the
  ``codex_responses`` api_mode).
* ``run_codex_create_stream_fallback`` — recovery path when the
  Responses ``stream=True`` initial create fails.
    )annotationsN)SimpleNamespace)AnyDictListvaluer   returnintc                j   t          | t                    rdS t          | t                    rt          | d          S t          | t                    rt          t          |           d          S t          | t
                    r/	 t          t          |           d          S # t          $ r Y dS w xY wdS )Nr   )
isinstanceboolr
   maxfloatstr
ValueError)r   s    :/home/wildlama/.hermes/hermes-agent/agent/codex_runtime.py_coerce_usage_intr      s    % q% 5!}}% "3u::q!!!% 	s5zz1%%% 	 	 	11	1s   B" "
B0/B0dict[str, Any]c                   | xj         dz  c_         t          |dd          }t          |t                    r|s| j        r| j        r|	 | j        s|                                  | j                            | j        | j	        d           n8# t          $ r+}t                              d| j        |           Y d}~nd}~ww xY wi S ddlm}m} t!          |                    d                    }t!          |                    d	                    }t!          |                    d
                    }t!          |                    d                    }	t!          |                    d                    }
 ||||d|	|          }|j        }|j        }|
p|j        }||||j        |j        |j        |j        |j        d}t          | dd          }|v	 |                    |           t          |dd          }t          |t4                    r|dk    r||_        n,# t          $ r t                              dd           Y nw xY w| xj        |z  c_        | xj        |z  c_        | xj        |z  c_        | xj        |j        z  c_        | xj         |j        z  c_         | xj!        |j        z  c_!        | xj"        |j        z  c_"        | xj#        |j        z  c_#         || j	        || j$        | j%        t          | dd                    }|j&        "| xj'        tQ          |j&                  z  c_'        |j)        | _*        |j+        | _,        | j        r| j        r	 | j        s|                                  | j                            | j        |j        |j        |j        |j        |j        |j&        tQ          |j&                  nd|j)        |j+        | j$        | j%        |j)        dk    rdnd| j	        d           n9# t          $ r,}t                              d| j        ||           Y d}~nd}~ww xY wi |||j&        tQ          |j&                  nd|j)        |j+        dS )a5  Translate Codex app-server token usage into Hermes accounting.

    Codex app-server reports usage via thread/tokenUsage/updated as:
    inputTokens, cachedInputTokens, outputTokens, reasoningOutputTokens,
    totalTokens.

    Hermes' canonical prompt bucket includes uncached input + cached input.
    The Codex app-server protocol does not currently expose cache-write tokens,
    so that bucket remains zero on this runtime.

    Even when Codex omits usage for a turn, Hermes should still count that turn
    as one API call for session/status accounting.
       token_usage_lastN)modelapi_call_countz=Codex app-server api-call persistence failed (session=%s): %sr   )CanonicalUsageestimate_usage_costinputTokenscachedInputTokensoutputTokensreasoningOutputTokenstotalTokens)input_tokensoutput_tokenscache_read_tokenscache_write_tokensreasoning_tokens	raw_usage)prompt_tokenscompletion_tokenstotal_tokensr!   r"   r#   r$   r%   context_compressormodel_context_windowz$codex app-server usage update failedTexc_infoapi_key )providerbase_urlr.   includedsubscription_included)r!   r"   r#   r$   r%   estimated_cost_usdcost_statuscost_sourcebilling_providerbilling_base_urlbilling_moder   r   zECodex app-server token persistence failed (session=%s, tokens=%d): %s)last_prompt_tokensr4   r5   r6   )-session_api_callsgetattrr   dict_session_db
session_id_session_db_created_ensure_db_sessionupdate_token_countsr   	Exceptionloggerdebugagent.usage_pricingr   r   r   getr'   r"   r)   r!   r#   r$   r%   update_from_responser
   context_lengthsession_prompt_tokenssession_completion_tokenssession_total_tokenssession_input_tokenssession_output_tokenssession_cache_read_tokenssession_cache_write_tokenssession_reasoning_tokensr0   r1   
amount_usdsession_estimated_cost_usdr   statussession_cost_statussourcesession_cost_source)agentturnusageexcr   r   r!   r#   r"   r%   reported_totalcanonical_usager'   r(   r)   
usage_dict
compressorcontext_windowcost_results                      r   _record_codex_app_server_usagerb   +   sv    
q D,d33EeT"" %  	!1 	0 /,,...!55$+#$ 6    
    S$c       
 	GGGGGGGG$UYY}%=%=>>L)%))4G*H*HII%eii&?&?@@M(3J)K)KLL&uyy'?'?@@N$n!#+)  O $1M'5!A_%AL&.$'4(6,>-@+<	 	J  4d;;J	P++J777$T+A4HHN.#.. ;>A3E3E,:
) 	P 	P 	PLL?$LOOOOO	P 
=0	##'88##	,.	/">>	?#@@	##'HH##	$$(JJ$$	""o&FF""%%y"--  K )((E+2H,I,II(( + 2E + 2E U- 	, +((***11 ,9-;"1"C#2#E!0!A)5 $))?#@#@#@;?'.'.!&!&%33 549=k ! 2    $  	 	 	LLW ,       	
+!- $K$:;;;37")")   sE   AB 
C !B;;C AH   &I	I	#B"P 
P<"P77P<F)should_review_memoryuser_messager   original_user_messagemessagesList[Dict[str, Any]]effective_task_idrc   r   Dict[str, Any]c          	        ddl m} t          | d          r| j        Zt	          | dd          pt          j                    }	 ddlm}  |            }	n# t          $ r d}	Y nw xY w |||	          | _        	 | j        
                    |          }
n}# t          $ rp}t                              d	           	 | j                                         n# t          $ r Y nw xY wd| _        d
| d|dddt          |          dcY d}~S d}~ww xY wt	          |
dd          rRt                              d|
j                   	 | j                                         n# t          $ r Y nw xY wd| _        |
j        r|                    |
j                   t	          | dd          |
j        z   | _        t+          | |
          }d}d}| j        dk    r"| j        | j        k    rd| j        v r	d}d| _        |
j        sR|
j        K	 |                     ||
j        d           n,# t          $ r t                              dd           Y nw xY w|
j        r^|
j        sW|s|rS	 |                     t;          |          ||           n,# t          $ r t                              dd           Y nw xY w|
j        |||
j         o|
j        du |
j        p|
j        du|
j        |
j        |
j        d|S )aN  Codex app-server runtime path. Hands the entire turn to a `codex
    app-server` subprocess and projects its events back into Hermes'
    messages list so memory/skill review keep working.

    Called from run_conversation() when agent.api_mode == "codex_app_server".
    Returns the same dict shape as the chat_completions path.
    r   )CodexAppServerSession_codex_sessionNsession_cwd)_get_approval_callback)cwdapproval_callback)
user_inputzcodex app-server turn failedzCodex app-server turn failed: z:. Fall back to default runtime with `/codex-runtime auto`.FT)final_responserf   	api_calls	completedpartialerrorshould_retirez1codex app-server session retired (turn error: %s)_iters_since_skillr   skill_manage)re   rr   interruptedzexternal memory sync raisedr,   )messages_snapshotreview_memoryreview_skillszbackground review spawn raised)rr   rf   rs   rt   ru   rv   codex_thread_idcodex_turn_id) )agent.transports.codex_app_server_sessionrk   hasattrrl   r<   osgetcwdtools.terminal_toolrn   rC   run_turnrD   	exceptioncloser   warningrv   projected_messagesextendtool_iterationsrx   rb   _skill_nudge_intervalvalid_tool_namesrz   _sync_external_memory_for_turn
final_textrE   _spawn_background_reviewlist	thread_idturn_id)rX   rd   re   rf   rh   rc   rk   ro   rn   rp   rY   r[   usage_resultrs   should_review_skillss                  r   run_codex_app_server_turnr      sN     POOOOO
 5*++ 
u/C/Ke]D11@RY[[	%BBBBBB 6 6 8 8 	% 	% 	% $	%44/ 
  
  

#,,,EE 
 
 
7888	 &&(((( 	 	 	D	#L L L L !XX

 

 
	
 
	
 
	
 
	
 
	
 
	

4 t_e,, 	$?J	
 	
 	
	 &&(((( 	 	 	D	#
  1/000 	+Q//$2FF 
 2%>>LI !#a''$(CCCe444##$   G
 2	G00&;#! 1    
  	G 	G 	GLL6LFFFFF	G 	J J "J &:J
	J**"&x..22 +    
  	J 	J 	JLL9DLIIIII	J /))@djD.@#=tz'=>
 
 
 
s   A A#"A#9B 
DD
:CD

C!D
 C!!#D
D
DE 
E+*E+H" "&I
I!%J &J0/J0>   response.failedresponse.completedresponse.incompleteeventnamedefaultc                    t          | |d          }|+t          | t                    r|                     ||          }||n|S )zSField access that handles both attr-style (SDK objects) and dict (raw JSON) events.N)r<   r   r=   rG   )r   r   r   r   s       r   _event_fieldr   e  sH    E4&&E}E400}		$((%5572    Nonec                    ddl m} t          | dd          pd                                } ||t          | d          t          | d                    )	zRaise a ``_StreamErrorEvent`` from a ``type=error`` SSE frame.

    Imported lazily so this module stays importable from places that don't
    pull in ``run_agent`` (e.g. plugin code, doc tools).
    r   )_StreamErrorEventmessager/   zstream emitted error eventcodeparam)r   r   )	run_agentr   r   strip)r   r   r   s      r   _raise_stream_errorr   m  sp     ,+++++E9b11Q5QXXZZG

%((5'**   r   )on_text_deltaon_reasoning_deltaon_first_deltaon_eventinterrupt_check
event_iterr   r   c          
     4   g }g }d}	d}
d}d}d}d}d}d}| D ]n}|J	  ||           n=# t           t          f$ r  t          $ r t                              dd           Y nw xY w| |            r nt          |dd          }t          |t                    sd}|d	k    rt          |           d
|v s|dk    rt          |dd          }|r|	                    |           |	sy|
s<d}
|8	  |             n,# t          $ r t                              dd           Y nw xY w|9	  ||           n,# t          $ r t                              dd           Y nw xY wJd|v rd}	d|v rTd|v rPt          |dd          }|r;|9	  ||           n,# t          $ r t                              dd           Y nw xY w|dk    r)t          |d          }||	                    |           |t          v rd}t          |d          }|Vt          |dd          }|*t          |t                    r|                    d          }t          |dd          }|*t          |t                    r|                    d          }|}t          |dd          }|*t          |t                    r|                    d          }t          |t                    r|}|dk    r=t          |dd          }|*t          |t                    r|                    d          }|dk    r=t          |d	d          }|*t          |t                    r|                    d	          }|dk    r|pd}n|dk    r|pd}n
|dk    r|pd} np|rt          |          }n@|r<|	s:d                    |          }t!          dddt!          d |!          g"          g}ng }|s|st#          d#          d                    |          }t!          ||||||||$          }|S )%ud  Consume a Codex Responses SSE event stream and return a final response.

    The returned object is a ``SimpleNamespace`` shaped like the SDK's typed
    ``Response`` for the fields downstream code actually reads:

    * ``output``: list of output items, assembled from ``response.output_item.done``.
      For tool-call turns this contains the function_call items; for plain-text
      turns it contains a synthesized ``message`` item built from streamed deltas
      if no message item was emitted directly.
    * ``output_text``: assembled text from ``response.output_text.delta`` deltas.
    * ``usage``: copied from the terminal event's ``response.usage`` (when present).
    * ``status``: ``completed`` / ``incomplete`` / ``failed`` (or ``completed`` if
      the stream ended without a terminal frame but produced content).
    * ``id``: ``response.id`` when present.
    * ``incomplete_details``: passed through for ``response.incomplete`` frames.
    * ``error``: passed through for ``response.failed`` frames.
    * ``model``: from kwargs (the wire model name is not authoritative).

    Critically, we never read ``response.output`` from the terminal event for
    content reconstruction — only ``usage``, ``status``, ``id``.  That field
    being ``null`` / ``[]`` / missing is fine.

    Callbacks:

    * ``on_text_delta(str)`` — fires per ``response.output_text.delta``, suppressed
      once a function_call event is seen (so tool-call turns don't bleed text
      into the chat).
    * ``on_reasoning_delta(str)`` — fires per ``response.reasoning.*.delta``.
    * ``on_first_delta()`` — one-shot, fires on the first text delta only.
    * ``on_event(event)`` — fires for every event before any other processing.
      Used for watchdog activity, debug logging, anything wire-shape-agnostic.
    * ``interrupt_check()`` — returns True to break the loop early.
    Frt   Nz!Codex stream on_event hook raisedTr,   typer/   rv   zoutput_text.deltazresponse.output_text.deltadeltaz"Codex stream on_first_delta raisedz!Codex stream on_text_delta raisedfunction_call	reasoningz&Codex stream on_reasoning_delta raisedzresponse.output_item.doneitemresponserZ   idrT   r   incomplete_detailsr   r   
incompletefailedr   	assistantoutput_text)r   text)r   rolerT   contentz7Codex Responses stream did not emit a terminal response)outputr   rZ   rT   r   r   r   rv   )TimeoutErrorInterruptedErrorrC   rD   rE   r   r   r   r   append_TERMINAL_EVENT_TYPESr<   r=   rG   r   joinr   RuntimeError)r   r   r   r   r   r   r   collected_output_itemscollected_text_deltashas_tool_callsfirst_delta_firedterminal_statusterminal_usageterminal_response_idterminal_incomplete_detailsterminal_errorsaw_terminalr   
event_type
delta_textreasoning_text	done_itemresp_objridrstatusr   	assembledassembled_textfinals                                r   _consume_codex_event_streamr   |  s   V )+')N&ON $'+NL _ _	Q "23     Q Q Q @4PPPPPQ &??+<+<&E!%44
*c** 	J   &&&*,,
>Z0Z0Z%eWb99J ]%,,Z888% ], b,0))5b . 0 0 0 0#, b b b &-Q\` a a a a ab$0])M*5555( ] ] ]"LL)LW[L\\\\\]j((!N *$$J)>)>)%"==N Z"4"@Z&&~6666  Z Z ZLL!ITXLYYYYYZ444$UF33I$&--i888...L#E:66H#!(7D!A!A!)j4.H.H)%-\\'%:%:Nhd33;:h#=#=;",,t,,C'*$!(Hd;;?z(D'A'A?&ll844Ggs++ .&-O!66629(DXZ^2_2_/2:z(TX?Y?Y:6>llCW6X6X3!222%,Xw%E%EN%-*Xt2L2L-)1g)>)>111"1"@[444"1"A\000"1"=XE? /H  ,--	 	~ 	GG122	!$-iHHHI	
 
 
    
 
E
 
 	
 WW233N"6	 	 	E LsE   )7A#"A#-
C88&D! D!'D33&EEF&F:9F:
api_kwargsr=   clientc                6    ddl }|p                     d          }d}g  _        d fd
}d fd}d fd}	d  fd}
t          |dz             D ]} j        rt          d          t          |          }d|d<   	  |j        j        d!i |}ng# |j	        |j
        |j        t          f$ rG}||k     r;t                              d|dz   |dz                                    |           Y d}~ d}~ww xY w	 t!          |d          rTt!          |d          sD|t#          |dd          }t%          |          r 	  |             c S # t&          $ r Y c S w xY wc S 	 t)          ||                    d          ||||	|
          }n# |j	        |j
        |j        t          f$ r}||k     rzt                              d|dz   |dz                                    |           Y d}~t#          |dd          }t%          |          r	  |             # t&          $ r Y w xY wՂ d}~ww xY w|j        dv r\t                              d|j        |j        |j        t5          d  j        D                                                                   |t#          |dd          }t%          |          r 	  |             c S # t&          $ r Y c S w xY wc S # t#          |dd          }t%          |          r	  |             w # t&          $ r Y w w xY ww xY wdS )"u  Execute one streaming Responses API request and return the final response.

    Uses ``responses.create(stream=True)`` (low-level raw event iteration)
    rather than the high-level ``responses.stream(...)`` helper.  This makes
    us structurally immune to backend drift in the ``response.completed``
    payload shape — we never let the SDK reconstruct a typed object from
    the terminal event's ``output`` field.
    r   Ncodex_stream_direct)reasonr   r   r   r	   r   c                f    j                             |                                |            d S N)_codex_streamed_text_partsr   _fire_stream_deltar   rX   s    r   _on_text_deltaz(run_codex_stream.<locals>._on_text_deltaM  s4    (//555  &&&&&r   c                2                         |            d S r   )_fire_reasoning_deltar   s    r   _on_reasoning_deltaz-run_codex_stream.<locals>._on_reasoning_deltaQ  s    ##D)))))r   r   r   c                b    t          j                     _                            d           d S )Nzreceiving stream response)time_codex_stream_last_event_ts_touch_activity)r   rX   s    r   	_on_eventz#run_codex_stream.<locals>._on_eventT  s,    ,0IKK)9:::::r   r   c                 ,    t           j                  S r   )r   _interrupt_requested)rX   s   r   _interrupt_checkz*run_codex_stream.<locals>._interrupt_checkY  s    E.///r   z+Agent interrupted before Codex stream retryTstreamzLCodex Responses stream connect failed (attempt %s/%s); retrying. %s error=%sr   __iter__r   r   )r   r   r   r   r   r   z\Codex Responses stream transport failed mid-iteration (attempt %s/%s); retrying. %s error=%s>   r   r   zbCodex Responses stream terminal status=%s (incomplete_details=%s, error=%s, streamed_chars=%d). %sc              3  4   K   | ]}t          |          V  d S r   )len).0ps     r   	<genexpr>z#run_codex_stream.<locals>.<genexpr>  s(      II1AIIIIIIr   )r   r   r	   r   r   r   r	   r   )r	   r    )httpx_ensure_primary_openai_clientr   ranger   r   r=   	responsescreateRemoteProtocolErrorReadTimeoutConnectErrorConnectionErrorrD   rE   _client_log_contextr   r<   callablerC   r   rG   rT   r   r   rv   sum)rX   r   r   r   _httpxactive_clientmax_stream_retriesr   r   r   r   attemptstream_kwargsevent_streamr[   close_fnr   s   `                r   run_codex_streamr  =  s    _eAAI^A__M-/E$' ' ' ' ' '* * * * * *; ; ; ; ; ;
0 0 0 0 0 0 +a/00 > >% 	R"#PQQQZ(("&h
	9=29JJMJJLL*F,>@SUde 	 	 	+++baK!3a!7--//  
 	+	 |X.. $w|Z7X7X $#D |Wd;;H!! HJJJJJJ    DDD  C3 $..11"0':#1&$4   .0BFDWYhi 	 	 	///LLA!%7!%;1133S	   HHH |Wd;;H!! HJJJJ    D 	 |777OL%":EKII(HIIIII--//   |Wd;;H!! HJJJJJJ    DDD   |Wd;;H!! HJJJJ    Du> >s   ?BC6/<C10C11C6:!K<
E		
EE)F	K	H,&<H'"K
H
H! H!&H''H,,A)K6
K
KK!L:
LL
L	LL	Lc                &    t          | ||          S )a  Backward-compatible alias for the unified event-driven path.

    Historically this was the fallback when the SDK's high-level
    ``responses.stream(...)`` helper raised on shape drift.  The primary
    path now does exactly what the fallback did, so this just forwards.
    Kept as a public symbol because tests and a small number of call sites
    still reference it by name.
    )r   )r  )rX   r   r   s      r    run_codex_create_stream_fallbackr    s     E:f====r   )r   r  r  r   )r   r   r	   r
   )r	   r   )rd   r   re   r   rf   rg   rh   r   rc   r   r	   ri   r   )r   r   r   r   r   r   r	   r   r   )r   r   r   r   r	   r   )NN)r   r=   r   r   )__doc__
__future__r   loggingr   r   typesr   typingr   r   r   	getLogger__name__rD   r   rb   r   	frozensetr   r   r   r   r  r  __all__r   r   r   <module>r     s     # " " " " "  				  ! ! ! ! ! ! " " " " " " " " " "		8	$	$   B B B BX "'T T T T T T\ "	 # # #   3 3 3 3 3   & ~ ~ ~ ~ ~ ~B] ] ] ] ]@	> 	> 	> 	> 	>  r   