
    Pmj$n                        d Z ddlZddlZddlZddlmZmZmZmZ ddl	m
Z
 ddlmZmZ dedee         fdZd	Z ej        d
d                    d eD                        d          Zdededee         fdZdedeeeeef                           dee         fdZ G d de
          ZddlmZ  ede           dS )u   OpenAI Responses API (Codex) transport.

Delegates to the existing adapter functions in agent/codex_responses_adapter.py.
This transport owns format conversion and normalization — NOT client lifecycle,
streaming, or the _run_codex_stream() call path.
    N)AnyDictListOptional)ProviderTransport)NormalizedResponseToolCallvaluereturnc                    | dS t          |                                           }|sdS t          |          dk    r|S t          j        |                    dd                                                    dd         }d| S )zCReturn a provider-safe cache key without changing session identity.N@   utf-8replaceerrors   pck_)strstriplenhashlibsha256encode	hexdigest)r
   keydigests      </home/thesage/.hermes/hermes-agent/agent/transports/codex.py_bounded_prompt_cache_keyr      s    }t
e**



C t
3xx2~~
^CJJwyJAABBLLNNsPRsSF&??    )zgpt-5.5-prozgpt-5.5zgpt-5.4zgpt-5.2zgpt-5.1-codex-maxzgpt-5.1-codex-minizgpt-5.1-chat-latestzgpt-5.1-codexzgpt-5.1zgpt-5-codexzgpt-5zgpt-4.1z(?:^|[./:])(?:|c              #   >   K   | ]}t          j        |          V  d S N)reescape).0names     r   	<genexpr>r'   .   s*      YY4ryYYYYYYr   z)(?:-\d{4}-\d{2}-\d{2})?$modelbase_urlc                    ddl m}  |t          |pd                                        d          }t	          |          dk    o0|d         dk    o$t          |d                   o|dd	         d
dgk    }|sd	S t          | pd                                                                                              dd          }t          
                    |          rdS d	S )z=Return ``24h`` for supported models on Amazon Bedrock Mantle.r   )base_url_hostname .   zbedrock-mantle      Napiaws_-24h)utilsr+   r   splitr   boolr   lowerr   _EXTENDED_PROMPT_CACHE_MODEL_REsearch)r(   r)   r+   hostname_partsis_bedrock_mantle
