
    it                       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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iZh dZd?dZd@dZdAdZdBdZdCdZ dZ!dDd Z"d!Z#dEd%Z$d&d'hZ%d&d'd'd(Z&d?d)Z'd*d*d*d*d+d*d,d,d*d+d-Z(dFd2Z)e G d3 d4                      Z*da+d5e,d6<   dGdHd:Z-dId<Z.dS )Ja  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)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)defaultcustom.)osenvirongetstriphermes_cli.profilesr   HOST	Exception)explicitr   profiles      A/home/ubuntu/.hermes/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%   8   s    9;;"]22r$   c                     t                      dz  } |                                 r| S t          j                    dz  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.jsonz.hermes)r   existsr   r"   r%   )
local_pathdefault_paths     r   resolve_config_pathr*   =   ss     !""]2J  9;;*]: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r/   s    r   _normalize_recall_moder4   W   s,    

"
"3
,
,C,,,33(:r$   r   boolc               J    | t          |           S |t          |          S |S )z@Resolve a bool config field: host wins, then root, then default.)r5   )host_valroot_valr   s      r   _resolve_boolr9   ]   s+    H~~H~~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r7   r8   r/   s      r   _parse_context_tokensrA   f   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<   )r7   r8   r   r/   s       r   _parse_int_configrD   q   s`    (#  ?3xx	*    
 NrB   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_depthrJ   |   sw    (#  ?1c#c((A../////	*    
 1s   *7A
A)minimallowmediumhighrH   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 )rL   )_VALID_REASONING_LEVELS).0lvls     r   
<listcomp>z1_parse_dialectic_depth_levels.<locals>.<listcomp>   s7        5555  r$   rL   )
isinstancelistlenappend)r7   r8   rO   r/   levelss        r   _parse_dialectic_depth_levelsr\      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   )rW   r   r   floatr?   r>   )r]   valueparseds      r   _resolve_optional_floatrc      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.re   )_OBSERVATION_MODE_ALIASESr   _VALID_OBSERVATION_MODESr3   s    r   _normalize_observation_moderl      s,    
#
'
'S
1
1C11133}Dr$   Tuser_observe_meuser_observe_othersai_observe_meai_observe_othersF)re   rd   modeobservation_objdict | Nonedictc                   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.
    re   userai	observeMern   observeOthersro   rp   rq   rm   )_OBSERVATION_PRESETSr   rW   ru   )rr   rs   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<   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d-<   dZded.<   d/Zded0<   dZded1<   dZ ded2<   dZ!ded3<   dZ"ded4<   d5Z#ded6<   dZ$ded7<    e%e&8          Z'd9ed:<    e%e&8          Z(d;ed<<   dZ)ded=<   e*	 	 dNdOd?            Z+e*	 	 dPdQdB            Z,e-dRdD            Z.dEZ/dFZ0e*dSdI            Z1	 	 	 	 dTdUdMZ2dS )VHonchoClientConfigz>Configuration for Honcho client, resolved for a specific host.r   hostr   workspace_idN
str | Noneapi_key
productionenvironmentbase_urlr^   timeout	peer_nameai_peerFr5   pin_peer_nameenabledTsave_messagesasyncz	str | intwrite_frequencyr:   context_tokensrL   dialectic_reasoning_leveldialectic_dynamicX  r=   dialectic_max_charsrF   dialectic_depthrP   dialectic_depth_levelsreasoning_heuristicrN   reasoning_level_capa  message_max_chars'  dialectic_max_input_charsr,   recall_modeinit_on_session_startre   observation_modern   ro   rp   rq   per-directorysession_strategysession_peer_prefix)default_factoryzdict[str, str]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   rc   r5   )clsr   r   resolved_hostr   r   r   s          r   from_envzHonchoClientConfig.from_envD  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          } | dOi d|d|	d |d|d|d|d!|                    d"          p|                    d"          d#|
d$t-          |                    d%          |                    d%          d&          d|d'|d(|d)t/          |                    d*          |                    d*                    d+|                    d,          p|                    d,          pd-d.t-          |                    d/          |                    d/          d	&          d0t1          |                    d1          |                    d1          d2&          d3t3          |                    d4          |                    d4                    d5t5          |                    d6          |                    d6          t3          |                    d4          |                    d4                    7          d8t-          |                    d9          |                    d9          d	&          d:|                    d;          p|                    d;          pd<d=t1          |                    d>          |                    d>          d?&          d@t1          |                    dA          |                    dA          dB&          dCt7          |                    dD          p|                    dD          pdE          dFt-          |                    dG          |                    dG          d&          dHt9          |                    dI          p|                    dI          p|rdJndK          t;          t9          |                    dI          p|                    dI          p|rdJndK          |                    dL          p|                    dL                    |||                    dMi           ||dNS )PzCreate 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   pinPeerName)r   r   r   r   contextTokensr   dialecticReasoningLevelrL   r   dialecticDynamicr   dialecticMaxCharsr   r   dialecticDepthr   dialecticDepthLevels)rO   r   reasoningHeuristicr   reasoningLevelCaprN   r   messageMaxCharsr   r   dialecticMaxInputCharsr   r   
recallModer,   r   initOnSessionStartr   observationModerd   re   observationr   )r   r   r   r   r   r#   )r    r*   r'   loggerdebugr   jsonloads	read_textJSONDecodeErrorOSErrorwarningr   r5   r   r   r   rc   r=   r?   r>   r   r9   rA   rD   rJ   r\   r4   rl   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_configZ  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 b
 b
 b
b
"b
 Gb
 $	b

 Xb
 Gb
 !nnZ00GCGGJ4G4Gb
 Gb
 (}--&&   b
 Gb
 (-b
  ,O!b
" 1//((  #b
, 899 774551b
4 ,122*++   5b
> !2233+,,! ! ! !?b
H 3/00())  Ib
P $A566.//,Z^^<L-M-MswwWgOhOhii$ $ $ $Qb
Z !.344,--! ! ! ![b
f 233 77.//kb
n 0011)**   ob
x '8788011' ' ' 'yb
B /|,, 77<((  Cb
L #0344,--# # # #Mb
` 9011 L77,--L!7JII]  
 #+NN#455 Pww011P%;N		 
 }--G1G1G kb
