2323 VectorStoreWrapper ,
2424)
2525from opentelemetry .instrumentation .mem0 .package import _instruments
26+ from opentelemetry .instrumentation .mem0 .types import set_memory_hooks
2627from opentelemetry .instrumentation .mem0 .version import __version__
2728from opentelemetry .instrumentation .utils import unwrap
2829from opentelemetry .semconv .schemas import Schemas
@@ -127,6 +128,12 @@ def _instrument(self, **kwargs: Any) -> None:
127128 # Optional: logger provider for GenAI events (util will no-op if not provided)
128129 logger_provider = kwargs .get ("logger_provider" )
129130
131+ # Optional hooks for extensions (e.g. commercial metrics). We only pass through.
132+ memory_before_hook = kwargs .get ("memory_before_hook" )
133+ memory_after_hook = kwargs .get ("memory_after_hook" )
134+ inner_before_hook = kwargs .get ("inner_before_hook" )
135+ inner_after_hook = kwargs .get ("inner_after_hook" )
136+
130137 # Create util GenAI handler (strong dependency, no fallback).
131138 # Avoid singleton here so tests (and multiple tracer providers) don't leak across runs.
132139 telemetry_handler = ExtendedTelemetryHandler (
@@ -144,13 +151,33 @@ def _instrument(self, **kwargs: Any) -> None:
144151 )
145152
146153 # Execute instrumentation (traces only, metrics removed)
147- self ._instrument_memory_operations (telemetry_handler )
148- self ._instrument_memory_client_operations (telemetry_handler )
154+ self ._instrument_memory_operations (
155+ telemetry_handler ,
156+ memory_before_hook = memory_before_hook ,
157+ memory_after_hook = memory_after_hook ,
158+ )
159+ self ._instrument_memory_client_operations (
160+ telemetry_handler ,
161+ memory_before_hook = memory_before_hook ,
162+ memory_after_hook = memory_after_hook ,
163+ )
149164 # Sub-phases controlled by toggle, avoid binding wrapper when disabled to reduce overhead
150165 if mem0_config .is_internal_phases_enabled ():
151- self ._instrument_vector_operations (tracer )
152- self ._instrument_graph_operations (tracer )
153- self ._instrument_reranker_operations (tracer )
166+ self ._instrument_vector_operations (
167+ tracer ,
168+ inner_before_hook = inner_before_hook ,
169+ inner_after_hook = inner_after_hook ,
170+ )
171+ self ._instrument_graph_operations (
172+ tracer ,
173+ inner_before_hook = inner_before_hook ,
174+ inner_after_hook = inner_after_hook ,
175+ )
176+ self ._instrument_reranker_operations (
177+ tracer ,
178+ inner_before_hook = inner_before_hook ,
179+ inner_after_hook = inner_after_hook ,
180+ )
154181
155182 def _uninstrument (self , ** kwargs : Any ) -> None :
156183 """Remove instrumentation."""
@@ -392,7 +419,13 @@ def _wrapper(wrapped, instance, args, kwargs):
392419
393420 return _wrapper
394421
395- def _instrument_memory_operations (self , telemetry_handler ):
422+ def _instrument_memory_operations (
423+ self ,
424+ telemetry_handler ,
425+ * ,
426+ memory_before_hook = None ,
427+ memory_after_hook = None ,
428+ ):
396429 """Instrument Memory and AsyncMemory operations."""
397430 try :
398431 if (
@@ -407,6 +440,11 @@ def _instrument_memory_operations(self, telemetry_handler):
407440 return
408441
409442 wrapper = MemoryOperationWrapper (telemetry_handler )
443+ set_memory_hooks (
444+ wrapper ,
445+ memory_before_hook = memory_before_hook ,
446+ memory_after_hook = memory_after_hook ,
447+ )
410448
411449 # Instrument Memory (sync)
412450 for method in self ._public_methods_of (
@@ -444,7 +482,13 @@ def _instrument_memory_operations(self, telemetry_handler):
444482 except Exception as e :
445483 logger .debug (f"Failed to instrument Memory operations: { e } " )
446484
447- def _instrument_memory_client_operations (self , telemetry_handler ):
485+ def _instrument_memory_client_operations (
486+ self ,
487+ telemetry_handler ,
488+ * ,
489+ memory_before_hook = None ,
490+ memory_after_hook = None ,
491+ ):
448492 """Instrument MemoryClient and AsyncMemoryClient operations."""
449493 try :
450494 if (
@@ -459,6 +503,11 @@ def _instrument_memory_client_operations(self, telemetry_handler):
459503 return
460504
461505 wrapper = MemoryOperationWrapper (telemetry_handler )
506+ set_memory_hooks (
507+ wrapper ,
508+ memory_before_hook = memory_before_hook ,
509+ memory_after_hook = memory_after_hook ,
510+ )
462511
463512 # Instrument MemoryClient (sync)
464513 for method in self ._public_methods_of (
@@ -594,7 +643,13 @@ def _factory_wrapper(wrapped, instance, args, kwargs):
594643 except Exception as e :
595644 logger .debug (f"Failed to wrap { factory_class } .create: { e } " )
596645
597- def _instrument_vector_operations (self , tracer ):
646+ def _instrument_vector_operations (
647+ self ,
648+ tracer ,
649+ * ,
650+ inner_before_hook = None ,
651+ inner_after_hook = None ,
652+ ):
598653 """Instrument VectorStore operations."""
599654 try :
600655 # Require both VectorStoreBase and VectorStoreFactory to be available
@@ -632,7 +687,11 @@ def _instrument_vector_operations(self, tracer):
632687 ]
633688
634689 # Create VectorStoreWrapper instance (trace-only)
635- vector_wrapper = VectorStoreWrapper (tracer )
690+ vector_wrapper = VectorStoreWrapper (
691+ tracer ,
692+ inner_before_hook = inner_before_hook ,
693+ inner_after_hook = inner_after_hook ,
694+ )
636695
637696 # Use generic factory wrapping method
638697 self ._wrap_factory_for_phase (
@@ -647,7 +706,13 @@ def _instrument_vector_operations(self, tracer):
647706 except Exception as e :
648707 logger .debug (f"Failed to instrument vector store operations: { e } " )
649708
650- def _instrument_graph_operations (self , tracer ):
709+ def _instrument_graph_operations (
710+ self ,
711+ tracer ,
712+ * ,
713+ inner_before_hook = None ,
714+ inner_after_hook = None ,
715+ ):
651716 """Instrument GraphStore operations."""
652717 try :
653718 # If factories are unavailable, graph subphase instrumentation cannot be enabled
@@ -687,7 +752,11 @@ def _instrument_graph_operations(self, tracer):
687752 ]
688753
689754 # Create GraphStoreWrapper instance (trace-only)
690- graph_wrapper = GraphStoreWrapper (tracer )
755+ graph_wrapper = GraphStoreWrapper (
756+ tracer ,
757+ inner_before_hook = inner_before_hook ,
758+ inner_after_hook = inner_after_hook ,
759+ )
691760
692761 # Use generic factory wrapping method
693762 self ._wrap_factory_for_phase (
@@ -702,7 +771,13 @@ def _instrument_graph_operations(self, tracer):
702771 except Exception as e :
703772 logger .debug (f"Failed to instrument graph store operations: { e } " )
704773
705- def _instrument_reranker_operations (self , tracer ):
774+ def _instrument_reranker_operations (
775+ self ,
776+ tracer ,
777+ * ,
778+ inner_before_hook = None ,
779+ inner_after_hook = None ,
780+ ):
706781 """Instrument Reranker operations."""
707782 try :
708783 if not _FACTORIES_AVAILABLE or RerankerFactory is None :
@@ -713,7 +788,11 @@ def _instrument_reranker_operations(self, tracer):
713788 return
714789
715790 # Create RerankerWrapper instance (trace-only)
716- reranker_wrapper = RerankerWrapper (tracer )
791+ reranker_wrapper = RerankerWrapper (
792+ tracer ,
793+ inner_before_hook = inner_before_hook ,
794+ inner_after_hook = inner_after_hook ,
795+ )
717796
718797 # Use generic factory wrapping method
719798 self ._wrap_factory_for_phase (
0 commit comments