
    epj              
          d Z ddlZddlmZmZ ddlmZ ddlmZm	Z	 ddl
mZ ddlmZ ddlmZmZmZ d	eeeef                  d
efdZdeeef         d	eeeef                  deeeef                  dz  ded
df
dZdededz  d
edz  fdZdededz  d
edz  fdZdedz  d
edz  fdZded
efdZded
efdZded
efdZ G d de          Zddlm Z   e de           dS )u  OpenAI Chat Completions transport.

Handles the default api_mode ('chat_completions') used by ~16 OpenAI-compatible
providers (OpenRouter, Nous, NVIDIA, Qwen, Ollama, DeepSeek, xAI, Kimi, etc.).

Messages and tools are already in OpenAI format — convert_messages and
convert_tools are near-identity.  The complexity lives in build_kwargs
which has provider-specific conditionals for max_tokens defaults,
reasoning configuration, temperature handling, and extra_body assembly.
    N)AnyDict)resolve_lmstudio_effort)is_moonshot_modelsanitize_moonshot_tools)DEVELOPER_ROLE_MODELS)ProviderTransport)NormalizedResponseToolCallUsagemessagesreturnc                 \   | rt          | d         t                    sdS | d         }|                    d          dvrdS |                    d          }t          |t                    r|S 	 t	          j        |ddd	          S # t          t          f$ r t          |pd          cY S w xY w)
a]  Return the stable system/developer prefix used for cache routing.

    Chat Completions carries instructions in its message list rather than a
    separate ``instructions`` field.  Only a leading system/developer message
    is static by contract; later messages are conversation state and must not
    split a warm prefix bucket on every turn.
    r    role>   system	developercontentTF),:)	sort_keysensure_ascii
separators)
isinstancedictgetstrjsondumps	TypeError
ValueError)r   firstr   s      G/home/thesage/.hermes/hermes-agent/agent/transports/chat_completions.py_static_prompt_instructionsr$      s      :hqk488 rQKEyy 777rii	""G'3 "z'TR\]]]]z" " " "7=b!!!!!"s   .B "B+*B+
api_kwargstoolssupports_prompt_cache_keyc                    |sdS |                      d          }d| v st          |t                    rd|v rdS ddlm}  |t          |          |          }|r|| d<   dS dS )zDAdd a content-addressed key only for an explicitly capable endpoint.N
extra_bodyprompt_cache_keyr   )_content_cache_key)r   r   r   agent.transports.codexr+   r$   )r%   r   r&   r'   r)   r+   	cache_keys          r#   _add_prompt_cache_keyr.   ,   s     %  --JZ'':t$$ ();z)I)I :99999""#>x#H#H%PPI 3)2
%&&&3 3    modelreasoning_configc                 (   t          |t                    s|S d| pd                                v rbt          |                    d          pd                                                                          dk    rt          |          }d|d<   |S |S )z4Return the model's wire-compatible reasoning config.zgpt-5.6r   effortultramax)r   r   lowerr   r   strip)r0   r1   
normalizeds      r#   _reasoning_config_for_modelr9   H   s    &--  ekr((**** $$X..4"55;;==CCEEPP*++
$
8r/   c                    |t          |t                    sdS | pd                                                                }|                    d          r|                    dd          d         }|                    d          sdS |                    d          du rd	diS t          |                    d
d          pd                                                                          }|dk    rd	diS d	di}|                    d          r|S |dvrd}|                    d          r-d|v r|dv rd|d<   n|dv rd|d<   nd|d<   nd|v r|dv rdnd|d<   |S )zLTranslate Hermes/OpenRouter-style reasoning config to Gemini thinkingConfig.Nr   zgoogle//   geminienabledFincludeThoughtsr3   mediumnoneTzgemini-2.5->   lowr5   highr4   xhighr@   minimal)zgemini-3z
gemini-3.1flash>   rB   rE   rB   thinkingLevel>   r5   rC   r4   rD   rC   pro)r   r   r7   r6   
startswithsplitr   r   )r0   r1   normalized_modelr3   thinking_configs        r#   _build_gemini_thinking_configrM   V   s   z2BD'I'It**,,2244""9-- =+11#q99!< &&x00 tI&&%// "5))!%%h99EXFFLLNNTTVVF!5))'8$&?O
 ""=11 RRR
 ""#=>> &&&+++3800<<<39003;00&&& $EEE5 O, r/   configc                    t          | t                    r| sdS i }t          |                     d          t                    r| d         |d<   t          |                     d          t                    rI| d                                         r/| d                                                                         |d<   t          |                     d          t          t          f          rt          | d                   |d<   |pdS )zEConvert Gemini thinking config keys to the OpenAI-compat field names.Nr?   include_thoughtsrG   thinking_levelthinkingBudgetthinking_budget)	r   r   r   boolr   r7   r6   intfloat)rN   
