
    `gj.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  ej"                  e      ZdZdZd	Zd
ZdZd-dZd.dZddddddddddddddgddZdddddddidgddZd d!ddd"ddd#dd$d%d&gddZd'd(dd%dd)did%gddZ G d* d+e      Zd/d,Z y)0u*  Mem0 memory plugin — MemoryProvider interface.

Server-side LLM fact extraction, semantic search, and automatic deduplication
via the Mem0 Platform API (cloud) or OSS (self-hosted) via Memory.

Original PR #2933 by kartik-mem0, adapted to MemoryProvider ABC.

Configuration
-------------
Secret (lives in $HERMES_HOME/.env or the environment):
  MEM0_API_KEY       — Mem0 Platform API key (required for platform mode)
  MEM0_HOST          — Base URL of a self-hosted Mem0 server. When set, the
                       plugin talks to that server directly over HTTP
                       (X-API-Key auth) instead of the cloud API.

Behavioral settings (live in $HERMES_HOME/mem0.json, set via `hermes memory
setup`):
  mode               — Backend mode: "platform" (default) or "oss"
  host               — Self-hosted Mem0 server URL (alt: MEM0_HOST env var).
                       When set, routes to the self-hosted HTTP backend.
  user_id            — Canonical user identifier. When set, it is applied
                       uniformly across every gateway (CLI, Telegram, Slack,
                       Discord, …) so the same human gets one merged memory
                       store. When unset, the gateway-native id (e.g. Telegram
                       numeric id, Discord snowflake) is used instead.
  agent_id           — Agent identifier (default: hermes)

The matching MEM0_MODE / MEM0_USER_ID / MEM0_AGENT_ID environment variables are
still read as a backward-compatible fallback, but mem0.json is the canonical
home for these non-secret settings.
    )annotationsN)AnyDictList)MemoryProvider)
tool_error   x      )MemoryNotFoundErrorValidationErrorhermes-userc                    t        |       j                  }|t        v ryt        |       j	                         }d|v xs
 d|v xs d|v S )zUTrue for user-caused errors (bad ID, not found) that should NOT trip circuit breaker.T404z	not foundz
valid uuid)type__name___CLIENT_ERROR_TYPESstrlower)excetypeerr_strs      O/root/.hermes/venv/lib/python3.12/site-packages/plugins/memory/mem0/__init__.py_is_client_errorr   @   sL    IE###hnnGGP{g5P9PP    c                    ddl m}  t        j                  j	                  dd      t        j                  j	                  dd      t        j                  j	                  dd      t        j                  j	                  dd	      i d
}t        j                  j	                  d      }|r||d<    |        dz  }|j                         rb	 t        j                  |j                  d            }|j                  |j                         D ci c]  \  }}||dk7  r|| c}}       |S |S c c}}w # t        $ r Y |S w xY w)a+  Load config from env vars, with $HERMES_HOME/mem0.json overrides.

    Environment variables provide defaults; mem0.json (if present) overrides
    individual keys.  This avoids a silent failure when the JSON file exists
    but is missing fields like ``api_key`` that the user set in ``.env``.
    r   )get_hermes_home	MEM0_MODEplatformMEM0_API_KEY 	MEM0_HOSTMEM0_AGENT_IDhermes)modeapi_keyhostagent_idossMEM0_USER_IDuser_id	mem0.jsonzutf-8)encoding)hermes_constantsr   osenvirongetexistsjsonloads	read_textupdateitems	Exception)r   configenv_user_idconfig_pathfile_cfgkvs          r   _load_configr?   M   s    1 

{J7::>>."5

{B/JJNN?H=F **..0K'y!#k1K	zz+"7"7"7"IJHMMHNN,< 9DAqmR a4 9 :
 M6M9 	M	s%   AD1 D+
D1 +D1 1	D>=D>mem0_searchu  Search the user's memories by meaning; returns facts ranked by relevance. Use this before answering any question that may depend on what you know about the user (preferences, facts, history, people, projects, past decisions). For multi-part or multi-hop questions, call it several times — vary the wording and run follow-up searches on what earlier results reveal; one search is rarely enough.objectstringzWhat to search for.)r   descriptionintegerz#Max results (default: 10, max: 50).booleanzBRerank results for relevance (default: false, platform mode only).)querytop_krerankrF   )r   
propertiesrequired)namerC   
parametersmem0_addu(  Store a durable fact about the user, verbatim (no LLM extraction). Call this the moment the user states a lasting preference, correction, decision, or personal detail worth recalling on future turns — don't wait to be asked to remember. Skip transient chit-chat and facts you've already stored.contentzThe fact to store.mem0_updateu   Replace the text of an existing memory by its ID (take the ID from a mem0_search result). Use when a stored fact has changed or was wrong — correct it in place instead of adding a duplicate.zMemory UUID to update.zNew text content.)	memory_idtextrP   rQ   mem0_deletezDelete a memory by its ID (take the ID from a mem0_search result). Use when a stored fact is obsolete or the user asks you to forget it; prefer mem0_update if the fact merely changed.zMemory UUID to delete.c                      e Zd ZdZd Zedd       ZddZd Zd Z	ddZ
d Zdd	Zd d
Zd Zd Zd!dZd"dZd"dZddZd#dZd$dZd%dZddd&dZddd'dZd(dZd)dZd Zd*dZy)+Mem0MemoryProviderzMem0 memory with server-side extraction and semantic search.

    Supports Platform API (cloud) and OSS (self-hosted) modes via MEM0_MODE.
    c                   d | _         d | _        d| _        d| _        d| _        t
        | _        d| _        d| _        d| _	        d | _
        d | _        d| _        d| _        d| _        d| _        d| _        t#        j$                         | _        t#        j$                         | _        t#        j$                         | _        d| _        y )Nr   r!   r$   Fclir   g        )_config_backend_mode_api_key_host_DEFAULT_USER_ID_user_id	_agent_id_rerank_default_channel_sync_thread_prefetch_thread_prefetch_query_prefetch_result_prefetch_done_consecutive_failures_breaker_open_until	threadingLock_breaker_lock
_sync_lock_prefetch_lock_atexit_registeredselfs    r   __init__zMem0MemoryProvider.__init__   s    

(!$  $! "#%&"#& &^^-#..*'nn."'r   c                     y)Nmem0 rn   s    r   rK   zMem0MemoryProvider.name   s    r   c                    t               }|j                  dd      }|dk(  r*t        |j                  di       j                  d            S t        |j                  d      xs |j                  d            S )Nr%   r   r)   vector_storer&   r'   )r?   r1   bool)ro   cfgr%   s      r   is_availablezMem0MemoryProvider.is_available   sd    nwwvz*5=r*..~>?? CGGI&9#''&/::r   c                    ddl }ddlm}  ||      dz  }i }|j                         r!	  |j                  |j                               }|j                  |       ddlm	}  |||d       y# t        $ r Y .w xY w)z'Write config to $HERMES_HOME/mem0.json.r   N)Pathr,   )atomic_json_writei  )r%   )
r3   pathlibrz   r2   r4   r5   r8   r6   utilsr{   )ro   valueshermes_homer3   rz   r;   existingr{   s           r   save_configzMem0MemoryProvider.save_config   sw     ;'+5%4::k&;&;&=> 	++xe<	  s    A, ,	A87A8c           	         t               }|j                  dd      }|dk7  }ddd|ddd	d
dddddddddddddddddgdgS )Nr%   r   r)   r&   zMem0 Platform API keyTr    zhttps://app.mem0.ai)keyrC   secretrJ   env_varurlr'   z3Self-hosted Mem0 server URL (leave blank for cloud)Fr"   )r   rC   rJ   r   r+   zUser identifierr   )r   rC   defaultr(   zAgent identifierr$   rH   zEnable reranking for recallfalsetrue)r   rC   r   choices)r?   r1   )ro   rw   r%   api_key_requireds       r   get_config_schemaz$Mem0MemoryProvider.get_config_schema   s    nwwvz*5=.EQUcs  AO  Xm  n+`ns  AL  M.?MZ/AhW-JW^lrt{k|}
 	
