+
    iHàj½.  ã                  ój  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHtH	t	 ^ RI
Ht ^ RIHtHtHtHtHt ]P$                  ! ]4      tR R ltRR	R
RRR/R R llt^tRt]! 0 Rm4      tR R lt]! R	R7       ! R R4      4       t]P:                  ! R]P<                  4      tR R lt  ! R R]4      t!R# )aH  Abstract base class for pluggable memory providers.

Plugins ship in ``plugins/memory/<name>/``, activated via ``memory.provider`` (ONE external
provider at a time). Lifecycle, driven by MemoryManager: initialize -> system_prompt_block /
prefetch / sync_turn per turn -> tool dispatch -> shutdown, plus optional ``on_*`` hooks.
)ÚannotationsN)ÚABCÚabstractmethod)Ú	dataclass)ÚAnyÚCallableÚDictÚListÚOptionalc               ó    € V ^8„  d   QhRRRR/# )é   ÚfnúCallable[..., Any]Úreturn© )Úformats   "Ú:/home/ubuntu/.hermes/hermes-agent/agent/memory_provider.pyÚ__annotate__r      s    € ÷ @ñ @Ð$ð @Ð);ñ @ó    c                ó>   a a€ \         P                  ! 4       oVV 3R l# )a  Bind ``fn`` to the CALLER's contextvars for another thread/executor. Profile isolation
is a ContextVar-scoped HERMES_HOME override plus the per-turn secret scope; a worker started
with an empty context silently lands on the default profile (or fails closed on secrets).c                 ó0   <€ SP                   ! S.V O5/ VB # ©N)Úrun)ÚargsÚkwargsÚctxr   s   *,€€r   Ú<lambda>Úctx_bound.<locals>.<lambda>   s   ø€  3§7¢7¨2Ð#?°Ò#?¸Ò#?r   )ÚcontextvarsÚcopy_context)r   r   s   f@r   Ú	ctx_boundr       s   ù€ ô ×
"Ò
"Ó
$€CÝ?Ð?r   ÚdaemonTr   r   c               ó0   € V ^8„  d   QhRRRRRRRRR	R
RR/# )r   Útargetr   ÚnameÚstrr!   Úboolr   Útupler   úOptional[dict[str, Any]]r   zthreading.Threadr   )r   s   "r   r   r      sB   € ÷ jñ jÐ!3ð j¸cð jÈ4ð jØ$ðjØ3KðjØWgñjr   c               óF   € \         P                  ! \        V 4      W4WR7      # )z´Unstarted thread running *target* under the spawner's contextvars (see :func:`ctx_bound`).
Every memory-provider background job (prefetch, sync, writer loops) must go through this.)r#   r   r   r$   r!   )Ú	threadingÚThreadr    )r#   r$   r!   r   r   s   &$$$$r   Úspawn_context_threadr,      s   € ô ×Ò¤9¨VÓ#4¸4ÐUYÔiÐir   u   ðŸ§ c               ó    € V ^8„  d   QhRRRR/# )r   r$   úOptional[str]r   r&   r   )r   s   "r   r   r   /   s   € ÷ Mñ M -ð M°Dñ Mr   c                ór   € \        T ;'       g    R4      P                  4       P                  4       \        9   # )zXTrue when ``memory.provider`` selects the built-in store rather than an external plugin.Ú )r%   ÚstripÚlowerÚCORE_MEMORY_PROVIDER_SENTINELS)r$   s   &r   Úis_core_memory_providerr4   /   s*   € äˆt�zˆz�r‹?× Ñ Ó"×(Ñ(Ó*Ô.LÑLÐLr   )Úfrozenc                  ó>   € ] tR t^4t$ RtR]R&   R]R&   ]tR]R&   RtR# )	ÚRecallStatuszßWhat the last prefetch injected, for the deterministic recall indicator
(``MemoryManager.describe_recall``). ``count == 0`` means content without a
discrete count (e.g. a synthesized reflect answer) and renders generically.r%   Úprovider_labelÚintÚcountÚglyphr   N)	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__ÚINDICATOR_GLYPHr;   Ú__static_attributes__r   r   r   r7   r7   4   s   ‡ ñSð ÓØƒJØ €Eˆ3× r   r7   c               ó    € V ^8„  d   QhRRRR/# )r   Útextr.   r   r&   r   )r   s   "r   r   r   K   s   € ÷ 3ñ 3˜Mð 3¨dñ 3r   c                ó´   € T ;'       g    RP                  4       pV'       d   VP                  R4      '       d   R# \        \        P	                  V4      4      # )z¦True for empty input, slash commands and bare greetings/acknowledgements (skipping
recall saves a round-trip and keeps stale context from derailing one-word replies).r0   Ú/T)r1   Ú
startswithr&   ÚTRIVIAL_PROMPT_REÚmatch)rE   Ústrippeds   & r   Úis_trivial_promptrL   K   sE   € ð —
�
˜×!Ñ!Ó#€Hß�x×*Ñ*¨3×/Ò/ÙÜÔ!×'Ñ'¨Ó1Ó2Ð2r   c                  ó”  € ] tR t^TtRt^t]]R R l4       4       t]R R l4       t	]R R l4       t
R R	 ltR
 R ltRR/R R lltRR/R R lltR R ltRRRRRR/R R llt]R R l4       tR R ltR R ltR R  ltR! R" ltR# R$ ltR%RR&R'R(R'/R) R* lltR+ R, ltR-R/R. R/ lltR0 R1 ltR2 R3 ltR9R4 R5 lltR6 R7 ltR8tR# ):ÚMemoryProvidera=  Abstract base class for memory providers.

