3636from pathlib import Path
3737from typing import Any , Callable , Dict , List , Optional , Union
3838
39+ from dhee .checkpoint_runtime import run_checkpoint_common
40+
3941logger = logging .getLogger (__name__ )
4042
4143
@@ -118,6 +120,11 @@ def kernel(self):
118120 """Access the CognitionKernel for direct state manipulation."""
119121 return self ._kernel
120122
123+ @property
124+ def memory (self ):
125+ """Expose the configured runtime memory engine for advanced integrations."""
126+ return self ._engram .memory
127+
121128 # ------------------------------------------------------------------
122129 # Hook registry
123130 # ------------------------------------------------------------------
@@ -153,6 +160,13 @@ def _fire_hooks(self, event: str, data: Any) -> None:
153160 except Exception :
154161 logger .debug ("Hook %s failed" , event )
155162
163+ @staticmethod
164+ def _health_error (component : str , exc : Exception ) -> Dict [str , str ]:
165+ return {
166+ "component" : component ,
167+ "error" : f"{ type (exc ).__name__ } : { exc } " ,
168+ }
169+
156170 # ------------------------------------------------------------------
157171 # Tool 1: remember
158172 # ------------------------------------------------------------------
@@ -257,7 +271,7 @@ def context(
257271 hyper_ctx = self ._buddhi .get_hyper_context (
258272 user_id = uid ,
259273 task_description = task_description ,
260- memory = self ._engram . _memory ,
274+ memory = self .memory ,
261275 )
262276 if operational :
263277 result = hyper_ctx .to_operational_dict ()
@@ -325,62 +339,29 @@ def checkpoint(
325339 if not what_worked :
326340 what_worked = outcome .get ("what_worked" )
327341
328- result : Dict [str , Any ] = {}
329- score = max (0.0 , min (1.0 , float (outcome_score ))) if outcome_score is not None else None
330-
331- # 1. Session digest
332- try :
333- from dhee .core .kernel import save_session_digest
334- digest = save_session_digest (
335- task_summary = summary , agent_id = agent_id , repo = repo ,
336- status = status , decisions_made = decisions ,
337- files_touched = files_touched , todos_remaining = todos ,
338- )
339- result ["session_saved" ] = True
340- if isinstance (digest , dict ):
341- result ["session_id" ] = digest .get ("session_id" )
342- except Exception :
343- result ["session_saved" ] = False
344-
345- # 2. Batch enrichment
346- memory = self ._engram ._memory
347- if hasattr (memory , "enrich_pending" ):
348- try :
349- enrich_result = memory .enrich_pending (
350- user_id = uid , batch_size = 10 , max_batches = 5 ,
351- )
352- enriched = enrich_result .get ("enriched_count" , 0 )
353- if enriched > 0 :
354- result ["memories_enriched" ] = enriched
355- except Exception :
356- pass
357-
358- # 3. Outcome recording
359- if task_type and score is not None :
360- insight = self ._buddhi .record_outcome (
361- user_id = uid , task_type = task_type , score = score ,
362- )
363- result ["outcome_recorded" ] = True
364- if insight :
365- result ["auto_insight" ] = insight .to_dict ()
366-
367- # 4. Insight synthesis
368- if any ([what_worked , what_failed , key_decision ]):
369- insights = self ._buddhi .reflect (
370- user_id = uid , task_type = task_type or "general" ,
371- what_worked = what_worked , what_failed = what_failed ,
372- key_decision = key_decision ,
373- outcome_score = score if score is not None else None ,
374- )
375- result ["insights_created" ] = len (insights )
376-
377- # 5. Intention storage
378- if remember_to :
379- intention = self ._buddhi .store_intention (
380- user_id = uid , description = remember_to ,
381- trigger_keywords = trigger_keywords ,
382- )
383- result ["intention_stored" ] = intention .to_dict ()
342+ result = run_checkpoint_common (
343+ logger = logger ,
344+ log_prefix = "Plugin checkpoint" ,
345+ user_id = uid ,
346+ summary = summary ,
347+ status = status ,
348+ agent_id = agent_id ,
349+ repo = repo ,
350+ decisions = decisions ,
351+ files_touched = files_touched ,
352+ todos = todos ,
353+ task_type = task_type ,
354+ outcome_score = outcome_score ,
355+ what_worked = what_worked ,
356+ what_failed = what_failed ,
357+ key_decision = key_decision ,
358+ remember_to = remember_to ,
359+ trigger_keywords = trigger_keywords ,
360+ enrich_pending_fn = self ._engram .enrich_pending ,
361+ record_outcome_fn = self ._buddhi .record_outcome ,
362+ reflect_fn = self ._buddhi .reflect ,
363+ store_intention_fn = self ._buddhi .store_intention ,
364+ )
384365
385366 # 6. Episode closure (via kernel)
386367 ep_result = self ._kernel .record_checkpoint_event (
@@ -441,8 +422,8 @@ def session_start(
441422 task_description = task_description or "session" ,
442423 task_type = task_type or "general" ,
443424 )
444- except Exception :
445- pass
425+ except Exception as exc :
426+ logger . warning ( "Session start episode initialization failed: %s" , exc , exc_info = True )
446427
447428 ctx = self .context (task_description = task_description , user_id = uid )
448429 return self ._render_system_prompt (ctx , task_description )
@@ -479,17 +460,19 @@ def _handle_tracker_signals(self, signals: Dict[str, Any], user_id: str) -> None
479460 if signals .get ("needs_auto_checkpoint" ):
480461 args = signals .get ("auto_checkpoint_args" , {})
481462 try :
482- self .checkpoint (user_id = user_id , ** args )
483- except Exception :
484- pass
463+ checkpoint_result = self .checkpoint (user_id = user_id , ** args )
464+ for warning in checkpoint_result .get ("warnings" , []):
465+ logger .warning ("Plugin auto-checkpoint warning: %s" , warning )
466+ except Exception as exc :
467+ logger .warning ("Plugin auto-checkpoint failed: %s" , exc , exc_info = True )
485468
486469 # Auto-context for new session
487470 if signals .get ("needs_auto_context" ):
488471 task = signals .get ("inferred_task" )
489472 try :
490473 self .context (task_description = task , user_id = user_id )
491- except Exception :
492- pass
474+ except Exception as exc :
475+ logger . warning ( "Plugin auto-context failed: %s" , exc , exc_info = True )
493476
494477 # ------------------------------------------------------------------
495478 # Cognition health (harness monitoring)
@@ -503,6 +486,7 @@ def cognition_health(self, user_id: Optional[str] = None) -> Dict[str, Any]:
503486 """
504487 uid = user_id or self ._user_id
505488 health : Dict [str , Any ] = {}
489+ errors : List [Dict [str , str ]] = []
506490
507491 health ["kernel" ] = self ._kernel .get_stats ()
508492 health ["buddhi" ] = self ._buddhi .get_stats ()
@@ -513,16 +497,45 @@ def cognition_health(self, user_id: Optional[str] = None) -> Dict[str, Any]:
513497 low_util = [p for p in policies if p .utility < - 0.2 and p .apply_count >= 3 ]
514498 if low_util :
515499 warnings .append (f"{ len (low_util )} policies with negative utility" )
500+ except Exception as exc :
501+ logger .warning (
502+ "Cognition health derivation failed for policies: %s" ,
503+ exc ,
504+ exc_info = True ,
505+ )
506+ errors .append (self ._health_error ("policies.get_user_policies" , exc ))
507+
508+ try :
516509 active_intentions = self ._kernel .intentions .get_active (uid )
517510 if len (active_intentions ) > 20 :
518- warnings .append (f"{ len (active_intentions )} active intentions (consider cleanup)" )
511+ warnings .append (
512+ f"{ len (active_intentions )} active intentions (consider cleanup)"
513+ )
514+ except Exception as exc :
515+ logger .warning (
516+ "Cognition health derivation failed for intentions: %s" ,
517+ exc ,
518+ exc_info = True ,
519+ )
520+ errors .append (self ._health_error ("intentions.get_active" , exc ))
521+
522+ try :
519523 contradictions = self ._kernel .beliefs .get_contradictions (uid )
520524 if len (contradictions ) > 5 :
521- warnings .append (f"{ len (contradictions )} unresolved belief contradictions" )
522- except Exception :
523- pass
525+ warnings .append (
526+ f"{ len (contradictions )} unresolved belief contradictions"
527+ )
528+ except Exception as exc :
529+ logger .warning (
530+ "Cognition health derivation failed for contradictions: %s" ,
531+ exc ,
532+ exc_info = True ,
533+ )
534+ errors .append (self ._health_error ("beliefs.get_contradictions" , exc ))
524535
525536 health ["warnings" ] = warnings
537+ if errors :
538+ health ["errors" ] = errors
526539 return health
527540
528541 # ------------------------------------------------------------------
@@ -640,14 +653,37 @@ def end_trajectory(
640653 # Store trajectory as memory for skill mining
641654 try :
642655 from dhee .skills .trajectory import TrajectoryStore
643- store = TrajectoryStore (memory = self ._engram . _memory )
656+ store = TrajectoryStore (memory = self .memory )
644657 store .save (trajectory )
645658 result ["stored" ] = True
646- except Exception :
659+ except Exception as exc :
660+ logger .warning ("Trajectory persistence failed: %s" , exc , exc_info = True )
647661 result ["stored" ] = False
662+ result ["storage_error" ] = str (exc )
648663
649664 return result
650665
666+ def close (self ) -> None :
667+ """Flush cognition state and release runtime resources."""
668+ errors : List [str ] = []
669+
670+ try :
671+ self ._buddhi .flush ()
672+ except Exception as exc :
673+ logger .exception ("DheePlugin close failed for buddhi.flush" )
674+ errors .append (f"buddhi.flush: { type (exc ).__name__ } : { exc } " )
675+
676+ try :
677+ self ._engram .close ()
678+ except Exception as exc :
679+ logger .exception ("DheePlugin close failed for engram.close" )
680+ errors .append (f"engram.close: { type (exc ).__name__ } : { exc } " )
681+
682+ if errors :
683+ raise RuntimeError (
684+ "Failed to close DheePlugin resources: " + "; " .join (errors )
685+ )
686+
651687 # ------------------------------------------------------------------
652688 # Framework export: OpenAI function calling
653689 # ------------------------------------------------------------------
0 commit comments