r   c                "    ddl m}  |||       y )N   )
post_setup)_setupr   )ro   r   r9   r   s       r   r   zMem0MemoryProvider.post_setup  s    &;'r   c                   	 ddl m}  |dd       	 | j                  dk(  r(ddlm}  || j                  j                  di             S | j                  r#dd	lm
}  || j                  | j                        S dd
lm}  || j                        S # t        $ r Y t        $ r Y w xY w# t        $ r;}t        j                  d| j                  |       t        |      | _        Y d }~y d }~ww xY w)Nr   )ensurezmemory.mem0F)promptr)   r   )
OSSBackend)SelfHostedBackend)PlatformBackendz/Mem0 backend failed to initialize (%s mode): %s)tools.lazy_depsr   ImportErrorr8   rY   rX   r   rW   r1   r[   r   rZ   r   loggererrorr   _init_error)ro   _lazy_ensurer   r   r   es         r   _create_backendz"Mem0MemoryProvider._create_backend
  s    	>u5
	zzU"0!$,,"2"25""=>>zz7(

CC1"4==11  	 		  	LLJDJJXYZ"1vD	s:   B 6B* 
.B* 9B* 	B'B'&B'*	C.31C))C.c                    | j                   5  | j                  t        k  r
	 ddd       yt        j                         | j
                  k\  rd| _        	 ddd       y	 ddd       y# 1 sw Y   yxY w)zBReturn True if the circuit breaker is tripped (too many failures).NFr   T)rj   rf   _BREAKER_THRESHOLDtime	monotonicrg   rn   s    r   _is_breaker_openz#Mem0MemoryProvider._is_breaker_open%  sm     	)),>>	 	 ~~4#;#;;-.*	 	 	 	 	s   A')A'A''A0c                   | d| }| j                   dk(  rjt        |      j                         }d|v sd|v sd|v rE| j                  j	                  di       j	                  di       }|d|j	                  dd	       d