z . 3WWZ,,"8Cb
 b
 b
 b
 b	
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   NrF   -)_HONCHO_SESSION_ID_MAX_LENrY   _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_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                    }| 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_nameS  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   )3__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   rn   ro   rp   rq   r   r   r   ru   r   r   r   classmethodr   r   staticmethodr   r   r   r  r  r#   r$   r   r   r      sy        HHD L    G#K####H G     I    G  MGM ")O((((!%N%%%% &+**** #""""""""" O 043333 !%$$$$%%%%% #""""%*****
  K #('''' *)))) !O     $$$$$M"""""+++++ %%%%%$uT:::H::::%555C5555 #('''' %
 
 
 
 [
*   #'E
 E
 E
 E
 [E
N    \( "%"#$ $ $ [$4 $(!%*.C! C! C! C! C! C! C!r$   r   zHoncho | None_honcho_clientconfigHonchoClientConfig | Noner   c                Z   t           t           S | t                                          } | j        s| j        st          d          	 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           }	t1          |	                    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   r
   zThoncho-ai is required for Honcho integration. Install it with: pip install honcho-ai)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>   r  r   ImportErrorr   hermes_cli.configr  r   rW   ru   r   rc   r   _DEFAULT_HTTP_TIMEOUTr   infor   r   r   r5   r   )r  r   resolved_base_urlresolved_timeoutr  
hermes_cfg
honcho_cfg	_is_local_raw_host_block_host_has_keyeffective_api_keykwargss                r   get_honcho_clientr,    s    !~#6688> 
&/ 
@
 
 	

!!!!!!! 
 
 
5
 
 	

 ~  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s   A A)?BD 
D,+D,Nonec                 
    da dS )z7Reset the Honcho client singleton (useful for testing).N)r  r#   r$   r   reset_honcho_clientr/    s     NNNr$   )r   r   )r   r   )r/   r   r   r   )r   r5   r   r5   )r   r:   )r   r=   r   r=   )r   r=   )rO   r=   r   rP   )r]   r   r   r^   )rr   r   rs   rt   r   ru   )N)r  r  r   r   )r   r-  )/r  
__future__r   r   r   loggingr   dataclassesr   r   pathlibr   hermes_constantsr   typingr   r	   r  r   	getLoggerr  r   r   r    r%   r*   r1   r2   r4   r9   rA   rD   rJ   rS   r\   r   rc   rk   rj   rl   r{   r   r   r  r  r,  r/  r#   r$   r   <module>r7     s     # " " " " "  				   ( ( ( ( ( ( ( (       , , , , , , % % % % % % % % 		8	$	$   ,3 3 3 3
( ( ( (, ) 444 ; ; ; ;             F    2     $ &}5 '0mVcdd E E E E  D 
  T 	 	    > f! f! f! f! f! f! f! f!R !% $ $ $ $\ \ \ \ \~     r$   