translateds     r#   "_snake_case_gemini_thinking_configrX      s    fd## 6 t!#J&**.//66 C)/0A)B
%&&**_--s33 O8O8U8U8W8W O'-o'>'D'D'F'F'L'L'N'N
#$&**-..e== F(+F3C,D(E(E
$%r/   base_urlc                     t          | pd                                                              d                                          }|sdS d|vrdS |                    d          S )Nr   r;   Fz!generativelanguage.googleapis.comz/openai)r   r7   rstripr6   endswith)rY   r8   s     r#   !_is_gemini_openai_compat_base_urlr]      sj    X^$$**,,33C88>>@@J u**<<uy)))r/   c                     	 ddl m}  |t          | pd                                                    j        pd                                }n# t          $ r Y dS w xY w|dk    S )a  True only for api.openai.com itself (exact host).

    OpenAI documents ``prompt_cache_key`` as a first-class body field and
    GPT-5.6+ docs recommend it for reliable cache routing, so the flag is
    implied for the real endpoint. Deliberately NOT a substring match:
    Azure OpenAI and strict OpenAI-compat endpoints may reject unknown
    fields and must stay opt-in via ``supports_prompt_cache_key``.
    r   )urlparser   Fzapi.openai.com)urllib.parser_   r   r7   hostnamer6   	Exception)rY   r_   hosts      r#   _is_openai_api_base_urlrd      s    ))))))X^,,224455>D"KKMM   uu###s   AA 
AAc                 X    t          | pd                                          }d|v pd|v S )u  True when the outgoing model is a Gemini family model that requires
    ``extra_content`` (thought_signature) to be replayed on tool calls.

    Gemini 3 thinking models attach ``extra_content`` to each tool call and
    reject subsequent requests with HTTP 400 if it is missing. Every other
    strict OpenAI-compatible provider (Fireworks, Mistral, ...) rejects the
    request with 400 if ``extra_content`` *is* present. So the field must be
    kept only when the target model is itself Gemini-family, and stripped
    otherwise — including when a non-Gemini model inherits stale Gemini
    ``extra_content`` from earlier in a mixed-provider session.
    r   r=   gemma)r   r6   )r0   ms     r#   !_model_consumes_thought_signaturerh      s4     	EKR  Aq=(GqL(r/   c                   t   e Zd ZdZedefd            Zdeeee	f                  deeee	f                  fdZ
deeee	f                  deeee	f                  fdZ	 dd	edeeee	f                  deeee	f                  dz  deee	f         fd
Zd Zde	defdZde	defdZde	deeef         dz  fdZdS )ChatCompletionsTransportzfTransport for api_mode='chat_completions'.

    The default path for OpenAI-compatible providers.
    r   c                     dS )Nchat_completions )selfs    r#   api_modez!ChatCompletionsTransport.api_mode   s    !!r/   r   c                    t          |                    d                     }d}|D ]t          t                    sdv sdv sdv sdv sdv sdv rd	} nxt	          d
 D                       rd	} n[                    d          }t          |t
                    r0|D ])}t          |t                    rd|v s