z  }|S )Nz: r)   
connectionrefusedtimeoutru   z (check that providervector storez is running))rY   r   r   rW   r1   )ro   prefixr   msgr   vss         r   _format_errorz Mem0MemoryProvider._format_error/  s    3% ::#hnn&Gw&)w*>)wBV\\%%eR044^RHrvvj.'I&J,WW
r   c                T    | j                   5  d| _        d d d        y # 1 sw Y   y xY w)Nr   )rj   rf   rn   s    r   _record_successz"Mem0MemoryProvider._record_success8  s(     	+)*D&	+ 	+ 	+s   'c                   | j                   5  | xj                  dz  c_        | j                  }|t        k\  r!t        j                         t
        z   | _        nd}d d d        t        k\  rrd}| j                  dk(  rD| j                  j                  di       j                  di       }|j                  dd      }d| d	}t        j                  d
|t
        |       y y # 1 sw Y   xY w)Nr   r   r!   r)   ru   r   unknown Check that your z' vector store is running and reachable.zXMem0 circuit breaker tripped after %d consecutive failures. Pausing API calls for %ds.%s)rj   rf   r   r   r   _BREAKER_COOLDOWN_SECSrg   rY   rW   r1   r   warning)ro   counthintr   r   s        r   _record_failurez"Mem0MemoryProvider._record_failure<  s     	&&!+&..E**+/>>+;>T+T(	 &&DzzU"\\%%eR044^RH66*i8*8*4[\NN/-t '	 	s   ACC(c                4   t               | _        | j                  j                  dd      | _        | j                  j                  dd      | _        | j                  j                  dd      | _        | j                  j                  d      }|t        k(  rd }|xs |j                  d      xs t        | _        | j                  j                  dd      | _        | j                  j                  d	d
      }t        |t              r|j                         dv n