normalizeds         r   +_default_prompt_cache_retention_for_requestr?   3   s   
 ('''''&&s8>r':':;;AA#FFNNq  	11!11	1"##	1 1225%.0	   tU[b!!''))//1199#sCCJ&--j99 u4r   instructionstoolsc                     | s|sdS d}|r4t          d |D             d           }t          j        |ddd	          }| pd d
| }t          j        |                    dd                                                    dd         }d| S )u  Content-address the prompt cache key from the static request prefix.

    Returns ``pck_<sha256[:24]>`` of (instructions + sorted tool schemas), or
    None when there is nothing static to key on. The cache key is a routing
    hint only — never a correctness boundary — so two requests sharing a system
    prompt and tool set intentionally resolve to the same warm prefix bucket.

    The fix this exists for: recurring cron jobs build session_id as
    ``cron_<id>_<timestamp>``, so using session_id as the cache key made every
    fire cache-cold. The static prefix (identity + tools) is identical across
    fires, so hashing it gives a stable key that stays warm within the
    provider's cache TTL. Sorting tools by name keeps the hash insertion-order
    independent.
    Nr,   c              3   D   K   | ]}t          |t                    |V  d S r"   )
isinstancedictr%   ts     r   r'   z%_content_cache_key.<locals>.<genexpr>^   s1      551At!4!45Q555555r   c                 t    t          |                     d          p|                     d          pd          S )Nr&   typer,   )r   get)rG   s    r   <lambda>z$_content_cache_key.<locals>.<lambda>_   s,    #aeeFmmBquuV}}BCC r   )r   TF),:)	sort_keysensure_ascii
separators r   r   r   r   r   )sortedjsondumpsr   r   r   r   )r@   rA   
tools_partsorted_toolscontentr   s         r   _content_cache_keyrX   J   s       tJ 
55555CC
 
 
 ZDu
 
 


 #5555G^GNN79NEEFFPPRRSVTVSVWF&??r   c                      e Zd ZU dZdZee         ed<   edefd            Z	de
eef         defdZdee
eef                  defd	Zd
ee
eef                  defdZ	 ddedee
eef                  d
eee
eef                           de
eef         fdZdedefdZdedefdZdddddededededef
dZdedefdZdS )ResponsesApiTransportzyTransport for api_mode='codex_responses'.

    Wraps the functions extracted into codex_responses_adapter.py (PR 1).
    N_last_issuer_kindr   c                     dS )Ncodex_responses )selfs    r   api_modezResponsesApiTransport.api_modex   s      r   paramsc                     ddl m}  ||                    d          du |                    d          du |                    d          du |                    d                    S )	z>Classify the current Responses endpoint from transport params.r   )_classify_responses_issueris_xai_responsesTis_github_responsesis_codex_backendr)   )rd   re   rf   r)   )agent.codex_responses_adapterrc   rJ   )r_   ra   rc   s      r   _resolve_issuer_kindz*ResponsesApiTransport._resolve_issuer_kind|   s|    LLLLLL))#ZZ(:;;tC &

+@ A AT I#ZZ(:;;tCZZ
++	
 
 
 	
r   messagesc                     ddl m} |                     |          }|| _         |||                    d          du |                    d          du t          |                    dd                    |          S )z:Convert OpenAI chat messages to Responses API input items.r   )!_chat_messages_to_responses_inputrd   Tre   replay_encrypted_reasoningrd   re   rl   current_issuer_kind)rg   rk   rh   r[   rJ   r8   )r_   ri   kwargsrk   issuers        r   convert_messagesz&ResponsesApiTransport.convert_messages   s    SSSSSS**622!'00#ZZ(:;;tC &

+@ A AT I'+

7>>( ( !'
 
 
 	
r   rA   c                 $    ddl m}  ||          S )zBConvert OpenAI tool schemas to Responses API function definitions.r   )_responses_tools)rg   rs   )r_   rA   rs   s      r   convert_toolsz#ResponsesApiTransport.convert_tools   s%    BBBBBB&&&r   r(   c           	      4   ddl m}m} ddlm} |                    dd          }|}	|sg|re|d                             d          dk    rFt          |d                             d          pd                                          }|d	d
         }	|s|}|                    d          du }
|                    d          du }|                    d          du }t          |                    dd                    }| 	                    |          }|| _
        d}d}|                    d          }|rLt          |t                    r7|                    d          du rd}n|                    d          r|d         }ddi}d|pd                                v rd|d<   |                    dd          r|                    dddd           |                    ||          } ||          }|rB|r@t          d |D                       }|r%d |D             }|                    ddi           |}|| ||	||
||           dd!}|r||d"<   d#|d$<   d|d%<   |                    d&          }t#          ||          p|}|
s	|s|r||d'<   t%          ||                    d(                    }|r|                    d)|           |r%|r#dd*lm} |rd+gng |d,<    ||          rd|i|d-<   n=|r2|
r|                    d.          }|||d-<   n|d#d/|d-<   |rd+gng |d,<   n	|
s|sg |d,<   |                    d0          }|r|                    |           d'|v r3t-          |d'                   }|r||d'<   n|                    d'd
           |r|                    d1d
           |                    d2|                    d2                    }t          |t0          t2          f          rRt          |t                    s=dt3          |          cxk     rt3          d3          k     rn nt3          |          |d2<   n|                    d2d
           |r}t-          |          }|rl|                    d4          } i }!t          | t                    r1|!                    d5 |                                 D                        ||!d&<   ||!d6<   |!|d4<   |                    d7          }"|"|s|"|d8<   |r|r|                    d4          } i }!t          | t                    r1|!                    d9 |                                 D                        ||!d:<   |!|d4<   |                    d;          }#i }$t          |#t                    r|$                    |#           |$                    d'|           |$|d;<   |                    d;          }%t          |%t                    r7d'|%v r3t-          |%d'                   }|r||%d'<   n|%                    d'd
           |S )<u  Build Responses API kwargs.

        Calls convert_messages and convert_tools internally.

        params:
            instructions: str — system prompt (extracted from messages[0] if not given)
            reasoning_config: dict | None — {effort, enabled}
            session_id: str | None — transcript/session id; drives the xAI
                x-grok-conv-id header and the Codex cache-scope headers, and is
                the fallback prompt_cache_key when there is no static prefix to
                content-address
            max_tokens: int | None — max_output_tokens
            timeout: float | None — per-request timeout forwarded to the SDK
            request_overrides: dict | None — extra kwargs merged in
            provider: str | None — provider name for backend-specific logic
            base_url: str | None — endpoint URL
            base_url_hostname: str | None — hostname for backend detection
            is_github_responses: bool — Copilot/GitHub models backend
            is_codex_backend: bool — chatgpt.com/backend-api/codex
            is_xai_responses: bool — xAI/Grok backend
            github_reasoning_extra: dict | None — Copilot reasoning params
        r   )rk   rs   )DEFAULT_AGENT_IDENTITYr@   r,   rolesystemrW   r/   Nre   Trf   rd   rl   mediumreasoning_configenabledFeffortminimallowzgpt-5.6maxultrahigh)xhighr   r   c              3   r   K   | ]2}t          |t                    o|                    d           dk    V  3dS )r&   
web_searchNrD   rE   rJ   rF   s     r   r'   z5ResponsesApiTransport.build_kwargs.<locals>.<genexpr>  sT       ( ( 1d##Ef(E( ( ( ( ( (r   c                 n    g | ]2}t          |t                    r|                    d           dk    0|3S )r&   r   r   rF   s     r   
<listcomp>z6ResponsesApiTransport.build_kwargs.<locals>.<listcomp>  sI       &q$//45EE&MM\4Q4Q 4Q4Q4Qr   rI   r   rm   )r(   r@   inputstorerA   autotool_choiceparallel_tool_calls
session_idprompt_cache_keyr)   prompt_cache_retention)grok_supports_reasoning_effortzreasoning.encrypted_contentinclude	reasoninggithub_reasoning_extra)r|   summaryrequest_overridesservice_tiertimeoutinfextra_headersc                 V    i | ]&\  }}|r|	t          |          t          |          'S r"   r   r%   r   r
   s      r   
<dictcomp>z6ResponsesApiTransport.build_kwargs.<locals>.<dictcomp>  sD        *U" (-'8  HHc%jj'8'8'8r   zx-client-request-id
max_tokensmax_output_tokensc                 V    i | ]&\  }}|r|	t          |          t          |          'S r"   r   r   s      r   r   z6ResponsesApiTransport.build_kwargs.<locals>.<dictcomp>  sD       &C $)#4 C#e**#4#4#4r   zx-grok-conv-id
extra_body)rg   rk   rs   	run_agentrv   rJ   r   r   r8   rh   r[   rD   rE   r9   updateanyappendrX   r?   
setdefaultagent.model_metadatar   r   popintfloatitems)&r_   r(   ri   rA   ra   rk   rs   rv   r@   payload_messagesre   rf   rd   rl   issuer_kindreasoning_effortreasoning_enabledrz   _effort_clampresponse_toolshas_client_web_searchfilteredro   r   	cache_keycache_retentionr   github_reasoningr   bounded_cache_keyr   cache_scope_idexisting_extra_headersmerged_extra_headersr   existing_extra_bodymerged_extra_bodyr   s&                                         r   build_kwargsz"ResponsesApiTransport.build_kwargs   s0   :	
 	
 	
 	
 	
 	
 	
 	

 	544444zz."55# 	0 0HQKOOF33x??"8A;??9#=#=#CDDJJLL#+ABB<  	21L$jj)>??4G!::&899TA!::&899TA%)JJ3T::&
 &
" //77!, $ !::&899 	>
+;T B B 	>##I..%77$)!!!%%h// >#3H#= "E*"++----%*M'"::(%00 	T  6&6!R!RSSS(,,-=?OPP))%00^  	* 	*$' ( ('( ( ( % %! % * -    6777!) (66 !1$7+E$/   
 
  	1,F7O$*F=!,0F()ZZ--
 '|^DDR
	 # 	3+; 	3	 	3)2F%&EJJz""
 
  	I6HHH 	#!1 	#KKKKKK 4NU.//SU 9 .-e44 C'/1A&B{# 	#" #)::.F#G#G #/*:F;'1Af&U&U{#7QY233WY y!! % 	#-= 	# "F9"JJ':;; 	-MM+,,,'' 9&AS:T U U  5->)**

-t444  	-JJ~t,,, **Y

9(=(=>>we--	(w--	( E'NN1111U5\\11111 %gF9JJy$''' 	? 7zBBN ?)/O)D)D&79$4d;; (// .D.J.J.L.L     6D$\2>L$%:;*>'ZZ--
!*:!*4F&' 	5
 	5%+ZZ%@%@"35 0$77 $++ *@*F*F*H*H     6@ !12&:F?# #)**\":":02-t44 >!(()<===(();YGGG#4F< ZZ--
j$'' 	9,>*,L,L 9*EW:X Y Y  91B
-..14888r   responsec                    ddl m} |                    d          p| j        } |||          \  }}d}|r	|j        rg }|j        D ]}i }	t          |d          r|j        r
|j        |	d<   t          |d          r|j        r
|j        |	d<   |                    t          t          |d          r|j
        nt          |d	          r|j        j        ndt          |d	          r|j        j        nt          |d
