Ë
    áß²j¥¯  ã                  óP  — 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	m
Z
mZmZ ddlmZ ddlmZmZmZmZmZ ddlmZmZmZmZ ddlmZ dd	lmZmZ dd
lm Z   ejB                  e"«      Z#dZ$dZ%dZ&d#d„Z'd$d„Z(d%d„Z)d&d„Z*d'ddœ	 	 	 d(d„Z+d)d„Z,d*d„Z-d+d„Z. ej^                  dej`                  «      Z1 ej^                  dej`                  «      Z2 ej^                  dej`                  «      Z3d,d„Z4 G d„ d«      Z5 ej^                  d«      Z6d,d„Z7d-d „Z8 G d!„ d"«      Z9y).uß   MemoryManager â€” fans the agent's memory hooks out to registered providers.

The builtin provider is always allowed; only ONE external plugin provider may be
registered at a time (tool-schema bloat, conflicting backends).
é    )ÚannotationsN)ÚFutureÚThreadPoolExecutorÚwait)Úpartial)ÚAnyÚCallableÚDictÚListÚOptional)ÚMemoryProviderÚ#PRE_COMPRESS_CHECKPOINT_API_VERSIONÚ	ctx_boundÚspawn_context_thread)Ú+extract_user_instruction_from_skill_message)Úget_spill_configÚspill_if_oversized)Ú
tool_erroré   g      @g       @c                ól   — 	 t        j                  | «      j                  S # t        t        f$ r Y yw xY w)zU``fn``'s parameter mapping, or None when uninspectable (C callables, exotic proxies).N)ÚinspectÚ	signatureÚ
parametersÚ	TypeErrorÚ
ValueError)Úfns    ú9/home/ubuntu/.hermes/hermes-agent/agent/memory_manager.pyÚ_signature_paramsr   %   s5   € ðÜ× Ñ  Ó$×/Ñ/Ð/øÜ”zÐ"ò Ùðús   ‚! ¡3²3c                óB   — t        d„ | j                  «       D «       «      S )Nc              3  óh   K  — | ]*  }|j                   t        j                  j                  u –— Œ, y ­w©N)Úkindr   Ú	ParameterÚVAR_KEYWORD©Ú.0Úps     r   ú	<genexpr>z"_has_var_kwargs.<locals>.<genexpr>.   s%   è ø€ ÒP¸1ˆq�v‰vœ×*Ñ*×6Ñ6Ô6ÑPùó   ‚02)ÚanyÚvalues)Úparamss    r   Ú_has_var_kwargsr-   -   s   € ÜÑPÀÇÁÃÔPÓPÐPó    c                óÜ   — t        | «      }|€yt        |j                  d«      dd«      }t        |«      xs6 |t        j
                  j                  t        j
                  j                  fv S )a#  True if ``fn`` can receive the ``require_checkpoint`` keyword (unreadable signatures -> False).

    Bare-shape v2 providers (``on_pre_compress(self, messages)``) would raise TypeError on the
    keyword, which the host would re-raise as a checkpoint failure despite a successful write.
    NFÚrequire_checkpointr"   )r   ÚgetattrÚgetr-   r   r#   ÚKEYWORD_ONLYÚPOSITIONAL_OR_KEYWORD)r   r,   r"   s      r   Ú_accepts_require_checkpointr5   1   s`   € ô ˜rÓ"€FØ€~ØÜ�6—:‘:Ð2Ó3°V¸TÓB€DÜ˜6Ó"Òw d¬w×/@Ñ/@×/MÑ/MÌw×O`ÑO`×OvÑOvÐ.wÐ&wÐwr.   c                óä   — t        | t        «      sy| j                  d«      dk(  r$t        | j                  d«      t        «      r| d   } | j                  dd«      }|rt        |t        «      r| S dS )a`  Return a bare function-tool dict with a resolvable top-level ``name``, else None.

    Providers should return ``{"name", "description", "parameters"}`` but some return the
    wrapped OpenAI form; wrapping that twice yields a nameless ``function`` and strict
    providers (DeepSeek) reject the ENTIRE request, so both shapes are normalized here.
    NÚtypeÚfunctionÚnameÚ )Ú
isinstanceÚdictr2   Ústr)Úschemar9   s     r   Únormalize_tool_schemar?   @   sd   € ô �fœdÔ#ØØ‡z�z�&Ó˜ZÒ'¬J°v·z±zÀ*Ó7MÌtÔ,TØ˜
Ñ#ˆØ�:‰:�f˜bÓ!€DÙœj¨¬sÔ3ˆ6Ð=¸Ð=r.   F©Úmemory_tool_presentc               ó®   ‡— |rd|v ry|s| €y| syd| v ry	 ddl mŠ t        ˆfd„| D «       «      S # t        $ r t        j                  dd¬«       Y yw xY w)	z@Return whether external memory-provider tools should be exposed.ÚmemoryFTr   )Úresolve_toolsetc              3  ó2   •K  — | ]  }d  ‰|«      v –— Œ y­w©rC   N© )r&   r9   rD   s     €r   r(   z0memory_provider_tools_enabled.<locals>.<genexpr>]   s   øè ø€ ÒR¸�8™¨tÓ4Ô4ÑRùs   ƒz<Failed to resolve enabled toolsets for memory-provider tools©Úexc_info)ÚtoolsetsrD   r*   Ú	ExceptionÚloggerÚdebug)Úenabled_toolsetsÚdisabled_toolsetsrA   rD   s      @r   Úmemory_provider_tools_enabledrP   O   so   ø€ ñ ˜XÐ):Ñ:ØÙÐ.Ð6ØÙØØÐ#Ñ#ØðÝ,äÓRÐAQÔRÓRÐRøÜò Ü�‰ÐSÐ^bˆÔcÙðús   —1 ± AÁAc                óh   — t        | t        «      r!| j                  di «      j                  d«      S d S )Nr8   r9   )r;   r<   r2   )Útools    r   Ú
_tool_namerS   c   s,   € Ü3=¸dÄDÔ3Iˆ4�8‰8�J Ó#×'Ñ'¨Ó/ÐSÈtÐSr.   c                óÀ   — t        | dd«      }t        |t        t        f«      xr t	        d„ |D «       «      }t        | dd«      t        | dd«      }}t        |||¬«      S )zÛWhether external memory-provider tools are exposed on ``agent``.

    Same gate as ``inject_memory_provider_tools`` so a provider's ``system_prompt_block()``
    never advertises tools absent from the tool surface.
    ÚtoolsNc              3  ó8   K  — | ]  }t        |«      d k(  –— Œ y­wrF   )rS   )r&   Úts     r   r(   z0memory_provider_tools_exposed.<locals>.<genexpr>n   s   è ø€ Ò6`ÐUV´zÀ!³}ÈÕ7PÑ6`ùs   ‚rN   rO   r@   )r1   r;   ÚlistÚtupler*   rP   )ÚagentrU   ÚpresentÚenabledÚdisableds        r   Úmemory_provider_tools_exposedr^   g   sa   € ô �E˜7 DÓ)€EÜ˜¤¤u Ó.Ò`´3Ñ6`ÐZ_Ô6`Ó3`€GÜ Ð'9¸4Ó@Ä'È%ÐQdÐfjÓBkˆX€GÜ(¨°(ÐPWÔXÐXr.   c                ó$  — t        | dd«      }t        | dd«      }|r|€yt        | «      sst        |dd«      xs g D �cg c]  }t        |dd«      dk7  r|‘Œ }}|rBt        j                  d	|D �cg c]"  }t        |dt	        |«      j
                  «      ‘Œ$ c}«       yt        |d