t        |      | _        |j                  d      xs d| _        | j                         | _        | j                   r4| j"                  s't%        j&                  | j(                         d| _        y y y )Nr%   r   r&   r!   r'   r+   r(   r$   rH   F)r   1yesrV   T)r?   rW   r1   rY   rZ   r[   r\   r]   r^   
isinstancer   r   rv   r_   r`   r   rX   rm   atexitregister_shutdown_backend)ro   
session_idkwargs
configured_rrs        r   
initializezMem0MemoryProvider.initializeP  s@   #~\\%%fj9
((B7\\%%fb1
 \\%%i0
))J"Ofjj&;O?O))*h?
 llx/3=c33GCIIK//TRUY 	 

:.7%,,.==!8!8OOD223&*D# "9=r   c                    d| j                   iS )Nr+   )r]   rn   s    r   _read_filtersz Mem0MemoryProvider._read_filterss  s     4==))r   c                :    | j                   rd| j                   iS i S )Nchannel)r`   rn   s    r   _write_metadataz"Mem0MemoryProvider._write_metadata{  s     .2]]	4==)BBr   c                    | j                   dk(  rd}n| j                  rd}nd}| j                   dk(  r| j                  sdnd}d| d	| j                   d
| S )Nr)   zOSS (self-hosted)zself-hosted (HTTP API)zplatform (cloud API)r   z Rerank is available on search.r!   z# Mem0 Memory
Active. Mode: z. User: u  .
You have persistent memory of this user from past conversations. You should call mem0_search before answering anything that could depend on prior context (the user's preferences, facts, history, people, projects, or earlier decisions) — do not rely on the chat window alone, and do not assume you have no memory.
For multi-part or multi-hop questions, run several searches with different wording/angles and follow-up searches on what the first results surface; one search is rarely enough. Keep searching until you have every fact the question needs before you answer.
Tools: mem0_search to find memories, mem0_add to store facts, mem0_update and mem0_delete to manage by ID.)rY   r[   r]   )ro   
mode_labelrerank_notes      r   system_prompt_blockz&Mem0MemoryProvider.system_prompt_block  sp    
 ::,JZZ1J/J<@JJ*<T]a]g]g7np'L @; <G-I	
r   c                &    | j                  |       y N)_start_prefetch)ro   turn_numbermessager   s       r   on_turn_startz Mem0MemoryProvider.on_turn_start  s    W%r   c                    | j                   5  | j                  |k7  s| j                  s
	 d d d        y | j                  }d| _        d| _        |cd d d        S # 1 sw Y   y xY w)Nr!   F)rl   rc   re   rd   )ro   rF   results      r   _consume_prefetch_resultz+Mem0MemoryProvider._consume_prefetch_result  sc       	##u,D4G4G	 	 **F$&D!"'D	 	 	s   AAA!c                $    r j                    j                         ry  j                    j                  5   j                  k(  rF j                  r
	 d d d        y  j
                  r$ j
                  j                         r
	 d d d        y  _        d _        d _        d d d         fd}t        j                  |dd      } j                  5  | _        d d d        |j                          y # 1 sw Y   UxY w# 1 sw Y   &xY w)Nr!   Fc                    d} 	 j                  j                         dd      }|xs g D cg c]&  }|j                  d      s|j                  dd      ( }}|rddj                  d |D              z   } j	                          j                  5  j                  k(  r| _        d
_        d d d        y c c}w # t
        $ r0}j                          t        j                  d	|       Y d }~ld }~ww xY w# 1 sw Y   y xY w)Nr!   
   FfiltersrG   rH   memoryz## Mem0 Memory

c              3  &   K   | ]	  }d |   yw)z- Nrs   ).0ls     r   	<genexpr>zCMem0MemoryProvider._start_prefetch.<locals>._run.<locals>.<genexpr>  s     9RqBqc(9Rs   zMem0 prefetch failed: %sT)searchr   r1   joinr   r8   r   r   debugrl   rc   rd   re   )bodyresultsrlinesr   backendrF   ro   s        r   _runz0Mem0MemoryProvider._start_prefetch.<locals>._run  s   D
<!..4#5#5#7r% )  8?}"Yxx,YY-		9RE9R0RRD$$& $$ /''50,0D)*.D'/ / Z  <$$&7;;</ /s:   +C B=B=/C C>=C 	C;&C66C;>DTzmem0-prefetchtargetdaemonrK   )rX   r   rl   rc   re   rb   is_aliverd   rh   Threadstart)ro   rF   r   tr   s   ``  @r   r   z"Mem0MemoryProvider._start_prefetch  s    -1F1F1H--   	(##u,&&	( 	( ((T-B-B-K-K-M	( 	( $)D $&D!"'D	(	/$ DOL   	&$%D!	&		?	( 	(:	& 	&s#   C:!'C:C:D:DDr!   )r   c               &   | j                  |      }||S | j                  |       | j                  5  | j                  |k(  r| j                  nd}ddd       r|j                  t               | j                  |      }||S y# 1 sw Y   7xY w)zDRecall memories for the CURRENT question with a short hot-path wait.Nr   r!   )r   r   rl   rc   rb   r   _PREFETCH_WAIT_SECS)ro   rF   r   cachedthreads        r   prefetchzMem0MemoryProvider.prefetch  s    ..u5MU#   	V.2.B.Be.KT**QUF	VKK 3K4..u5M	V 	Vs   BBc                    j                    j                         ry fd} j                  5   j                  r6 j                  j	                         r j                  j                  d        j                  r$ j                  j	                         r
	 ddd       yt        j                  |dd       _         j                  j                          ddd       y# 1 sw Y   yxY w)zESend the turn to Mem0 for server-side fact extraction (non-blocking).Nc                 B   j                   } | y 	 ddddg}| j                  |j                  j                  dj	                                j                          y # t        $ r0}j                          t        j                  d|       Y d }~y d }~ww xY w)NuserrolerN   	assistantTr+   r(   infermetadatazMem0 sync failed: %s)
