
    ip<             
         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Zddl	Z	ddl
Z
ddlmZmZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ  ej        e          Zd
ZdZdZdZdZ dZ!h dZ"dddddddddd	Z#dgd Z$dhd"Z%i Z&d#e'd$<    e
j(                    Z)did*Z*	 	 djdkd0Z+	 dldmd1Z,da-d2e'd3<   da.d4e'd5<    e
j(                    Z/ e0            Z1dnd7Z2efdod8Z3d9d:d;d<d=d>d<d?d>d@dAd<idBdCdDdEgdFdGZ4dHdId;dJd<dKd>idJgdFdGZ5dLdMd;dJd<dNd>idJgdFdGZ6dpdPZ7dqdRZ8drdSZ9dsdVZ:dtdXZ;ddYdud[Z<dvd\Z=ddYdwd]Z>dxd^Z?dydbZ@ G dc dde          ZAdzdfZBdS ){u  Hindsight memory plugin — MemoryProvider interface.

Long-term memory with knowledge graph, entity resolution, and multi-strategy
retrieval. Supports cloud (API key) and local modes.

Configurable request timeout via HINDSIGHT_TIMEOUT env var or config.json.
Configurable embedded daemon idle timeout via HINDSIGHT_IDLE_TIMEOUT env var
or config.json idle_timeout.

Original PR #1811 by benfrank241, adapted to MemoryProvider ABC.

Config via environment variables:
  HINDSIGHT_API_KEY                — API key for Hindsight Cloud
  HINDSIGHT_BANK_ID                — memory bank identifier (default: hermes)
  HINDSIGHT_BUDGET                 — recall budget: low/mid/high (default: mid)
  HINDSIGHT_API_URL                — API endpoint
  HINDSIGHT_MODE                   — cloud or local (default: cloud)
  HINDSIGHT_TIMEOUT                — API request timeout in seconds (default: 120)
  HINDSIGHT_IDLE_TIMEOUT           — embedded daemon idle timeout seconds; 0 disables shutdown (default: 300)
  HINDSIGHT_RETAIN_TAGS            — comma-separated tags attached to retained memories
  HINDSIGHT_RETAIN_SOURCE          — metadata source value attached to retained memories
  HINDSIGHT_RETAIN_USER_PREFIX     — label used before user turns in retained transcripts
  HINDSIGHT_RETAIN_ASSISTANT_PREFIX — label used before assistant turns in retained transcripts

Or via $HERMES_HOME/hindsight/config.json (profile-scoped), falling back to
~/.hindsight/config.json (legacy, shared) for backward compatibility.
    )annotationsN)datetimetimezone)AnyDictList)MemoryProvider)get_hermes_home)
tool_error)cfg_getz"https://api.hindsight.vectorize.iozhttp://localhost:88880.4.22x   i,  z0.5.0>   lowmidhighgpt-4o-minizclaude-haiku-4-5zgemini-2.5-flashzopenai/gpt-oss-120bzqwen/qwen3.5-9bzMiniMax-M2.7z
gemma3:12bzlocal-modelzyour-model-name	openai	anthropicgeminigroq
openrouterminimaxollamalmstudioopenai_compatiblevaluer   defaultintreturnc                    | | dk    r|S 	 t          |           S # t          t          f$ r! t                              d| |           |cY S w xY w)zAParse an integer config/env value, falling back on invalid input.N z6Invalid integer Hindsight setting %r; using default %s)r   	TypeError
ValueErrorloggerwarning)r   r   s     F/home/piyush/.hermes/hermes-agent/plugins/memory/hindsight/__init__.py_parse_int_settingr(   K   sg    }5zzz"   OQVX_```s    /AAtuple[bool, str | None]c                     	 t          j        d           t          j        d           dS # t          $ r} dt          |           fcY d} ~ S d} ~ ww xY w)aB  Return whether local embedded Hindsight imports cleanly.

    On older CPUs, importing the local Hindsight stack can raise a runtime
    error from NumPy before the daemon starts. Treat that as "unavailable"
    so Hermes can degrade gracefully instead of repeatedly trying to start
    a broken local memory backend.
    	hindsightz$hindsight_embed.daemon_embed_manager)TNFN)	importlibimport_module	Exceptionstr)excs    r'   _check_local_runtimer1   V   sm    ,,, FGGGz   c#hhs   (, 
AAAAzDict[str, bool]_append_capability_cacheactual
str | Nonerequiredr/   boolc                j    | sdS 	 ddl m}  ||            ||          k    S # t          $ r Y dS w xY w)uJ   Return True if *actual* ≥ *required* (semver). False on missing/invalid.Fr   Version)packaging.versionr9   r.   )r3   r5   r9   s      r'   _meets_minimum_versionr;   q   se     u------wv''("3"333   uus   $ 
22      @api_urlapi_keytimeoutfloatc                   ddl }ddl}| sdS |                     d          dz   }|j                            |          }|r|                    dd|            	 |j                            ||          5 }|                                                    dd	
          }ddd           n# 1 swxY w Y   t          j
        |          }n4# t          $ r'}	t                              d||	           Y d}	~	dS d}	~	ww xY wt          |t                    sdS |                    d          p|                    d          }
|
rt#          |
          ndS )u)  GET ``<api_url>/version`` and return the version string (or None on failure).

    Hindsight's `/version` endpoint returns ``{"version": "0.5.6", ...}``.
    Any failure (timeout, 404, malformed JSON, missing key) → None, which
    the caller treats as "legacy API, no update_mode support".
    r   N/z/versionAuthorizationzBearer r?   utf-8replace)errorsz*Hindsight /version probe failed for %s: %sversionapi_version)urllib.errorurllib.requestrstriprequestRequest
add_headerurlopenreaddecodejsonloadsr.   r%   debug
isinstancedictgetr/   )r=   r>   r?   urlliburlreqresppayloaddatar0   rH   s              r'   _fetch_hindsight_api_versionr_   |   s     t
..



*C
.
 
 
%
%C =(;'(;(;<<<^##C#99 	DTiikk(((CCG	D 	D 	D 	D 	D 	D 	D 	D 	D 	D 	D 	D 	D 	D 	Dz'""   A3LLLttttt dD!! thhy!!<TXXm%<%<G",3w<<<,s<   C 7*B-!C -B11C 4B15C 
C>C99C>c                   | sdS t           5  | t          v rt          |          cddd           S 	 ddd           n# 1 swxY w Y   t          | |          }t          |t                    }t           5  t                              |           }||t          | <   n|}ddd           n# 1 swxY w Y   |s)t                              d| |t          t                     nt                              d| |           |S )u   Cached capability check for ``update_mode='append'`` on *api_url*.

    Probes once per URL per process. Returns False on any probe failure —
    that's the safe default: a per-process unique ``document_id`` and no
    ``update_mode`` keeps the resume-overwrite fix (#6654) intact.
    FNu  Hindsight API at %s reports version %r, older than %s. Falling back to per-process document_id — retains across processes/sessions create separate documents instead of appending to a session-scoped one. Upgrade Hindsight to %s+ to enable update_mode='append' deduplication.z9Hindsight API %s version %s supports update_mode='append')	_append_capability_lockr2   r_   r;   #_MIN_VERSION_FOR_UPDATE_MODE_APPENDrX   r%   r&   rU   )r=   r>   rH   	supportedcacheds        r'   &_check_api_supports_update_mode_appendre      s     u	  5 5...+G45 5 5 5 5 5 5 5.5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 +7G<<G&w0STTI	   )--g66>09$W--I                '@
 WA/	
 	
 	
 	
 	Pg	' 	' 	's!   <A A 3*B))B-0B-z asyncio.AbstractEventLoop | None_loopzthreading.Thread | None_loop_threadasyncio.AbstractEventLoopc                 D   t           5  t          ,t                                          rt          cddd           S t          j                    ad } t          j        | dd          at                                           t          cddd           S # 1 swxY w Y   dS )z>Return a long-lived event loop running on a background thread.Nc                 j    t          j        t                     t                                           d S N)asyncioset_event_looprf   run_forever     r'   _runz_get_loop.<locals>._run   s+    "5)))rp   Tzhindsight-looptargetdaemonname)	
_loop_lockrf   
is_runningrl   new_event_loop	threadingThreadrg   start)rq   s    r'   	_get_loopr|      s     
  !1!1!3!3        &((	  	  	  !'tDGWXXX                 s   'BABBBc                t    t                      }t          j        | |          }|                    |          S )z8Schedule *coro* on the shared loop and block until done.rD   )r|   rl   run_coroutine_threadsaferesult)coror?   loopfutures       r'   	_run_syncr      s1    ;;D-dD99F===)))rp   hindsight_retainzStore information to long-term memory. Hindsight automatically extracts structured facts, resolves entities, and indexes for retrieval.objectstringzThe information to store.)typedescriptionz9Short label (e.g. 'user preference', 'project decision').arrayr   zDOptional per-call tags to merge with configured default retain tags.)r   itemsr   )contentcontexttagsr   )r   
propertiesr5   )ru   r   
parametershindsight_recallzSearch long-term memory. Returns memories ranked by relevance using semantic search, keyword matching, entity graph traversal, and reranking.queryzWhat to search for.hindsight_reflectzSynthesize a reasoned answer from long-term memories. Unlike recall, this reasons across all stored memories to produce a coherent response.zThe question to reflect on.rW   c                 b   ddl m}  t                      dz  dz  }|                                r9	 t	          j        |                    d                    S # t          $ r Y nw xY w|                                 dz  dz  }|                                r9	 t	          j        |                    d                    S # t          $ r Y nw xY wt          j
                            dd	          t          j
                            d