d«      }t        |«      syt        | dd«      €t        «       | _        |D �ch c]  }t        |t        «      sŒt        |«      ’Œ  }}d} |«       D ]y  }	t        |	«      }
|
€t        j                  d|	«       Œ'|
d   |vsŒ/|j                  d|
dœ«       | j                  j                  |
d   «       |j                  |
d   «       |dz  }Œ{ |S c c}w c c}w c c}w )zZAppend external memory-provider tool schemas to an agent tool surface; return count added.Ú_memory_managerNrU   r   Ú	providersr9   r:   ÚbuiltinuÃ   Memory provider(s) %s configured but the 'memory' toolset is gated off for this session (platform_toolsets / agent.disabled_toolsets) â€” provider tools and system-prompt block are both withheld.Úget_all_tool_schemasÚvalid_tool_nameszlMemory provider returned a tool schema with no resolvable name; skipping to avoid poisoning the request (%r)r8   )r7   r8   r   )r1   r^   rL   Úinfor7   Ú__name__ÚcallableÚsetrd   r;   r<   rS   r?   ÚwarningÚappendÚadd)rZ   Úmemory_managerrU   r'   Ú
_providersÚget_schemasrR   Úexisting_tool_namesÚaddedÚ
raw_schemar>   s              r   Úinject_memory_provider_toolsrr   s   s©  € ä˜UÐ$5°tÓ<€NÜ�E˜7 DÓ)€EÙ˜U˜]Øä(¨Ô/ô ")¨¸ÀdÓ!KÒ!QÈrö >˜AÜ   F¨BÓ/°9Ò<ò ð >ˆ
ð >áÜ�K‰Kð+ð @JÖJ¸!”˜˜F¤D¨£G×$4Ñ$4Õ5ÒJôð ä˜.Ð*@À$ÓG€KÜ�KÔ ØäˆuÐ(¨$Ó/Ð7Ü!$£ˆÔØ8=ÖX°ÄÈDÔRVÕAWœ: dÕ+ÐXÐÐXØ€EÙ!“mò ˆ
Ü& zÓ2ˆØˆ>Ü�N‰NðEØFPõð �F‰^Ð#6Ò6Ø�L‰L *¸&ÑAÔBØ×"Ñ"×&Ñ& v¨f¡~Ô6Ø×#Ñ# F¨6¡NÔ3Ø�Q‰J‰Eðð €LùòA>ùò Kùò Ys   ¾FÁ/'F
ÃFÃ-Fz</?\s*memory-context\s*>z5<\s*memory-context\s*>[\s\S]*?</\s*memory-context\s*>z¨\[System note:\s*The following is recalled memory context,\s*NOT new user input\.\s*Treat as (?:informational background data|authoritative reference data[^\]]*)\.\]\s*c                óV   — t         t        t        fD ]  }|j                  d| «      } Œ | S )zQStrip fence tags, injected context blocks, and system notes from provider output.r:   )Ú_INTERNAL_CONTEXT_REÚ_INTERNAL_NOTE_REÚ_FENCE_TAG_REÚsub)ÚtextÚpatterns     r   Úsanitize_contextrz   «   s.   € ä(Ô*;¼]ÐKò %ˆØ�{‰{˜2˜tÓ$‰ð%à€Kr.   c                  ób   — e Zd ZdZdZdZdd„Zdd„Zdd„Zdd„Z	e
dd„«       Zdd	„Zdd
„Zdd„Zy)ÚStreamingContextScrubberan  Stateful scrubber for streaming text whose memory-context spans may straddle deltas.

    ``sanitize_context`` needs both tags in one string, so a split span would leak to the UI;
    this holds back partial-tag tails between ``feed()`` calls and drops span interiors.
    One scrubber (or ``reset()``) per top-level response; call ``flush()`` at end of stream.
    z<memory-context>z</memory-context>c                ó$   — | j                  «        y r!   )Úreset©Úselfs    r   Ú__init__z!StreamingContextScrubber.__init__½   s   € Ø�
‰
�r.   c                ó.   — d| _         d| _        d| _        y )NFr:   T)Ú_in_spanÚ_bufÚ_at_block_boundaryr   s    r   r~   zStreamingContextScrubber.resetÀ   s   € Ø#ˆŒØˆŒ	Ø(,ˆÕr.   c                óæ  — |sy| j                   |z   }d| _         g }|�rC| j                  r>| j                  }|j                  «       j	                  |«      }| j                  ||«      }nv| j                  }| j                  |«      }t        |«      }|j                  «       j                  |«      r| j                  |d|  «      r|nd}|xs | j                  ||«      }|dk(  r6| j                  s| j                  ||r|d|  n|«       |r|| d nd| _         nH| j                  s| j                  ||d| «       ||t        |«      z   d }| j                   | _        |r�ŒCdj                  |«      S )z^Return the visible portion of ``text``; a possible partial tag tail is held for the next call.r:   Nr   éÿÿÿÿ)r„   rƒ   Ú
_CLOSE_TAGÚlowerÚfindÚ_max_partial_suffixÚ	_OPEN_TAGÚ_find_boundary_open_tagÚlenÚendswithÚ_ends_at_block_boundaryÚ_append_visibleÚjoin)	r€   rx   ÚbufÚoutÚtagÚidxÚheldÚnÚpendings	            r   ÚfeedzStreamingContextScrubber.feedÅ   s_  € áØØ�i‰i˜$ÑˆØˆŒ	ØˆÚØ�}Š}Ø—o‘o�Ø—i‘i“k×&Ñ& sÓ+�Ø×/Ñ/°°SÓ9‘à—n‘n�Ø×2Ñ2°3Ó7�ä˜“H�Ø"Ÿy™y›{×3Ñ3°CÔ8¸T×=YÑ=YÐZ]Ð^aÐ`aÐ_aÐZbÔ=c™!Ðij�ØÒD $×":Ñ":¸3ÀÓ"D�Ø�bŠyà—}’}Ø×(Ñ(¨¹T¨c°&°D°5©kÀsÔKÙ+/˜C   ™K°R�”	ØØ—=’=Ø×$Ñ$ S¨#¨d¨s¨)Ô4Ø�cœC ›H‘n�oÐ&ˆCØ $§¡Ð-ˆDŒMó+ ð, �w‰w�s‹|Ðr.   c                óV   — | j                   rdn| j                  }d| _        d| _         |S )z Emit the held-back tail at end-of-stream; inside an unterminated span it is discarded
        (leaking partial memory context is worse than a truncated answer).r:   F)rƒ   r„   )r€   Útails     r   ÚflushzStreamingContextScrubber.flushä   s(   € ð —]’]‰r¨¯	©	ˆØˆŒ	ØˆŒØˆr.   c                óÌ   ‡‡— |j                  «       | j                  «       cŠŠt        t        t        ‰«      t        ‰«      dz
  «      dd«      }t	        ˆˆfd„|D «       d«      S )zXLength of the longest buf-suffix that is a (case-insensitive) prefix of ``tag``, else 0.r   r   r‡   c              3  óN   •K  — | ]  }‰j                  ‰| d  «      sŒ|–— Œ y ­wr!   )Ú
startswith)r&   ÚiÚ	buf_lowerÚ	tag_lowers     €€r   r(   z?StreamingContextScrubber._max_partial_suffix.<locals>.<genexpr>ñ   s&   øè ø€ ÒM˜1¨	×(<Ñ(<¸YÈÀrÀs¸^Õ(L”QÑMùs   ƒ%ž%)r‰   ÚrangeÚminrŽ   Únext)r“   r•   Úspanr¢   r£   s      @@r   r‹   z,StreamingContextScrubber._max_partial_suffixì   sR   ù€ ð  #Ÿy™y›{¨C¯I©I«KÐˆ	�9Ü”Sœ˜Y›¬¨Y«¸!Ñ);Ó<¸aÀÓDˆÜÔM ÔMÈqÓQÐQr.   c                ó8  — |j                  «       t        | j                  «      }}|j                  | j                  «      }|dk7  rU||z   }| j	                  |d| «      r|t        |«      k  r	||   dv r|S |j                  | j                  |dz   «      }|dk7  rŒUy)zVFind an opening fence only when it starts a block-like span (own line, newline after).r‡   Nz
r   )r‰   rŽ   rŒ   rŠ   r�   )r€   r“   r¢   Útag_lenr–   Ú	after_idxs         r   r�   z0StreamingContextScrubber._find_boundary_open_tagó   s•   € à ŸY™Y›[¬#¨d¯n©nÓ*=�7ˆ	Ø�n‰n˜TŸ^™^Ó,ˆØ�RŠiØ˜g™ˆIØ×+Ñ+¨C°°¨IÔ6¸9ÄsÈ3ÃxÒ;OÐTWÐXaÑTbÐflÑTlØ�
Ø—.‘. §¡°°q±Ó9ˆCð	 �R‹ið
 r.   c                óˆ   — |j                  d«      \  }}}|j                  «       dk(  xr t        |«      xs | j                  S )z¨Whether emitting ``text`` leaves the stream at a line start (blank tail after the last newline;
        no newline at all -> only whitespace and already at a boundary).ú