d|v s|rd|v rd	} n*|r n|s|S t          |          t          |          D ]\  t          t                    sddt          t          t          f         ffd}dv sdv sdv sdv sdv sdv r |            }|	                    dd           |	                    dd           |	                    dd           |	                    dd           |	                    dd           |	                    dd           d D             }	|	r% |            }|	D ]}
|	                    |
d                               d          }t          |t
                    rd}t          |          D ]\  }}t          |t                    ryd|v p	d|v p|od|v }|ri|t          |          }t          |          }|	                    dd           |	                    dd           |r|	                    dd           |||<   || |            d<   S )u  Messages are already in OpenAI format — strip internal fields
        that strict chat-completions providers reject with HTTP 400/422
        (or, in the case of some OpenAI-compatible gateways, 5xx):

        - Codex Responses API fields: ``codex_reasoning_items`` /
          ``codex_message_items`` on the message, ``call_id`` /
          ``response_item_id`` on ``tool_calls`` entries.
        - ``extra_content`` on ``tool_calls`` (Gemini thought_signature) —
          stripped unless the outgoing ``model`` is itself Gemini-family.
          Gemini 3 thinking models attach it for replay, but strict providers
          (Fireworks, Mistral) reject any payload containing it with
          ``Extra inputs are not permitted, field: 'messages[N].tool_calls[M].extra_content'``.
          It must be kept for Gemini targets (replay required) and dropped for
          everyone else, including non-Gemini models that inherited stale
          Gemini ``extra_content`` earlier in a mixed-provider session.
        - ``tool_name`` on tool-result messages — written by
          ``make_tool_result_message()`` for the SQLite FTS index, but not
          part of the Chat Completions schema. Strict providers (Fireworks,
          Moonshot/Kimi) reject any payload containing it with
          ``Extra inputs are not permitted, field: 'messages[N].tool_name'``.
          Permissive providers (OpenRouter, MiniMax) silently ignore the
          field, which masked the bug for months.
        - Hermes-internal scaffolding markers — any top-level message key
          starting with ``_`` (e.g. ``_empty_recovery_synthetic``,
          ``_empty_terminal_sentinel``, ``_thinking_prefill``). These are
          bookkeeping flags the agent loop attaches to messages so the
          persistence layer can later strip its own scaffolding; they must
          never reach the wire. Permissive providers (real OpenAI,
          Anthropic) silently drop unknown message keys, but strict
          gateways (e.g. opencode-go, codex.nekos.me) reject with
          ``Extra inputs are not permitted, field: 'messages[N]._empty_recovery_synthetic'``,
          which then poisons every subsequent request in the session.
        r0   Fcodex_reasoning_itemscodex_message_items	tool_nameeffect_disposition	timestampapi_contentTc              3   j   K   | ].}t          |t                    o|                    d           V  /dS )_Nr   r   rI   .0ks     r#   	<genexpr>z<ChatCompletionsTransport.convert_messages.<locals>.<genexpr>  s=      II:a%%;!,,s*;*;IIIIIIr/   