d          t          t          j
                            d          t                    t          t          j
                            d          t                    t          j
                            dd          t          j
                            dd          t          j
                            dd          t          j
                            dd          dt          j
                            dd          t          j
                            dd          ddid	S )zLoad config from profile-scoped path, legacy path, or env vars.

    Resolution order:
      1. $HERMES_HOME/hindsight/config.json  (profile-scoped)
      2. ~/.hindsight/config.json             (legacy, shared)
      3. Environment variables
    r   Pathr+   config.jsonrE   encoding
.hindsightHINDSIGHT_MODEcloudHINDSIGHT_API_KEYr"   HINDSIGHT_TIMEOUTHINDSIGHT_IDLE_TIMEOUTHINDSIGHT_RETAIN_TAGSHINDSIGHT_RETAIN_SOURCEHINDSIGHT_RETAIN_USER_PREFIXUser!HINDSIGHT_RETAIN_ASSISTANT_PREFIX	AssistanthermesHINDSIGHT_BANK_IDHINDSIGHT_BUDGETr   T)bankIdbudgetenabled)	modeapiKeyr?   idle_timeoutretain_tagsretain_sourceretain_user_prefixretain_assistant_prefixbanks)pathlibr   r
   existsrS   rT   	read_textr.   homeosenvironrX   r(   _DEFAULT_TIMEOUT_DEFAULT_IDLE_TIMEOUT)r   profile_pathlegacy_paths      r'   _load_configr   &  s     #$${2]BL 	:l44g4FFGGG 	 	 	D	 ))++,}<K 	:k33W3EEFFF 	 	 	D	 
/99*..!4b99%bjnn5H&I&IK[\\*2:>>:R+S+SUjkkz~~&=rBB(A2FF jnn-KVTT#%:>>2UWb#c#c*..)<hGG*..);UCC 
  s#   'A 
A%$A%'B? ?
CC	List[str]c                n   | g S t          | t                    r| }nt          | t                    r|                                 }|sg S |                    d          rV	 t          j        |          }n# t          $ r d}Y nw xY wt          |t                    r|}n/|                    d          }n|                    d          }n| g}g }t                      }|D ]T}t          |                                          }|r||v r*|
                    |           |                    |           U|S )zCNormalize tag config/tool values to a deduplicated list of strings.N[,)rV   listr/   strip
startswithrS   rT   r.   splitsetaddappend)r   	raw_itemstextparsed
normalizedseenitemtags           r'   _normalize_retain_tagsr   S  sT   }	 % 			E3		 {{}} 	I??3 
	(D))   &$'' ,"		 JJsOO		

3IIG	J55D  $iioo 	cTkk#s    A5 5BBc                     t          j        t          j                                      d                              dd          S )zHReturn current UTC timestamp in ISO-8601 with milliseconds and Z suffix.milliseconds)timespecz+00:00Z)r   nowr   utc	isoformatrF   ro   rp   r'   _utc_timestampr   x  s7    <%%///HHPPQY[^___rp   configdict[str, Any]c                P    |                      dd          }t          |pd          S )zBReturn the Hindsight embedded profile name for this Hermes config.profiler   )rX   r/   )r   r   s     r'   _embedded_profile_namer   }  s(    jjH--Gw"(###rp   dict[str, str]c                H   |                                  si S i }|                     d                                          D ]`}|r|                    d          sd|vr|                    dd          \  }}|                                ||                                <   a|S )zEParse a simple KEY=VALUE env file, ignoring comments and blank lines.rE   r   #=   )r   r   
splitlinesr   r   r   )pathvalueslinekeyr   s        r'   _load_simple_envr     s    ;;== 	F00;;== , , 	ts++ 	s$ZZQ''
U#kkmmsyy{{Mrp   llm_api_keyr   c                  |}|J|                      d          p4|                      d          pt          j                             dd          }|                      dd          }|                      dd          }|                      d          pt          j                             d	d          }|d
v rdn|}t          |          t          |pd          t          |          dd}|rt          |          |d	<   |                      d          |                      d          nt          j                             d          }|+|dk    r%t          t	          |t
                              |d<   |S )zKBuild the profile-scoped env file that standalone hindsight-embed consumes.N	llmApiKeyr   HINDSIGHT_LLM_API_KEYr"   llm_provider	llm_modelllm_base_urlHINDSIGHT_API_LLM_BASE_URLr   r   r   info)HINDSIGHT_API_LLM_PROVIDERHINDSIGHT_API_LLM_API_KEYHINDSIGHT_API_LLM_MODELHINDSIGHT_API_LOG_LEVELr   r   #HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT)rX   r   r   r/   r(   r   )	r   r   current_keycurrent_providercurrent_modelcurrent_base_urldaemon_provider
env_valuesr   s	            r'   _build_embedded_profile_envr     s   KJJ{## ;zz-((;z~~5r:: 	 zz."55JJ{B//Mzz.11eRZ^^D`bd5e5e #36Y"Y"Yhh_oO '*/&:&:%():%;%;#&}#5#5#)	 J  I367G3H3H
/0 ::n%%1 	

>"""Z^^455 
 LB$6$6<?|-BCC=
 =

89 rp   c                h    ddl m} |                                dz  dz  t          |            dz  S )Nr   r   r   profiles.env)r   r   r   r   )r   r   s     r'   _embedded_profile_env_pathr    sC    99;;%
28Nv8V8V5\5\5\\\rp   c               
   t          |           }|j                            dd           t          | |          }|                    d                    d |                                D                       d           |S )zGWrite the profile-scoped env file that standalone hindsight-embed uses.Tparentsexist_okr   r"   c              3  ,   K   | ]\  }}| d | dV  dS )r   
Nro   ).0r   r   s      r'   	<genexpr>z4_materialize_embedded_profile_env.<locals>.<genexpr>  s7      HHzsE3"""""HHHHHHrp   rE   r   )r  parentmkdirr   
write_textjoinr   )r   r   profile_envr   s       r'   !_materialize_embedded_profile_envr    s    ,V44KTD999,VMMMJ
HHZ5E5E5G5GHHHHH     rp   c                (   | sdS g }d}t          |           D ]S}|                                s|dk    s|dk    r|                    |           d}:|s|                    d           d}Td                    |                              d          S )zSanitize a bank_id_template placeholder value.

    Bank IDs should be safe for URL paths and filesystem use. Replaces any
    character that isn't alphanumeric, dash, or underscore with a dash, and
    collapses runs of dashes.
    r"   F-_T-_)r/   isalnumr   r  r   )r   out	prev_dashchs       r'   _sanitize_bank_segmentr    s      r
CI%jj ! !::<< 	!299c		JJrNNNII !

3 	773<<d###rp   templatefallbackplaceholdersc                   | s|S d |                                 D             }	  | j        d	i |}n=# t          t          f$ r)}t                              d| ||           |cY d}~S d}~ww xY wd|v r|                    dd          }d|v d|v r|                    dd          }d|v |                    d          }|p|S )
u  Resolve a bank_id template string with the given placeholders.

    Supported placeholders (each is sanitized before substitution):
      {profile}   — active Hermes profile name (from agent_identity)
      {workspace} — Hermes workspace name (from agent_workspace)
      {platform}  — "cli", "telegram", "discord", etc.
      {user}      — platform user id (gateway sessions)
      {session}   — current session id

    Missing/empty placeholders are rendered as the empty string and then
    collapsed — e.g. ``hermes-{user}`` with no user becomes ``hermes``.

    If the template is empty, resolution falls back to *fallback*.
    Returns the sanitized bank id.
    c                4    i | ]\  }}|t          |          S ro   )r  )r
  kvs      r'   
<dictcomp>z-_resolve_bank_id_template.<locals>.<dictcomp>  s'    OOO$!Q*1--OOOrp   u5   Invalid bank_id_template %r: %s — using fallback %rNz--r  __r  r  ro   )r   formatKeyError
IndexErrorr%   r&   rF   r   )r  r  r  	sanitizedrenderedr0   s         r'   _resolve_bank_id_templater)    s      OO,:L:L:N:NOOOI"8?//Y//j!   Nh	0 	0 	0 (

##D#.. (