Multiplexing contract (#140058). One gateway process can serve several profiles, and each agent's
``MemoryManager`` owns its own provider instance, initialized for one profile. A provider must:

- hand every load a NEW instance (``register(ctx)`` / the loader constructs one per agent). The
  manager refuses an instance another profile's manager already bound, rather than rebinding it;
- bind every store, path, client, bank or tenant from ``initialize()``'s ``hermes_home`` (and
  scoped secrets read during ``initialize``) and keep that binding on the instance;
- keep no profile-specific mutable state at module or class level, and never "rebind" a shared
  binding per call: two profiles' calls interleave on different threads.

The manager runs tool calls and lifecycle hooks only from the profile the instance was initialized
for (refusing callers that name another profile, or none on a multiplexed process), runs its
background hooks under that profile's ``HERMES_HOME``, and passes ``hermes_home`` /
``agent_identity`` / ``caller_gsk`` to ``handle_tool_call`` when it accepts ``**kwargs``. Those
keywords name the same profile the instance is bound to; they are not a reason to rebind. Core
cannot see inside a provider: one that keeps a process-wide binding still breaks this contract.
c               ó   € V ^8„  d   QhRR/# ©r   r   r%   r   )r   s   "r   r   ÚMemoryProvider.__annotate__o   s   € ÷ Zñ Z�cñ Zr   c                ó   € R# )zKShort identifier for this provider (e.g. 'builtin', 'honcho', 'hindsight').Nr   ©Úselfs   &r   r$   ÚMemoryProvider.namem   ó   ‚ r   c               ó   € V ^8„  d   QhRR/# )r   r   r&   r   )r   s   "r   r   rQ   u   s   € ÷ hñ h˜dñ hr   c                ó   € R# )zYConfigured, credentialed and ready? Gates activation; check config/deps only, no network.Nr   rS   s   &r   Úis_availableÚMemoryProvider.is_availablet   rV   r   c               ó    € V ^8„  d   QhRRRR/# )r   Ú
session_idr%   r   ÚNoner   )r   s   "r   r   rQ   y   s   € ÷ ñ  Sð °tñ r   c                ó   € R# )u†  Initialize once at agent startup (connections, resources, threads).