r:   )Ú
rpartitionÚstripÚboolr…   )r€   rx   ÚheadÚseprœ   s        r   r�   z0StreamingContextScrubber._ends_at_block_boundaryþ   s=   € ð Ÿ/™/¨$Ó/‰ˆˆc�4Ø�z‰z‹|˜rÑ!ÒL¤t¨C£yÒ'K°D×4KÑ4KÐLr.   c                óX   — |r(|j                  |«       | j                  |«      | _        y y r!   )rj   r�   r…   )r€   r”   rx   s      r   r‘   z(StreamingContextScrubber._append_visible  s)   € ÙØ�J‰J�tÔØ&*×&BÑ&BÀ4Ó&HˆDÕ#ð r.   N©ÚreturnÚNone©rx   r=   r´   r=   ©r´   r=   )r“   r=   r•   r=   r´   Úint)r“   r=   r´   r¸   )rx   r=   r´   r¯   )r”   z	list[str]rx   r=   r´   rµ   )rf   Ú
__module__Ú__qualname__Ú__doc__rŒ   rˆ   r�   r~   rš   r�   Ústaticmethodr‹   r�   r�   r‘   rG   r.   r   r|   r|   ²   sN   „ ñð #€IØ$€Jóó-ó
ó>ð òRó ðRó	óMôIr.   r|   z
[-*+]\s+\Sc                ó>  — | j                  d«      }t        «       }g }t        |«      D ]â  \  }}|j                  «       }|r%|d   j	                  «       r|j                  |«       Œ=t        t        j                  |«      «      }|r|s|j                  «        |ra|dz   t        |«      k  r||dz      nd}t        |j                  «       «      xr |d   j	                  «       }	|	s||v rŒÁ|j                  |«       |j                  |«       Œä dj                  |«      S )uš  Drop a recalled bullet that an EARLIER line of this same block already states.

    Providers merge several stores (and this merges several providers), so one prefetch routinely
    surfaces the same fact two or three times. A byte-identical repeat inside one block tells the
    model nothing the block has not already said, and it is not free: the composed block is stamped
    into the user row's ``api_content`` sidecar and replayed verbatim on every later request for as
    long as that row is in context, so each duplicate is paid once per turn, forever.

    The ``seen`` set is scoped per section â€” every non-bullet line at column 0 (a heading of any
    style, a ``---`` rule, prose) starts a new one â€” so a repeat is only dropped when the SAME
    section already states it.

    Only a SELF-CONTAINED bullet is considered â€” a marker, whitespace, content, and no continuation
    line indented beneath it. A bullet that carries continuation lines is never dropped and never
    suppresses a later one, because two entries can share a headline and differ underneath it
    (``- prefers draft PRs`` / ``  (logged 12 Jan, builtin)`` vs the same headline logged elsewhere):
    dropping one would re-parent its provenance under the other and invent a record neither provider
    reported. Headings â€” including ``**bold**`` ones â€” prose, blank lines, separators and numbered
    items are left exactly as written.
    r¬   r   r   r:   )Úsplitrh   Ú	enumerater®   Úisspacerj   r¯   Ú_RECALL_BULLET_REÚmatchÚclearrŽ   rk   r’   )
rx   ÚlinesÚseenÚkeptÚindexÚlineÚstrippedÚ	is_bulletÚ	followingÚcarries_continuations
             r   Ú_drop_repeated_recall_linesrÍ     s  € ð* �J‰J�tÓ€EÜ“U€DØ€DÜ  Ó'ò ‰ˆˆtØ—:‘:“<ˆñ ˜˜Q™Ÿ™Ô)Ø�K‰K˜ÔØÜÔ*×0Ñ0°Ó:Ó;ˆ	á™IØ�J‰JŒLÙØ,1°A©I¼¸E»
Ò,B˜˜e a™iÒ(ÈˆIÜ#'¨	¯©Ó(9Ó#:Ò#U¸yÈ¹|×?SÑ?SÓ?UÐ Ù'Ø˜tÑ#ØØ—‘˜Ô"Ø�‰�DÕð%ð& �9‰9�T‹?Ðr.   c                ó”   — | r| j                  «       syt        | «      }|| k7  rt        j                  d«       t	        |«      }d|› d�S )z:Wrap prefetched memory in a fenced block with system note.r:   z6memory provider returned pre-wrapped context; strippeduÐ   <memory-context>
[System note: The following is recalled memory context, NOT new user input. Treat as authoritative reference data â€” this is the agent's persistent memory and should inform all responses.]

z
</memory-context>)r®   rz   rL   ri   rÍ   )Úraw_contextÚ	sanitizedÚcleans      r   Úbuild_memory_context_blockrÒ   =  sX   € á˜k×/Ñ/Ô1ØÜ  Ó-€IØ�KÒä�‰ÐOÔPÜ'¨	Ó2€Eð	Vð ˆ'ð ð		ðr.   c                  ó2  — e Zd ZdZddœd5d„Zej                  dddœ	 	 	 	 	 d6d„Zd7d„Ze	d8d	„«       Z
d9d
„Zd:d„Z ee«      Zddœd;d„Zddœd<d„Zd:d„Zddœd=d„Zed>d„«       Zddddœ	 	 	 	 	 d?d„Zddœd@d„ZdAd„ZdBdCd„ZdDd„ZdEd„ZdFd„ZdGd„ZdHd„ZdId„Zdd d!œ	 	 	 	 	 dJd"„Zdddd#œ	 	 	 dKd$„Z edLd%„«       Z!e"fdMd&„Z#dde"d'œ	 	 	 	 	 	 	 dNd(„Z$edOd)„«       Z%	 dB	 	 	 dPd*„Z&h d+£Z'edQd,„«       Z(dd-œ	 	 	 dRd.„Z)dd/œdSd0„Z*dTd1„Z+e	dUd2„«       Z,dTd3„Z-dVd4„Z.y)WÚMemoryManagerz¿Builtin provider (always first) plus at most one external provider.

    Failures in one provider never block the other: every fan-out hook logs and
    swallows per-provider exceptions.
    N)Úexternal_prefetch_timeoutc               óH  — g | _         i | _        d | _        d| _        |}|€t        n
t        |«      }|dk  rt        d«      ‚|| _        i | _        t        j                  «       | _        d | _        t        j                  «       | _        i | _        d| _        dddddœ| _        y )NFr   z*external_prefetch_timeout must be positiveÚnot_started©ÚstatusÚabandoned_writesÚabandoned_prefetchesÚactive_tasks)rm   Ú_tool_to_providerÚ_external_prefetch_spill_configÚ_has_externalÚ_EXTERNAL_PREFETCH_TIMEOUT_SÚfloatr   Ú_external_prefetch_timeoutÚ_external_prefetch_threadsÚ	threadingÚLockÚ_external_prefetch_lockÚ_sync_executorÚ_sync_executor_lockÚ_background_futuresÚ_shutting_downÚ_shutdown_drain_state)r€   rÕ   Útimeouts      r   r�   zMemoryManager.__init__W  s©   € Ø02ˆŒØ<>ˆÔØIMˆÔ,Ø#(ˆÔØ+ˆØ29°/Õ.ÄuÈWÃ~ˆØ�aŠ<ÜÐIÓJÐJØ*1ˆÔ'ØGIˆÔ'Ü'0§~¡~Ó'7ˆÔ$ð =AˆÔÜ#,§>¡>Ó#3ˆÔ ð 79ˆÔ Ø#ˆÔà#¸ÐTUÐghñ6
ˆÕ"r.   F)Úlevelra   rI   c          
     óÚ   — g }|€| j                   n|D ]  }	 |j                   ||«      «       Œ |S # t        $ r/}t        j	                  |d|j
                  |||¬«       Y d}~ŒRd}~ww xY w)z´Call ``call(provider)`` per provider, logging+swallowing failures; returns successes in order.
        ``label`` completes the log line ``Memory provider '<name>' <label>: <exc>``.NzMemory provider '%s' %s: %srH   )rm   rj   rK   rL   Úlogr9   )	r€   ÚlabelÚcallrí   ra   rI   ÚresultsÚproviderÚes	            r   Ú_each_providerzMemoryManager._each_providero  sy   € ð  ˆØ+4Ð+<˜ŸšÀ)ò 	mˆHðmØ—‘™t H›~Õ.ð	mð
 ˆøô ò mÜ—
‘
˜5Ð"?ÀÇÁÐPUÐWXÐck�
×lÑlûðmús   —2²	A*»%A%Á%A*c                óø  — |j                   dk7  rK| j                  r?t        d„ | j                  D «       d«      }t        j                  d|j                   |«       yt        |j                  «       «      }|j                   dk7  rd| _        t        «       | _	        | j                  j                  |«       ddlm} |D ]’  }t        |«      }|€Œ|d	   }||v r"t        j                  d
|j                   |«       Œ<|| j                  v r:t        j                  d|| j                  |   j                   |j                   «       Œ„|| j                  |<   Œ” t        j                  d|j                   t!        |«      «       y)zHRegister a provider; builtin always accepted, only ONE external allowed.rb   c              3  óT   K  — | ]   }|j                   d k7  sŒ|j                   –— Œ" y­w)rb   N©r9   r%   s     r   r(   z-MemoryManager.add_provider.<locals>.<genexpr>~  s   è ø€ ÒT¨ÀÇÁÈ)Ó@S˜QŸV�VÑTùs   ‚(—(Úunknownu¿   Rejected memory provider '%s' â€” external provider '%s' is already registered. Only one external memory provider is allowed at a time. Configure which one via memory.provider in config.yaml.NTr   ©Ú_HERMES_CORE_TOOLSr9   u¡   Memory provider '%s' tool '%s' shadows a reserved core tool name; registration ignored. Core tools always win â€” rename the provider's tool to something unique.zJMemory tool name conflict: '%s' already registered by %s, ignoring from %sz*Memory provider '%s' registered (%d tools))r9   rß   r¦   rm   rL   ri   rX   Úget_tool_schemasr   rÞ   rj   rJ   rû   r?   rÝ   re   rŽ   )r€   ró   ÚexistingÚschemasrû   rq   r>   Ú	tool_names           r   Úadd_providerzMemoryManager.add_provider{  sX  € à�=‰=˜IÒ%¨$×*<Ò*<ÜÑT¨T¯_©_ÔTÐV_Ó`ˆHÜ�N‰Nð"ð $,§=¡=°(ô	ð ô
 �x×0Ñ0Ó2Ó3ˆà�=‰=˜IÒ%Ø!%ˆDÔÜ3CÓ3EˆDÔ0à�‰×Ñ˜xÔ(õ 	0à!ò 	=ˆJÜ*¨:Ó6ˆFØˆ~ØØ˜v™ˆIØÐ.Ñ.Ü—‘ðFàGOÇ}Á}ÐV_õð
 ˜d×4Ñ4Ñ4Ü—‘ð'Ø(1°4×3IÑ3IÈ)Ñ3T×3YÑ3YÐ[c×[hÑ[hõð
 5=�×&Ñ& yÒ1ð#	=ô& 	�‰Ð@À(Ç-Á-ÔQTÐU\ÓQ]Õ^r.   c                ó,   — t        | j                  «      S r!   )rX   rm   r   s    r   ra   zMemoryManager.providers®  s   € ä�D—O‘OÓ$Ð$r.   c                óB   ‡— t        ˆfd„| j                  D «       d «      S )Nc              3  óB   •K  — | ]  }|j                   ‰k(  sŒ|–— Œ y ­wr!   rø   )r&   r'   r9   s     €r   r(   z-MemoryManager.get_provider.<locals>.<genexpr>³  s   øè ø€ ÒB˜1°1·6±6¸T³>”QÑBùs   ƒ˜)r¦   rm   )r€   r9   s    `r   Úget_providerzMemoryManager.get_provider²  s   ø€ ÜÓB §¡ÔBÀDÓIÐIr.   c                óx   — | j                  dd„ t        j                  ¬«      }dj                  d„ |D «       «      S )zKJoin every provider's non-empty ``system_prompt_block()`` with blank lines.zsystem_prompt_block() failedc                ó"   — | j                  «       S r!   )Úsystem_prompt_block©r'   s    r   ú<lambda>z3MemoryManager.build_system_prompt.<locals>.<lambda>·  s   € Èq×OdÑOdÓOf€ r.   ©rí   ú