(

##D#.. (

~~d##Hxs   2 A,A'!A,'A,c                     e Zd ZdZd ZedId            ZdJdZd ZdKdZ	d Z
d Zd ZdLdZdMdZdMdZdMdZdMdZd ZdIdZdNdZdOdZdIdZd d!dPd#Zd d!dQd$ZdRd(ZdSd-Zd.d.d.d.d.d/dTd;Zd d!dUd<ZdVd>ZdWdAZd dBdCdXdGZdMdHZ d.S )YHindsightMemoryProviderzMHindsight long-term memory with knowledge graph and multi-strategy retrieval.c                ~   d | _         d | _        t          | _        d| _        d| _        d| _        d| _        d| _        d| _	        g | _
        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d	| _        d | _        t2          | _        t6          | _        d| _        t=          j                    | _         d | _!        tE          j#                    | _$        d | _%        t=          j&                    | _'        d
| _(        d | _)        d| _*        d| _+        d| _,        d | _-        d | _.        d| _/        d| _0        d| _1        d| _2        d| _3        d	| _4        g | _5        d| _6        d| _7        d | _8        d| _9        d| _:        d| _;        d | _<        d| _=        d S )Nr   r   r   r"   hybridrecallr   r   r   FanyTr   .conversation between Hermes Agent and the User      )>_config_api_key_DEFAULT_API_URL_api_url_bank_id_budget_mode_llm_base_url_memory_mode_prefetch_method_retain_tags_retain_source_retain_user_prefix_retain_assistant_prefix	_platform_user_id
_user_name_chat_id
_chat_name
_chat_type
_thread_id_agent_identity_agent_workspace_turn_index_clientr   _timeoutr   _idle_timeout_prefetch_resultry   Lock_prefetch_lock_prefetch_threadqueueQueue_retain_queue_writer_threadEvent_shutting_down_atexit_registered_sync_thread_session_id_parent_session_id_document_id_tags_recall_tags_recall_tags_match_auto_retain_retain_every_n_turns_retain_async_retain_context_turn_counter_session_turns_auto_recall_recall_max_tokens_recall_types_recall_prompt_preamble_recall_max_input_chars_bank_mission_bank_retain_mission_bank_id_templateselfs    r'   __init__z HindsightMemoryProvider.__init__  s   ( 
$ (') #) (3%! "(2 "'n.. $
 +0+--7;'o//"' !"$ (,
.2"' !%&"!O)+ !"&/3')$'*$  04!!#rp   r    r/   c                    dS )Nr+   ro   rn  s    r'   ru   zHindsightMemoryProvider.nameL  s    {rp   r6   c                   	 t                      }|                    dd          }|dv rt                      \  }}|S |dk    rdS t          |                    d          p4|                    d          pt          j                            dd	                    }t          |                    d
          pt          j                            dd	                    }|p|S # t          $ r Y dS w xY w)Nr   r   )locallocal_embeddedlocal_externalTr   r>   r   r"   r=   HINDSIGHT_API_URLF)r   rX   r1   r6   r   r   r.   )ro  cfgr   	availabler  has_keyhas_urls          r'   is_availablez$HindsightMemoryProvider.is_availableP  s    	..C7767++D222355	1  '''t!! ;779%%;:>>"5r:: G
 3779--X@SUW1X1XYYG%g% 	 	 	55	s   :C" C" BC" "
C0/C0c                v   ddl }ddlm}  ||          dz  }|                    dd           |dz  }i }|                                r4	  |j        |                                          }n# t          $ r Y nw xY w|                    |           |	                     |j
        |d	                     dS )
z3Write config to $HERMES_HOME/hindsight/config.json.r   Nr   r+   Tr  r      )indent)rS   r   r   r  r   rT   r   r.   updater  dumps)ro  r   hermes_homerS   r   
config_dirconfig_pathexistings           r'   save_configz#HindsightMemoryProvider.save_configc  s          T+&&4
555 =0 	%4:k&;&;&=&=>>   ztz(1===>>>>>s   "A/ /
A<;A<r  r   rW   Nonec           	     d   ddl }ddl}ddl}ddl}ddlm} ddlm} ddlm	}	 t          d           t          | j        t                    r| j        nt                      }
t          |
t                    si }
g d}g d}|
                    d	          }||v r|                    |          nd} |	d
||          }||         }t          |
          }||d	<   i }d}d| }d}|dk    r|g}n|dk    r|g}n|g}t          d           |                    d          }|s=t          d           t          d|j         dd                    |                      n	 |                    |ddd|j        ddg|z   ddd           t          d           nV# t*          $ rI}t          d|            t          d |j         dd                    |                      Y d}~nd}~ww xY w|d!k    rt          d"           t,          j                            d#d$          }|rt1          |          d%k    rd&|d'd          nd(}|j                            d)| d*           |j                                         |j                                        r|                     d$+          n*|j                                                                        }n|j                            d,           |j                                         |j                                        r|                     d$+          n*|j                                                                        }|r||d#<   tA          d-tB           d.                                          }|r||d/<   n)|dk    rtA          d0tD           d.                                          }|ptD          |d/<   |j                            d1           |j                                         |j                                        r|                     d$+          n*|j                                                                        }|r||d#<   nWtG          tH          %                                          }d2 |D             }|                    d3          }||v r|                    |          nd}  |	d4||           }!||!         }"|"|d3<   |"d5k    rQ|                    d6d$          }#d7}$|#r	|$d8|# d9z  }$|$d:z  }$tA          |$                                          }|r||d6<   n|"d;k    rd<|d6<   tH                              |"d=          }%|                    d>          p|%}&tA          d?|& d.                                          }|p|&|d><   |j                            d@           |j                                         |j                                        r|                     d$+          n*|j                                                                        }'|'r|'|dA<   n ||          dBz  }(d$})|(&                                r\|('                                (                                D ]5}*|*)                    dC          r|**                    dDdE          dE         }) n6|)|dA<   |+                    dFdG           |+                    dHdI           |                    dJ          }+|+|+ntX          },|,|dJ<   t[          |,          |dK<   |dk    r7|                    dL          }-|-|-nt\          }.|.|dL<   t[          |.          |dM<   dN|dO         dP<    ||           |                     ||           |rx ||          dBz  }(|(j/        0                    ddQ           g }/|(&                                r&|('                                (                                }/tc                      }0g }1|/D ]}*dD|*v rC|*)                    dR          s.|**                    dDdE          d                                         nd}2|2r:|2|v r6|12                    |2 dD||2                     |03                    |2           |12                    |*           |4                                D ]#\  }3}4|3|0vr|12                    |3 dD|4            $|(5                    dS                    |1          dSz              |dk    rt          |          }5 ||          dNz  dTz  }6	 tm          j7        |6'                    dUV                    }5n# t*          $ r Y nw xY w|                    dAd$          }7|7s/tq           ||          dBz                                dAd$          }7|7s0tq          ts          |5                                        dWd$          }7tu          |5|7pdX           t          dY| dZ           |rt          d[           t          d\           dS )]uL   Custom setup wizard — installs only the deps needed for the selected mode.r   Nr   )r  )_curses_selectz!
  Configuring Hindsight memory:
r   rt  ru  ))Cloudz8Hindsight Cloud API (lightweight, just needs an API key))zLocal Embeddedz7Run Hindsight locally (downloads ~200MB, needs LLM key))zLocal Externalz)Connect to an existing Hindsight instancer   z  Select moder   r   hindsight-client>=zhindsight-allrt  ru  z
  Checking dependencies...uvuR     ⚠ uv not found — install it: curl -LsSf https://astral.sh/uv/install.sh | shz-  Then run manually: uv pip install --python  pipinstall--python--quiet	--upgradeTr   checkr?   capture_outputu     ✓ Dependencies up to dateu     ⚠ Install failed: z(  Run manually: uv pip install --python r   z9
  Get your API key at https://ui.hindsight.vectorize.io
r   r"      z...r   z  API key (current: z, blank to keep): )promptz  API key: z  API URL [z]: r=   z  Hindsight API URL [z%  API key (optional, blank to skip): c                2    g | ]}|d t           |          fS )zdefault model: )_PROVIDER_DEFAULT_MODELS)r
  ps     r'   