tool_callscall_idresponse_item_idextra_contentNr   c                  4     t                      <    S N)r   )
copied_msgmsgmsg_idx	sanitizeds   r#   mutable_msgz>ChatCompletionsTransport.convert_messages.<locals>.mutable_msg!  s$    %!%cJ)3Ig&!!r/   c                 f    g | ].}t          |t                    |                    d           ,|/S )rx   ry   rz   s     r#   
<listcomp>z=ChatCompletionsTransport.convert_messages.<locals>.<listcomp><  s9    XXX1z!S/A/AXallSVFWFWXQXXXr/   )
rh   r   r   r   anylist	enumerater   r   pop)rn   r   kwargsstrip_extra_contentneeds_sanitizer~   tcr   out_msginternal_keyskeycopied_tool_callstc_idxshould_copy_tc	copied_tcr   r   r   r   s                  @@@@r#   convert_messagesz)ChatCompletionsTransport.convert_messages   s   H #DJJw#
 #
 
  	 	Cc4(( '3..(C//#%%'3..#%% C''!%IISIIIII !%..J*d++ 
$  B!"d++ !R-33/ 44Cr4I4I)-! E 	ONN	%h// ;	D ;	DLGSc4(( 04J"c3h " " " " " " " " " (3..(C//#%%'3..#%% C''%+--3T:::14888K...0$777K...M4000 YXXXXM +%+--( + +CKKT****..J*d++ D6:!"+J"7"7 B BJFB!"d++ B%O O1R7O 3 M28M '
 * B08484D4D 1(,RI%MM)T:::%MM*<dCCC2 E )ot D D D8A-f5$02CKKMM,/r/   r&   c                     |S )u0   Tools are already in OpenAI format — identity.rm   )rn   r&   s     r#   convert_toolsz&ChatCompletionsTransport.convert_toolsY  s    r/   Nr0   c           
        ' |                      ||          }|                    d          }|r|                     |||||          S |                    d|pd                                          '|rzt	          |d         t
                    r_|d                             d          dk    r@t          'fdt          D                       r t          |          }i |d         dd	i|d<   ||d
}|                    d          }|||d<   |r#t          |          rt          |          }||d<   |                    d          }	|                    d          }
|                    d          }|                    d          }|                    dd          }|                    dd          }t          ||                    d                    }|
!|	r|                     |	|
                     n*|!|	r|                     |	|                     n|||d<   |rt          |o+t	          |t
                    o|                    d          du           }|s_d}|rVt	          |t
                    rA|                    d          pd                                                                }|dv r|}||d<   |rt          |o+t	          |t
                    o|                    d          du           }|s_d}|rVt	          |t
                    rA|                    d          pd                                                                }|dv r|}||d<   |                    dd          r@|                    dd          r*t          ||                    d                    }|||d<   i }|                    dd          }|                    d d          }t!          |                    d!          pd                                                                          }|                    d"          }|                    d#          }|r|r||d$<   |rh|d%k    rb|                    d&          }|K|dk    rE	 t#          |          }n# t$          t&          f$ r d}Y nw xY w|d'|cxk    rd(k    rn n	d)|d*g|d+<   |r=d,}|r.t	          |t
                    r|                    d          du rd}d-|rdnd.i|d/<   |                    dd          rn|                    dd          sX|r|                    d0          }|||d1<   n9d} |r-t	          |t
                    r|                    dd          pd} d,| d2|d1<   |d3k    rst)          ||          }!t+          |          rMt-          |!          }"|"r;|                    d4i           }#|#                    d5i           }$|"|$d6<   |$|#d5<   |#|d4<   n|!r|!|d6<   |                    d7          }%|%r|                    |%           |r||d4<   |                    d8          }&|&r|                    |&           t/          |||                    d          t          |                    d9                    p!t1          |                    d"                    :           |S );u  Build chat.completions.create() kwargs.

        params (all optional):
            timeout: float — API call timeout
            max_tokens: int | None — user-configured max tokens
            ephemeral_max_output_tokens: int | None — one-shot override
            max_tokens_param_fn: callable — returns {max_tokens: N} or {max_completion_tokens: N}
            reasoning_config: dict | None
            request_overrides: dict | None
            session_id: str | None
            model_lower: str — lowercase model name for pattern matching
            # Provider profile path (all per-provider quirks live in providers/)
            provider_profile: ProviderProfile | None — when present, delegates to
                _build_kwargs_from_profile(); all flag params below are bypassed.
            # Legacy-path flags — only used when provider_profile is None
            # (i.e. custom / unregistered providers). Known providers all go
            # through provider_profile.
            is_openrouter: bool
            is_nous: bool
            is_qwen_portal: bool
            is_github_models: bool
            is_nvidia_nim: bool
            is_kimi: bool
            is_tokenhub: bool
            is_lmstudio: bool
            is_custom_provider: bool
            ollama_num_ctx: int | None
            # Provider routing
            provider_preferences: dict | None
            # Qwen-specific
            qwen_prepare_fn: callable | None — runs AFTER codex sanitization
            qwen_prepare_inplace_fn: callable | None — in-place variant for deepcopied lists
            qwen_session_metadata: dict | None
            # Temperature
            fixed_temperature: Any — from _fixed_temperature_for_model()
            omit_temperature: bool
            # Reasoning
            supports_reasoning: bool
            github_reasoning_extra: dict | None
            lmstudio_reasoning_options: list[str] | None  # raw allowed_options from /api/v1/models
            # Claude on OpenRouter/Nous max output
            anthropic_max_output: int | None
            extra_body_additions: dict | None
            supports_prompt_cache_key: bool — explicit endpoint capability for
                the top-level Chat Completions request field; defaults off.
        )r0   provider_profilemodel_lowerr   r   r   r   c              3       K   | ]}|v V  	d S r   rm   )r{   pr   s     r#   r}   z8ChatCompletionsTransport.build_kwargs.<locals>.<genexpr>  s(      DDA$DDDDDDr/   r   r0   r   timeoutNr&   max_tokens_param_fnephemeral_max_output_tokens
max_tokensanthropic_max_outputis_kimiFis_tokenhubr1   r>   r@   r3   >   rB   rC   r@   reasoning_effortrC   is_lmstudiosupports_reasoninglmstudio_reasoning_optionsis_openrouteris_github_modelsprovider_namerY   provider_preferencesproviderzopenrouter/pareto-codeopenrouter_min_coding_scoreg        g      ?zpareto-router)idmin_coding_scorepluginsTtypedisabledthinkinggithub_reasoning_extra	reasoning)r>   r3   r=   r)   googlerL   extra_body_additionsrequest_overridesr'   r   r&   r'   )r   r   _build_kwargs_from_profiler6   r   r   r   r   r   r   r   r9   updaterT   r7   r   r   rV   r    r!   rM   r]   rX   r.   rd   )(rn   r0   r   r&   paramsr   _profiler%   r   max_tokens_fn	ephemeralr   anthropic_max_outr   r   r1   _kimi_thinking_off_kimi_effort_e_tokenhub_thinking_off_tokenhub_effort
_lm_effortr)   r   r   r   rY   provider_prefs_pareto_score_pareto_score_f_kimi_thinking_enabledgh_reasoning_effortraw_thinking_configrL   openai_compat_extragoogle_extra	additions	overridesr   s(                                          @r#   build_kwargsz%ChatCompletionsTransport.build_kwargs]  s4   p ))(%)@@	 ::011 	22%E6   jj"0C0C0E0EFF	A9Q<..	A !  ((H44DDDD.CDDDDD 5 YI@il@FK@@IaL !&
 &


 **Y''$+Jy!  	( !'' 7/66"'Jw 

#899JJ<==	ZZ--
"JJ'=>>**Y..jj666ufjjI[>\>\]] ] mmI667777##mmJ778888*'8J|$  	>!%  =/66=$((33u<" "
 & >'# *
3CT(J(J **..x88>BEEGGMMOOB666')1=
-.  	B%)  =/66=$((33u<& &"
 * B#) # .
3CT(J(J .*..x88>BEEGGMMOOB666+-(1A
-. ::mU++ 	<

;OQV0W0W 	<0 

788 J %1;
-. &(


?E::!::&8%@@FJJ77=2>>DDFFLLNN::j))$:;; 	4m 	4%3Jz"
  
	U&>>>"JJ'DEEM(]b-@-@+&+M&:&:OO!:. + + +&*OOO+".3/3P3P3P3PS3P3P3P3P3P.OTT-Jy)
  	%)" 3J/?$F$F 3#''	22e;;-2*%;K		&Jz" ::*E22 		O6::mUZ;[;[ 		O O%zz*BCC+.:J{+"# S
3CT(J(J S.228XFFR(G6:g*N*N
;'H$$"?GW"X"X0:: 	D"DEX"Y"Y" C*4..r*J*J'#6#:#:8R#H#HL6EL!234@'1/BJ|,$ D0C
,- JJ566	 	)i((( 	2'1J|$ JJ233	 	)i(((..))&*6::6Q+R+R&S&S '?&vzz*'='=>>	
 	
 	
 	
 s   R R,+R,c                 	   ddl m} |                    |          }|pd                                |rzt	          |d         t
                    r_|d                             d          dk    r@t          fdt          D                       r t          |          }i |d         ddi|d<   ||d}|j
        |u rn.|j
        |j
        |d
<   n|                    d
          }|||d
<   |                    d          }	|	|	|d<   |r#t          |          rt          |          }||d<   |                    d          }
|                    d          }|                    d          }|                    d          }|                    |          }|!|
r|                     |
|                     nM|!|
r|                     |
|                     n*|r!|
r|                     |
|                     n|||d<   t          ||                    d                    }|                    ||                    dd          |                    d          ||                    d          |                    d          |                    d                    \  }}|                    |           i }|                    |                    d          |                    d          ||                    d          ||                    d                    }|r|                    |           |r|                    |           |                    d          }|r|                    |           |                    d          }|rP|                                D ];\  }}|dk    r+t	          |t
                    r|                    |           6|||<   <|r_	 ddlm}  ||                    d                    }n# t*          $ r d}Y nw xY w|rd  |                                D             }|r||d<   t-          |||                    d          t/          |j                  !           |S )"u   Build API kwargs using a ProviderProfile — single path, no legacy flags.

        This method replaces the entire flag-based kwargs assembly when a
        provider_profile is passed. Every quirk comes from the profile object.
        r   )OMIT_TEMPERATUREr   r   r   c              3       K   | ]}|v V  	d S r   rm   )r{   r   _model_lowers     r#   r}   zFChatCompletionsTransport._build_kwargs_from_profile.<locals>.<genexpr>`  s(      EE!A%EEEEEEr/   r   r   Ntemperaturer   r&   r   r   r   r   r1   r   Fqwen_session_metadatarY   ollama_num_ctx
session_id)r1   r   r   r0   rY   r   r   r   r   )r   r   r0   rY   r1   r   r   r   r)   )is_native_gemini_base_urlc                 "    i | ]\  }}|d v 	||S ))rL   thinkingConfigrm   )r{   r|   vs      r#   
<dictcomp>zGChatCompletionsTransport._build_kwargs_from_profile.<locals>.<dictcomp>  s4       !QAAA qAAAr/   r   )providers.baser   prepare_messagesr6   r   r   r   r   r   r   fixed_temperaturer   r   get_max_tokensr   r9   build_api_kwargs_extrasbuild_extra_bodyitemsagent.gemini_native_adapterr   rb   r.   rT   r'   )rn   profiler0   r   r&   r   r   r%   tempr   r   r   user_maxanthropic_maxprofile_maxr1   extra_body_from_profiletop_level_from_profiler)   profile_bodyr   r   r|   r   r   _native_geminir   s                             @r#   r   z3ChatCompletionsTransport._build_kwargs_from_profileO  s`    	433333 ,,Y77	 **,,	A9Q<..	A !  ((H44EEEE/DEEEEE 5 YI@il@FK@@IaL !&
 &

 $(888&2(/(AJ}%% ::m,,D,0
=) **Y''$+Jy!  	( '' 7/66"'Jw 

#899JJ<==	::l++

#9:: ,,U33 ] mmI667777!m!mmH556666 	5] 	5mmK889999&'4J|$ 7ufjjI[>\>\]]++!1#)::.BE#J#J&,jj1H&I&IJ//%zz*:;;!::l33 ,   	8!7 	0111 &(
 //zz,//!',B!C!CZZ
++-(.

3P(Q(Q 0 
 
  	,l+++ # 	75666 JJ566	 	)i((( JJ233	 	&!)) & &1$$At)<)<$%%a(((($%JqMM 	6'QQQQQQ!:!:6::j;Q;Q!R!R ' ' '!&'  %/%5%5%7%7  
  6+5
<(..))&*7+L&M&M		
 	
 	
 	
 s   *$P PPresponsec           	          |j         d         }|j        }|j        }t          |t                    rt          |          }|pd}d}|j        rg }|j        D ]}i }	t          |dd          }