c              3  óH   K  — | ]  }|sŒ|j                  «       sŒ|–— Œ y ­wr!   ©r®   )r&   Úbs     r   r(   z4MemoryManager.build_system_prompt.<locals>.<genexpr>¹  s   è ø€ Ò@ ²°a·g±gµiœ1Ñ@ùó   ‚"Š"›")rõ   ÚloggingÚWARNINGr’   )r€   Úblockss     r   Úbuild_system_promptz!MemoryManager.build_system_promptµ  s9   € à×$Ñ$Ð%CÑEfÜ,3¯O©Oð %ó =ˆà�{‰{Ñ@ fÔ@Ó@Ð@r.   r:   ©Ú
session_idc               óŽ   ‡ ‡‡— ‰ j                  |«      Š‰sy‰ j                  dˆˆ ˆfd„«      }dj                  d„ |D «       «      S )zMMerge non-empty prefetch context from all providers (failures are non-fatal).r:   zprefetch failed (non-fatal)c                ó,   •— ‰j                  | ‰‰¬«      S ©Nr  )Ú_prefetch_provider)r'   Úclean_queryr€   r  s    €€€r   r	  z,MemoryManager.prefetch_all.<locals>.<lambda>Å  s   ø€ °T×5LÑ5LÈQÐP[ÐhrÐ5LÓ5s€ r.   r  c              3  óH   K  — | ]  }|sŒ|j                  «       sŒ|–— Œ y ­wr!   r  r%   s     r   r(   z-MemoryManager.prefetch_all.<locals>.<genexpr>Ç  s   è ø€ Ò? ªq°Q·W±WµYœ1Ñ?ùr  )Ú_strip_skill_scaffoldingrõ   r’   )r€   Úqueryr  Úpartsr  s   ` ` @r   Úprefetch_allzMemoryManager.prefetch_all¿  sF   ú€ à×3Ñ3°EÓ:ˆÙØØ×#Ñ#Ø)Õ+só
ˆð �{‰{Ñ? eÔ?Ó?Ð?r.   c               ó$  ‡‡‡‡— ‰j                   dk(  r‰j                  ‰‰¬«      S i Šdˆˆˆˆfd„}t        |d‰j                   › �¬«      }| j                  5  | j                  j                  ‰j                   «      }|�:|j                  «       r*t        j                  d‰j                   «       	 ddd«       y|| j                  ‰j                   <   |j                  «        ddd«       |j                  | j                  «       |j                  «       r,t        j                  d	‰j                   | j                  «       y| j                  5  | j                  j                  ‰j                   «      |u r&| j                  j                  ‰j                   d«       ddd«       d
‰v r‰d
   ‚‰j                  dd«      }|r6|j                  «       r&t        |‰‰j                   › d�| j                   ¬«      }|S # 1 sw Y   �ŒxY w# 1 sw Y   ŒkxY w)zÇRun one provider's prefetch; external providers are bounded by a timeout. A stuck external
        call keeps running on its daemon thread and the provider is skipped on later turns until it returns.rb   r  c                 ór   •— 	 ‰j                  ‰‰¬«      xs d‰d<   y # t        $ r} | ‰d<   Y d } ~ y d } ~ ww xY w)Nr  r:   ÚvalueÚerror)ÚprefetchrK   )Úexcró   r  Ú
result_boxr  s    €€€€r   Ú_runz.MemoryManager._prefetch_provider.<locals>._runÑ  sB   ø€ ð*Ø&.×&7Ñ&7¸È*Ð&7Ó&UÒ&[ÐY[�
˜7Ò#øÜò *Ø&)�
˜7Ö#ûð*ús   ƒ ž	6§1±6zmemory-prefetch-rø   NzBMemory provider '%s' prefetch is still running; skipping this turnr:   z]Memory provider '%s' prefetch timed out after %.1fs; skipping it until the stuck call returnsr#  r"  z memory prefetch)r  ÚsourceÚconfigr³   )r9   r$  r   ræ   rã   r2   Úis_aliverL   rM   Ústartr’   râ   ri   Úpopr®   r   rÞ   )	r€   ró   r  r  r'  Úthreadrý   Úresultr&  s	    ```    @r   r  z MemoryManager._prefetch_providerÉ  s×  û€ ð �=‰=˜IÒ%Ø×$Ñ$ U°zÐ$ÓBÐBà%'ˆ
÷	*ð 	*ô & dÐ3CÀHÇMÁMÀ?Ð1SÔTˆØ×)Ñ)ñ 	Ø×6Ñ6×:Ñ:¸8¿=¹=ÓIˆHØÐ#¨×(9Ñ(9Ô(;Ü—‘ÐaÐck×cpÑcpÔqØ÷		ð 	ð
 >DˆD×+Ñ+¨H¯M©MÑ:Ø�L‰LŒN÷	ð 	�‰�D×3Ñ3Ô4Ø�?‰?ÔÜ�N‰Nð)Ø*2¯-©-¸×9XÑ9Xôð à×)Ñ)ñ 	IØ×.Ñ.×2Ñ2°8·=±=ÓAÀVÑKØ×/Ñ/×3Ñ3°H·M±MÀ4ÔH÷	Ið �jÑ Ø˜WÑ%Ð%Ø—‘ ¨Ó,ˆÙ�f—l‘l”nô (Ø :¸¿¹¸ÐGWÐ6XØ×;Ñ;ôˆFð ˆ÷;	ñ 	ú÷ 	Ið 	Iús    ÁAG9Â:)G9ÅAHÇ9HÈHc                ó  — g }| j                  dd„ «      D ]d  }|€Œ|j                  dk(  rdn |j                  dkD  rd|j                  › d�nd}|j                  |j                  › d|j                  › d	|› �«       Œf d
j                  |«      S )uÓ   Deterministic recall indicator line (e.g. ``"ðŸ§  Provider â€” recalled 3 memories"``); ``""`` if none.
        Call right after :meth:`prefetch_all` so the user SEES memory was used even if the model is silent.z recall_status failed (non-fatal)c                ó"   — | j                  «       S r!   )Úrecall_statusr  s    r   r	  z/MemoryManager.describe_recall.<locals>.<lambda>û  s   € ÐXY×XgÑXgÓXi€ r.   r   zrecalled 1 memoryz	recalled z	 memorieszrecalled relevant memoryú u    â€” z  )rõ   Úcountrj   ÚglyphÚprovider_labelr’   )r€   ÚsegmentsrÙ   Údetails       r   Údescribe_recallzMemoryManager.describe_recall÷  s¥   € ð !ˆØ×)Ñ)Ð*LÑNiÓjò 	TˆFØˆ~Øà-3¯\©\¸QÒ->Ñ)ØŸ™¨Ò)ð GPÐPV×P\ÑP\È~Ð]fÑDgØ/Ið à�O‰O˜vŸ|™|˜n¨A¨f×.CÑ.CÐ-DÀEÈ&ÈÐRÕSð	Tð �y‰y˜Ó"Ð"r.   c               ó˜   ‡ ‡‡‡— t        ‰ j                  «      Š‰r‰ j                  |«      ndŠ‰sy‰ j                  ˆˆˆ ˆfd„d¬«       y)zPQueue background prefetch on all providers for the next turn (see ``sync_all``).Nc                 ó4   •— ‰j                  dˆ ˆfd„‰¬«      S )Nz!queue_prefetch failed (non-fatal)c                ó*   •— | j                  ‰‰¬«      S r  )Úqueue_prefetch)r'   r  r  s    €€r   r	  zDMemoryManager.queue_prefetch_all.<locals>.<lambda>.<locals>.<lambda>  s   ø€ ¸1×;KÑ;KÈKÐdnÐ;KÓ;o€ r.   ©ra   ©rõ   )r  ra   r€   r  s   €€€€r   r	  z2MemoryManager.queue_prefetch_all.<locals>.<lambda>
  s    ø€ ¨×(;Ñ(;Ø/Ô1oØð )<ó )