<listcomp>z6HindsightMemoryProvider.post_setup.<locals>.<listcomp>  s<        C&>q&ACCD  rp   r   z  Select LLM providerr   r   z5  LLM endpoint URL (e.g. http://192.168.1.10:8080/v1)z []: r   zhttps://openrouter.ai/api/v1r   r   z  LLM model [z  LLM API key: r   r  zHINDSIGHT_LLM_API_KEY=r   r   bank_idr   recall_budgetr   r?   r   r   r   r+   memoryproviderr  r   r	  r   rE   r   r   r   u$   
  ✓ Hindsight memory configured (z mode)z  API keys saved to .envz$
  Start a new session to activate.
);getpass
subprocessshutilsysr   r   hermes_cli.configr  hermes_cli.memory_setupr  printrV   r3  rW   r   rX   indexwhich
executabler  runr.   r   r   lenstdoutwriteflushstdinisattyreadliner   inputr5  _DEFAULT_LOCAL_URLr   r  keysr   r   r   r   r   
setdefaultr   r/   r   r  r  r   r   r   r   r  rS   rT   r   r  r  )8ro  r  r   r  r  r  r  r   r  r  existing_configmode_values
mode_itemsexisting_modemode_default_idxmode_idxr   provider_config
env_writes_MIN_CLIENT_VERSION	cloud_dep	local_depdeps_to_installuv_patheexisting_keymaskedr>   valproviders_list	llm_itemsexisting_llm_providerllm_default_idxllm_idxr   existing_base_urlr  provider_default_modelr   llm_keyenv_pathexisting_llm_keyr   existing_timeouttimeout_valexisting_idle_timeoutidle_timeout_valexisting_linesupdated_keys	new_lines	key_matchr   r!  materialized_configr  r   s8                                                           r'   
post_setupz"HindsightMemoryProvider.post_setups  s   


      111111::::::3444*4T\4*H*H\$,,lnn/400 	! O DCC
 
 


 (++F33?LP[?[?[;,,];;;ab!>/:GWXXX8$ $_ 5 5"&
 '>)<>>	#	###(kOO%%%(kOO(kO,---,,t$$ 	ofgggn#.nnSVS[S[\kSlSlnnoooooeY
CNIWbcfuuD     56666 o o o2q22333mmmRURZRZ[jRkRkmmnnnnnnnno
 7??OPPP:>>*=rBBL m69,6G6G!6K6K2|BCC0222QV
  !R!R!R!RSSS
  """8;	8H8H8J8Jl'///444PSPYPbPbPdPdPjPjPlPl
  ///
  """8;	8H8H8J8Jl'///444PSPYPbPbPdPdPjPjPlPl :29
./;&6;;;<<BBDDC 1-0	*%%%G0BGGGHHNNPPC),)B0BOI&JDEEEJ47I4D4D4F4FhgooRo000CIL^L^L`L`LfLfLhLhG :29
./ "":"?"?"A"ABBN '  I %4$7$7$G$G!MbftMtMtn223HIIIz{O$n%<iQ`aaaG)'2L.:ON+222$3$7$7$K$K!P$ 87#47777F$Fmm))++ :69ON3--2P/%=%A%A,P]%^%^"+//<<V@VM::::;;AACCC+.+?-OK(J.///J47I4D4D4F4FhgooRo000CIL^L^L`L`LfLfLhLhG 
G6=
2334,,v5#% ??$$ " ( 2 2 4 4 ? ? A A " "??+CDD "/3zz#q/A/A!/D,!E" 7G
23 	""9h777""?E::: +..y99*:*F&&L\%0	"*-k*:*:
&'###$3$7$7$G$G!8M8Y44_t.>ON+367G3H3HJ/0'2x$F+666 	=tK((61HO!!$!>>>N   C!)!3!3!5!5!@!@!B!B55LI& + +=@D[[QUQ`Q`adQeQe[DJJsA..q177999ko	 +j!8!8$$	%K%KJy4I%K%KLLL $$Y////$$T****"((** 1 11L(($$ZZAZZ000		) 4 4t ;<<<###"&"7"7${++k9MIK&*j1F1FPW1F1X1X&Y&Y##    %..)@"EEK l.ttK/@/@6/IJJNNOfhjkk ./IJ]/^/^__cc/ 
 .#'/4   
 	BdBBBCCC 	.,---677777s*    7F 
G+"?G&&G+8(e! !
e.-e.c                   g dddg ddddt           ddidd	d
dddddidddt          ddidd	dddddiddddg dddidddddddddddd ddidd!d"d#dt          d$ddid%d&d'd(d)d*d+dd)d,d-d.d/d0d.d1d2d3g d4dd5d6d7g d8dd9d:d;d;d<gdd=d>dd)d?d@dd)dAdBdCd)dDdEdFd)dGdHdd)dIdJdKg dLddMdNdd)dOdPdd)dQdRdSd)dTdUdd)dVdWdXd)dYdZd[d)d\d]d^d)d_d`d.dadbt          d)dcddt          ddidS )eNr   zConnection moder   r  )r   r   r   choicesr=   zHindsight Cloud API URL)r   r   r   whenr>   zHindsight Cloud API keyTr   z!https://ui.hindsight.vectorize.io)r   r   secretenv_varrZ   r  zHindsight API URLru  zAPI key (optional))r   r   r  r  r  r   zLLM providerr   r   rt  )r   r   r   r  r  r   z/Endpoint URL (e.g. http://192.168.1.10:8080/v1)r"   r   )r   r   r   z,LLM API key (optional for openai_compatible)r   r   z	LLM modelr   )fieldmap)r   r   r   default_fromr  r  zAMemory bank name (static fallback when bank_id_template is unset)r   )r   r   r   bank_id_templatezOptional template to derive bank_id dynamically. Placeholders: {profile}, {workspace}, {platform}, {user}, {session}. Example: hermes-{profile}bank_missionz/Mission/purpose description for the memory bank)r   r   bank_retain_missionz-Custom extraction prompt for memory retentionr  zRecall thoroughnessr   )r   r   r   memory_modezMemory integration moder-  )r-  r   toolsrecall_prefetch_methodzAuto-recall methodr.  reflectr   z;Default tags applied to retained memories (comma-separated)r   z3Metadata source value attached to retained memoriesr   z4Label used before user turns in retained transcriptsr   r   z9Label used before assistant turns in retained transcriptsr   recall_tagsz8Tags to filter when searching memories (comma-separated)recall_tags_matchzTag matching mode for recallr/  )r/  all
any_strict
all_strictauto_recallz.Automatically recall memories before each turnauto_retainz'Automatically retain conversation turnsretain_every_n_turnsz%Retain every N turns (1 = every turn)r   retain_asyncz5Process retain asynchronously on the Hindsight serverretain_contextz#Context label for retained memoriesr0  recall_max_tokensz!Maximum tokens for recall resultsr1  recall_max_input_charsz*Maximum input query length for auto-recallr2  recall_prompt_preamblez0Custom preamble for recalled memories in contextr?   zAPI request timeout in secondsr   zBEmbedded daemon idle timeout in seconds (0 disables auto-shutdown))r5  r  r  r   r   rn  s    r'   get_config_schemaz)HindsightMemoryProvider.get_config_schema=  s   $
+<  ^K  ^K  ^K  L  L$
 .GTdouw~n  A  A$
 .GSWdw  Ad  ou  w~  n  @  @	$
 .AN`kq  tD  kE  F  F$
 .Bd_r  ~D  FV  }W  X  X$
 #>h  dQ  dQ  dQ  \b  dt  [u  v  v$
 #3dqs  GW  i|  ~}  ~}  ~  ~$
 "2`lp  ~U  `f  hx  _y  z  z$
  q  Ia  hb  hb  ms  uE  lF  G  G$
 .q  G  H  H$
 '  8I  VX  Y  Y$
 #3dee$
  *:ijj!$
" $4IV[h~h~h~#$
$ "2KX`  nL  nL  nL  M  M%$
& -=Q^ft|  H  tI  J  J'$
( "2o|~)$
* $4ivxyy+$
, )9o  }C  D  D-$
. .>y  GR  S  S/$
0 "2ly{||1$
2 (8Vch  v`  v`  v`  a  a3$
4 "2bostt5$
6 "2[hlmm7$
8 +;bopqq9$
: #2ivz{{;$
< %5Z  hX  Y  Y=$
> (8[hlmm?$
@ -=ivyzzA$
B -=oppC$
D .N[kllE$
F #3w  EZ  ek  m}  d~    G$
 $	
rp   c           	        | j         M| j        dk    rt                      \  }}|st          d|rd| ndz             ddlm} d |_        | j                            d	d          }|d
v rd}t          
                    d| j                            dd          |           t          | j                            dd          || j                            d          p9| j                            d          pt          j                            dd          | j                            dd                    }| j        r
| j        |d<   t          | j                            d          | j                            d          n$t          j                            d| j                  t"                    }|| _        ||d<    |di || _         nddlm} | j        pt*          }| j        t/          |          d}| j        r
| j        |d<   t          
                    d| j        t3          | j                  |d                     |di || _         | j         S )z:Return the cached Hindsight client (created once, reused).Nrt  z&Hindsight local runtime is unavailabler  r"   r   )HindsightEmbeddedc                    d S rk   ro   rn  s    r'   <lambda>z5HindsightMemoryProvider._get_client.<locals>.<lambda>o  s     rp   r   r   r   z;Creating HindsightEmbedded client (profile=%s, provider=%s)r   r   r   r   r   r   )r   r   r   r   r   r   r   )	Hindsight)base_urlr?   r>   z@Creating Hindsight cloud client (url=%s, has_key=%s, timeout=%s)r?   ro   )rK  r9  r1   RuntimeErrorr+   r  __del__r3  rX   r%   rU   rW   r   r   r:  r(   rM  r   hindsight_clientr   rL  r   r6  r@   r4  r6   )	ro  rx  reasonr  r   kwargsr   r   r?   s	            r'   _get_clientz#HindsightMemoryProvider._get_clientd  s   <z---$8$:$:!	6  &@,2:====<   877777,=,=!)#|//CC#FFF#+LZ!\--iBBLR R R L,,YAA!- $ 0 0 = =  !PAQAQR_A`A`  !Pdfdndrdr  tK  MO  eP  eP"l..{B??	   % @-1-?F>*1|''77C L$$^444(@$BTUU)	    &2")5~&00::6::666666-;+;&*mgOO= 6(,F9%_!]D,?,?	ART T T(y22622|rp   c                .    t          || j                  S )z@Schedule *coro* on the shared loop using the configured timeout.rD   )r   rL  )ro  r   s     r'   r   z!HindsightMemoryProvider._run_sync  s    t}5555rp   r0   r.   c                    | j         dk    rdS t          |          j         d|                                 t	          fddD                       S )z:Return True for stale embedded-daemon connection failures.rt  Fr  c              3      K   | ]}|v V  	d S rk   ro   )r
  markerr   s     r'   r  zRHindsightMemoryProvider._is_retriable_embedded_connection_error.<locals>.<genexpr>  s;       
 
 dN
 
 
 
 
 
rp   )zcannot connect to hostzconnection refusedzconnect call failedclientconnectorerror)r9  r   __name__lowerr/  )ro  r0   r   s     @r'   '_is_retriable_embedded_connection_errorz?HindsightMemoryProvider._is_retriable_embedded_connection_error  sx    :)))5s))$----3355 
 
 
 

 
 
 
 
 	
rp   c                    | j         }||                                rdS | j                                         t	          j        | j        dd          }|| _         || _        |                                 dS )zLazy-start the single retain-writer thread.

        We don't start the writer in initialize() so providers that never
        retain (e.g. tools-only mode) don't pay for an idle thread.
        NTzhindsight-writerrr   )	rU  is_aliverW  clearry   rz   _writer_looprY  r{   )ro  threads     r'   _ensure_writerz&HindsightMemoryProvider._ensure_writer  s     $&//"3"3F 	!!###!$#
 
 

 % #rp   c                   	 	 | j                             d          }n1# t          j        $ r | j                                        rY dS Y Kw xY w	 |t          u r	 | j                                          dS 	  |             n4# t          $ r'}t          
                    d|d           Y d}~nd}~ww xY w| j                                          n# | j                                          w xY w)zDrain the retain queue serially. Exits on sentinel.

        Each job() is wrapped so a single failure can't kill the writer.
        task_done() always fires so queue.join() works in tests.
        Tg      ?rD   NzHindsight retain failed: %sexc_info)rT  rX   rR  EmptyrW  is_set_WRITER_SENTINEL	task_doner.   r%   r&   )ro  jobr0   s      r'   r  z$HindsightMemoryProvider._writer_loop  s1   	/(,,S,99;   &--// FF/*** ",,.....VCEEEE  V V VNN#@#PTNUUUUUUUUV ",,....",,....	/sE    (AA	C 7
B C 
B3B.)C .B33C C+c                X    | j         rdS d| _         t          j        | j                   dS )a?  Register an idempotent atexit hook to drain the writer.

        Without this, a CLI exit that doesn't go through MemoryManager.
        shutdown_all() would leave in-flight retain jobs racing interpreter
        teardown, producing "cannot schedule new futures" warnings and
        unclosed aiohttp sessions.
        NT)rX  atexitregister_atexit_shutdownrn  s    r'   _register_atexitz(HindsightMemoryProvider._register_atexit  s5     " 	F"&-.....rp   c                    | j                                         rd S 	 |                                  d S # t          $ r&}t                              d|           Y d }~d S d }~ww xY w)Nz$Hindsight atexit shutdown failed: %s)rW  r  shutdownr.   r%   rU   )ro  r0   s     r'   r!  z(HindsightMemoryProvider._atexit_shutdown  s    %%'' 	F	FMMOOOOO 	F 	F 	FLL?EEEEEEEEE	Fs   3 
A#AA#c                x   |                                  }	 |                      ||                    S # t          $ r{}|                     |          s t                              d|           d| _        |                                  }|| _        |                      ||                    cY d}~S d}~ww xY w)zKRun an async Hindsight client operation, retrying once after idle shutdown.zVHindsight embedded daemon appears unreachable; recreating client and retrying once: %sN)r  r   r.   r  r%   r   rK  )ro  	operationclientr0   s       r'   _run_hindsight_operationz0HindsightMemoryProvider._run_hindsight_operation  s    !!##	5>>))F"3"3444 
	5 
	5 
	5??DD KKh    DL%%''F!DL>>))F"3"344444444
	5s   4 
B9A0B4.B94B9c                    | j         dk    r.| j        't          | j        dd          }|rt          |          S | j        pdS )zReturn the URL to probe /version on.

        For local_embedded the daemon is on a per-profile dynamic port,
        so we prefer the running client's URL when available; otherwise
        fall back to the configured api_url.
        rt  NrZ   r"   )r9  rK  getattrr/   r6  )ro  rZ   s     r'   
_probe_urlz"HindsightMemoryProvider._probe_url  sL     :)))dl.F$,t44C  3xx}""rp   fallback_document_idtuple[str, str | None]c                    | j         s|dfS t          |                                 | j                  r	| j         dfS |dfS )u  Pick (document_id, update_mode) based on live API capability.

        On Hindsight ≥ 0.5.0 the API supports ``update_mode='append'``,
        which lets us reuse a stable session-scoped ``document_id`` across
        process lifecycles without overwriting prior turns. On older APIs
        we fall back to *fallback_document_id* (the per-process unique
        ``f"{session_id}-{start_ts}"`` minted at initialize / switch time)
        and don't pass ``update_mode`` at all — that's the only way the
        resume-overwrite fix (#6654) keeps working on legacy servers.

        Probe is cached at module level per API URL, so this is one HTTP
        round-trip per (process, api_url) pair regardless of how many
        retains fire.
        Nr   )rZ  re   r+  r4  )ro  r,  s     r'   _resolve_retain_targetz.HindsightMemoryProvider._resolve_retain_target  sQ      	.'--1$//2C2CT]SS 	.#X--#T))rp   
session_idc                    t          |pd                                           _        t          |                    dd          pd                                           _        t          j                                        d          } j         d|  _        	 ddl	m
} ddlm}  |d          } ||           |t                    k     rt                              d	|t                     dd l}dd l}dd l}	|                    d
          }
|
r	 |                    |
ddd|	j        dddt           gddd           t                              dt                     nX# t.          $ r+}t                              d|t                     Y d }~n(d }~ww xY wt                              dt                     n# t.          $ r Y nw xY wt1                       _        t          |                    d          pd                                           _        t          |                    d          pd                                           _        t          |                    d          pd                                           _        t          |                    d          pd                                           _        t          |                    d          pd                                           _        t          |                    d          pd                                           _        t          |                    d          pd                                           _         t          |                    d          pd                                           _!        t          |                    d          pd                                           _"        d _#        g  _$         j                            d d!           _%        tM           j                            d"           j                            d"          ntN          j(                            d#          tR                     _*        tM           j                            d$           j                            d$          ntN          j(                            d%          tV                     _,         j%        d&k    rd' _%         j%        d'k    r7t[                      \  }}|s$t                              d(|           d) _%        d S  j                            d*          p9 j                            d+          ptN          j(                            d,d           _.         j%        d-v rt^          nt`          } j                            d.          ptN          j(                            d/|           _1         j                            d0d           _2        tg           j        d1d2i 3          } j                            d4          p|                    d5d2          } j                            d6d          pd _4        tk           j4        | j!         j"         j         j         j        7           _6         j                            d8          p/ j                            d9          p|                    d9d:          }|tn          v r|nd: _8         j                            d;d<          }|d=v r|nd< _9         j                            d>          p j                            d?d@          }|dAv r|nd@ _:         j                            dBd           _;         j                            dC          pd  _<        t{           j                            dD          ptN          j(                            dEd                     _>         j>        pd  _?         j                            dF          pd  _@         j                            dGdH           _A        t           j                            dI          ptN          j(                            dJd                                                     _B        t           j                            dK          ptN          j(                            dLdM                                                    pdM _C        t           j                            dN          ptN          j(                            dOdP                                                    pdP _D         j                            dQd           _E        t          dRt           j                            dSdR                               _H         j                            dTdU           _I         j                            dVd           _J        t           j                            dWdX                     _K         j                            dY          pd  _L         j                            dZd           _M        t           j                            d[d\                     _N         j                            d]d           _O        d^}	 ddl	m
}  |d          }n# t.          $ r Y nw xY wt                              d_ j%         j1         j6         j8         j9         j:        |            j4        r>t          P                    d` j4         j!         j"         j         j         j6                   t          P                    da jE         jJ         jH         jO         jI         jK         jN         j?         j@        
  
          j%        d'k    r2 fdb}t          jR        |ddcd          }|S                                 d S d S )eNr"   parent_session_id%Y%m%d_%H%M%S_%fr  r   )rH   r8   zhindsight-clientzBhindsight-client %s is outdated (need >=%s), attempting upgrade...r  r  r  r  r  r  r  Tr   r  z!hindsight-client upgraded to >=%szCAuto-upgrade failed: %s. Run: uv pip install 'hindsight-client>=%s'z5uv not found. Run: pip install 'hindsight-client>=%s'platformuser_id	user_namechat_id	chat_name	chat_type	thread_idagent_identityagent_workspacer   r   r?   r   r   r   rs  rt  zKHindsight local mode disabled because its runtime could not be imported: %sdisabledr   r>   r   )rt  ru  r=   rv  r   r   r   r  r  r   r  )r  r   	workspacer4  usersessionr  r   r   r  r-  )r   r  r-  r  prefetch_methodr.  )r.  r  r  r  r   r   r  r  r/  r   r   r   r   r   r   r   r   r  r   r  r  r0  r  r  r1  recall_typesr  r  r2  r  unknownzmHindsight initialized: mode=%s, api_url=%s, bank=%s, budget=%s, memory_mode=%s, prefetch_method=%s, client=%sz`Hindsight bank resolved from template %r: profile=%s workspace=%s platform=%s user=%s -> bank=%szHindsight config: auto_retain=%s, auto_recall=%s, retain_every_n=%d, retain_async=%s, retain_context=%s, recall_max_tokens=%d, recall_max_input_chars=%d, tags=%s, recall_tags=%sc                 8   dd l } t                      dz  }|                    dd           |dz  }	 dd lm} ddlm}  |t          |d          d	          |_        	                                }j
                            d
