
    `gjl                        d Z ddlm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dZddZddZd	d	d	d	d
	 	 	 	 	 	 	 	 	 	 	 ddZd	d	d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy	)aZ  Warn when an in-session model switch will trigger preflight compression on the next turn.

Addresses part of #23767 ("user-facing guardrail when switching from a
high-context provider to a substantially lower-context provider"). The other
proposed fixes from that issue (hard preflight token guard, metadata cache
invalidation on switch, compression safety invariant, oversized tool-output
handling) are tracked separately.

Mirrors the expensive-model guard pattern: merge into ``ModelSwitchResult.warning_message``
so Herm TUI, CLI, and gateway surfaces that already show switch warnings pick it up.
    )annotations)AnyCallableListOptional)MINIMUM_CONTEXT_LENGTH)ModelSwitchResultresolve_display_context_lengthc                X    | j                   r| j                    d| | _         y || _         y )Nz | )warning_message)resulttexts     R/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/context_switch_guard.py_append_warningr      s-    $*$:$:#;3tf!E!%    c                :    t        t        | |z        t              S )N)maxintr   )context_lengththreshold_percents     r   _threshold_tokensr      s    s>$5568NOOr   c                   t        | dd       }|y ||t        t        |dd            t        t        |dd            z   dz   }t        |      |k  ry 	 ddlm} t        | d	d       xs d
}t        | dd       }t         ||||xs d             S t        t        |dd      xs d      }|dkD  r|S t        t        | dd      xs d      }|dkD  r|S d S # t
        $ r Y Ow xY w)Ncontext_compressorprotect_first_n   protect_last_n      r   )estimate_request_tokens_rough_cached_system_prompt tools)system_promptr"   last_prompt_tokenssession_prompt_tokens)getattrr   lenagent.model_metadatar   	Exception)	agentmessagesccprotectr   r#   r"   lastsession_prompts	            r   _estimate_tokensr0       s   	,d	3B	zgb"3Q783B("-<
 
 x=G#	J#E+BDIORME7D1E-"/-4  wr/38q9Dax(?CHqIN+a/>9T9  		s   ;C 	CCNr*   r+   custom_providersconfig_context_lengthc                  | j                   r|yt        |dd      syt        |dd      }|yt        t        |dd      xs d      }t        | j                  | j
                  | j                  xs t        |dd      xs d| j                  xs t        |d	d      xs d| j                  ||
      }|syt        ||      }|yt        t        |dd            }	t        ||	      }
||
k  ryt        t        |dd      xs d      dk\  ryg }|r||k  r|j                  d|dd|dd       |j                  d|dd| j                   d|dd|
dd	       t        | dj                  |             y)zJIf the next user message will likely preflight-compress, append a warning.Ncompression_enabledTr   r   r   base_urlr!   api_key)r6   r7   
model_infor2   r3   r   g      ?_ineffective_compression_count   zContext window shrinks (,u    → z). zSession is ~z	 tokens; z allows z (auto-compress at ~zM). Your next message will run preflight compression before the model replies.)successr&   r   r
   	new_modeltarget_providerr6   r7   r8   r0   floatr   appendr   join)r   r*   r+   r2   r3   r,   old_ctxnew_ctxestimatepctnew_thresholdpartss               r   #merge_preflight_compression_warningrH   A   s    >>U]5/6	,d	3B	z'".27a8G,HGE:r$BHbE'%B"?E2$$)3G x0H
/5
6C%gs3M-
727;@qAQFE7W$&wqkwqkE	
 
LL
xl)
HWQK 0+A. /U	V FBGGEN+r   )r2   load_gateway_configc               f   t        |dd      }t        |dd      }d}|*|(|5  |j                  |      }	|	r
|	d   |	d   }ddd       |yd}
|[	  |       }t        |t              r|j                  di       ni }t        |t              r|j                  d      t	        |d         }
d}t        |dd      }t        |dd      }|/|-	 |j                  |      }	|j                  |	j                        }t        | ||||
	       y# 1 sw Y   xY w# t
        $ r Y uw xY w# t
        $ r Y 7w xY w)
z3Gateway helper: cached agent + session DB messages._agent_cache_lockN_agent_cacher   modelr   _session_dbsession_storer1   )
r&   get
isinstancedictr   r)   get_or_create_sessionget_messages_as_conversation
session_idrH   )r   runnersession_keysourcer2   rI   lockcacher*   entrycfg_ctxcfg	model_cfgr+   dbstores                   r   (enrich_model_switch_warnings_for_gatewayra   z   si    6.5DFND1EEE- 	!IIk*Eq-a	! }G&	%'C0:30E,2I)T*y}}=M/N/Zi(89: H		-BFOT2E	~%+	//7E66u7G7GHH ()%7	! 	!  		  		s0   D	AD ,D$ 	D	D! D!$	D0/D0)r   r	   r   strreturnNone)r   r   r   r?   rc   r   )r*   r   r+   Optional[List[dict]]rc   zOptional[int])r   r	   r*   r   r+   re   r2   list | Noner3   z
int | Nonerc   rd   )r   r	   rV   r   rW   rb   rX   r   r2   rf   rI   zCallable[[], dict] | Nonerc   rd   )__doc__
__future__r   typingr   r   r   r   r(   r   hermes_cli.model_switchr	   r
   r   r   r0   rH   ra    r   r   <module>rl      s   
 # 0 0 7 U&P:H %)$((,6,6, 6, #	6,
 "6, &6, 
6,~ %)59/// 	/
 / "/ 3/ 
/r   