kwargs always include ``hermes_home`` (profile-scoped storage; never hardcode
``~/.hermes``) and ``platform``; may include ``agent_context`` ("primary" |
"subagent" | "cron" | "flush" â€” skip writes for non-primary contexts),
``agent_identity``, ``agent_workspace``, ``parent_session_id``, ``user_id``, ``user_id_alt``.
Nr   )rT   r\   r   s   &&,r   Ú
initializeÚMemoryProvider.initializex   rV   r   c               ó   € V ^8„  d   QhRR/# rP   r   )r   s   "r   r   rQ   ‚   s   € ÷ ñ  Cñ r   c                ó   € R# )z[User-facing hint for the "provider unavailable" warning (``initialize()`` never runs then).r0   r   rS   s   &r   Úunavailable_reasonÚ!MemoryProvider.unavailable_reason‚   ó   € ár   c               ó   € V ^8„  d   QhRR/# rP   r   )r   s   "r   r   rQ   †   s   € ÷ ñ  Sñ r   c                ó   € R# )zZSTATIC system-prompt text; "" to skip. Recalled context goes through prefetch(), not here.r0   r   rS   s   &r   Úsystem_prompt_blockÚ"MemoryProvider.system_prompt_block†   re   r   r\   r0   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úqueryr%   r\   r   r   )r   s   "r   r   rQ   Š   s!   € ÷ ñ ˜cð °#ð ¸sñ r   c               ó   € R# )u¬   Formatted recall context for the upcoming turn ("" if none). Must be fast â€” recall
in the background and return cached results; ``session_id`` scopes concurrent sessions.r0   r   ©rT   rk   r\   s   &&$r   ÚprefetchÚMemoryProvider.prefetchŠ   s   € ñ r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rk   r%   r\   r   r]   r   )r   s   "r   r   rQ   �   s&   € ÷ [ñ [ Cð [¸ð [ÀTñ [r   c               ó   € R# )zLQueue a background recall after each turn; prefetch() consumes it next turn.Nr   rm   s   &&$r   Úqueue_prefetchÚMemoryProvider.queue_prefetch�   rV   r   c               ó   € V ^8„  d   QhRR/# )r   r   zOptional[RecallStatus]r   )r   s   "r   r   rQ   ’   s   € ÷ ñ Ð5ñ r   c                ó   € R# )z‰What the most recent :meth:`prefetch` injected (``None`` = no indicator). Must reflect
only the LAST prefetch, never a stale prior count.Nr   rS   s   &r   Úrecall_statusÚMemoryProvider.recall_status’   s   € ñ r   ÚmessagesNÚturn_authorc               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r   Úuser_contentr%   Úassistant_contentr\   rx   zOptional[list[dict[str, Any]]]ry   r(   r   r]   r   )r   s   "r   r   rQ   —   sH   € ÷ Nñ NØðNØ47ðNàðNà(FðNð .ðNð 
ñ	Nr   c               ó   € R# )zÙPersist a completed turn (non-blocking). ``messages`` is the OpenAI-style list so far.
``turn_author`` (``{"id", "name", "is_bot"}``) is who wrote the user side; the manager sends it only to signatures that accept it.Nr   )rT   r{   r|   r\   rx   ry   s   &&&$$$r   Ú	sync_turnÚMemoryProvider.sync_turn—   rV   r   c               ó   € V ^8„  d   QhRR/# ©r   r   úlist[dict[str, Any]]r   )r   s   "r   r   rQ       s   € ÷ cñ cÐ"6ñ cr   c                ó   € R# )zTOpenAI function-calling schemas ({"name", "description", "parameters"}); [] if none.Nr   rS   s   &r   Úget_tool_schemasÚMemoryProvider.get_tool_schemasŸ   rV   r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú	tool_namer%   r   údict[str, Any]r   r   )r   s   "r   r   rQ   £   s'   € ÷ \ñ \¨#ð \°^ð \ÐRUñ \r   c                ó8   € \        RV P                   RV 24      h)z?Handle one of this provider's tools; must return a JSON string.z	Provider z does not handle tool )ÚNotImplementedErrorr$   )rT   r‡   r   r   s   &&&,r   Úhandle_tool_callÚMemoryProvider.handle_tool_call£   s   € ä! I¨d¯i©i¨[Ð8NÈyÈkÐ"ZÓ[Ð[r   c               ó   € V ^8„  d   QhRR/# )r   r   r]   r   )r   s   "r   r   rQ   §   s   € ÷ Bñ B˜$ñ Br   c                ó   € R# )u3   Clean shutdown â€” flush queues, close connections.Nr   rS   s   &r   ÚshutdownÚMemoryProvider.shutdown§   rV   r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úturn_numberr9   Úmessager%   r   r]   r   )r   s   "r   r   rQ   ¬   s&   € ÷ oñ o¨ð o°sð oÈñ or   c                ó   € R# )a7  Per-turn tick. kwargs may include remaining_tokens, model, platform, tool_count, author_id, author_name,
author_is_bot. The author trio names who wrote THIS turn (None, None, False without one): a shared session
carries several participants, so a provider keying durable state on identity must read it per turn.Nr   )rT   r’   r“   r   s   &&&,r   Úon_turn_startÚMemoryProvider.on_turn_start¬   rV   r   c               ó   € V ^8„  d   QhRR/# )r   r   rˆ   r   )r   s   "r   r   rQ   ±   s   € ÷ ñ  Nñ r   c                ó   € / # )a)  Identity-mapping values that must bust a cached gateway agent when they change (writer identity, alias
tables, session-name prefixing). Provider-namespaced keys, JSON-serializable values. The gateway calls this
on an uninitialized instance on every inbound message, so keep it cheap and read-only.r   rS   s   &r   Úidentity_signatureÚ!MemoryProvider.identity_signature±   s	   € ð ˆ	r   c               ó    € V ^8„  d   QhRRRR/# )r   rx   r‚   r   r]   r   )r   s   "r   r   rQ   ·   s   € ÷ `ñ `Ð';ð `Àñ `r   c                ó   € R# )zQEnd-of-session extraction; fires only at real session boundaries, never per-turn.Nr   ©rT   rx   s   &&r   Úon_session_endÚMemoryProvider.on_session_end·   rV   r   Úparent_session_idÚresetFÚrewoundc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   Únew_session_idr%   r    r¡   r&   r¢   r   r]   r   )r   s   "r   r   rQ   º   s4   € ÷ 5ñ 5Ø!ð5Ø9<ð5ØJNð5Øaeð5à	ñ5r   c               ó   € R# )a$  session_id reassigned mid-process (/resume, /branch, /reset, /new, compression)
without teardown: rebind per-session state so later writes land in the right record.
``reset`` is True only for a genuinely new conversation (flush buffers); ``rewound``:
same id but the transcript was truncated.Nr   )rT   r¤   r    r¡   r¢   r   s   &&$$$,r   Úon_session_switchÚ MemoryProvider.on_session_switchº   rV   r   c               ó    € V ^8„  d   QhRRRR/# )r   rx   r‚   r   r%   r   )r   s   "r   r   rQ   Â   s   € ÷ ñ Ð(<ð Àñ r   c                ó   € R# )zWExtract insights from ``messages`` about to be compressed, fed into the summary prompt.r0   r   r�   s   &&r   Úon_pre_compressÚMemoryProvider.on_pre_compressÂ   re   r   Úchild_session_idc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Útaskr%   Úresultr¬   r   r]   r   )r   s   "r   r   rQ   Æ   s/   € ÷ hñ h #ð h¨sð hÈð hÐ`dñ hr   c               ó   € R# )zYPARENT-side observation of a completed delegation (the subagent has no provider session).Nr   )rT   r®   r¯   r¬   r   s   &&&$,r   Úon_delegationÚMemoryProvider.on_delegationÆ   rV   r   c               ó   € V ^8„  d   QhRR/# r�   r   )r   s   "r   r   rQ   É   s   € ÷ ñ Ð#7ñ r   c                ó   € . # )a4  Setup fields for ``hermes memory setup`` ([] if none): ``key``, ``description``,
optional ``secret`` (goes to .env), ``required``, ``default``, ``choices``, ``type``
(text | integer | number | boolean), ``minimum``/``maximum``/``step``, ``url``,
``env_var`` (explicit secret env var; default auto-generated).r   rS   s   &r   Úget_config_schemaÚ MemoryProvider.get_config_schemaÉ   s	   € ð
 ˆ	r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úvaluesrˆ   Úhermes_homer%   r   r]   r   )r   s   "r   r   rQ   Ð   s&   € ÷ Yñ Y .ð Y¸sð YÀtñ Yr   c                ó   € R# )z¤Write non-secret setup ``values`` to the provider's native config. Plugins MUST either