d          }t          j
                  }t          j
                  }t          |          }	|	|k    }
|
rt          j
                  }|j                            |          rWt          |d          5 }|                    d           d d d            n# 1 swxY w Y   |j                            |           |                                 t          |d          5 }|                    d           d d d            d S # 1 swxY w Y   d S # t*          $ rh}t          |d          5 }|                    d| d           |                     |           d d d            n# 1 swxY w Y   Y d }~d S Y d }~d S d }~ww xY w)Nr   logsTr  zhindsight-embed.log)ConsoleaF)fileforce_terminalr   r   z+
=== Config changed, restarting daemon ===
z%
=== Daemon started successfully ===
z
=== Daemon startup failed: z ===
)rH  )	tracebackr
   r  $hindsight_embed.daemon_embed_managerdaemon_embed_managerrich.consolerF  openconsoler  r3  rX   r  r   r   r  _managerrw   r  stop_ensure_startedr.   	print_exc)rJ  log_dirlog_pathdemrF  r'  r   r  expected_envsavedconfig_changedfr  ro  s                r'   _start_daemonz9HindsightMemoryProvider.initialize.<locals>._start_daemon  sQ       )++f4dT:::"%:: 4 GFFFFF444444")'tHc/B/BSX"Y"Y"YCK!--//F"l..y(CCG
 #=T\"J"JK#>t|#L#LL,[99E%*l%:N% :&G&U&U!?55g>> :!%h!4!4 Y !(W X X XY Y Y Y Y Y Y Y Y Y Y Y Y Y Y"O00999**,,,h,, K IJJJK K K K K K K K K K K K K K K K K K  4 4 4h,, 4 I I I IJJJ!+++3334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 44s   CF' D."F' .D22F' 5D26AF' 7FF' FF' !F"F' '
