
    epj3                    X   U d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ erddlmZ  ej        e          ZdZd]dZ d^dZ!d_dZ"d`dZ#d`dZ$ddiZ%h dZ&dadZ'dbd"Z(dcd$Z)ddd&Z*ded(Z+dfd-Z,	 dgdhd/Z-did0Z.d1Z/djd4Z0d5Z1dkd7Z2dld;Z3d<d=hZ4d<d=d=d>Z5dad?Z6d@d@d@d@dAd@dBdBd@dAdCZ7dmdGZ8e	 G dH dI                      Z9 e            Z:dJe;dK<   da<d:e;dL<   dMa=dNe;dO<   dndPZ>dndQZ?dodTZ@dpdVZAdqdYZBdrdsd[ZCdtd\ZDdS )ua  Honcho client initialization and configuration.

Resolution order for config file:
  1. $HERMES_HOME/honcho.json  (instance-local, enables isolated Hermes instances)
  2. ~/.honcho/config.json     (global, shared across all Honcho-enabled apps)
  3. Environment variables     (HONCHO_API_KEY, HONCHO_ENVIRONMENT)

Resolution order for host-specific settings:
  1. Explicit host block fields (always win)
  2. Flat/global fields from config root
  3. Defaults (host name as workspace/peer)
    )annotationsN)	dataclassfield)Path)urlparse)
get_secret)get_hermes_home)_get_default_hermes_home)SingletonSlot)AnyTYPE_CHECKINGHonchohermesprofile
str | Nonereturnstrc                    | r| dv rt           S d                    d | D                                           d          }t            d|pd S )z5Return the safe Honcho host key for a Hermes profile.>   customdefault c              3  N   K   | ] }|                                 s|d v r|ndV  !dS )z_-_N)isalnum).0cs     B/home/thesage/.hermes/hermes-agent/plugins/memory/honcho/client.py	<genexpr>z#profile_host_key.<locals>.<genexpr>+   s;      PP1QYY[[>AII3PPPPPP    r   r   )HOSTjoinstrip)r   	sanitizeds     r   profile_host_keyr%   '   sb     g!666PPPPPPPVVWZ[[I--Y+)---r    rawdicthostc                   |                      d          pi }|                     |i           }|s|                    t           d          s|S t           d|t          t                    dz   d          }|                     |i           S )z@Return host config, accepting legacy dot-form profile host keys.hostsr   .   N)get
startswithr!   len)r&   r(   r*   blocklegacys        r   _host_blockr2   /   s    GGG"EIIdBE DOOtJJJ// --tCIIMNN+--F99VR   r    c                 "   t           j                            dd                                          } | r| S 	 ddlm}  |            }t          |          }n# t          $ r
 t          }Y nw xY w|t          k    r	 t                      }|
                                rat          j        |                    d                    }t          |                    dd                                                    }|r|S n# t          $ r Y nw xY w|S )aW  Derive the Honcho host key from the active Hermes profile.

    Resolution order:
      1. HERMES_HONCHO_HOST env var (explicit override)
      2. Active profile name via profiles system -> ``hermes_<profile>``
      3. defaultHost from the active config, but only for the default profile
      4. Fallback: ``"hermes"`` (default profile)
    HERMES_HONCHO_HOSTr   r   )get_active_profile_nameutf-8encodingdefaultHost)osenvironr-   r#   hermes_cli.profilesr5   r%   	Exceptionr!   resolve_config_pathexistsjsonloads	read_textr   )explicitr5   r   profile_hostpathr&   default_hosts          r   resolve_active_hostrG   9   s3    z~~2B77==??H ??????))++'00    t	&((D{{}} (j!A!ABB"377="#=#=>>DDFF ('' 	 	 	D	 s$   A A,+A,;BC? ?
DDr   c                 4    t          j                    dz  dz  S )z:Return the shared Honcho config path for the current HOME.z.honchozconfig.json)r   home r    r   resolve_global_config_pathrK   _   s    9;;"]22r    c                     t                      dz  } |                                 r| S t                      dz  }|| k    r|                                r|S t                      S )uo  Return the active Honcho config path.

    Resolution order:
      1. $HERMES_HOME/honcho.json      (profile-local, if it exists)
      2. ~/.hermes/honcho.json          (default profile — shared host blocks live here)
      3. ~/.honcho/config.json          (global, cross-app interop)

    Returns the global path if none exist (for first-time setup writes).
    zhoncho.json)r	   r?   r
   rK   )