override this or use only env vars (every schema field carrying ``env_var``).Nr   )rT   r¸   r¹   s   &&&r   Úsave_configÚMemoryProvider.save_configÐ   rV   r   c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   Úactionr%   r#   ÚcontentÚmetadatar(   r   r]   r   )r   s   "r   r   rQ   Ô   s1   € ÷ ñ  cð °3ð Àð ÐPhð Ðtxñ r   c                ó   € R# )aB  Mirror a built-in memory-tool write (``action``: add | replace | remove; ``target``:
memory | user; ``metadata``: provenance such as write_origin, session_id, tool_name).
For replace/remove, ``metadata["previous_content"]`` is the full entry selected
under the native-store lock. A memory-tool patch arrives as a replace whose
``content`` is the whole entry after the edit. Notifications follow a successful complete write
or batch; each batch operation sees the preceding operation's result. Older
callers may omit this field: ``old_text`` alone is not authoritative identity.
Nr   )rT   r¾   r#   r¿   rÀ   s   &&&&&r   Úon_memory_writeÚMemoryProvider.on_memory_writeÔ   rV   r   c               ó   € V ^8„  d   QhRR/# )r   r   z	list[str]r   )r   s   "r   r   rQ   Þ   s   € ÷ ñ ˜iñ r   c                ó   € . # )z®Absolute paths of provider state OUTSIDE HERMES_HOME for ``hermes backup``/``import``
(paths outside the home dir are skipped). MUST work without ``initialize()`` or network.r   rS   s   &r   Úbackup_pathsÚMemoryProvider.backup_pathsÞ   s	   € ð ˆ	r   r   r   )r<   r=   r>   r?   r@   Ú#pre_compress_checkpoint_api_versionÚpropertyr   r$   rY   r_   rc   rh   rn   rr   rv   r~   r„   r‹   r�   r•   r™   rž   r¦   rª   r±   rµ   r»   rÂ   rÆ   rC   r   r   r   rN   rN   T   s  † ñð, +,Ð'àØôZó ó ðZð
 ôhó ðhð ôó ðõõð¸÷ ð