€ r.   r$  ©r"   ©rX   rm   r  Ú_submit_background)r€   r  r  r  ra   s   ` `@@r   Úqueue_prefetch_allz MemoryManager.queue_prefetch_all  sH   û€ ä˜Ÿ™Ó)ˆ	Ù>G�d×3Ñ3°EÔ:ÈTˆÙØØ×Ñö !
ð ð 	 õ 	r.   c                óZ   — t        | j                  «      }|du xs t        |«      xs ||v S )uI   Whether ``sync_turn`` accepts ``keyword`` (uninspectable â†’ assume yes).N)r   Ú	sync_turnr-   )ró   Úkeywordr,   s      r   Ú_provider_sync_acceptsz$MemoryManager._provider_sync_accepts  s2   € ô # 8×#5Ñ#5Ó6ˆØ˜ˆ~ÒM¤°Ó!8ÒM¸GÀvÐ<MÐMr.   )r  ÚmessagesÚturn_authorc               ó¶   ‡ ‡‡‡‡‡‡	— t        ‰ j                  «      Š	‰	r‰ j                  |«      ndŠ‰sy||dœŠdˆˆˆˆ ˆfd„Š‰ j                  ˆˆ	ˆ fd„«       y)am  Sync a completed turn to all providers on the background worker.

        Never inline: a provider's ``sync_turn`` may block for minutes, which kept ``run_conversation``
        open after the user saw the response. The single worker also serializes writes (turn N before N+1).
        ``turn_author`` reaches only providers whose ``sync_turn`` accepts it.
        N)rG  rH  c                óœ   •— d‰i}‰j                  «       D ]   \  }}|€Œ	‰j                  | |«      sŒ|||<   Œ"  | j                  ‰‰fi |¤Ž y )Nr  )ÚitemsrF  rD  )	ró   ÚkwargsrE  r"  Úassistant_contentÚclean_user_contentÚoptional_kwargsr€   r  s	       €€€€€r   Ú_syncz%MemoryManager.sync_all.<locals>._sync$  sb   ø€ Ø&2°JÐ%?ˆFØ"1×"7Ñ"7Ó"9ò ,‘�˜ØÑ$¨×)DÑ)DÀXÈwÕ)WØ&+�F˜7’Oð,ð ˆH×ÑÐ1Ð3DÑOÈÓOr.   c                 óJ   •— ‰j                  d‰ t        j                  ‰¬«      S )Nzsync_turn failed©rí   ra   ©rõ   r  r  )rP  ra   r€   s   €€€r   r	  z(MemoryManager.sync_all.<locals>.<lambda>,  s!   ø€ �D×'Ñ'Ð(:¸EÌÏÉÐdmÐ'Ón€ r.   ©ró   r   r´   rµ   r@  )
r€   Úuser_contentrM  r  rG  rH  rP  rN  rO  ra   s
   ` ``  @@@@r   Úsync_allzMemoryManager.sync_all  sX   þ€ ô ˜Ÿ™Ó)ˆ	ÙLU˜T×:Ñ:¸<ÔHÐ[_ÐÙ!ØØ'/ÀÑLˆ÷	Pñ 	Pð 	×ÑÝnõ	
r.   Úwriter?  c               óf  — t        |«      }| j                  rdn| j                  }|€[| j                  sO| j                  5  | j                  €"| j                  s	 ddlm}  |dd¬«      | _        | j                  }ddd«       d}	 | j                  5  | j                  r t        j                  d|«       	 ddd«       y|� |j                  |«      }|| j                  |<   ddd«       |�|j                  | j                  «       y	  |«        y# t        $ r }t        j                  d|«       Y d}~ŒÅd}~ww xY w# 1 sw Y   ŒÂxY w# 1 sw Y   ŒhxY w# t        $ r' | j                  rt        j                  d	|«       Y yY Œšw xY w# t        $ r }t        j                  d
|«       Y d}~yd}~ww xY w)u  Queue ``fn`` on the serialized worker (created lazily; None once shutting down) and track its
        durability class. Runs under the caller's contextvars (``ctx_bound``). If the executor is
        unavailable outside shutdown, run inline â€” the historical fail-safe.Nr   )ÚDaemonThreadPoolExecutorr   zmem-sync)Úmax_workersÚthread_name_prefixz)Failed to create memory sync executor: %sz7Memory manager is shutting down; rejecting late %s taskz<Memory manager shut down during %s submission; task rejectedz(Inline memory background task failed: %s)r   rê   rç   rè   Útools.daemon_poolrY  rK   rL   ri   Úsubmitré   ÚRuntimeErrorÚadd_done_callbackÚ_forget_background_futurerM   )r€   r   r"   ÚexecutorrY  rô   Úfutures          r   rA  z MemoryManager._submit_background/  s¨  € ô �r‹]ˆØ×.Ò.‘4°D×4GÑ4GˆØÐ D×$7Ò$7Ø×)Ñ)ñ /Ø×&Ñ&Ð.°t×7JÒ7JðWåNÙ.FÐSTÐisÔ.t˜Ô+ð  ×.Ñ.�÷/ð ˆð	ð ×)Ñ)ñ <Ø×&Ò&Ü—N‘NÐ#\Ð^bÔcØ÷<ð <ð Ð'Ø%Ÿ_™_¨RÓ0�FØ7;�D×,Ñ,¨VÑ4÷<ð ÐØ×$Ñ$ T×%CÑ%CÔDØð	HÙ�Døô- %ò WÜŸ™Ð'RÐTU×VÑVûðWú÷/ð /ú÷<ð <ûô ò 	Ø×"Ò"Ü—‘Ð]Ð_cÔdÙñ #ð	ûô ò 	HÜ�L‰LÐCÀQ×GÑGûð	Hús„   Á D<ÁDÁ/D<ÂE Â$EÂ6E Â?"EÃ!E ÄF Ä	D9ÄD4Ä/D<Ä4D9Ä9D<Ä<EÅEÅE Å+FÆFÆ	F0ÆF+Æ+F0c                ó~   — | j                   5  | j                  j                  |d «       d d d «       y # 1 sw Y   y xY wr!   )rè   ré   r,  )r€   rb  s     r   r`  z'MemoryManager._forget_background_futureV  s6   € Ø×%Ñ%ñ 	7Ø×$Ñ$×(Ñ(¨°Ô6÷	7÷ 	7ñ 	7ús   �3³<c                ó´   — | j                   }|€y	 |j                  d„ «      j                  |¬«       y# t        $ r}t	        |t
        «      cY d}~S d}~ww xY w)z�Block until queued sync/prefetch work has drained (False on timeout).
        With a single worker, a sentinel task completing proves every earlier task ran.NTc                  ó   — y r!   rG   rG   r.   r   r	  z-MemoryManager.flush_pending.<locals>.<lambda>a  s   � r.   ©rì   )rç   r]  r.  rK   r;   r^  )r€   rì   ra  rô   s       r   Úflush_pendingzMemoryManager.flush_pendingZ  s[   € ð ×&Ñ&ˆØÐØð	/Ø�O‰O™LÓ)×0Ñ0¸Ð0ÔAð øô ò 	/Ü˜a¤Ó.Õ.ûð	/ús   ‘"4 ´	A½AÁAÁAc                ó„   ‡‡‡— ddl mŠ g Št        «       Šdˆˆˆfd„}| j                  d|t        j
                  ¬«       ‰S )z–Collect deduplicated tool schemas from all providers; reserved core tool names are
        skipped because :meth:`add_provider` refuses to route them.r   rú   c                óø   •— | j                  «       D ]f  }t        |«      }|€"t        j                  d| j                  |«       Œ2|d   ‰vsŒ:|d   ‰vsŒB‰j                  |«       ‰j                  |d   «       Œh y )NzRMemory provider '%s' returned a tool schema with no resolvable name; skipping (%r)r9   )rü   r?   rL   ri   r9   rj   rk   )ró   rq   r>   rû   rþ   rÅ   s      €€€r   Ú_collectz4MemoryManager.get_all_tool_schemas.<locals>._collectn  s{   ø€ Ø&×7Ñ7Ó9ò 	-�
Ü.¨zÓ:�Ø�>Ü—N‘Nð<Ø=E¿]¹]ÈJõð ˜F‘^Ð+=Ò=À&ÈÁ.ÐX\ÒB\Ø—N‘N 6Ô*Ø—H‘H˜V F™^Õ,ñ	-r.   zget_tool_schemas() failedr
  rT  )rJ   rû   rh   rõ   r  r  )r€   rj  rû   rþ   rÅ   s     @@@r   rc   z"MemoryManager.get_all_tool_schemasf  s:   ú€ õ 	0à(*ˆÜ‹uˆ÷
	-ð 	×ÑÐ7¸ÌÏÉÐÔYØˆr.   c                ó,   — t        | j                  «      S r!   )rh   rÝ   r   s    r   Úget_all_tool_namesz MemoryManager.get_all_tool_names}  s   € Ü�4×)Ñ)Ó*Ð*r.   c                ó   — || j                   v S r!   )rÝ   )r€   rÿ   s     r   Úhas_toolzMemoryManager.has_tool€  s   € Ø˜D×2Ñ2Ð2Ð2r.   c                ó  — | j                   j                  |«      }|€t        d|› d�«      S 	  |j                  ||fi |¤ŽS # t        $ r=}t
        j                  d|j                  ||«       t        d|› d|› �«      cY d}~S d}~ww xY w)zQRoute a tool call to its provider; returns a JSON string (tool_error on failure).Nz!No memory provider handles tool 'ú'z4Memory provider '%s' handle_tool_call(%s) failed: %szMemory tool 'z
' failed: )rÝ   r2   r   Úhandle_tool_callrK   rL   r#  r9   )r€   rÿ   ÚargsrL  ró   rô   s         r   rq  zMemoryManager.handle_tool_callƒ  s™   € à×)Ñ)×-Ñ-¨iÓ8ˆØÐÜÐ AÀ)ÀÈAÐNÓOÐOð	HØ,�8×,Ñ,¨Y¸ÑGÀÑGÐGøÜò 	HÜ�L‰LÐOÐQY×Q^ÑQ^Ð`iÐklÔmÜ ¨i¨[¸
À1À#ÐFÓGÕGûð	Hús   ®A Á	BÁ2BÁ=BÂBc                ó>   ‡‡‡— dˆˆˆfd„}| j                  d|«       y )Nc                óÔ   •— t        | j                  «      }|�t        |«      r‰n(‰j                  «       D ��ci c]  \  }}||v sŒ||“Œ c}}} | j                  ‰‰fi |¤Ž y c c}}w r!   )r   Úon_turn_startr-   rK  )r'   r,   ÚkÚvÚacceptedrL  ÚmessageÚturn_numbers        €€€r   Ú_tickz*MemoryManager.on_turn_start.<locals>._tick�  ss   ø€ ä& q§¡Ó7ˆFØ!' ´?À6Ô3J‘vÐbh×bnÑbnÓbp÷  QAÑZ^ÐZ[Ð]^ÐtuÐyÒtÐQRÐTUÑQUó  QAˆHØˆA�O‰O˜K¨Ñ=°HÓ=ùó QAs   ¹A$ÁA$zon_turn_start failed)r'   r   r´   rµ   r>  )r€   rz  ry  rL  r{  s    ``` r   ru  zMemoryManager.on_turn_startŽ  s   ú€ ÷	>ð 	×ÑÐ2°EÕ:r.   c                óR   ‡— | j                  dˆfd„t        j                  d¬«       y )Nzon_session_end failedc                ó&   •— | j                  ‰«      S r!   )Úon_session_end)r'   rG  s    €r   r	  z.MemoryManager.on_session_end.<locals>.<lambda>˜  s   ø€ ¸q×?OÑ?OÐPXÓ?Y€ r.   T)rí   rI   rS  )r€   rG  s    `r   r~  zMemoryManager.on_session_end—  s(   ø€ Ø×ÑÐ3Ó5YÔah×apÑapØ%)ð 	õ 	+r.   Únew_session)Úparent_session_idÚreasonc               ó|   ‡ ‡‡‡‡— ‰ j                   syt        |xs g «      Šdˆˆˆˆ ˆfd„}‰ j                  |«       y)u—  Queue old-session extraction + provider rebinding as ONE serialized task.

        ``on_session_end`` (LLM-bound, seconds) must run strictly BEFORE ``on_session_switch`` rebinds
        provider state; an ad-hoc thread raced the inline switch and misattributed transcripts.

        Running extraction inline blocked the /new command for the whole LLM round-trip (#16454); running it
        on an ad-hoc thread raced the inline switch â€” providers key off internal state, so a late
        ``on_session_end`` ran against post-switch bindings (transcript misattributed to the new session id,
        double-ingest of the old turn buffer, new-session buffers cleared).
        Submitting BOTH hooks as one task on the manager's single background worker gives both properties at
        a single chokepoint: the caller returns immediately, and the worker's FIFO order serializes
        endâ†’switch against every other provider write (per-turn ``sync_all``, prefetches), which already
        share the same worker. If the executor is unavailable, ``_submit_background`` degrades to inline
        execution â€” the pre-#16454 synchronous behavior, slow but correct.
        Nc                 ó  •— 	 ‰j                  ‰«       	 ‰j	                  ‰‰d‰¬«       y # t        $ r } t        j                  d| «       Y d } ~ Œ;d } ~ ww xY w# t        $ r } t        j                  d| «       Y d } ~ y d } ~ ww xY w)Nz&Session-boundary extraction failed: %sT)r€  r~   r�  z"Session-boundary switch failed: %s)r~  rK   rL   ri   Úon_session_switch)rô   Únew_session_idr€  r�  r€   Úsnapshots    €€€€€r   r'  z9MemoryManager.commit_session_boundary_async.<locals>._run°  s‚   ø€ ðLØ×#Ñ# HÔ-ðHØ×&Ñ& ~ÐIZÐbfÐouÐ&Õvøô ò LÜ—‘ÐGÈ×KÑKûðLûô ò HÜ—‘ÐCÀQ×GÑGûðHús+   ƒ+ •A «	A´AÁAÁ	B Á A;Á;B r³   )rm   rX   rA  )r€   rG  r…  r€  r�  r'  r†  s   ` ``` @r   Úcommit_session_boundary_asyncz+MemoryManager.commit_session_boundary_async›  s9   ü€ ð" �ŠØÜ˜š BÓ'ˆ÷	Hñ 	Hð 	×Ñ Õ%r.   )r€  r~   Úrewoundc               óP   ‡‡‡‡— ‰sy|rd‰d<   | j                  dˆˆˆˆfd„«       y)zÑNotify providers that ``AIAgent.session_id`` rotated without teardown
        (``/resume``, ``/branch``, ``/reset``, ``/new``, compression). ``rewound=True``
        (``/undo``): same id, truncated transcript.NTrˆ  zon_session_switch failedc                ó0   •—  | j                   ‰f‰‰dœ‰¤ŽS )N)r€  r~   )r„  )r'   rL  r…  r€  r~   s    €€€€r   r	  z1MemoryManager.on_session_switch.<locals>.<lambda>Ç  s$   ø€ Ð)�a×)Ñ)¨.ÐuÐL]ÐejÑuÐntÑu€ r.   r>  )r€   r…  r€  r~   rˆ  rL  s    ``` `r   r„  zMemoryManager.on_session_switch¼  s,   û€ ñ
 ØÙØ $ˆF�9ÑØ×ÑØ&Þuõ	