H1H0G=1H=H	HH	HHzhindsight-daemon-startrr   )Tr/   r   rZ  rX   r[  r   r   strftimer\  importlib.metadatarH   r:   r9   r  r%   r&   r  r  r  r  r  r  r   r.   r   r3  rA  rB  rC  rD  rE  rF  rG  rH  rI  rJ  re  r9  r(   r   r   r   rL  r   rM  r1   r4  r  r5  r6  r:  r   rm  r)  r7  _VALID_BUDGETSr8  r;  r<  rk  rl  r   r=  r]  r^  r_  r>  r?  r@  r`  maxr   ra  rc  rf  rg  rh  ri  rj  rb  rU   ry   rz   r{   )ro  r0  r  start_tspkg_versionr9   	installedr  r  r  r  r  rx  r  default_urlr   static_bank_idr   r  rA  _client_versionr[  ts   `                      r'   
initializez"HindsightMemoryProvider.initialize  sr   z/R006688"%fjj1Db&I&I&OR"P"P"V"V"X"X <>>**+=>>#/<<(<<	AAAAAA111111#$677Iwy!!GG,?$@$@@@c(*=? ? ?!!!!


 ,,t,, q	?"$eY
CN&5_J]5_5_a"&D '   
 $GI\]]]]$ ? ? ?'l'(*=? ? ? ? ? ? ? ?? NN#Z\oppp 	 	 	D	 $~~VZZ
339r::@@BBFJJy117R88>>@@fjj55;<<BBDDFJJy117R88>>@@fjj55;<<BBDDfjj55;<<BBDDfjj55;<<BBDD"6::.>#?#?#E2FFLLNN #FJJ/@$A$A$GR H H N N P P \%%fg66
*+/<+;+;I+F+F+RDLY'''XZXbXfXfgzX{X{
 
 0040@0@0P0P0\DL^,,,bdblbpbp  rJ  cK  cK!
 

 :  )DJ:))) 4 6 6Iv a   (
((22|dl6F6Fy6Q6Q|UWU_UcUcdwy{U|U|,0J:^,^,^((dt((33grz~~FY[f7g7g!\--nbAAgxDDD)))44U		(H8U8U!%!1!12Db!I!I!OR1"#(+^$
 
 
 !!/22ndl6F6Fx6P6PnTYT]T]^fhmTnTn!'>!9!9vvul&&}h??+6:X+X+XKK^f,**+CDDuHXHXYjltHuHu3BF[3[3[ai "\--nbAA$(L$4$45J$K$K$St! 3L]++ ;z~~5r::
 
 &.$
 L,,];;Ct"&,"2"23F"N"N!L_--^@Y[]1^1^
 

%'' 	 $'L122lbjnnEcek6l6l$
 $

%''$ 	  ),L677{2:>>Jmoz;{;{)
 )

%'')!  	%
 !L,,]DAA%(C0@0@AWYZ0[0[,\,\%]%]"#|//0@Brss !L,,]DAA"%dl&6&67JD&Q&Q"R"R!\--n==E'+|'7'78PRT'U'U$'*4<+;+;<TVY+Z+Z'['[$!\--ndCC#	AAAAAA)k*<==OO 	 	 	D	  DZt|TM^`d`u  xG	H 	H 	H! 	GLL{/1EtG\G G G 	 D&(94;U')=t?VX\XtZ!2		4 	4 	4 :)))%4 %4 %4 %4 %4N  dIabbbAGGIIIIIS *)sP   A8F? AE& %F? &
F0!FF? F#F? ?
GGk* *
k76k7c                    | j         dk    rd| j         d| j         dS | j         dk    rd| j         d| j         dS d| j         d| j         d	S )
Nr   z0# Hindsight Memory
Active (context mode). Bank: z
, budget: z<.
Relevant memories are automatically injected into context.r  z.# Hindsight Memory
Active (tools mode). Bank: zc.
Use hindsight_recall to search, hindsight_reflect for synthesis, hindsight_retain to store facts.z!# Hindsight Memory
Active. Bank: z.
Relevant memories are automatically injected into context. Use hindsight_recall to search, hindsight_reflect for synthesis, hindsight_retain to store facts.)r;  r7  r8  rn  s    r'   system_prompt_blockz+HindsightMemoryProvider.system_prompt_block  s    	))N04N NIMN N N
 ''4.2m4 4GK|4 4 40!]0 06:l0 0 0	
rp   r"   )r0  r   c                  | j         rN| j                                         r5t                              d           | j                             d           | j        5  | j        }d| _        d d d            n# 1 swxY w Y   |st                              d           dS t                              dt          |                     | j        pd}| d| S )	Nz3Prefetch: waiting for background thread to complete      @rD   r"   zPrefetch: no results availablez'Prefetch: returning %d chars of contextz# Hindsight Memory (persistent cross-session context)
Use this to answer questions about the user and prior sessions. Do not call tools to look up information that is already present here.z

)	rQ  r  r%   rU   r  rP  rN  r  ri  )ro  r   r0  r   headers        r'   prefetchz HindsightMemoryProvider.prefetch  s'     	4T%:%C%C%E%E 	4LLNOOO!&&s&333  	' 	'*F$&D!	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	'  	LL9:::2>FLLL- 
U 	
 &&f&&&s   A88A<?A<c                    j         dk    rt                              d           d S  j        st                              d           d S  j                                        rt                              d           d S  j        r't                     j        k    rd  j                  fd}t          j	        |dd           _
         j
                                         d S )	Nr  z#Prefetch: skipped (tools-only mode)z(Prefetch: skipped (auto_recall disabled)z!Prefetch: skipped (shutting down)c                 j   	 j         dk    rQt                              dj        t	                                                   fd          } | j        pd}nj        j        j        dj	        rj	        d<   j
        d<   j        r
j        d<   t                              d	j        t	                    j                                       fd
          } | j        rt	          | j                  nd}t                              d|           | j        r$d                    d | j        D                       nd}|r)j        5  |_        d d d            d S # 1 swxY w Y   d S d S # t           $ r(}t                              d|d           Y d }~d S d }~ww xY w)Nr  z1Prefetch: calling reflect (bank=%s, query_len=%d)c                H    |                      j        j                  S N)r  r   r   areflectr7  r8  r'  r   ro  s    r'   r  zFHindsightMemoryProvider.queue_prefetch.<locals>._run.<locals>.<lambda>  s2    `d`muz  DH  DP  IQ  IQ rp   r"   r  r   r   
max_tokensr   
tags_matchtypesz;Prefetch: calling recall (bank=%s, query_len=%d, budget=%s)c                     | j         di S Nro   arecallr'  recall_kwargss    r'   r  zFHindsightMemoryProvider.queue_prefetch.<locals>._run.<locals>.<lambda>)  s    HgHgYfHgHg rp   r   z$Prefetch: recall returned %d resultsr	  c              3  8   K   | ]}|j         	d |j          V  dS )z- Nr   )r
  rs     r'   r  zGHindsightMemoryProvider.queue_prefetch.<locals>._run.<locals>.<genexpr>,  s1      $S$SqAF$S]!&]]$S$S$S$S$S$Srp   zHindsight prefetch failed: %sTr  )r<  r%   rU   r7  r  r(  r   r8  rg  r^  r_  rh  resultsr  rP  rN  r.   )r\   r   num_resultsr  r~  r   ro  s       @r'   rq   z4HindsightMemoryProvider.queue_prefetch.<locals>._run  s`   P(I55LL!TVZVcehineoeoppp88  :Q  :Q  :Q  :Q  :Q  R  RD9?DD $(=5"&,d>U+ +M ( N040Af-6:6Ml3) D151Cg.LL!^!%E

DLJ J J889g9g9g9ghhD7;|"J#dl"3"3"3KLL!GUUUW[Wck499$S$SDL$S$S$SSSSikD 5, 5 504-5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 55 5  P P P<a$OOOOOOOOOPs<   EF  E1$F  1E55F  8E59F   
F2
F--F2Tzhindsight-prefetchrr   )r;  r%   rU   rf  rW  r  rj  r  ry   rz   rQ  r{   )ro  r   r0  rq   s   ``  r'   queue_prefetchz&HindsightMemoryProvider.queue_prefetch	  s	   ''LL>???F  	LLCDDDF%%'' 	LL<===F' 	9CJJ9U,U,U74778E	P 	P 	P 	P 	P 	P8 !* 0TPd e e e##%%%%%rp   user_contentassistant_contentList[Dict[str, str]]c                    t          j        t          j                                                  }d| j         d| |dd| j         d| |dgS )Nr?  r  )roler   	timestamp	assistant)r   r   r   r   r   r?  r@  )ro  r  r  r   s       r'   _build_turn_messagesz,HindsightMemoryProvider._build_turn_messages6  sv    l8<((2244 "6HH,HH   $";RR?PRR  
 	
rp   message_countr   
turn_indexDict[str, str]c                  t                      t          |          t          |          d}| j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j        r
| j        |d<   | j	        r
| j	        |d	<   | j
        r
| j
        |d
<   | j        r
| j        |d<   |S )N)retained_atr  r  sourcer0  r4  r5  r6  r7  r8  r9  r:  r;  )r   r/   r>  rZ  rA  rB  rC  rD  rE  rF  rG  rH  )ro  r  r  metadatas       r'   _build_metadataz'HindsightMemoryProvider._build_metadataE  s   )++ //j//$
 $

  	5!%!4HX 	6%)%5H\"> 	2#'>HZ = 	0"&-HY? 	4$(OH[!= 	0"&-HY? 	4$(OH[!? 	4$(OH[!? 	4$(OH[! 	>)-)=H%&rp   N)r   document_idr  r   r  r   r   r4   r  r  Dict[str, str] | Noner   List[str] | Noner  bool | NoneDict[str, Any]c               
   | j         ||p|                     d| j                  d}|||d<   |r||d<   |||d<   t          | j                  }t          |          D ]}	|	|vr|                    |	           |r||d<   |S )Nr   r  r  )r  r   r  r   r  r  r   )r7  r  rJ  r   r=  r   )
ro  r   r   r  r  r   r  r  merged_tagsr   s
             r'   _build_retain_kwargsz,HindsightMemoryProvider._build_retain_kwargsa  s     } fD$8$8qUYUe$8$f$f"
 "

  'F9 	0$/F=!#%1F>",T->??)$// 	( 	(C+%%""3''' 	)(F6Nrp   c               x   	
  j         st                              d           dS  j                                        rt                              d           dS |r&t          |                                           _        t          j	         
                    ||          d          } j                            |            xj        dz  c_         j         _         j         j        z  dk    r@t                              d j         j         j         j         j        z  z
  z              dS t                              d	t!           j                  t#          d
  j        D                                  dd                     j                  z   dz   g 	 j        r	                    d j                     j        r	                    d j                                         t!           j                  dz   j                  