local_pathdefault_paths     r   r>   r>   d   sn     !""]2J  ,--=Lz!!l&9&9&;&;!%'''r    autohybrid>   toolsrP   contextvalc                R    t                               | |           } | t          v r| ndS )u?   Normalize legacy recall mode values (e.g. 'auto' → 'hybrid').rP   )_RECALL_MODE_ALIASESr-   _VALID_RECALL_MODESrS   s    r   _normalize_recall_moderX   ~   s,    

"
"3
,
,C,,,33(:r    r   boolc                6    |D ]}|t          |          c S | S )aE  Resolve a bool config field: first non-None wins, else default.

    Variadic to support aliased keys (e.g. ``pinUserPeer`` shadowing
    ``pinPeerName`` for backwards compatibility).  Pass values in
    precedence order: caller's preferred alias first, then fallback
    aliases, in (host, root) interleaving as needed.
    )rY   )r   valsrS   s      r   _resolve_boolr\      s4       ?99 Nr    
int | Nonec                j    | |fD ]-}|)	 t          |          c S # t          t          f$ r Y )w xY w.dS )z@Parse contextTokens: host wins, then root, then None (uncapped).Nint
ValueError	TypeErrorhost_valroot_valrS   s      r   _parse_context_tokensrf      s`    (#  ?3xx	*    
 4   //r`   c                j    | |fD ]-}|)	 t          |          c S # t          t          f$ r Y )w xY w.|S )z<Parse an integer config: host wins, then root, then default.r_   rd   re   r   rS   s       r   _parse_int_configrj      s`    (#  ?3xx	*    
 Nrg   floatc                    | |fD ];}|7	 t          dt          |                    c S # t          t          f$ r Y 7w xY w<|S )uH   Parse a float config: host wins, then root, then default. Clamped ≥ 0.Ng        )maxrk   ra   rb   ri   s       r   _parse_float_configrn      sm    (#  ?3c

+++++	*    
 Ns   )==host_objroot_objkeydict[str, str]c                L   || v r| |         n|                     |          }t          |t                    si S i }|                                D ]T\  }}t	          |                                          }|!t	          |                                          nd}|r|r|||<   U|S )z@Parse a string-to-string map with host-level whole-map override.Nr   )r-   
isinstancer'   itemsr   r#   )	ro   rp   rq   sourceresultraw_key	raw_value	alias_keyalias_values	            r   _parse_string_mapr|      s    !XooXc]]8<<3D3DFfd## 	F$llnn , ,LL&&((	090Ec)nn**,,,2 	, 	, +F9Mr    r   c                    || v r|                      |          }n|                     ||          }||S t          |                                          S )zEParse a string field where host-level empty string can override root.)r-   r   r#   )ro   rp   rq   r   values        r   _parse_optional_stringr      sU     hS!!S'**}u::r    c           	         | |fD ]I}|E	 t          dt          t          |          d                    c S # t          t          f$ r Y Ew xY wJdS )zCParse dialecticDepth: host wins, then root, then 1. Clamped to 1-3.Nr,      )rm   minr`   ra   rb   rc   s      r   _parse_dialectic_depthr      sw    (#  ?1c#c((A../////	*    
 1s   *7A
A)minimallowmediumhighrm   depthlist[str] | Nonec                    | |fD ]l}|ht          |t                    rSd |d|         D             }t          |          |k     r(|                    d           t          |          |k     (|c S mdS )zParse dialecticDepthLevels: optional array of reasoning levels per pass.

    Returns None when not configured (use proportional defaults).
    When configured, validates each level and truncates/pads to match depth.
    Nc                (    g | ]}|t           v r|nd S )r   )_VALID_REASONING_LEVELS)r   lvls     r   
<listcomp>z1_parse_dialectic_depth_levels.<locals>.<listcomp>   s7        5555  r    r   )rt   listr/   append)rd   re   r   rS   levelss        r   _parse_dialectic_depth_levelsr      s     (# 	 	?z#t44? vv;  F
 f++%%e$$$ f++%%MMM4r    g      >@base_urlc                   | sdS 	 t          |           }|j        pd                                                                }n# t          $ r d}Y nw xY w|dv rdS |sdS 	 t          j        |          }n# t          $ r Y dS w xY w|j        s|j	        s|j
        rdS |j        dk    r6t          j        d          |cxk    rt          j        d          k    rn ndS dS )an  Return True for loopback/LAN/VPN self-hosted Honcho URLs.

    Local Honcho deployments can run without auth, but the SDK requires a
    non-empty api_key argument.  Treat loopback plus RFC1918/link-local/ULA
    and carrier-grade-NAT IPs as local so LAN/VPN URLs such as
    ``http://192.168.2.112:8000`` get the same placeholder-key behavior as
    localhost.
    Fr   >   ::1	127.0.0.1	localhostT   z
100.64.0.0z100.127.255.255)r   hostnamer#   lowerr=   	ipaddress
ip_addressra   is_loopback
is_privateis_link_localversion)r   parsedr(   ips       r   _is_local_base_urlr      s9     u(##%2,,..4466    000t u!$''   uu 
~  "*: t 
zQ9/==nnnnyG[\mGnGnnnnnnt5s#   <A AA A5 5
BBvaluesr   float | Nonec                     | D ]c}|t          |t                    r|                                }|s1	 t          |          }n# t          t
          f$ r Y Uw xY w|dk    r|c S ddS )z=Return the first non-empty value coerced to a positive float.Nr   )rt   r   r#   rk   rb   ra   )r   r~   r   s      r   _resolve_optional_floatr     s      =eS!! 	KKMME 	5\\FF:& 	 	 	H	A::MMM 4s   AAAunifieddirectional)sharedseparatecrossc                R    t                               | |           } | t          v r| ndS )z"Normalize observation mode values.r   )_OBSERVATION_MODE_ALIASESr-   _VALID_OBSERVATION_MODESrW   s    r   _normalize_observation_moder   5  s,    
#
'
'S
1
1C11133}Dr    Tuser_observe_meuser_observe_othersai_observe_meai_observe_othersF)r   r   modeobservation_objdict | Nonec                   t                               | t           d                   }|rt          |t                    st          |          S |                    d          pi }|                    d          pi }|                    d|d                   |                    d|d                   |                    d|d                   |                    d|d	                   d
S )aj  Resolve per-peer observation booleans.

    Config forms:
      String shorthand:  ``"observationMode": "directional"``
      Granular object:   ``"observation": {"user": {"observeMe": true, "observeOthers": true},
                                           "ai": {"observeMe": true, "observeOthers": false}}``

    Granular fields override preset defaults.
    r   userai	observeMer   observeOthersr   r   r   r   )_OBSERVATION_PRESETSr-   rt   r'   )r   r   preset
user_blockai_blocks        r   _resolve_observationr   I  s     "%%d,@,OPPF *_d"C"C F|| $$V,,2J""4((.BH &>>+v>O7PQQ)~~ovF[?\]]!k6/3JKK%\\/6BU;VWW	  r    c                  "   e Zd ZU dZeZded<   dZded<   dZded<   d	Z	ded
<   dZ
ded<   dZded<   dZded<   dZded<   dZded<    ee          Zded<   dZded<   dZded<   dZded<   dZded<   dZded<   d Zded!<   dZded"<   d#Zd$ed%<   d&Zd$ed'<   dZd(ed)<   dZded*<   d+Zded,<   d-Zd$ed.<   d/Zd$ed0<   d1Z ded2<   dZ!ded3<   d4Z"ded5<   d&Z#d$ed6<   d&Z$d$ed7<   dZ%ded8<   d9Z&d:ed;<   d<Z'd:ed=<   d>Z(ded?<   dZ)ded@<   dZ*dedA<   dZ+dedB<   dZ,dedC<   dDZ-dedE<   dZ.dedF<    ee          Z/dedG<    ee          Z0dHedI<   dZ1dedJ<   e2	 	 d[d\dL            Z3e2	 	 d]d^dO            Z4e5d_dQ            Z6dRZ7dSZ8e2d`dV            Z9	 	 	 	 dadbdZZ:dS )cHonchoClientConfigz>Configuration for Honcho client, resolved for a specific host.r   r(   r   workspace_idNr   api_key
productionenvironmentr   r   timeout	peer_nameai_peerFrY   pin_peer_name)default_factoryrr   user_peer_aliasesr   runtime_peer_prefixenabledTsave_messagesasyncz	str | intwrite_frequencyr]   context_tokensr   dialectic_reasoning_leveldialectic_dynamicX  r`   dialectic_max_charsr,   dialectic_depthr   dialectic_depth_levelsreasoning_heuristicr   reasoning_level_capa  message_max_chars'  dialectic_max_input_charsrP   recall_modeinit_on_session_start
every-turninjection_frequencycontext_cadencedialectic_cadencequery_rewrite      @rk   first_turn_base_wait       @first_turn_dialectic_waitr   observation_moder   r   r   r   per-directorysession_strategysession_peer_prefixsessionszdict[str, Any]r&   explicitly_configuredr   c                   |pt                      }t          d          }t          j                            dd                                          pd}t          t          j                            d                    } | |||t          j                            dd          |||t          |p|                    S )	z4Create config from environment variables (fallback).HONCHO_API_KEYHONCHO_BASE_URLr   NHONCHO_TIMEOUTHONCHO_ENVIRONMENTr   )r(   r   r   r   r   r   r   r   )rG   r   r:   r;   r-   r#   r   rY   )clsr   r(   resolved_hostr   r   r   s          r   from_envzHonchoClientConfig.from_env  s     5 3 5 5-..:>>"3R88>>@@HD)"*..9I*J*JKKs%
';\JJ!,H--	
 	
 	
 		
r    config_pathPath | Nonec                "   |pt                      }|pt                      }|                                s1t                              d|           |                     |          S 	 t          j        |                    d                    }nU# t          j	        t          f$ r<}t                              d||           |                     |          cY d}~S d}~ww xY wt          ||          }t          |          p|                    d          du }|                    d	          p|                    d	          p|}	|                    d
          p|                    d
          p|}
|                    d          p#|                    d          pt          d          }|                    d          p|                    dd          }|                    d          pH|                    d          p3t           j                            dd                                          pd}t'          |                    d          |                    d          |                    d          |                    d          t           j                            d                    }|                    d          }|                    d          }||}n||}nt          |p|          }|                    d          p|                    d          pd}	 t)          |          }n&# t*          t,          f$ r t/          |          }Y nw xY w|                    d          }||n|                    dd          }|                    d          p|                    dd          }|                    d          }||n|                    dd          } | dci d|d|	d|d|d|d|d |                    d!          p|                    d!          d"|
d#t1          |                    d$          |                    d%          |                    d$          |                    d%          d&          d't3          ||d(          d)t5          ||d*          d|d+|d,|d-t7          |                    d.          |                    d.                    d/|                    d0          p|                    d0          pd1d2t1          |                    d3          |                    d3          d&          d4t9          |                    d5          |                    d5          d6&          d7t;          |                    d8          |                    d8                    d9t=          |                    d:          |                    d:          t;          |                    d8          |                    d8                    ;          d<t1          |                    d=          |                    d=          d&          d>|                    d?          p|                    d?          pd@dAt9          |                    dB          |                    dB          dC&          dDt9          |                    dE          |                    dE          dF&          dGt?          |                    dH          p|                    dH          pdI          dJt1          |                    dK          |                    dK          d&          dL|                    dM          p|                    dMdN          dOt9          |                    dP          |                    dP          dQ&          dRt9          |                    dS          |                    dS          dQ&          dTt1          |                    dU          |                    dU          d&          dVtA          |                    dW          |                    dW          dX&          dYtA          |                    dZ          |                    dZ          d[&          d\tC          |                    d]          p|                    d]          p|rd^nd_          tE          tC          |                    d]          p|                    d]          p|rd^nd_          |                    d`          p|                    d`                    |||                    dai           ||dbS )dzCreate config from the resolved Honcho config path.

        Resolution: $HERMES_HOME/honcho.json -> ~/.honcho/config.json -> env vars.
        When host is None, derives it from the active Hermes profile.
        z2No global Honcho config at %s, falling back to env)r(   r6   r7   z*Failed to read %s: %s, falling back to envNr   T	workspaceaiPeerapiKeyr   r   r   baseUrlr   r   r   r   requestTimeoutr   writeFrequencyr   saveMessagessessionStrategyr   sessionPeerPrefixFr(   r   r   r   peerNamer   r   pinUserPeerpinPeerName)r   r   userPeerAliasesr   runtimePeerPrefixr   r   r   contextTokensr   dialecticReasoningLevelr   r   dialecticDynamicr   dialecticMaxCharsr   r   dialecticDepthr   dialecticDepthLevels)r   r   reasoningHeuristicr   reasoningLevelCapr   r   messageMaxCharsr   r   dialecticMaxInputCharsr   r   
recallModerP   r   initOnSessionStartr   injectionFrequencyr   r   contextCadencer,   r   dialecticCadencer   queryRewriter   firstTurnBaseWaitr   r   firstTurnDialecticWaitr   r   observationModer   r   observationr   )r   r   r   r&   r   rJ   )#rG   r>   r?   loggerdebugr   r@   rA   rB   JSONDecodeErrorOSErrorwarningr2   rY   r-   r   r:   r;   r#   r   r`   rb   ra   r   r\   r|   r   rf   rj   r   r   rX   rn   r   r   )r   r(   r   r   rE   r&   e
host_block_explicitly_configuredr   r   r   r   r   r   host_enabledroot_enabledr   raw_wfr   	host_saver   r   host_prefixr   s                            r   from_global_configz%HonchoClientConfig.from_global_config  s!    5 3 5 53133{{}} 	4LLMtTTT<<]<333	4*T^^W^==>>CC$g. 	4 	4 	4NNGqQQQ<<]<33333333	4 !m44
 "&j!1!1!OSWWY5G5G45O NN;'' ww{## 	 NN8$$ wwx   	 NN8$$ ,wwx  ,*++ 	 NN=)) 4ww}l33 	 GGI wwz""z~~/44::<< 	 	 *NN9%%NN+,,GGIGG$%%JNN+,,
 
 "~~i00wwy))#"GG%"GG 7.h//G NN+,, ww'(( 	
	*),VOO:& 	* 	* 	*!&kkOOO	* NN>22	%.%:		X\@]@] NN,-- ;ww(/:: 	 !nn%899&2KK,e44 	
 s R
 R
 R
R
"R
 GR
 $	R

 XR
 GR
 !nnZ00GCGGJ4G4GR
 GR
 ( }--}--&&&&   R
, 0!  -R
6 !7#! ! !7R
@ GAR
B (-CR
D ,OER
F 1//((  GR
P 899 77455UR
X ,122*++   YR
b !2233+,,! ! ! !cR
l 3/00())  mR
t $A566.//,Z^^<L-M-MswwWgOhOhii$ $ $ $uR
~ !.344,--! ! ! !R
J 233 77.//OR
R 0011)**   SR
\ '8788011' ' ' ']R
f /|,, 77<((  gR
p #0344,--# # # #qR
~ 344 ?77/>>AR
D ./00())   ER
N 0122*++   OR
X (~..''   YR
b "5233+,," " " "cR
l ':788011' ' ' 'mR
@ 9011 L77,--L!7JII]  
 #+NN#455 Pww011P%;N		 
 }--G1G1G KR
Z . 3WWZ,,"8cR
 R
 R
 R
 R	
s0   '(B C"&1CC"C"#L3 3 MMcwdc           
         ddl }	 |                    g ddddd| d|j                  }|j        dk    r+t	          |j                                                  j        S n# t          |j	        f$ r Y nw xY wdS )	zBReturn the git repo root directory name, or None if not in a repo.r   N)gitz	rev-parsez--show-toplevelTr6   replace   )capture_outputtextr8   errorsr-  r   stdin)

subprocessrunDEVNULL
returncoder   stdoutr#   namer"  TimeoutExpired)r-  r6  roots      r   _git_repo_namez!HonchoClientConfig._git_repo_name  s     			>>777#$X[ef ( "  D
 !##DK--//0055 $23 	 	 	D	ts   AA! !A54A5d      r$   originalc                "   | j         }t          |          |k    r|S | j        }t          j        |                    d                                                    d|         }||z
  dz
  }|d|                             d          }| d| S )a]  Truncate a sanitized session ID to Honcho's 100-char limit.

        The common case (short keys) short-circuits with no modification.
        For over-limit keys, keep a prefix of the sanitized ID and append a
        deterministic ``-<sha256 prefix>`` suffix so two distinct long keys
        that share a leading segment don't collide onto the same truncated ID.
        The hash is taken over the *original* pre-sanitization key, so two
        inputs that sanitize to the same string still collide intentionally
        (same logical session), but two inputs that only share a prefix do not.
        r6   Nr,   -)_HONCHO_SESSION_ID_MAX_LENr/   _HONCHO_SESSION_ID_HASH_LENhashlibsha256encode	hexdigestrstrip)r   r$   rA  max_lenhash_lendigest
prefix_lenprefixs           r   _enforce_session_id_limitz,HonchoClientConfig._enforce_session_id_limit  s     0y>>W$$2 8 899CCEEixiP x'!+
;J;'..s33##6###r    session_title
session_idgateway_session_keyc                   ddl }|st          j                    }|rB|                    dd|                              d          }|r|                     ||          S | j        dk    r|r| j        r| j        r| j         d| S |S | j	        
                    |          }|r|S |rH|                    dd|                              d          }|r| j        r| j        r| j         d| S |S | j        dk    rE|                     |          pt          |          j        }| j        r| j        r| j         d| S |S | j        dv r0t          |          j        }| j        r| j        r| j         d| S |S | j        S )ua  Resolve Honcho session name.

        Resolution order:
          1. Gateway session key (stable per-chat identifier from gateway platforms)
          2. per-session strategy — Hermes session_id ({timestamp}_{hex}); authoritative,
             so a generated title never remaps a live conversation
          3. Manual directory override from sessions map
          4. Hermes session title (from /title command; non-per-session)
          5. per-repo strategy — git repo root directory name
          6. per-directory strategy — directory basename
          7. global strategy — workspace name
        r   Nz[^a-zA-Z0-9_-]+rC  per-sessionzper-repo>   rU  r   )rer:   getcwdsubr#   rP  r   r   r   r   r-   r>  r   r;  r   )	selfr-  rQ  rR  rS  rV  r$   manualbases	            r   resolve_session_namez'HonchoClientConfig.resolve_session_name  s   & 				 	)++C  	V138KLLRRSVWWI V55iATUUU
  M11j1' 8DN 8.77:777 ""3'' 	M  	!13FFLLSQQI !+ ; ;"n::y:::    J..&&s++=tCyy~D' 2DN 2.114111K  $DDD99>D' 2DN 2.114111K   r    )r   N)r   r   r(   r   r   r   NN)r(   r   r   r   r   r   )r-  r   r   r   )r$   r   rA  r   r   r   )NNNN)
r-  r   rQ  r   rR  r   rS  r   r   r   );__name__
__module____qualname____doc__r!   r(   __annotations__r   r   r   r   r   r   r   r   r   r'   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r&   r   classmethodr   r,  staticmethodr>  rD  rE  rP  r\  rJ   r    r   r   r   h  s        HHD L    G#K####H G     I    G  M ).d(C(C(CCCCC!!!!!GM ")O((((!%N%%%% &+**** #""""""""" O 043333 !%$$$$%%%%% #""""%*****
  K #(''''+++++O  M #&%%%%'***** *)))) !O     $$$$$M"""""+++++ %%%%%$uT:::H::::%555C5555 #('''' %
 
 
 
 [
*   #'x
 x
 x
 x
 [x
t    \* "%"#$ $ $ [$4 $(!%*.C! C! C! C! C! C! C!r    r   r   _honcho_client_slot_cached_timeoutr]  ztuple[int | None, float | None]_honcho_json_timeout_memoc                    	 ddl m}   |                                 di           }t          |t                    r6t          |                    d          |                    d                    S dS # t          $ r Y dS w xY w)zJRead honcho.timeout / honcho.request_timeout via the cached config loader.r   )load_config_readonlyhonchor   request_timeoutN)hermes_cli.configri  r-   rt   r'   r   r=   )ri  
honcho_cfgs     r   _config_yaml_timeoutrn  e  s    ::::::))++//"==
j$'' 	*y))011   t   tts   A.A3 3
B Bc                 8   	 t                      } 	 |                                 j        }n# t          $ r d}Y nw xY wt          d         |k    rt          d         S d}|dk    rt          j        |                     d                    }t          |t                                }t          |                    d          |                    d          |                    d          |                    d                    }||fa|S # t          $ r Y dS w xY w)	zRRead timeout/requestTimeout from honcho.json (host block wins), memoized on mtime.r   r,   Nr6   r7   r   r  )r>   statst_mtime_nsr"  rg  r@   rA   rB   r2   rG   r   r-   r=   )rE   mtime_nsr   r&   r%  s        r   _honcho_json_timeoutrt  u  s*   "$$	 IIKK3HH 	 	 	HHH	$Q'833,Q//r>>*T^^W^==>>C$S*=*?*?@@J-y))/00	""())	 G &.w$7!   tts3   D + D :D : D B/D 
DDconfigHonchoClientConfig | Nonec                    | | j         }n<t                      }|,t          t          j                            d                    }|t                      }||nt          S )a  Mirror the build path's timeout resolution so the staleness check agrees with it.

    With an explicit config this matches ``_build`` (config.timeout, then
    config.yaml, then default).  With no config it matches what
    ``from_global_config`` + ``_build`` would produce: honcho.json host
    block/root keys, then HONCHO_TIMEOUT, then config.yaml, then default.
    Any source skew here makes the check disagree with the built client
    forever and rebuild it on every call.
    Nr   )r   rt  r   r:   r;   r-   rn  _DEFAULT_HTTP_TIMEOUT)ru  r   s     r   _resolve_timeout_from_sourcesry    s_     .&((?-bjnn=M.N.NOOG&(()77/DDr    Nonec                    	 ddl m} |                    t                      | j                  \  }}|r	|| _        dS dS # t          $ r  t                              dd           Y dS w xY w)zRefresh a near-expiry OAuth grant and point ``config.api_key`` at it.

    No-op for static API keys or when refresh fails (fail-open: the stale token
    is left in place and the existing 401 handling degrades gracefully).
    r   oauthz%Honcho OAuth pre-build refresh failedTexc_infoN)	plugins.memory.honchor}  ensure_fresh_tokenr>   r(   r   r=   r  r#  )ru  r}  tokenr   s       r   _apply_fresh_oauth_tokenr    s    O//////++,?,A,A6;OOq 	#"FNNN	# 	# O O O>NNNNNNOs   9? &A)(A)client'Honcho'c                X   	 ddl m} ||j        nt                      }|                    t                      |          \  }}|r3|r3|                    | |          st                                           dS dS dS dS # t          $ r  t                              dd           Y dS w xY w)zRotate the cached client's Bearer in place when its OAuth token is stale.

    If the SDK shape changed and the in-place rotation can't apply, the slot is
    reset so the next acquisition rebuilds with the fresh token.
    r   r|  Nz"Honcho OAuth cached refresh failedTr~  )r  r}  r(   rG   r  r>   apply_token_to_clientre  resetr=   r  r#  )r  ru  r}  r(   r  	refresheds         r   _refresh_cached_oauthr    s    L//////$0v{{6I6K6K 334G4I4I4PPy 	( 	(u'B'B65'Q'Q 	(%%'''''	( 	( 	( 	( 	( 	( L L L;dKKKKKKLs   A5A? ?&B)(B)r   c                    t                                           }|Jt                     }|t          k    rt                                            dad}nt          |            |S  t                                           t                       j	        s j
        st          d          d fd}t                               |          S )a  Get or create the Honcho client singleton.

    When no config is provided, attempts to load ~/.honcho/config.json
    first, falling back to environment variables.

    Thread-safe: the client is built exactly once even under concurrent
    first calls (double-checked locking via ``SingletonSlot``), so racing
    threads can't each construct a client and leak the loser's connection.
    NzHoncho API key not found. Get your API key at https://app.honcho.dev, then run 'hermes honcho setup' or set HONCHO_API_KEY. For local instances, set HONCHO_BASE_URL instead.r   r  c                    	 ddl m} m}  |dd           n# t          $ r Y nt          $ r Y nw xY w	 ddlm} n# t          $ r t          d          w xY wj        }j        }|r|	 ddl	m
}  |            }|                    d	i           }t          |t                    rd|s*|                    d
d                                          pd }|6t          |                    d          |                    d                    }n# t          $ r Y nw xY w|t           }|r"t"                              d|j                   n&t"                              dj        j                   t+          |          }|rgj        pi }	|	                    d          pi                     j        i           }
t/          |
                    d                    }|rj        nd}nj        }|r.dd l}|                    dd|                              d          }j        |j        d}|r||d
<   |||d<   |a |di |S )Nr   )FeatureUnavailableensurezmemory.honchoF)promptr   zhoncho-ai is required for Honcho integration. Install it with: pip install honcho-ai  (or run `hermes honcho setup` to configure).)load_configrj  r   r   r   rk  z8Initializing Honcho client (base_url: %s, workspace: %s)z4Initializing Honcho client (host: %s, workspace: %s)r*   r   localz/v\d+/*$/)r   r   r   rJ   )tools.lazy_depsr  r  ImportErrorr=   rj  r   r   r   rl  r  r-   rt   r'   r#   r   rx  r  infor   r(   r   r&   rY   r   rV  rX  rJ  r   rf  )r  _lazy_ensurer   resolved_base_urlresolved_timeoutr  
hermes_cfgrm  	_is_local_rawr2   _host_has_keyeffective_api_key_rekwargsru  s                  r   _buildz!get_honcho_client.<locals>._build  s   		RRRRRRRRL77777 	 	 	D 	 	 	 D	
	%%%%%%% 	 	 	?  	 #O!>  	$4$<999999([]]
'^^Hb99
j$// , [,6NN:r,J,J,P,P,R,R,ZVZ)'/+B&NN955&NN+<==, ,(    
 #4 	rKKRTegmgz{{{{KKNPVP[]c]pqqq ''899	 
	/
 :#D88G,,277RHHK !:!:;;M2? LW &  	X #R9J K K R RSV W W #/(!-
 

  	3!2F:' 0F9 +vs,    
1	11< A,BD 
DD)r   r  )re  peekry  rf  r  r  r   r,  r  r   r   ra   r-   )ru  cachednew_timeoutr  s   `   r   get_honcho_clientr    s     !%%''F 4F;;/))%%'''"OFF!&&111M~#6688 V$$$> 
&/ 
@
 
 	
_  _  _  _  _  _ B ""6***r    c                 @    t                                            dadadS )z7Reset the Honcho client singleton (useful for testing).Nr]  )re  r  rf  rg  rJ   r    r   reset_honcho_clientr  T  s'     O ,r    )r   r   r   r   )r&   r'   r(   r   r   r'   )r   r   )r   r   )rS   r   r   r   )r   rY   r   rY   )r   r]   )r   r`   r   r`   )r   rk   r   rk   )ro   r'   rp   r'   rq   r   r   rr   )r   )
ro   r'   rp   r'   rq   r   r   r   r   r   )r   r`   )r   r`   r   r   )r   r   r   rY   )r   r   r   r   )r   r   r   r   r   r'   )r   r   )ru  rv  r   rk   )ru  r   r   rz  )r  r  ru  rv  r   rz  )N)ru  rv  r   r   )r   rz  )Era  
__future__r   r@   r:   loggingrF  r   dataclassesr   r   pathlibr   urllib.parser   agent.secret_scoper   hermes_constantsr	   r<   r
   plugins.plugin_utilsr   typingr   r   rj  r   	getLoggerr^  r  r!   r%   r2   rG   rK   r>   rU   rV   rX   r\   rf   rj   rn   r|   r   r   r   r   rx  r   r   r   r   r   r   r   r   re  rb  rf  rg  rn  rt  ry  r  r  r  r  rJ   r    r   <module>r     sI     # " " " " "  				       ( ( ( ( ( ( ( (       ! ! ! ! ! ! ) ) ) ) ) ) , , , , , , 8 8 8 8 8 8 . . . . . . % % % % % % % % 		8	$	$. . . .! ! ! !# # # #L3 3 3 3
( ( ( (, ) 444 ; ; ; ;                 >@
 
 
 
 
    F    2  # # # #L   $ &}5 '0mVcdd E E E E  D 
  T 	 	    > n! n! n! n! n! n! n! n!b &3]__  4 4 4 4 $ $ $ $ $ >J  I I I I       8E E E E*O O O O L L L L"J+ J+ J+ J+ J+Z- - - - - -r    