|
Ft          |d          r6t          |j	        t                    r|j	        ni                     d          }
|
;t          |
d          r&	 |
                                }
n# t          $ r Y nw xY w|
|	d<   |                    t          |j        |j        j        |j        j        |	pd                     d}t          |d          rS|j        rL|j        }t+          t          |d	d          pdt          |d
d          pdt          |dd          pd          }t          |dd          }t          |dd          }|Dt          |d          r4t          |dd          pi }t          |t                    rd|v r|d         }i }|||d<   t          |dd          }|r||d<   |j        }t          |dd          }|Mt          |d          r=t          |dd          pi }t          |t                    r|                    d          }t          |t
                    r]|                                rI||d<   t          |t
                    o|                                }t1          |          }|s
|s|}|dv rd}t3          ||||||pd          S )u  Normalize OpenAI ChatCompletion to NormalizedResponse.

        For chat_completions, this is near-identity — the response is already
        in OpenAI format.  extra_content on tool_calls (Gemini thought_signature)
        is preserved via ToolCall.provider_data.  reasoning_details (OpenRouter
        unified format) and reasoning_content (DeepSeek/Moonshot) are also
        preserved for downstream replay.
        r   stopNr   model_extra
model_dump)r   name	argumentsprovider_datausageprompt_tokenscompletion_tokenstotal_tokens)r   r  r  r   reasoning_contentreasoning_detailsrefusal)Nr   content_filter)r   r~   finish_reasonr   r   r   )choicesmessager  r   rU   r   r~   getattrhasattrr   r   r   r   rb   appendr   r   functionr   r   r   r   r   r7   rT   r
   )rn   r   r   choicer   _frr  r~   r   tc_provider_dataextrar   ur   r  r   r   rdr   r  