t!           j                                        j                  \   j         j         j        d	
 f
d}                                                                     j                            |           dS )ue  Enqueue a retain for the current turn. Non-blocking.

        The actual aretain_batch runs on a single long-lived writer thread
        that drains an in-memory queue. Once shutdown() has been called,
        further sync_turn() calls are dropped — this prevents post-exit
        retains from reaching aiohttp after interpreter shutdown begins.
        z)sync_turn: skipped (auto_retain disabled)Nz"sync_turn: skipped (shutting down)F)ensure_asciir   r   z4sync_turn: buffered turn %d (will retain at turn %d)z=sync_turn: retaining %d turns, total session content %d charsc              3  4   K   | ]}t          |          V  d S rk   )r  )r
  rf  s     r'   r  z4HindsightMemoryProvider.sync_turn.<locals>.<genexpr>  s(      2W2Wa3q662W2W2W2W2W2Wrp   r   r   r  session:parent:r}  r  r    r  c            
     j  
  	                     pd                                 dd                                 dd            

 d<   t                              d
t	                               	                     fd           t                              d           d S )Nr   r  r   r  r  update_modezRHindsight retain: bank=%s, doc=%s, mode=%s, async=%s, content_len=%d, num_turns=%dc                8    |                      g          S N)r  r   r  r  )aretain_batch)r'  r  r  r   retain_async_flags    r'   r  zGHindsightMemoryProvider.sync_turn.<locals>._do_retain.<locals>.<lambda>  s*    v33#& +!2	  4     rp   zHindsight retain succeeded)r  popr%   rU   r  r(  )r   r  r   r  lineage_tagsmetadata_snapshot	num_turnsr  r  ro  r  s   @r'   
_do_retainz5HindsightMemoryProvider.sync_turn.<locals>._do_retain  s    ,,&*!)T	 -  D HHY%%%HH^T***&&1]#LLm +{<MsSZ||]fh h h))         LL566666rp   r    r  )r`  r%   rU   rW  r  r/   r   rZ  rS   r  r  re  r   rd  rJ  ra  r  sumr  r[  r  r/  r\  r7  rb  rc  r  r"  rT  put)ro  r  r  r0  turnr  r  r   r  r  r  r  r  r  r  s   `     @@@@@@@@@r'   	sync_turnz!HindsightMemoryProvider.sync_turn~  s      	LLDEEEF%%'' 	LL=>>>F 	7":4466Dz$33LBSTTchiii""4(((a- ::a??LLO+T-?4C]`d`ruy  vP  aP  DP  .QR R RFT,--s2W2W4CV2W2W2W/W/W	Y 	Y 	Y!4555;"$ 	? =4+; = =>>>" 	E C$*A C CDDD !00d122Q6' 1 
 
 +,,	#'#>#>t?P#Q#Q [- .-	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7 	7. 	z*****rp   List[Dict[str, Any]]c                D    | j         dk    rg S t          t          t          gS )Nr   )r;  RETAIN_SCHEMARECALL_SCHEMAREFLECT_SCHEMArn  s    r'   get_tool_schemasz(HindsightMemoryProvider.get_tool_schemas  s"    	))I}n==rp   	tool_nameargsc                   
 |dk    r%|                     dd          }|st          d          S |                     d          }	                      |||                     d                    t                              d j        t          |          |                                fd	           t                              d
           t          j	        ddi          S # t          $ r9}t                              d|d           t          d|           cY d }~S d }~ww xY w|dk    r|                     dd          

st          d          S 	  j        
 j         j        d j        r j        d<    j        d<    j        r
 j        d<   t                              d j        t          
           j                                        fd          }|j        rt          |j                  nd}t                              d|           |j        st          j	        ddi          S d t%          |j        d          D             }	t          j	        dd                    |	          i          S # t          $ r9}t                              d|d           t          d |           cY d }~S d }~ww xY w|d!k    r|                     dd          

st          d          S 	 t                              d" j        t          
           j                                        
 fd#          }t                              d$t          |j        pd                     t          j	        d|j        pdi          S # t          $ r9}t                              d%|d           t          d&|           cY d }~S d }~ww xY wt          d'|           S )(Nr   r   r"   z#Missing required parameter: contentr   r   )r   r   z:Tool hindsight_retain: bank=%s, content_len=%d, context=%sc                     | j         di S rz  )aretain)r'  retain_kwargss    r'   r  z:HindsightMemoryProvider.handle_tool_call.<locals>.<lambda>  s    ^V^=\=\m=\=\ rp   zTool hindsight_retain: successr   zMemory stored successfully.zhindsight_retain failed: %sTr  zFailed to store memory: r   r   z!Missing required parameter: queryru  rw  rx  z7Tool hindsight_recall: bank=%s, query_len=%d, budget=%sc                     | j         di S rz  r{  r}  s    r'   r  z:HindsightMemoryProvider.handle_tool_call.<locals>.<lambda>  s    NFNDcDcUbDcDc rp   r   z!Tool hindsight_recall: %d resultszNo relevant memories found.c                ,    g | ]\  }}| d |j          S )z. r  )r
  ir  s      r'   r  z<HindsightMemoryProvider.handle_tool_call.<locals>.<listcomp>  s,    QQQdaA))))QQQrp   r   r	  zhindsight_recall failed: %szFailed to search memory: r   z8Tool hindsight_reflect: bank=%s, query_len=%d, budget=%sc                H    |                      j        j                  S rq  rr  rt  s    r'   r  z:HindsightMemoryProvider.handle_tool_call.<locals>.<lambda>  s%    6?? $U4< $3 $ $ rp   z'Tool hindsight_reflect: response_len=%dzhindsight_reflect failed: %szFailed to reflect: zUnknown tool: )rX   r   r  r%   rU   r7  r  r(  rS   r  r.   r&   r8  rg  r^  r_  rh  r  	enumerater  r   )ro  r  r  r  r   r   r  r\   r  linesr   r~  r  s   `         @@@r'   handle_tool_callz(HindsightMemoryProvider.handle_tool_call  s   ***hhy"--G I!"GHHHhhy))GB $ 9 9#&)) !: ! !
 Y!]CLL'C C C--.\.\.\.\]]]=>>>z8-J"KLLL B B B<a$OOO!"@Q"@"@AAAAAAAAB ,,,HHWb))E G!"EFFFC#}u"&"9' ' $ J,0,=M&)262IM,/% @-1-?M'*V!]CJJF F F445c5c5c5cdd37<Fc$,///Q@+NNN| Q:x1N&OPPPQQia6P6PQQQz8TYYu-=-=">??? C C C<a$OOO!"Aa"A"ABBBBBBBBC ---HHWb))E G!"EFFF=W!]CJJF F F44     
 FDIOY[H\H\]]]z8TY-W:W"XYYY = = ==q4PPP!";";";<<<<<<<<= 6966777sd   	B!C+ +