rX   addr]   r^   r   r   r8   r   r   r   )r   messagesr   assistant_contentro   user_contents      r   _syncz+Mem0MemoryProvider.sync_turn.<locals>._sync  s    mmG:#=(5FG  MM!^^!113   $$& :$$&5q99:s   AA% %	B.&BB      @r   Tz	mem0-syncr   )	rX   r   rk   ra   r   r   rh   r   r   )ro   r  r  r   r  s   ```  r   	sync_turnzMem0MemoryProvider.sync_turn  s    == D$9$9$;	:* __ 	&  T%6%6%?%?%A!!&&s&3  T%6%6%?%?%A	& 	& !* 0 0dQ\ ]D##%	& 	& 	&s   A*C''7C''C0c                .    t         t        t        t        gS r   )SEARCH_SCHEMA
ADD_SCHEMAUPDATE_SCHEMADELETE_SCHEMArn   s    r   get_tool_schemasz#Mem0MemoryProvider.get_tool_schemas  s    z=-HHr   c                
   | j                   t        | dd      }d}| j                  dk(  rD| j                  j	                  di       j	                  di       }|j	                  dd      }d| d	}t        j                  d
d| d| i      S | j                         rmd}| j                  dk(  rE| j                  j	                  di       j	                  di       }|d|j	                  dd       dz  }t        j                  d
|i      S |dk(  rS|j	                  dd      }	|	st        d      S 	 t        dt        t        |j	                  dd            d            }
|j	                  dt        | dd            }t        |t              r|j                         dv}nt        |      }| j                   j!                  |	| j#                         |
|      }| j%                          |st        j                  ddi      S |D cg c]7  }|j	                  d      |j	                  dd      |j	                  d d!      d"9 }}t        j                  |t'        |      d#      S |d%k(  r|j	                  d&d      }|st        d'      S 	 | j                   j1                  d(|d)g| j2                  | j4                  d| j7                         *      }| j%                          t        |t8              r|j	                  d+      nd }| j                  dk(  s| j:                  rd,nd-}t        j                  ||d.      S |d0k(  r|j	                  d1d      }|j	                  d2d      }|st        d3      S |st        d4      S 	 | j                   j=                  ||      }| j%                          t        j                  |      S |d7k(  r`|j	                  d1d      }|st        d3      S 	 | j                   j?                  |      }| j%                          t        j                  |      S t        d9|       S c c}w # t(        $ r@}t+        |      s| j-                          t        | j/                  d$|            cY d }~S d }~ww xY w# t(        $ r5}| j-                          t        | j/                  d/|            cY d }~S d }~ww xY w# t(        $ rS}t+        |      rt        d5|       cY d }~S | j-                          t        | j/                  d6|            cY d }~S d }~ww xY w# t(        $ rS}t+        |      rt        d5|       cY d }~S | j-                          t        | j/                  d8|            cY d }~S d }~ww xY w):Nr   zunknown errorr!   r)   ru   r   r   z Check that z is running and reachable.r   zMem0 backend not initialized: .zWMem0 temporarily unavailable (multiple consecutive failures). Will retry automatically.r   z is running.r@   rF   z!Missing required parameter: queryr   rG   r   2   rH   r_   F)r   0nor   r   zNo relevant memories found.idr   scorer   )r  r   r  )r   r   zSearch failedrM   rN   z#Missing required parameter: contentr   r   r   event_idzFact stored.zFact queued for storage.)r   r  zFailed to storerO   rP   rQ   z%Missing required parameter: memory_idz Missing required parameter: textzMemory not found: zUpdate failedrR   zDelete failedzUnknown tool: ) rX   getattrrY   rW   r1   r3   dumpsr   r   maxminintr   r   r   rv   r   r   r   lenr8   r   r   r   r   r]   r^   r   dictr[   r6   delete)ro   	tool_nameargsr   errr   r   r   r   rF   rG   
rerank_rawrH   r   r   r7   r   rN   r   r  rP   rQ   s                         r   handle_tool_callz#Mem0MemoryProvider.handle_tool_call  s   == $?CDzzU"\\%%eR044^RH66*n=%hZ/IJ::w*HQtf(UVWW  "kCzzU"\\%%eR044^RH*266*n+M*Nl[[::wn--%HHWb)E!"EFFJAs3txx'<#=rBC!XXh>OQV0WX
j#.'--/7KKF!*-F--..ud>P>P>RZ_hn.o$$&::x1N&OPP?FH:; !"dquuXr7J#$55!#46 H Hzzec%j"IJJ *$hhy"-G!"GHHL**$9: MM!^^!113 +  $$&5?5M6::j1SW)-u)<

