
    j                       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mZ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dEdZdFdZdFdZddiZh dZdGdZdHdZdIdZ dJdZ!dKd"Z"	 dLdMd$Z#dNd%Z$d&Z%dOd)Z&d*Z'dPd.Z(d/d0hZ)d/d0d0d1Z*dGd2Z+d3d3d3d3d4d3d5d5d3d4d6Z,dQd:Z-e G d; d<                      Z.da/d=e0d><   dRdSdBZ1dTdDZ2d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)get_hermes_home)_get_default_hermes_home)AnyTYPE_CHECKINGHonchohermesreturnstrc                     t           j                            dd                                          } | r| S 	 ddlm}  |            }|r|dvrt           d| S n# t          $ r Y nw xY wt          S )a	  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. Fallback: ``"hermes"`` (default profile)
    HERMES_HONCHO_HOST r   )get_active_profile_name>   customdefault.)osenvirongetstriphermes_cli.profilesr   HOST	Exception)explicitr   profiles      ;/usr/local/lib/hermes-agent/plugins/memory/honcho/client.pyresolve_active_hostr!   #   s     z~~2B77==??H ??????))++ 	'w&;;;&&W&&&   Ks   !A 
A('A(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    resolve_global_config_pathr&   9   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   existsr   r&   )
local_pathdefault_paths     r    resolve_config_pathr+   >   sn     !""]2J  ,--=Lz!!l&9&9&;&;!%'''r%   autohybrid>   toolsr-   contextvalc                R    t                               | |           } | t          v r| ndS )u?   Normalize legacy recall mode values (e.g. 'auto' → 'hybrid').r-   )_RECALL_MODE_ALIASESr   _VALID_RECALL_MODESr0   s    r    _normalize_recall_moder5   X   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.
    )r6   )r   valsr0   s      r    _resolve_boolr9   ^   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_valr0   s      r    _parse_context_tokensrC   l   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<   )rA   rB   r   r0   s       r    _parse_int_configrF   w   s`    (#  ?3xx	*    
 NrD   host_objdict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   
isinstancerH   itemsr   r   )	rG   rI   rJ   sourceresultraw_key	raw_value	alias_keyalias_values	            r    _parse_string_maprU      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   )rG   rI   rJ   r   values        r    _parse_optional_stringrX      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.N      )maxminr=   r>   r?   r@   s      r    _parse_dialectic_depthr^      sw    (#  ?1c#c((A../////	*    
 1s   *7A
A)minimallowmediumhighr\   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).0lvls     r    
<listcomp>z1_parse_dialectic_depth_levels.<locals>.<listcomp>   s7        5555  r%   r`   )rM   listlenappend)rA   rB   rc   r0   levelss        r    _parse_dialectic_depth_levelsro      s     (# 	 	?z#t44? vv;  F
 f++%%e$$$ f++%%MMM4r%   g      >@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   )rM   r   r   floatr?   r>   )rp   rW   parseds      r    _resolve_optional_floatru      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.rw   )_OBSERVATION_MODE_ALIASESr   _VALID_OBSERVATION_MODESr4   s    r    _normalize_observation_moder~      s,    
#
'
'S
1
1C11133}Dr%   Tuser_observe_meuser_observe_othersai_observe_meai_observe_othersF)rw   rv   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.
    rw   userai	observeMer   observeOthersr   r   r   r   )_OBSERVATION_PRESETSr   rM   rH   )r   r   preset
user_blockai_blocks        r    _resolve_observationr      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<   dZ&ded9<   d:Z'ded;<   dZ(ded<<    ee          Z)ded=<    ee          Z*d>ed?<   dZ+ded@<   e,	 	 dQdRdB            Z-e,	 	 dSdTdE            Z.e/dUdG            Z0dHZ1dIZ2e,dVdL            Z3	 	 	 	 dWdXdPZ4dS )YHonchoClientConfigz>Configuration for Honcho client, resolved for a specific host.r   hostr   workspace_idN
str | Noneapi_key
productionenvironmentbase_urlrq   timeout	peer_nameai_peerFr6   pin_peer_name)default_factoryrK   user_peer_aliasesr   runtime_peer_prefixenabledTsave_messagesasyncz	str | intwrite_frequencyr:   context_tokensr`   dialectic_reasoning_leveldialectic_dynamicX  r=   dialectic_max_charsrZ   dialectic_depthrd   dialectic_depth_levelsreasoning_heuristicrb   reasoning_level_capa  message_max_chars'  dialectic_max_input_charsr-   recall_modeinit_on_session_startrw   observation_moder   r   r   r   per-directorysession_strategysession_peer_prefixsessionszdict[str, Any]rawexplicitly_configuredr   c                   |pt                      }t          j                            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   )r!   r   r   r   r   ru   r6   )clsr   r   resolved_hostr   r   r   s          r    from_envzHonchoClientConfig.from_envl  s     5 3 5 5*..!122:>>"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|                    d          pi                     |i           }t          |          p|                    d          d	u }|                    d
          p|                    d
          p|}	|                    d          p|                    d          p|}
|                    d          p3|                    d          pt          j                            d          }|                    d          p|                    dd          }|                    d          pH|                    d          p3t          j                            dd                                          pd}t#          |                    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          } | dTi d|d|	d |d|d|d|d!|                    d"          p|                    d"          d#|
d$t-          |                    d%          |                    d&          |                    d%          |                    d&          d'          d(t/          ||d)          d*t1          ||d+          d|d,|d-|d.t3          |                    d/          |                    d/                    d0|                    d1          p|                    d1          pd2d3t-          |                    d4          |                    d4          d	'          d5t5          |                    d6          |                    d6          d7'          d8t7          |                    d9          |                    d9                    d:t9          |                    d;          |                    d;          t7          |                    d9          |                    d9                    <          d=t-          |                    d>          |                    d>          d	'          d?|                    d@          p|                    d@          pdAdBt5          |                    dC          |                    dC          dD'          dEt5          |                    dF          |                    dF          dG'          dHt;          |                    dI          p|                    dI          pdJ          dKt-          |                    dL          |                    dL          d'          dMt=          |                    dN          p|                    dN          p|rdOndP          t?          t=          |                    dN          p|                    dN          p|rdOndP          |                    dQ          p|                    dQ                    |||                    dRi           ||dSS )UzCreate 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   utf-8)encodingz*Failed to read %s: %s, falling back to envNhostsr   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)rc   r   reasoningHeuristicr   reasoningLevelCaprb   r   messageMaxCharsr   r   dialecticMaxInputCharsr   r   
recallModer-   r   initOnSessionStartr   observationModerv   rw   observationr   )r   r   r   r   r   r$   ) r!   r+   r(   loggerdebugr   jsonloads	read_textJSONDecodeErrorOSErrorwarningr   r6   r   r   r   ru   r=   r?   r>   r   r9   rU   rX   rC   rF   r^   ro   r5   r~   r   )r   r   r   r   pathr   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 ggg&&,"11-DD
 "&j!1!1!OSWWY5G5G45O NN;'' ww{## 	 NN8$$ wwx   	 NN8$$ 0wwx  0z~~.// 	 NN=)) 4ww}l33 	 GGI wwz""z~~/44::<< 	 	 *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 t
 t
 t
t
"t
 Gt
 $	t

 Xt
 Gt
 !nnZ00GCGGJ4G4Gt
 Gt
 ( }--}--&&&&   t
, 0!  -t
6 !7#! ! !7t
@ GAt
B (-Ct
D ,OEt
F 1//((  Gt
P 899 77455Ut
X ,122*++   Yt
b !2233+,,! ! ! !ct
l 3/00())  mt
t $A566.//,Z^^<L-M-MswwWgOhOhii$ $ $ $ut
~ !.344,--! ! ! !t
J 233 77.//Ot
R 0011)**   St
\ '8788011' ' ' ']t
f /|,, 77<((  gt
p #0344,--# # # #qt
D 9011 L77,--L!7JII]  
 #+NN#455 Pww011P%;N		 
 }--G1G1G Ot
^ . 3WWZ,,"8gt
 t
 t
 t
 t	
s0   '(B C"&1CC"C"&L6 6 MMcwdc                    ddl }	 |                    g ddd| d          }|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-toplevelT   )capture_outputtextr   r   )	
subprocessrun
returncoder   stdoutr   namer   TimeoutExpired)r   r   roots      r    _git_repo_namez!HonchoClientConfig._git_repo_name\  s     		>>777#$C "  D !##DK--//0055 $23 	 	 	D	ts   AA A-,A-d      	sanitized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.
        r   NrZ   -)_HONCHO_SESSION_ID_MAX_LENrl   _HONCHO_SESSION_ID_HASH_LENhashlibsha256encode	hexdigestrstrip)r   r  r  max_lenhash_lendigest
prefix_lenprefixs           r    _enforce_session_id_limitz,HonchoClientConfig._enforce_session_id_limitt  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                    }| j                            |          }|r|S |rH|                    dd|                              d          }|r| j        r| j        r| j         d| S |S |rB|                    dd|                              d          }|r| 	                    ||          S | j
        dk    r|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 )u  Resolve Honcho session name.

        Resolution order:
          1. Manual directory override from sessions map
          2. Hermes session title (from /title command)
          3. Gateway session key (stable per-chat identifier from gateway platforms)
          4. per-session strategy — Hermes session_id ({timestamp}_{hex})
          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_-]+r
  per-sessionzper-repo>   r  r   )rer   getcwdr   r   subr   r   r   r  r   r  r   r  r   )	selfr   r  r  r  r  manualr  bases	            r    resolve_session_namez'HonchoClientConfig.resolve_session_name  s   $ 				 	)++C ""3'' 	M  	!13FFLLSQQI !+ ; ;"n::y:::    	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  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   r  r   r   r   )NNNN)
r   r   r  r   r  r   r  r   r   r   )5__name__
__module____qualname____doc__r   r   __annotations__r   r   r   r   r   r   r   r   r   rH   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  r  r  r  r#  r$   r%   r    r   r     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"""""+++++ %%%%%$uT:::H::::%555C5555 #('''' %
 
 
 
 [
*   #'W
 W
 W
 W
 [W
r    \( "%"#$ $ $ [$4 $(!%*.C! C! C! C! C! C! C!r%   r   zHoncho | None_honcho_clientconfigHonchoClientConfig | Noner   c                   t           t           S | t                                          } | j        s| j        st          d          	 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                   |od|v pd|v pd|v }	|	rg| j        pi }
|
                    d          pi                     | j        i           }t7          |                    d                    }|r| j        nd}n| j        }| j        || j        d}|r||d<   |||d<    |di |a t           S )zGet or create the Honcho client singleton.

    When no config is provided, attempts to load ~/.honcho/config.json
    first, falling back to environment variables.
    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   )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_confighonchor   r   r   request_timeoutz8Initializing Honcho client (base_url: %s, workspace: %s)z4Initializing Honcho client (host: %s, workspace: %s)	localhostz	127.0.0.1z::1r   r   local)r   r   r   r$   )r+  r   r   r   r   r>   tools.lazy_depsr/  r0  ImportErrorr   r3  r   r   hermes_cli.configr2  r   rM   rH   r   ru   _DEFAULT_HTTP_TIMEOUTr   infor   r   r   r6   r   )r,  r/  _lazy_ensurer   resolved_base_urlresolved_timeoutr2  