r.   c                ób   — 	 t        t        | dt        «      «      S # t        t        f$ r Y yw xY w)zOProvider's advertised pre-compress checkpoint API version; None if unparseable.Ú#pre_compress_checkpoint_api_versionN)r¸   r1   Ú _LEGACY_PRE_COMPRESS_API_VERSIONr   r   )ró   s    r   Ú_checkpoint_api_versionz%MemoryManager._checkpoint_api_versionÊ  s4   € ð	Ü”w˜xÐ)NÔPpÓqÓrÐrøÜœ:Ð&ò 	Ùð	ús   ‚ œ.­.c                óX   ‡ ‡— ˆ fd„‰ j                   D «       }t        ˆfd„|D «       «      S )zDReturn whether an active provider guarantees checkpoint API support.c              3  ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wr!   )rŽ  )r&   r'   r€   s     €r   r(   zAMemoryManager.supports_pre_compress_checkpoint.<locals>.<genexpr>Ô  s   øè ø€ ÒM¸�D×0Ñ0°×3ÑMùs   ƒc              3  ó4   •K  — | ]  }|d uxr |‰k\  –— Œ y ­wr!   rG   )r&   rw  Úapi_versions     €r   r(   zAMemoryManager.supports_pre_compress_checkpoint.<locals>.<genexpr>Õ  s"   øè ø€ ÒH¸!�1˜D�=Ò5 Q¨+Ñ%5Ó5ÑHùs   ƒ)rm   r*   )r€   r’  Úversionss   `` r   Ú supports_pre_compress_checkpointz.MemoryManager.supports_pre_compress_checkpointÒ  s"   ù€ ãM¸T¿_¹_ÔMˆÜÓH¸xÔHÓHÐHr.   )Úevidence_messagesr0   Úcheckpoint_api_versionc               óø  — g }d}| j                   D ]‰  }| j                  |«      }|€t        }||k\  }	|	xr |du}
|
r|n|}i }|	rt        |j                  «      r||d<   	  |j                  |fi |¤Ž}|r!|j                  «       r|j                  |«       |xs |	}Œ‹ |r|st        d|› �«      ‚dj                  |«      S # t        $ r0}t        j                  d|j                  |«       |r|	r‚ Y d}~Œãd}~ww xY w)u�  Notify providers before compression; return their combined summary-prompt text.

        ``messages`` is the raw v1 transcript; ``evidence_messages`` is the host-normalized list handed
        only to checkpoint (v2+) providers. With ``require_checkpoint`` at least one checkpoint provider
        must succeed â€” its exception propagates so the caller keeps the uncompressed transcript.
        FNr0   z/Memory provider '%s' on_pre_compress failed: %szANo active memory provider completed pre-compress checkpoint API vr  )rm   rŽ  r�  r5   Úon_pre_compressr®   rj   rK   rL   rM   r9   r^  r’   )r€   rG  r•  r0   r–  r  Úcheckpoint_succeededró   ÚversionÚis_checkpoint_providerÚuse_evidenceÚprovider_messagesrL  r.  rô   s                  r   r˜  zMemoryManager.on_pre_compress×  s+  € ð ˆØ$ÐØŸ™ò 	ˆHØ×2Ñ2°8Ó<ˆGØˆÜ:�Ø%,Ð0FÑ%FÐ"Ø1ÒSÐ6GÈtÐ6SˆLÙ5AÑ 1ÀxÐØ%'ˆFá%Ô*EÀh×F^ÑF^Ô*_Ø/A�Ð+Ñ,ðØ1˜×1Ñ1Ð2CÑNÀvÑN�Ù˜fŸl™lœnØ—L‘L Ô(Ø';Ò'UÐ?UÑ$ð	ñ( Ñ&:ÜØSÐTjÐSkÐlóð ð �{‰{˜5Ó!Ð!øô ò Ü—‘ÐNÐPX×P]ÑP]Ð_`ÔaÙ%Ñ*@Øÿøðús   Á<C Ã 	C9Ã	&C4Ã4C9c                ó¢   — t        | j                  «      }|�t        |«      sd|v ryt        d„ |j	                  «       D «       «      }|dk\  rdS dS )zYHow to pass metadata to ``on_memory_write``: "keyword", "positional", or "legacy" (none).ÚmetadatarE  c              3  óh   K  — | ]*  }|j                   t        j                  j                  u–— Œ, y ­wr!   )r"   r   r#   ÚVAR_POSITIONALr%   s     r   r(   zEMemoryManager._provider_memory_write_metadata_mode.<locals>.<genexpr>  s%   è ø€ Ò_È!�q—v‘v¤W×%6Ñ%6×%EÑ%EÔEÑ_ùr)   é   Ú
positionalÚlegacy)r   Úon_memory_writer-   Úsumr+   )ró   r,   rx  s      r   Ú$_provider_memory_write_metadata_modez2MemoryManager._provider_memory_write_metadata_modeü  sQ   € ô # 8×#;Ñ#;Ó<ˆØˆ>œ_¨VÔ4¸
ÀfÑ8LØÜÑ_ÈvÏ}É}ËÔ_Ó_ˆØ'¨1š}ˆ|Ð:°(Ð:r.   c                ó¦   ‡ ‡‡‡‡— dˆˆˆˆ ˆfd„}‰ j                   D �cg c]  }|j                  dk7  sŒ|‘Œ }}‰ j                  d||¬«       yc c}w )z[Notify external providers when the built-in memory tool writes (skips builtin, the source).c           	     óì   •— ‰j                  | «      }|dk(  r| j                  ‰‰‰«       y |dk(  r"| j                  ‰‰‰t        ‰xs i «      «       y | j                  ‰‰‰t        ‰xs i «      ¬«       y )Nr¤  r£  ©rŸ  )r§  r¥  r<   )ró   ÚmodeÚactionÚcontentrŸ  r€   Útargets     €€€€€r   Ú_notifyz.MemoryManager.on_memory_write.<locals>._notify	  sv   ø€ Ø×<Ñ<¸XÓFˆDØ�xÒØ×(Ñ(¨°¸ÕAØ˜Ò%Ø×(Ñ(¨°¸Ä$ÀxÂ~ÐSUÓBVÕWà×(Ñ(¨°¸Ì4ÐPXÒP^Ð\^ÓK_Ð(Õ`r.   rb   zon_memory_write failedr=  NrT  )rm   r9   rõ   )r€   r¬  r®  r­  rŸ  r¯  r'   Úexternals   `````   r   r¥  zMemoryManager.on_memory_write  sO   ü€ ÷	añ 	að  $Ÿ™ÖF˜!°!·&±&¸IÓ2E’AÐFˆÐFØ×ÑÐ4°gÈÐÕRùò Gs
   žA³A>   rk   ÚremoveÚreplacec                óà   — t        | t        «      r	 t        j                  | «      } t        | t
        «      xr( | j                  d«      du xr | j                  d«      duS # t        $ r Y yw xY w)zÌTrue only when the built-in memory tool actually committed a write. Fails closed (non-JSON,
        non-dict, missing ``success``, staged for approval) so providers never mirror a write that did not land.FÚsuccessTÚstaged)r;   r=   ÚjsonÚloadsrK   r<   r2   )r.  s    r   Ú_memory_tool_result_succeededz+MemoryManager._memory_tool_result_succeeded  sl   € ô �fœcÔ"ðÜŸ™ FÓ+�ô ˜&¤$Ó'Òn¨F¯J©J°yÓ,AÀTÐ,IÒnÈfÏjÉjÐYaÓNbÐjnÐNnÐnøô ò Ùðús   ’A! Á!	A-Á,A-)Úbuild_metadatac          
     óŠ  — | j                  |«      syt        |j                  d«      xs d«      }|j                  d«      }t        |t        «      r|r|n|gD ]»  }t        |t
        «      rt        |j                  d«      xs d«      nd}|| j                  vrŒB	 t        |r |«       ni «      }|j                  d«      }	|	rt        |	«      |d<   | j                  ||t        |j                  d«      xs |j                  d	«      xs d«      |¬
«       Œ½ y# t        $ r!}
t        j                  d||
«       Y d}
~
Œäd}
~
ww xY w)aH  Mirror a built-in memory tool call to external providers.

        Gates on a committed write, expands single-op and batched ``operations`` shapes, keeps only
        mutating actions, and forwards ``old_text`` plus provenance from ``build_metadata`` (the loop
        knows session/task/tool-call identity; we do not).
        Nr®  rC   Ú
operationsr¬  r:   Úold_textr­  Únew_textrª  z-notify_memory_tool_write failed for op %s: %s)r¸  r=   r2   r;   rX   r<   Ú_MIRRORED_MEMORY_ACTIONSr¥  rK   rL   rM   )r€   Útool_resultÚ	tool_argsr¹  r®  r»  Úopr¬  rŸ  r¼  rô   s              r   Únotify_memory_tool_writez&MemoryManager.notify_memory_tool_write$  s+  € ð ×1Ñ1°+Ô>ØÜ�Y—]‘] 8Ó,Ò8°Ó9ˆØ—]‘] <Ó0ˆ
Ü *¨:´tÔ <Á‘*ÐR[ÐQ\ò 	YˆBÜ4>¸rÄ4Ô4H”S˜Ÿ™ Ó)Ò/¨RÔ0ÈbˆFØ˜T×:Ñ:Ñ:ØðYÜ±N¡Ô 0ÈÓK�ØŸ6™6 *Ó-�ÙÜ+.¨x«=�H˜ZÑ(Ø×$Ñ$ V¨V´S¸¿¹À	Ó9JÒ9fÈbÏfÉfÐU_ÓN`Ò9fÐdfÓ5gÐrzÐ$Õ{ñ	Yøô ò YÜ—‘ÐLÈfÐVW×XÑXûðYús   ÂA9DÄ	EÄ!D=Ä=E)Úchild_session_idc               ó<   ‡‡‡‡— | j                  dˆˆˆˆfd„«       y )Nzon_delegation failedc                ó0   •—  | j                   ‰‰fd‰i‰¤ŽS )NrÃ  )Úon_delegation)r'   rÃ  rL  r.  Útasks    €€€€r   r	  z-MemoryManager.on_delegation.<locals>.<lambda>@  s    ø€ �o�a—o‘o d¨FÑ`ÐEUÐ`ÐY_Ñ`€ r.   r>  )r€   rÇ  r.  rÃ  rL  s    ````r   rÆ  zMemoryManager.on_delegation=  s   û€ Ø×ÑØ"Þ`õ	
r.   c           	     óŒ   — | j                  «        | j                  dd„ t        j                  | j                  ddd…   ¬«       y)zSDrain the background executor (bounded), then shut providers down in reverse order.zshutdown failedc                ó"   — | j                  «       S r!   )Úshutdownr  s    r   r	  z,MemoryManager.shutdown_all.<locals>.<lambda>F  s   € ¸¿¹»€ r.   Nr‡   rR  )Ú_drain_sync_executorrõ   r  r  rm   r   s    r   Úshutdown_allzMemoryManager.shutdown_allC  s=   € à×!Ñ!Ô#Ø×ÑÐ-Ñ/EÌWÏ_É_Ø&*§o¡o±d¸°dÑ&;ð 	õ 	=r.   c                óp   — | j                   5  t        | j                  «      cddd«       S # 1 sw Y   yxY w)z;Snapshot of the most recent bounded shutdown drain outcome.N)rè   r<   rë   r   s    r   Úshutdown_drain_statez"MemoryManager.shutdown_drain_stateI  s0   € ð ×%Ñ%ñ 	4Ü˜×2Ñ2Ó3÷	4÷ 	4ò 	4ús   �,¬5c                óÎ  — | j                   5  d| _        | j                  }d| _        t        | j                  «      }|�dndddt        d„ |D «       «      dœ| _        ddd«       €y|j                  dd¬	«       t        t        «      t        ¬
«      \  }}|D �cg c]  }|j                  «       sŒ||   ‘Œ }}t        |«      t        |«      z
  }|j                  d«      }t        |«      |z
  }	| j                   5  | j                  j                  |rdnd|	||¬«       ddd«       |syt        j!                  dt        |	||«       y# 1 sw Y   ŒîxY wc c}w # 1 sw Y   Œ;xY w)z@Give queued FIFO work a bounded chance, then abandon explicitly.TNÚdrainingÚdrainedr   c              3  ó>   K  — | ]  }|j                  «        –— Œ y ­wr!   )Údone)r&   rb  s     r   r(   z5MemoryManager._drain_sync_executor.<locals>.<genexpr>Y  s   è ø€ Ò#L¸&¨¯©«Ô$5Ñ#Lùs   ‚rØ   F)r   Úcancel_futuresrf  r$  Ú	timed_outz�Memory shutdown drain timed out after %.2fs; abandoning %d queued memory write(s) and %d queued prefetch(es); %d active task(s) remain detached)rè   rê   rç   r<   ré   r¦  rë   rÊ  r   rY   Ú_SYNC_DRAIN_TIMEOUT_SÚcancelrŽ   r3  ÚupdaterL   ri   )