nQkzzSh"GHH
 -'b1I88FB'D!"IJJ!"DEEJ--i>$$&zz&)) -'b1I!"IJJJ--i8$$&zz&)) N9+677yH  J'*((*!$"4"4_a"HIIJ,  L$$&!$"4"45F"JKKL  J#A&%(:9+&FGG$$&!$"4"4_a"HII	J  J#A&%(:9+&FGG$$&!$"4"4_a"HII	Js   /CP4 ?P4 <P/?"P4 B/R  ;A S !?T  /P4 4	Q==5Q82Q=8Q= 	R>	*R93R>9R>	T
T"T(*TTT 	U<)U7U<*U71U<7U<c                    	 | j                   r"| j                   j                          d | _         y y # t        $ r Y y w xY wr   )rX   closer8   rn   s    r   r   z$Mem0MemoryProvider._shutdown_backendb  s>    	}}##% $   		s   -1 	==c                    | j                   | j                  fD ](  }|s|j                         s|j                  d       * | j	                          y )Nr  r   )rb   ra   r   r   r   )ro   r   s     r   shutdownzMem0MemoryProvider.shutdownj  sI    ''):):; 	$AQZZ\s#	$ 	 r   N)returnr   )r&  rv   )r   r   r9   r  r&  None)r   r   r   r8   r&  r   )r   r   r&  r'  )r&  zDict[str, Any])r   r  r   r   r&  r'  )rF   r   r&  z
str | None)rF   r   r&  r'  )rF   r   r   r   r&  r   )r  r   r  r   r   r   r&  r'  )r&  zList[Dict[str, Any]])r  r   r  r  r&  r   r&  r'  )r   
__module____qualname____doc__rp   propertyrK   rx   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r!  r   r%  rs   r   r   rT   rT      s    
(.  ;=

(6+(!+F*C

:&#J 9;   Y[ !&FI\8|!r   rT   c                6    | j                  t                      y)z*Register Mem0 as a memory provider plugin.N)register_memory_providerrT   )ctxs    r   r   r   q  s      !3!56r   )r   r8   r&  rv   )r&  r  r(  )!r+  
__future__r   r   r3   loggingr/   rh   r   typingr   r   r   agent.memory_providerr   tools.registryr   	getLoggerr   r   r   r   r   r   r\   r   r?   r  r	  r
  r  rT   r   rs   r   r   <module>r6     sg  @ #    	   " " 0 %			8	$    @  ! Q P 	G &7LM'8]^(9}~

 I, 	 9MN
 K
& 	N
 "*;ST%6IJ
 !&)$ 	D
 (;ST
 !M*m! m!`7r   