_msg_extra	_has_text_has_tool_callss                          r#   normalize_responsez+ChatCompletionsTransport.normalize_response  s    !!$n"c3 	c((Cv
> 	Jn  
 46 OT::=WR%?%?=/9".$/O/OWR^^UW\\]lmmE$ul33 !!$)$4$4$6$6EE( ! ! ! D!8=$_5!!5[-"$+"7&6&>$	      8W%% 	(. 	A%a!<<A")!-@!"D"D"I$Q::?a  E Cd33	#C)<dCC$m)D)D$!#}d;;ArK+t,, E1D1S1S$/0C$D!(*(1BM-.S-t44 	413M-. +#y$//?wsM::? mT::@bJ*d++ 4$..33gs## 	5 	5 (/M)$"7C00DW]]__I":..O  5_ 5! N22$4M!!''/4
 
 
 	
s   C
C('C(c                 R    |dS t          |d          r|j        dS |j        sdS dS )z&Check that response has valid choices.NFr  T)r  r  )rn   r   s     r#   validate_responsez*ChatCompletionsTransport.validate_responseW  sA    5x++ 	x/?/G5 	5tr/   c                     t          |dd          }|dS t          |dd          }|rt          |dd          pdnd}|rt          |dd          pdnd}|st          |dd          pd}|s|r||dS dS )	zExtract cache stats from prompt_tokens_details (OpenRouter/OpenAI)
        or DeepSeek's native top-level prompt_cache_hit_tokens field.r   Nprompt_tokens_detailscached_tokensr   cache_write_tokensprompt_cache_hit_tokens)r  creation_tokens)r
  )rn   r   r   detailscachedwrittens         r#   extract_cache_statsz,ChatCompletionsTransport.extract_cache_statsa  s     '400=4%!8$??>EL/155:1DKR''#7;;@qQR 	G U$=qAAFQF 	IW 	I%+HHHtr/   r   )__name__