[¸b÷ [õð
NàðNàIMðNð 15÷Nð ôcó ðcõ\õBõ
oõ
õ`ð5Ø?Að5ØQVð5Øhm÷5õðhÈr÷ hõõY÷÷ñ r   rN   r   >   r0   ÚnoneÚbuiltinÚdefaultúbuilt-inzí^(yes|no|ok|okay|sure|thanks|thank you|y|n|yep|nope|yeah|nah|hi|hey|hello|yo|sup|continue|go ahead|do it|proceed|got it|cool|nice|great|done|next|lgtm|k)[\s!?.:;,"'~\u2018\u2019\u201c\u201d\u2014\u2013\u2026()\[\]{}<>*&^%$#@!+=`\u00a0]*$)"r@   Ú
__future__r   r   ÚloggingÚrer*   Úabcr   r   Údataclassesr   Útypingr   r   r   r	   r
   Ú	getLoggerr<   Úloggerr    r,   Ú#PRE_COMPRESS_CHECKPOINT_API_VERSIONrB   Ú	frozensetr3   r4   r7   ÚcompileÚ
IGNORECASErI   rL   rN   r   r   r   Ú<module>rÚ      sÒ   ðñõ #ã Û Û 	Û ß #Ý !ß 6Õ 6à	×	Ò	˜8Ó	$€õ@ðjÐRVð jØ')ðjØNR÷jð '(Ð #ð €ñ "+Ò+YÓ!ZÐ õMñ
 �$Ô÷!ð !ó ð!ð —J’Jðgð ‡M�MóÐ õ3ôM�Sö Mr   