88
99from __future__ import annotations
1010
11+ import contextlib
1112import json
1213import logging
13- import os
1414import re
1515import sys
1616import threading
17+
1718from pathlib import Path
18- from typing import Any , Dict , List
19+ from typing import Any
20+
1921
2022# Add this directory to sys.path so sibling modules (config, bridge_client, …) resolve
2123_PLUGIN_DIR = Path (__file__ ).resolve ().parent
2224if str (_PLUGIN_DIR ) not in sys .path :
2325 sys .path .insert (0 , str (_PLUGIN_DIR ))
2426
25- from agent .memory_provider import MemoryProvider
26- from tools .registry import tool_error
27+ from agent .memory_provider import MemoryProvider # noqa: E402
28+ from tools .registry import tool_error # noqa: E402
29+
2730
2831logger = logging .getLogger (__name__ )
2932
5154 re .compile (r'^\s*\{["\']?ok["\']?\s*:\s*true\s*\}\s*$' , re .IGNORECASE ),
5255 re .compile (r'^\s*\{["\']?success["\']?\s*:\s*true\s*\}\s*$' , re .IGNORECASE ),
5356 re .compile (r'^\s*\{["\']?status["\']?\s*:\s*["\']?ok["\']?\s*\}\s*$' , re .IGNORECASE ),
54- re .compile (r' ^Operation interrupted:' , re .IGNORECASE ),
55- re .compile (r' ^Error:' , re .IGNORECASE ),
56- re .compile (r' waiting for model response.*elapsed' , re .IGNORECASE ),
57- re .compile (r' ^\s*$' ),
57+ re .compile (r" ^Operation interrupted:" , re .IGNORECASE ),
58+ re .compile (r" ^Error:" , re .IGNORECASE ),
59+ re .compile (r" waiting for model response.*elapsed" , re .IGNORECASE ),
60+ re .compile (r" ^\s*$" ),
5861]
5962
6063_MIN_CONTENT_LENGTH = 6
@@ -74,7 +77,10 @@ def _is_trivial(text: str) -> bool:
7477 keys = {k .lower () for k in obj }
7578 if keys <= {"ok" , "success" , "status" , "result" , "error" , "message" }:
7679 vals = list (obj .values ())
77- if all (isinstance (v , (bool , type (None ))) or (isinstance (v , str ) and len (v ) < 20 ) for v in vals ):
80+ if all (
81+ isinstance (v , (bool , type (None ))) or (isinstance (v , str ) and len (v ) < 20 )
82+ for v in vals
83+ ):
7884 return True
7985 except (json .JSONDecodeError , TypeError ):
8086 pass
@@ -100,6 +106,7 @@ def name(self) -> str:
100106 def is_available (self ) -> bool :
101107 try :
102108 from config import find_bridge_script
109+
103110 find_bridge_script ()
104111 return True
105112 except Exception :
@@ -109,6 +116,7 @@ def initialize(self, session_id: str, **kwargs) -> None:
109116 self ._session_id = session_id
110117
111118 from daemon_manager import ensure_daemon
119+
112120 try :
113121 info = ensure_daemon ()
114122 logger .info (
@@ -121,6 +129,7 @@ def initialize(self, session_id: str, **kwargs) -> None:
121129 logger .warning ("Failed to start MemTensor daemon: %s" , e )
122130
123131 from bridge_client import MemosCoreBridge
132+
124133 try :
125134 self ._bridge = MemosCoreBridge ()
126135 logger .info ("MemTensor bridge connected" )
@@ -175,6 +184,7 @@ def _run():
175184 if pending and self ._bridge :
176185 try :
177186 from config import OWNER
187+
178188 user_content , assistant_content , sid = pending
179189 messages = []
180190 if user_content :
@@ -201,9 +211,7 @@ def _do_recall(self, query: str) -> str:
201211 parts : list [str ] = []
202212
203213 try :
204- search_resp = self ._bridge .search (
205- query , max_results = 5 , min_score = 0.4 , owner = OWNER
206- )
214+ search_resp = self ._bridge .search (query , max_results = 5 , min_score = 0.4 , owner = OWNER )
207215 hits = search_resp .get ("hits" ) or search_resp .get ("memories" ) or []
208216 for h in hits :
209217 text = h .get ("original_excerpt" ) or h .get ("content" ) or h .get ("summary" , "" )
@@ -225,9 +233,7 @@ def _do_recall(self, query: str) -> str:
225233
226234 return "\n " .join (parts )
227235
228- def sync_turn (
229- self , user_content : str , assistant_content : str , * , session_id : str = ""
230- ) -> None :
236+ def sync_turn (self , user_content : str , assistant_content : str , * , session_id : str = "" ) -> None :
231237 """Queue turn data for deferred ingest.
232238
233239 Hermes calls sync_all() BEFORE queue_prefetch_all(), so ingesting
@@ -239,8 +245,11 @@ def sync_turn(
239245 if not self ._bridge :
240246 return
241247 if _is_trivial (user_content ) and _is_trivial (assistant_content ):
242- logger .debug ("sync_turn: skipping trivial turn (user=%r, assistant=%r)" ,
243- user_content [:80 ] if user_content else "" , assistant_content [:80 ] if assistant_content else "" )
248+ logger .debug (
249+ "sync_turn: skipping trivial turn (user=%r, assistant=%r)" ,
250+ user_content [:80 ] if user_content else "" ,
251+ assistant_content [:80 ] if assistant_content else "" ,
252+ )
244253 return
245254 if _is_trivial (user_content ):
246255 user_content = ""
@@ -249,10 +258,10 @@ def sync_turn(
249258 sid = session_id or self ._session_id or "default"
250259 self ._pending_ingest = (user_content , assistant_content , sid )
251260
252- def get_tool_schemas (self ) -> List [ Dict [str , Any ]]:
261+ def get_tool_schemas (self ) -> list [ dict [str , Any ]]:
253262 return [MEMORY_SEARCH_SCHEMA ]
254263
255- def handle_tool_call (self , tool_name : str , args : Dict [str , Any ], ** kwargs ) -> str :
264+ def handle_tool_call (self , tool_name : str , args : dict [str , Any ], ** kwargs ) -> str :
256265 if tool_name != "memory_search" :
257266 return tool_error (f"Unknown tool: { tool_name } " )
258267
@@ -265,6 +274,7 @@ def handle_tool_call(self, tool_name: str, args: Dict[str, Any], **kwargs) -> st
265274
266275 try :
267276 from config import OWNER
277+
268278 resp = self ._bridge .search (query , max_results = 8 , owner = OWNER )
269279 hits = resp .get ("hits" ) or resp .get ("memories" ) or []
270280 if not hits :
@@ -285,6 +295,7 @@ def on_memory_write(self, action: str, target: str, content: str) -> None:
285295 return
286296
287297 from config import OWNER
298+
288299 label = "user_profile" if target == "user" else "memory"
289300 messages = [
290301 {"role" : "system" , "content" : f"[{ label } ] { content } " },
@@ -298,14 +309,16 @@ def _write():
298309 owner = OWNER ,
299310 )
300311 self ._bridge .flush ()
301- logger .info ("MemTensor on_memory_write: %s %s (%d chars)" , action , target , len (content ))
312+ logger .info (
313+ "MemTensor on_memory_write: %s %s (%d chars)" , action , target , len (content )
314+ )
302315 except Exception as e :
303316 logger .warning ("MemTensor on_memory_write failed: %s" , e )
304317
305318 t = threading .Thread (target = _write , daemon = True , name = "memtensor-memory-write" )
306319 t .start ()
307320
308- def on_session_end (self , messages : List [ Dict [str , Any ]]) -> None :
321+ def on_session_end (self , messages : list [ dict [str , Any ]]) -> None :
309322 if not self ._bridge :
310323 return
311324 # Flush any deferred ingest that hasn't been picked up by queue_prefetch
@@ -314,6 +327,7 @@ def on_session_end(self, messages: List[Dict[str, Any]]) -> None:
314327 if pending :
315328 try :
316329 from config import OWNER
330+
317331 user_content , assistant_content , sid = pending
318332 msgs = []
319333 if user_content :
@@ -334,10 +348,8 @@ def shutdown(self) -> None:
334348 if t and t .is_alive ():
335349 t .join (timeout = 5.0 )
336350 if self ._bridge :
337- try :
351+ with contextlib . suppress ( Exception ) :
338352 self ._bridge .shutdown ()
339- except Exception :
340- pass
341353 self ._bridge = None
342354
343355
0 commit comments