__module____qualname____doc__propertyr   ro   r   r   r   r   r   r   r   r
   r  rT   r  rU   r#  rm   r/   r#   rj   rj      s        
 "# " " " X"ET#s(^,E	d38n	E E E EN4S#X#7 Dc3h<P     .2	p pp tCH~&p DcN#d*	p 
c3hp p p pdS S Sjq
3 q
=O q
 q
 q
 q
f# $    C DcNT4I      r/   rj   )register_transportrl   )!r'  r   typingr   r   agent.lmstudio_reasoningr   agent.moonshot_schemar   r   agent.prompt_builderr   agent.transports.baser	   agent.transports.typesr
   r   r   r   r   r   r$   rT   r.   r9   rM   rX   r]   rd   rh   rj   agent.transportsr)  rm   r/   r#   <module>r1     s  	 	          < < < < < < L L L L L L L L 6 6 6 6 6 6 3 3 3 3 3 3 F F F F F F F F F F"$tCH~*> "3 " " " ",3S#X3 4S>"3 S#X$&	3
  $3 
3 3 3 38s dTk dUYk    5 5t 5PTW[P[ 5 5 5 5ptd{ td{    * * * * * *$c $d $ $ $ $$)S )T ) ) ) ) h
 h
 h
 h
 h
0 h
 h
 h
X 0 / / / / /  %'? @ @ @ @ @r/   