r€   ra  ÚtrackedÚ_r™   rb  Ú	cancelledrÜ   rÛ   rÚ   s
             r   rË  z"MemoryManager._drain_sync_executorO  sg  € à×%Ñ%ñ 		Ø"&ˆDÔØ×*Ñ*ˆHØ"&ˆDÔÜ˜4×3Ñ3Ó4ˆGà(0Ð(<™*À)Ø$%¸qÜ #Ñ#LÀGÔ#LÓ Lñ*ˆDÔ&÷		ð ÐØð 	×Ñ˜u°UÐÔ;Üœ% ›.Ô2GÔH‰
ˆˆ7Ø3:ÖN¨¸f¿m¹m½o�W˜V“_ÐNˆ	ÐNÜ˜7“|¤c¨)£nÑ4ˆØ(Ÿ™¨zÓ:ÐÜ˜y›>Ð,@Ñ@ÐØ×%Ñ%ñ 	Ø×&Ñ&×-Ñ-Ù&-‘{°9ÐO_Ø%9Èð .ô ÷	ñ
 ØÜ�‰ð\ä!Ð#3Ð5IÈ<õ	
÷9		ð 		üò" O÷	ð 	ús$   �AE
ÂEÂ2EÃ=$EÅ
EÅE$c                óŽ   ‡‡— d‰vrddl m} t         |«       «      ‰d<   | j                  dˆˆfd„t        j
                  ¬«       y)zYInitialize all providers, injecting ``hermes_home`` so they resolve profile-scoped paths.Úhermes_homer   )Úget_hermes_homezinitialize failedc                ó,   •—  | j                   dd‰i‰¤ŽS )Nr  rG   )Ú
initialize)r'   rL  r  s    €€r   r	  z.MemoryManager.initialize_all.<locals>.<lambda>x  s   ø€ ¸<¸1¿<¹<Ñ;hÐS]Ð;hÐagÑ;h€ r.   r
  N)Úhermes_constantsrÞ  r=   rõ   r  r  )r€   r  rL  rÞ  s    `` r   Úinitialize_allzMemoryManager.initialize_alls  s@   ù€ à Ñ&Ý8Ü$'©Ó(9Ó$:ˆF�=Ñ!Ø×ÑÐ/Ô1hÜ")§/¡/ð 	õ 	3r.   )rÕ   úOptional[float]r´   rµ   )rð   r=   rñ   zCallable[[MemoryProvider], Any]rí   r¸   ra   zOptional[List[MemoryProvider]]rI   r¯   r´   z	List[Any]rT  )r´   zList[MemoryProvider])r9   r=   r´   zOptional[MemoryProvider]r·   )r  r=   r  r=   r´   r=   )ró   r   r  r=   r  r=   r´   r=   )r  r=   r  r=   r´   rµ   )ró   r   rE  r=   r´   r¯   )rU  r=   rM  r=   r  r=   rG  úOptional[List[Dict[str, Any]]]rH  úOptional[Dict[str, Any]]r´   rµ   )r"   r=   r´   rµ   )rb  r   r´   rµ   r!   )rì   rã  r´   r¯   )r´   úList[Dict[str, Any]])r´   rh   )rÿ   r=   r´   r¯   )rÿ   r=   rr  úDict[str, Any]r´   r=   )rz  r¸   ry  r=   r´   rµ   )rG  ræ  r´   rµ   )
rG  ræ  r…  r=   r€  r=   r�  r=   r´   rµ   )
r…  r=   r€  r=   r~   r¯   rˆ  r¯   r´   rµ   )ró   r   r´   zOptional[int])r’  r¸   r´   r¯   )
rG  ræ  r•  rä  r0   r¯   r–  r¸   r´   r=   )ró   r   r´   r=   )
r¬  r=   r®  r=   r­  r=   rŸ  rå  r´   rµ   )r.  r   r´   r¯   )r¿  r   rÀ  rç  r¹  z&Optional[Callable[[], Dict[str, Any]]]r´   rµ   )rÇ  r=   r.  r=   rÃ  r=   r´   rµ   r³   )r´   rç  )r  r=   r´   rµ   )/rf   r¹   rº   r»   r�   r  ÚDEBUGrõ   r   Úpropertyra   r  r  r¼   r   r  r  r  r8  rB  rF  rV  rA  r`  rg  rc   rl  rn  rq  ru  r~  r‡  r„  rŽ  r   r”  r˜  r§  r¥  r¾  r¸  rÂ  rÆ  rÌ  rÎ  rË  râ  rG   r.   r   rÔ   rÔ   P  sO  „ ñð HLõ 
ð0 ah×`mÑ`mØCGÐZ_ñ
Ø"@ð
ØSWð
Ødmó
ó1_ðf ò%ó ð%óJóAñ  ,Ð,WÓXÐà<>õ @ð ]_õ ,ó\#ð CEõ 	ð òNó ðNð
 XZØ<@Ø9=ñ
Ø9ð
à6ð
àBFó
ð4 5<õ %HóN7ô
óó.+ó3ó	Hó;ó+ð
 @BÐQ^ñ&Ø9<ð&ØKNð&Øcgó&ðB RTÐchØ*/ñ
Ø#'ð
Ø>Bó
ð òó ðð Cfô Ið MQÐmrØ6Yñ#"Ø+Ið#"Øfjð#"à03ð#"à^aó#"ðJ ò;ó ð;ð >BðSØ":ðSØFJóSò$  <Ðàòoó ðoð [_ñYØ1WðYØcgóYð2 PRõ 
ó=ð ò4ó ð4ó
"
ôH3r.   rÔ   )r   úCallable[..., Any])r´   r¯   )r   rê  r´   r¯   )r>   r   r´   rå  r!   )rN   úOptional[List[str]]rO   rë  rA   r¯   r´   r¯   )rR   r   r´   r   )rZ   r   r´   r¯   )rZ   r   r´   r¸   r¶   )rÏ   r=   r´   r=   ):r»   Ú
__future__r   Úcontextvarsr   r¶  r  Úrerä   Úconcurrent.futuresr   r   r   Ú	functoolsr   Útypingr   r	   r
   r   r   Úagent.memory_providerr   r   r   r   Úagent.skill_commandsr   Útools.hook_output_spillr   r   Útools.registryr   Ú	getLoggerrf   rL   r�  rÖ  rà   r   r-   r5   r?   rP   rS   r^   rr   ÚcompileÚ
IGNORECASErv   rt   ru   rz   r|   rÁ   rÍ   rÒ   rÔ   rG   r.   r   ú<module>rù     s<  ðñõ #ã Û Û Û Û 	Û ß ?Ñ ?Ý ß 6Õ 6ç vÓ vÝ Lß HÝ %à	ˆ×	Ñ	˜8Ó	$€ð $%Ð  ð Ð Ø"Ð ó
óQó
xó>ðØAFñØ:>ðØKOóó(Tó	Yó+ð` �—
‘
Ð6¸¿¹ÓF€Ø!�r—z‘zÐ"ZÐ\^×\iÑ\iÓjÐ Ø�B—J‘Jð pØ‡M�MóÐ ó÷UIñ UIðt �B—J‘J˜}Ó-Ð ó+ó\÷&i3ò i3r.   