d          t          |d	          r|j        j        nt          |dd          |	pd                     i }	|r!t          |d          r|j        r
|j        |	d<   |r!t          |d          r|j        r
|j        |	d<   |r!t          |d          r|j        r
|j        |	d<   t%          |r|j        nd||pd|rt          |d          r|j        ndd|	pd          S )z=Normalize Codex Responses API response to NormalizedResponse.r   )_normalize_codex_responser   )r   Ncall_idresponse_item_ididfunctionr&   r,   	argumentsz{})r   r&   r   provider_datacodex_reasoning_itemscodex_message_itemsreasoning_detailsstopr   )rW   
tool_callsfinish_reasonr   usager   )rg   r   rJ   r[   r   hasattrr   r   r   r	   r   r   r&   getattrr   r   r   r   r   rW   r   )
r_   r   ro   r   r   msgr   r   tcr   s
             r   normalize_responsez(ResponsesApiTransport.normalize_response  s   	
 	
 	
 	
 	
 	
 jj//I43I66x[YYY]
 	3> 	Jn   "2y)) :bj :/1zM),2122 Lr7J L8:8KM"45!!( 'D 1 1nruuGTVXbLcLc8m8H8Him-4R-D-Da))'RTV\^`JaJa7>r:7N7Nrbk33T[\^`kmqTrTr"/"74	# # #      	O73 788 	OS=V 	O585NM12 	K73 566 	K3;R 	K363JM/0 	G73 344 	G9N 	G141FM-.!#&0CKKD!'16'*RwsK/H/HRcmmd'/4
 
 
 	
r   c                 f   |dS t          |dd          }t          |t                    r|st          t          |dd          pd                                                                          }t          |dd          }t          |t                    rIt          |                    d          pd                                                                          }nDt          t          |dd          pd                                                                          }|dk    o|d	k    S d
S )u  Check Codex Responses API response has valid output structure.

        Returns True only if response.output is a non-empty list. Also treats
        terminal content-filter incomplete responses as valid: the Responses API
        may return status=incomplete with incomplete_details.reason='content_filter'
        and no output items. That is a provider refusal signal, not a malformed
        response, and must reach normalization so the agent loop can use the
        content-policy / fallback path instead of invalid-response retries.

        Does NOT check output_text fallback — the caller handles that with
        diagnostic logging for stream backfill recovery.
        NFoutputstatusr,   incomplete_detailsreason