D.5.D)#D.)D. C"J AJ 
K.K	K	K BN 
O#.OOOF)r2  resetnew_session_idr2  r  c                   t          |pd                                          }|sdS  j        r$t           j                   j        } j        } j        }                     t                    dz  |          g |r	                    d|            |r	                    d|            dd
                              z   d	z                         j                  \   fd
}	 j                                        sB                                                                     j                            |	            j        r4 j                                        r j        
                    d            j        5  d _        ddd           n# 1 swxY w Y   |r&t          |                                           _        | _        t/          j                                        d          }
 j         d|
  _        g  _        d _        d _        t6                              d j         j        | j                   dS )u  Refresh cached per-session state when the agent rotates session_id.

        Fires on /resume, /branch, /reset, /new, and context compression.
        Without this hook, initialize()-cached state (``_session_id``,
        ``_document_id``, ``_session_turns``, ``_turn_counter``) would keep
        pointing at the previous session and writes would land in the wrong
        document. See hermes-agent#6672.

        Always update ``_session_id`` so metadata and tags on subsequent
        retains reflect the active session. Always mint a fresh
        ``_document_id`` so the new session's retain doesn't overwrite the
        old session's document on vectorize-io/hindsight#1303. Always clear
        the accumulated batch buffers (``_session_turns``, ``_turn_counter``,
        ``_turn_index``) — even for /resume and /branch, the new session's
        batching must start from zero so an in-flight retain doesn't flush
        under the wrong ``_document_id``.

        Before clearing, flush any buffered turns under the *old*
        ``_document_id``. Users who set ``retain_every_n_turns > 1`` would
        otherwise silently lose whatever's in ``_session_turns`` at the
        moment of switch — the same data-loss class as the shutdown race,
        just at a different lifecycle event.

        Also wait for any in-flight prefetch from the old session and drop
        its cached result; otherwise the new session's first ``prefetch()``
        could read stale recall text from before the switch.

        ``parent_session_id`` is recorded for lineage tags on future retains.
        ``reset`` is accepted but not needed for Hindsight's state model —
        buffer clearing is correct for every session switch, not only /reset.
        r"   Nr}  r  r  r  r   r   r  c            	        	                      j        pd                               dd                                dd            d<   t                              dj        t                                                   fd           d S # t          $ r(} t          	                    d| d	           Y d } ~ d S d } ~ ww xY w)
Nr  r  r  r  zAHindsight flush-on-switch: bank=%s, doc=%s, mode=%s, num_turns=%dc                L    |                      j        gj                  S r  )r  r7  rb  )r'  r   old_document_idro  s    r'   r  zKHindsightMemoryProvider.on_session_switch.<locals>._flush.<locals>.<lambda>j  s/    v';';$(M#'&(7)-);	 (< ( ( rp   z$Hindsight flush-on-switch failed: %sTr  )
r  rc  r  r%   rU   r7  r  r(  r.   r&   )	r  r   old_contentr  old_lineage_tagsold_metadata	old_turnsold_update_modero  s	    @r'   _flushz9HindsightMemoryProvider.on_session_switch.<locals>._flushY  s/   ]44# $ 4!--5	 5  D HHY---HH^T222&2.=]+LL[Y   11          ! ] ] ]NN#I1W[N\\\\\\\\\]s   BB# #
C-CCrk  rD   r3  r  r   zEHindsight on_session_switch: new_session=%s parent=%s reset=%s doc=%s)r/   r   re  r   rZ  r[  rJ  r  r  r   r  r/  r\  rW  r  r  r"  rT  r  rQ  r  rP  rN  r   r   r\  rd  r%   rU   )ro  r  r2  r  r  new_idold_session_idold_parent_session_idold_turn_indexr  r`  r  r  r  r  r  r  s   `          @@@@@@r'   on_session_switchz)HindsightMemoryProvider.on_session_switch  s   N ^)r**0022 	F
  ;	/T011I!-N$($;!!-N//!)nnq0) 0  L +- E ''(C>(C(CDDD$ K ''(I2G(I(IJJJ 3 33c9K
 04/J/J!0 0,O_] ] ] ] ] ] ] ] ] ] ]B &--// /##%%%%%'''"&&v...   	4T%:%C%C%E%E 	4!&&s&333  	' 	'$&D!	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	' 	'  	E&)*;&<&<&B&B&D&DD#!<>>**+=>>#/<<(<< Sd5ud>O	
 	
 	
 	
 	
s   F11F58F5c                   t                               d           | j                                         | j        }||                                r	 | j                            t                     n# t          $ r Y nw xY w|
                    d           |                                r2t                               d| j                                                   | j        r4| j                                        r| j        
                    d           | j        	 | j        dk    rt!          | j        dd           }|Ot#          |d          r?t%          |                                           	 d | j        _        n# t          $ r Y nw xY w	 | j                                         n<# t*          $ r Y n0w xY w|                     | j                                                   n# t          $ r Y nw xY wd | _        d S d S )	NzDHindsight shutdown: stopping writer + waiting for background threadsg      $@rD   zIHindsight writer did not stop within 10s; abandoning %d pending retain(s)r<   rt  rK  aclose)r%   rU   rW  r   rU  r  rT  r  r  r.   r  r&   qsizerQ  rK  r9  r*  hasattrr   r  closer  )ro  writerinner_clients      r'   r$  z HindsightMemoryProvider.shutdown  s>   [\\\ 	!!! $&//"3"3"&&'78888   KKK%%%   6&,,..  
   	4T%:%C%C%E%E 	4!&&s&333<#:!111 $+4<D#I#IL#/GL(4S4S/!,"5"5"7"7888!37DL00( ! ! ! D!**,,,,'    NN4<#6#6#8#8999   DLLL1 $#sm   A2 2
A?>A?!AG+ 6F G+ 
FG+ FG+ F. -G+ .
F;8G+ :F;;/G+ +
G87G8r    r/   )r    r6   )r  r/   r   rW   r    r  )r0   r.   r    r6   r  )r,  r/   r    r-  )r0  r/   r    r  )r   r/   r0  r/   r    r/   )r   r/   r0  r/   r    r  )r  r/   r  r/   r    r  )r  r   r  r   r    r  )r   r/   r   r4   r  r4   r  r  r   r  r  r  r    r  )r  r/   r  r/   r0  r/   r    r  )r    r  )r  r/   r  rW   r    r/   )r  r/   r2  r/   r  r6   r    r  )!r  
__module____qualname____doc__rp  propertyru   r{  r  r  r  r  r   r  r  r  r"  r!  r(  r+  r/  rg  ri  rm  r  r  r  r  r  r  r  r  r$  ro   rp   r'   r+  r+    s       WWD$ D$ D$L    X   &? ? ? H8 H8 H8 H8T%
 %
 %
N+ + +Z6 6 6
 
 
 
   ./ / / /./ / / /F F F F5 5 5"# # # #* * * **E E E EN
 
 
 
, 9; ' ' ' ' ' '$ ?A +& +& +& +& +& +&Z
 
 
 
   @ #"&*.!%$(     : Y[ K+ K+ K+ K+ K+ K+Z> > > >
B8 B8 B8 B8P "$~
 ~
 ~
 ~
 ~
 ~
@/  /  /  /  /  / rp   r+  r  c                H    |                      t                                 dS )z/Register Hindsight as a memory provider plugin.N)register_memory_providerr+  )ctxs    r'   r   r     s#      !8!:!:;;;;;rp   )r   r   r   r   r    r   )r    r)   )r3   r4   r5   r/   r    r6   )Nr<   )r=   r/   r>   r4   r?   r@   r    r4   rk   )r=   r/   r>   r4   r    r6   )r    rh   )r?   r@   )r    rW   )r   r   r    r   r  )r   r   r    r/   )r    r   )r   r   r   r4   r    r   )r   r   )r   r   r   r4   )r   r/   r    r/   )r  r/   r  r/   r  r/   r    r/   r  )Cr  
__future__r   rl   r  r,   rS   loggingr   rR  ry   r   r   typingr   r   r   agent.memory_providerr	   hermes_constantsr
   tools.registryr   r  r   	getLoggerr  r%   r5  r  r  r   r   rb   r^  r  r(   r1   r2   __annotations__rO  ra   r;   r_   re   rf   rg   rv   r   r  r|   r   r  r  r  r   r   r   r   r   r   r  r  r  r)  r+  r   ro   rp   r'   <module>r     s    8 # " " " " "         				      ' ' ' ' ' ' ' ' " " " " " " " " " " 0 0 0 0 0 0 , , , , , , % % % % % % % % % % % %		8	$	$7 ,     '. #'''# !#*
 
       . -/  . . . .().**     FJ25- - - - -< BF# # # # #V +/ . . . .(, , , , ,Y^
 688    " &6 * * * * *" 	S  (9TUU (9tuu (+e 
 
 K  , 	T h7LMM
 I     	R h7TUU
 I  (* * * *Z" " " "J` ` ` `
$ $ $ $    VZ # # # # # #L] ] ] ] \` 	 	 	 	 	 	$ $ $ $,       J@  @  @  @  @ n @  @  @ \&< < < < < <rp   