hermes_cfg
honcho_cfg	_is_local_raw_host_block_host_has_keyeffective_api_keykwargss                  r    get_honcho_clientrG    sO    !~#6688> 
&/ 
@
 
 	
	NNNNNNNN_U33333       	

!!!!!!! 
 
 
;
 
 	

 ~  0 8	555555$J#"55J*d++ ( W(2z2(F(F(L(L(N(N(VRV%#+'>"y11"'899( ($  	 	 	D	
 0 nNPacicvwwwwJFKY_Ylmmm " (( 	&++	&%% 
  +zRxx((.B33FKDD[__X6677.;HFNN"N +$) F
  /.z#,yV%%f%%Ns7   A 
A6*	A65A6:B B1BE 
EENonec                 
    da dS )z7Reset the Honcho client singleton (useful for testing).N)r+  r$   r%   r    reset_honcho_clientrJ  E  s     NNNr%   )r   r   )r   r   )r0   r   r   r   )r   r6   r   r6   )r   r:   )r   r=   r   r=   )rG   rH   rI   rH   rJ   r   r   rK   )r   )
rG   rH   rI   rH   rJ   r   r   r   r   r   )r   r=   )rc   r=   r   rd   )rp   r	   r   rq   )r   r   r   r   r   rH   )N)r,  r-  r   r   )r   rH  )3r'  
__future__r   r   r   loggingr  dataclassesr   r   pathlibr   hermes_constantsr   r   r   typingr	   r
   r3  r   	getLoggerr$  r   r   r!   r&   r+   r2   r3   r5   r9   rC   rF   rU   rX   r^   rg   ro   r:  ru   r}   r|   r~   r   r   r   r+  r(  rG  rJ  r$   r%   r    <module>rR     s     # " " " " "  				   ( ( ( ( ( ( ( (       , , , , , , 8 8 8 8 8 8 % % % % % % % % 		8	$	$   ,3 3 3 3
( ( ( (, ) 444 ; ; ; ;              >@
 
 
 
 
    F    2     $ &}5 '0mVcdd E E E E  D 
  T 	 	    > ~! ~! ~! ~! ~! ~! ~! ~!B !% $ $ $ $l l l l l^     r%   