incompletecontent_filterT)r   rD   listr   r   r9   rE   rJ   )r_   r   r   r   r   r   s         r   validate_responsez'ResponsesApiTransport.validate_response  s%    58T22&$'' 	Iv 	I8R88>B??EEGGMMOOF!(3G!N!N,d33 ^/33H==CDDJJLLRRTTW%72FFL"MMSSUU[[]]\)Hf8H.HHtr   Fallow_streamre   sanitize_harmony_tokens
api_kwargsr   re   r   c                `   ddl m}  |||||          }d|v r3t          |d                   }|r||d<   n|                    dd           |                    d          }t          |t                    r7d|v r3t          |d                   }|r||d<   n|                    dd           |S )a(  Validate and sanitize Codex API kwargs before the call.

        Normalizes input items, strips unsupported fields, validates structure.
        ``sanitize_harmony_tokens`` is enabled only for the ChatGPT Codex
        backend, which rejects literal reserved Harmony wire tokens in text.
        r   )_preflight_codex_api_kwargsr   r   Nr   )rg   r   r   r   rJ   rD   rE   )	r_   r   r   re   r   r   r>   boundedr   s	            r   preflight_kwargsz&ResponsesApiTransport.preflight_kwargs  s     	NMMMMM00% 3$;	
 
 

 ++/
;M0NOOG 918
-..14888^^L11
j$'' 	9,>*,L,L/
;M0NOOG 918
-..14888r   
raw_reasonc                 <    ddddd}|                     |d          S )aK  Map Codex response.status to OpenAI finish_reason.

        Codex uses response.status ('completed', 'incomplete') +
        response.incomplete_details.reason for granular mapping.
        This method handles the simple status string; the caller
        should check incomplete_details separately for 'max_output_tokens'.
        r   length)	completedr   failed	cancelled)rJ   )r_   r   _MAPs      r   map_finish_reasonz'ResponsesApiTransport.map_finish_reasonB  s2      "	
 
 xx
F+++r   r"   )__name__
__module____qualname____doc__r[   r   r   __annotations__propertyr`   r   r   rh   r   rq   rt   r   r   r   r8   r   rE   r   r   r^   r   r   rZ   rZ   k   s          (,x}+++!# ! ! ! X!
4S> 
c 
 
 
 

d38n)= 
C 
 
 
 
'4S#X#7 'C ' ' ' ' 15	w ww tCH~&w T#s(^,-	w 
c3hw w w wr	.
3 .
=O .
 .
 .
 .
`# $    < #$)(-# # ## 	#
 "# "&# 
# # # #J,C ,C , , , , , ,r   rZ   )register_transportr]   )r   r   rS   r#   typingr   r   r   r   agent.transports.baser   agent.transports.typesr   r	   r   r   _EXTENDED_PROMPT_CACHE_MODELScompilejoinr:   r?   rX   rZ   agent.transportsr   r^   r   r   <module>r      s      				 , , , , , , , , , , , , 3 3 3 3 3 3 ? ? ? ? ? ? ? ?S Xc]    !  #-"* chhYY;XYYYYY      # #  c]   .S $tCH~:N1O T\]`Ta    Be, e, e, e, e,- e, e, e,R 0 / / / / /  $&; < < < < <r   