claude-mpm 3.8.1__py3-none-any.whl → 3.9.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +59 -135
- claude_mpm/agents/MEMORY.md +39 -30
- claude_mpm/agents/WORKFLOW.md +54 -4
- claude_mpm/agents/agents_metadata.py +25 -1
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +88 -0
- claude_mpm/agents/templates/project_organizer.json +178 -0
- claude_mpm/agents/templates/research.json +33 -30
- claude_mpm/agents/templates/ticketing.json +3 -3
- claude_mpm/cli/commands/agents.py +8 -3
- claude_mpm/core/claude_runner.py +31 -10
- claude_mpm/core/config.py +2 -2
- claude_mpm/core/container.py +96 -25
- claude_mpm/core/framework_loader.py +43 -1
- claude_mpm/core/interactive_session.py +47 -0
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +454 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +144 -43
- claude_mpm/services/agents/memory/agent_memory_manager.py +4 -3
- claude_mpm/services/framework_claude_md_generator/__init__.py +10 -3
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +14 -11
- claude_mpm/services/response_tracker.py +3 -5
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/ticket_manager_di.py +1 -1
- claude_mpm/services/version_control/semantic_versioning.py +80 -7
- claude_mpm/services/version_control/version_parser.py +528 -0
- claude_mpm-3.9.2.dist-info/METADATA +200 -0
- {claude_mpm-3.8.1.dist-info → claude_mpm-3.9.2.dist-info}/RECORD +32 -28
- claude_mpm-3.8.1.dist-info/METADATA +0 -327
- {claude_mpm-3.8.1.dist-info → claude_mpm-3.9.2.dist-info}/WHEEL +0 -0
- {claude_mpm-3.8.1.dist-info → claude_mpm-3.9.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.8.1.dist-info → claude_mpm-3.9.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.8.1.dist-info → claude_mpm-3.9.2.dist-info}/top_level.txt +0 -0
    
        claude_mpm/core/container.py
    CHANGED
    
    | @@ -18,6 +18,7 @@ from enum import Enum | |
| 18 18 | 
             
            from typing import Any, Callable, Dict, List, Optional, Set, Type, TypeVar, Union
         | 
| 19 19 |  | 
| 20 20 | 
             
            from .logger import get_logger
         | 
| 21 | 
            +
            from claude_mpm.services.core.interfaces import IServiceContainer
         | 
| 21 22 |  | 
| 22 23 | 
             
            logger = get_logger(__name__)
         | 
| 23 24 |  | 
| @@ -144,10 +145,13 @@ class ServiceScope: | |
| 144 145 | 
             
                    self.dispose()
         | 
| 145 146 |  | 
| 146 147 |  | 
| 147 | 
            -
            class DIContainer:
         | 
| 148 | 
            +
            class DIContainer(IServiceContainer):
         | 
| 148 149 | 
             
                """
         | 
| 149 150 | 
             
                Enhanced Dependency Injection Container.
         | 
| 150 151 |  | 
| 152 | 
            +
                Implements IServiceContainer interface to provide a complete
         | 
| 153 | 
            +
                dependency injection solution.
         | 
| 154 | 
            +
                
         | 
| 151 155 | 
             
                Provides:
         | 
| 152 156 | 
             
                - Service registration with multiple lifetime options
         | 
| 153 157 | 
             
                - Automatic constructor injection
         | 
| @@ -174,6 +178,34 @@ class DIContainer: | |
| 174 178 | 
             
                    self._current_scope: Optional[ServiceScope] = None
         | 
| 175 179 |  | 
| 176 180 | 
             
                def register(
         | 
| 181 | 
            +
                    self,
         | 
| 182 | 
            +
                    service_type: type,
         | 
| 183 | 
            +
                    implementation: type,
         | 
| 184 | 
            +
                    singleton: bool = True
         | 
| 185 | 
            +
                ) -> None:
         | 
| 186 | 
            +
                    """
         | 
| 187 | 
            +
                    Register a service implementation (IServiceContainer interface method).
         | 
| 188 | 
            +
                    
         | 
| 189 | 
            +
                    Args:
         | 
| 190 | 
            +
                        service_type: The interface/base type to register
         | 
| 191 | 
            +
                        implementation: The concrete implementation class
         | 
| 192 | 
            +
                        singleton: Whether to use singleton lifetime (default True)
         | 
| 193 | 
            +
                        
         | 
| 194 | 
            +
                    Examples:
         | 
| 195 | 
            +
                        # Register interface with implementation
         | 
| 196 | 
            +
                        container.register(ILogger, ConsoleLogger)
         | 
| 197 | 
            +
                        
         | 
| 198 | 
            +
                        # Register as transient (new instance each time)
         | 
| 199 | 
            +
                        container.register(IService, ServiceImpl, singleton=False)
         | 
| 200 | 
            +
                    """
         | 
| 201 | 
            +
                    lifetime = ServiceLifetime.SINGLETON if singleton else ServiceLifetime.TRANSIENT
         | 
| 202 | 
            +
                    self._register_internal(
         | 
| 203 | 
            +
                        service_type=service_type,
         | 
| 204 | 
            +
                        implementation=implementation,
         | 
| 205 | 
            +
                        lifetime=lifetime
         | 
| 206 | 
            +
                    )
         | 
| 207 | 
            +
                
         | 
| 208 | 
            +
                def _register_internal(
         | 
| 177 209 | 
             
                    self,
         | 
| 178 210 | 
             
                    service_type: Type[T],
         | 
| 179 211 | 
             
                    implementation: Optional[Union[Type[T], Callable[..., T]]] = None,
         | 
| @@ -183,7 +215,7 @@ class DIContainer: | |
| 183 215 | 
             
                    dependencies: Optional[Dict[str, Type]] = None
         | 
| 184 216 | 
             
                ) -> None:
         | 
| 185 217 | 
             
                    """
         | 
| 186 | 
            -
                     | 
| 218 | 
            +
                    Internal registration method with full flexibility.
         | 
| 187 219 |  | 
| 188 220 | 
             
                    Args:
         | 
| 189 221 | 
             
                        service_type: The interface/base type to register
         | 
| @@ -192,19 +224,6 @@ class DIContainer: | |
| 192 224 | 
             
                        factory: Optional factory function
         | 
| 193 225 | 
             
                        instance: Pre-created instance (for singleton)
         | 
| 194 226 | 
             
                        dependencies: Explicit dependency mapping for constructor params
         | 
| 195 | 
            -
                        
         | 
| 196 | 
            -
                    Examples:
         | 
| 197 | 
            -
                        # Register interface with implementation
         | 
| 198 | 
            -
                        container.register(ILogger, ConsoleLogger)
         | 
| 199 | 
            -
                        
         | 
| 200 | 
            -
                        # Register with factory
         | 
| 201 | 
            -
                        container.register(IDatabase, factory=lambda c: Database(c.resolve(IConfig)))
         | 
| 202 | 
            -
                        
         | 
| 203 | 
            -
                        # Register singleton instance
         | 
| 204 | 
            -
                        container.register(IConfig, instance=Config())
         | 
| 205 | 
            -
                        
         | 
| 206 | 
            -
                        # Register with explicit dependencies
         | 
| 207 | 
            -
                        container.register(IService, ServiceImpl, dependencies={'logger': ILogger})
         | 
| 208 227 | 
             
                    """
         | 
| 209 228 | 
             
                    with self._lock:
         | 
| 210 229 | 
             
                        registration = ServiceRegistration(
         | 
| @@ -220,6 +239,50 @@ class DIContainer: | |
| 220 239 | 
             
                        # If instance provided, store as singleton
         | 
| 221 240 | 
             
                        if instance is not None:
         | 
| 222 241 | 
             
                            self._singletons[service_type] = instance
         | 
| 242 | 
            +
                
         | 
| 243 | 
            +
                def register_instance(self, service_type: type, instance: Any) -> None:
         | 
| 244 | 
            +
                    """
         | 
| 245 | 
            +
                    Register a service instance (IServiceContainer interface method).
         | 
| 246 | 
            +
                    
         | 
| 247 | 
            +
                    Args:
         | 
| 248 | 
            +
                        service_type: The interface/base type to register
         | 
| 249 | 
            +
                        instance: Pre-created instance to register as singleton
         | 
| 250 | 
            +
                        
         | 
| 251 | 
            +
                    Examples:
         | 
| 252 | 
            +
                        # Register a pre-created instance
         | 
| 253 | 
            +
                        config = Config()
         | 
| 254 | 
            +
                        container.register_instance(IConfig, config)
         | 
| 255 | 
            +
                    """
         | 
| 256 | 
            +
                    self._register_internal(
         | 
| 257 | 
            +
                        service_type=service_type,
         | 
| 258 | 
            +
                        instance=instance,
         | 
| 259 | 
            +
                        lifetime=ServiceLifetime.SINGLETON
         | 
| 260 | 
            +
                    )
         | 
| 261 | 
            +
                
         | 
| 262 | 
            +
                def resolve_all(self, service_type: type) -> List[Any]:
         | 
| 263 | 
            +
                    """
         | 
| 264 | 
            +
                    Resolve all implementations of a service type (IServiceContainer interface method).
         | 
| 265 | 
            +
                    
         | 
| 266 | 
            +
                    Args:
         | 
| 267 | 
            +
                        service_type: The type to resolve
         | 
| 268 | 
            +
                        
         | 
| 269 | 
            +
                    Returns:
         | 
| 270 | 
            +
                        List of all registered implementations for the service type
         | 
| 271 | 
            +
                        
         | 
| 272 | 
            +
                    Examples:
         | 
| 273 | 
            +
                        # Register multiple implementations
         | 
| 274 | 
            +
                        container.register(IPlugin, PluginA)
         | 
| 275 | 
            +
                        container.register(IPlugin, PluginB)
         | 
| 276 | 
            +
                        
         | 
| 277 | 
            +
                        # Get all implementations
         | 
| 278 | 
            +
                        plugins = container.resolve_all(IPlugin)
         | 
| 279 | 
            +
                    """
         | 
| 280 | 
            +
                    with self._lock:
         | 
| 281 | 
            +
                        # For now, return a list with the single registered implementation
         | 
| 282 | 
            +
                        # In the future, we could support multiple registrations for the same type
         | 
| 283 | 
            +
                        if service_type in self._registrations:
         | 
| 284 | 
            +
                            return [self._resolve_internal(service_type)]
         | 
| 285 | 
            +
                        return []
         | 
| 223 286 |  | 
| 224 287 | 
             
                def register_singleton(
         | 
| 225 288 | 
             
                    self,
         | 
| @@ -274,12 +337,12 @@ class DIContainer: | |
| 274 337 | 
             
                    else:
         | 
| 275 338 | 
             
                        # Normal registration without name
         | 
| 276 339 | 
             
                        if instance is not None:
         | 
| 277 | 
            -
                            self. | 
| 340 | 
            +
                            self._register_internal(interface, instance=instance)
         | 
| 278 341 | 
             
                        elif implementation is not None and not inspect.isclass(implementation):
         | 
| 279 342 | 
             
                            # It's an instance passed as implementation (backward compatibility)
         | 
| 280 | 
            -
                            self. | 
| 343 | 
            +
                            self._register_internal(interface, instance=implementation)
         | 
| 281 344 | 
             
                        else:
         | 
| 282 | 
            -
                            self. | 
| 345 | 
            +
                            self._register_internal(interface, implementation, lifetime=ServiceLifetime.SINGLETON)
         | 
| 283 346 |  | 
| 284 347 | 
             
                    # Handle disposal handler
         | 
| 285 348 | 
             
                    if dispose_handler:
         | 
| @@ -321,7 +384,7 @@ class DIContainer: | |
| 321 384 | 
             
                            context = container.get(IRequestContext)  # Created
         | 
| 322 385 | 
             
                            context2 = container.get(IRequestContext)  # Same instance
         | 
| 323 386 | 
             
                    """
         | 
| 324 | 
            -
                    self. | 
| 387 | 
            +
                    self._register_internal(interface, implementation, lifetime=ServiceLifetime.SCOPED)
         | 
| 325 388 | 
             
                    if name:
         | 
| 326 389 | 
             
                        self._named_registrations[name] = self._registrations[interface]
         | 
| 327 390 |  | 
| @@ -335,7 +398,7 @@ class DIContainer: | |
| 335 398 |  | 
| 336 399 | 
             
                    Convenience method for registering transient services.
         | 
| 337 400 | 
             
                    """
         | 
| 338 | 
            -
                    self. | 
| 401 | 
            +
                    self._register_internal(service_type, implementation, lifetime=ServiceLifetime.TRANSIENT)
         | 
| 339 402 |  | 
| 340 403 | 
             
                def register_factory(
         | 
| 341 404 | 
             
                    self,
         | 
| @@ -363,7 +426,7 @@ class DIContainer: | |
| 363 426 | 
             
                            lifetime=ServiceLifetime.SINGLETON
         | 
| 364 427 | 
             
                        )
         | 
| 365 428 | 
             
                    """
         | 
| 366 | 
            -
                    self. | 
| 429 | 
            +
                    self._register_internal(interface, factory=factory, lifetime=lifetime)
         | 
| 367 430 | 
             
                    self._factories[interface] = factory
         | 
| 368 431 | 
             
                    if name:
         | 
| 369 432 | 
             
                        self._named_registrations[name] = self._registrations[interface]
         | 
| @@ -551,6 +614,12 @@ class DIContainer: | |
| 551 614 | 
             
                                    module = frame.f_globals
         | 
| 552 615 | 
             
                                    if param_type in module:
         | 
| 553 616 | 
             
                                        param_type = module[param_type]
         | 
| 617 | 
            +
                                    else:
         | 
| 618 | 
            +
                                        # Try looking in registrations by name
         | 
| 619 | 
            +
                                        for reg_type in self._registrations:
         | 
| 620 | 
            +
                                            if reg_type.__name__ == param_type:
         | 
| 621 | 
            +
                                                param_type = reg_type
         | 
| 622 | 
            +
                                                break
         | 
| 554 623 | 
             
                                except:
         | 
| 555 624 | 
             
                                    # If we can't resolve, skip this parameter
         | 
| 556 625 | 
             
                                    if param.default != param.empty:
         | 
| @@ -564,11 +633,13 @@ class DIContainer: | |
| 564 633 | 
             
                                param_type = next((arg for arg in args if arg is not type(None)), None)
         | 
| 565 634 |  | 
| 566 635 | 
             
                            if param_type and param_type in self._registrations:
         | 
| 567 | 
            -
                                #  | 
| 568 | 
            -
                                if param_type  | 
| 636 | 
            +
                                # Check for circular dependency
         | 
| 637 | 
            +
                                if param_type in self._resolving:
         | 
| 638 | 
            +
                                    # Circular dependency detected
         | 
| 639 | 
            +
                                    cycle = " -> ".join(str(t.__name__) for t in self._resolving) + f" -> {param_type.__name__}"
         | 
| 640 | 
            +
                                    raise CircularDependencyError(f"Circular dependency detected: {cycle}")
         | 
| 641 | 
            +
                                else:
         | 
| 569 642 | 
             
                                    kwargs[param_name] = self.resolve(param_type)
         | 
| 570 | 
            -
                                elif param.default != param.empty:
         | 
| 571 | 
            -
                                    kwargs[param_name] = param.default
         | 
| 572 643 | 
             
                            elif param.default != param.empty:
         | 
| 573 644 | 
             
                                # Use default value
         | 
| 574 645 | 
             
                                kwargs[param_name] = param.default
         | 
| @@ -204,6 +204,37 @@ class FrameworkLoader: | |
| 204 204 | 
             
                                content["project_workflow"] = "system"
         | 
| 205 205 | 
             
                                self.logger.info("Using system WORKFLOW.md")
         | 
| 206 206 |  | 
| 207 | 
            +
                def _load_memory_instructions(self, content: Dict[str, Any]) -> None:
         | 
| 208 | 
            +
                    """
         | 
| 209 | 
            +
                    Load MEMORY.md with project-specific override support.
         | 
| 210 | 
            +
                    
         | 
| 211 | 
            +
                    Precedence:
         | 
| 212 | 
            +
                    1. Project-specific: .claude-mpm/agents/MEMORY.md
         | 
| 213 | 
            +
                    2. System default: src/claude_mpm/agents/MEMORY.md
         | 
| 214 | 
            +
                    
         | 
| 215 | 
            +
                    Args:
         | 
| 216 | 
            +
                        content: Dictionary to update with memory instructions
         | 
| 217 | 
            +
                    """
         | 
| 218 | 
            +
                    # Check for project-specific memory instructions first
         | 
| 219 | 
            +
                    project_memory_path = Path.cwd() / ".claude-mpm" / "agents" / "MEMORY.md"
         | 
| 220 | 
            +
                    if project_memory_path.exists():
         | 
| 221 | 
            +
                        loaded_content = self._try_load_file(project_memory_path, "project-specific MEMORY.md")
         | 
| 222 | 
            +
                        if loaded_content:
         | 
| 223 | 
            +
                            content["memory_instructions"] = loaded_content
         | 
| 224 | 
            +
                            content["project_memory"] = "project"
         | 
| 225 | 
            +
                            self.logger.info("Using project-specific MEMORY.md")
         | 
| 226 | 
            +
                            return
         | 
| 227 | 
            +
                    
         | 
| 228 | 
            +
                    # Fall back to system memory instructions
         | 
| 229 | 
            +
                    if self.framework_path:
         | 
| 230 | 
            +
                        system_memory_path = self.framework_path / "src" / "claude_mpm" / "agents" / "MEMORY.md"
         | 
| 231 | 
            +
                        if system_memory_path.exists():
         | 
| 232 | 
            +
                            loaded_content = self._try_load_file(system_memory_path, "system MEMORY.md")
         | 
| 233 | 
            +
                            if loaded_content:
         | 
| 234 | 
            +
                                content["memory_instructions"] = loaded_content
         | 
| 235 | 
            +
                                content["project_memory"] = "system"
         | 
| 236 | 
            +
                                self.logger.info("Using system MEMORY.md")
         | 
| 237 | 
            +
                
         | 
| 207 238 | 
             
                def _load_single_agent(self, agent_file: Path) -> tuple[Optional[str], Optional[str]]:
         | 
| 208 239 | 
             
                    """
         | 
| 209 240 | 
             
                    Load a single agent file.
         | 
| @@ -277,7 +308,9 @@ class FrameworkLoader: | |
| 277 308 | 
             
                        "working_claude_md": "",
         | 
| 278 309 | 
             
                        "framework_instructions": "",
         | 
| 279 310 | 
             
                        "workflow_instructions": "",
         | 
| 280 | 
            -
                        "project_workflow": ""
         | 
| 311 | 
            +
                        "project_workflow": "",
         | 
| 312 | 
            +
                        "memory_instructions": "",
         | 
| 313 | 
            +
                        "project_memory": ""
         | 
| 281 314 | 
             
                    }
         | 
| 282 315 |  | 
| 283 316 | 
             
                    # Load instructions file from working directory
         | 
| @@ -311,6 +344,9 @@ class FrameworkLoader: | |
| 311 344 | 
             
                    # Load WORKFLOW.md - check for project-specific first, then system
         | 
| 312 345 | 
             
                    self._load_workflow_instructions(content)
         | 
| 313 346 |  | 
| 347 | 
            +
                    # Load MEMORY.md - check for project-specific first, then system
         | 
| 348 | 
            +
                    self._load_memory_instructions(content)
         | 
| 349 | 
            +
                    
         | 
| 314 350 | 
             
                    # Discover agent directories
         | 
| 315 351 | 
             
                    agents_dir, templates_dir, main_dir = self._discover_framework_paths()
         | 
| 316 352 |  | 
| @@ -364,6 +400,12 @@ class FrameworkLoader: | |
| 364 400 | 
             
                            instructions += f"\n\n{workflow_content}\n"
         | 
| 365 401 | 
             
                            # Note: project-specific workflow is being used (logged elsewhere)
         | 
| 366 402 |  | 
| 403 | 
            +
                        # Add MEMORY.md after workflow instructions
         | 
| 404 | 
            +
                        if self.framework_content.get("memory_instructions"):
         | 
| 405 | 
            +
                            memory_content = self._strip_metadata_comments(self.framework_content['memory_instructions'])
         | 
| 406 | 
            +
                            instructions += f"\n\n{memory_content}\n"
         | 
| 407 | 
            +
                            # Note: project-specific memory instructions being used (logged elsewhere)
         | 
| 408 | 
            +
                        
         | 
| 367 409 | 
             
                        # Add dynamic agent capabilities section
         | 
| 368 410 | 
             
                        instructions += self._generate_agent_capabilities_section()
         | 
| 369 411 |  | 
| @@ -40,6 +40,29 @@ class InteractiveSession: | |
| 40 40 | 
             
                    self.session_id = None
         | 
| 41 41 | 
             
                    self.original_cwd = os.getcwd()
         | 
| 42 42 |  | 
| 43 | 
            +
                    # Initialize response tracking for interactive sessions
         | 
| 44 | 
            +
                    # WHY: Interactive sessions need response logging just like oneshot sessions.
         | 
| 45 | 
            +
                    # The hook system captures events, but we need the ResponseTracker to be
         | 
| 46 | 
            +
                    # initialized to actually store them.
         | 
| 47 | 
            +
                    self.response_tracker = None
         | 
| 48 | 
            +
                    
         | 
| 49 | 
            +
                    # Check if response logging is enabled in configuration
         | 
| 50 | 
            +
                    try:
         | 
| 51 | 
            +
                        response_config = self.runner.config.get('response_logging', {})
         | 
| 52 | 
            +
                        response_logging_enabled = response_config.get('enabled', False)
         | 
| 53 | 
            +
                    except (AttributeError, TypeError):
         | 
| 54 | 
            +
                        # Handle mock or missing config gracefully
         | 
| 55 | 
            +
                        response_logging_enabled = False
         | 
| 56 | 
            +
                    
         | 
| 57 | 
            +
                    if response_logging_enabled:
         | 
| 58 | 
            +
                        try:
         | 
| 59 | 
            +
                            from claude_mpm.services.response_tracker import ResponseTracker
         | 
| 60 | 
            +
                            self.response_tracker = ResponseTracker(self.runner.config)
         | 
| 61 | 
            +
                            self.logger.info("Response tracking initialized for interactive session")
         | 
| 62 | 
            +
                        except Exception as e:
         | 
| 63 | 
            +
                            self.logger.warning(f"Failed to initialize response tracker: {e}")
         | 
| 64 | 
            +
                            # Continue without response tracking - not fatal
         | 
| 65 | 
            +
                    
         | 
| 43 66 | 
             
                def initialize_interactive_session(self) -> Tuple[bool, Optional[str]]:
         | 
| 44 67 | 
             
                    """Initialize the interactive session environment.
         | 
| 45 68 |  | 
| @@ -71,6 +94,18 @@ class InteractiveSession: | |
| 71 94 | 
             
                                component="session"
         | 
| 72 95 | 
             
                            )
         | 
| 73 96 |  | 
| 97 | 
            +
                        # Initialize response tracking session if enabled
         | 
| 98 | 
            +
                        # WHY: The ResponseTracker needs to know about the session to properly
         | 
| 99 | 
            +
                        # correlate prompts and responses during the interactive session.
         | 
| 100 | 
            +
                        if self.response_tracker and self.response_tracker.enabled:
         | 
| 101 | 
            +
                            try:
         | 
| 102 | 
            +
                                # Set the session ID in the tracker for correlation
         | 
| 103 | 
            +
                                if hasattr(self.response_tracker, 'session_logger') and self.response_tracker.session_logger:
         | 
| 104 | 
            +
                                    self.response_tracker.session_logger.set_session_id(self.session_id)
         | 
| 105 | 
            +
                                    self.logger.debug(f"Response tracker session ID set to: {self.session_id}")
         | 
| 106 | 
            +
                            except Exception as e:
         | 
| 107 | 
            +
                                self.logger.debug(f"Could not set session ID in response tracker: {e}")
         | 
| 108 | 
            +
                        
         | 
| 74 109 | 
             
                        return True, None
         | 
| 75 110 |  | 
| 76 111 | 
             
                    except Exception as e:
         | 
| @@ -213,6 +248,18 @@ class InteractiveSession: | |
| 213 248 | 
             
                                "event": "session_end",
         | 
| 214 249 | 
             
                                "session_id": self.session_id
         | 
| 215 250 | 
             
                            })
         | 
| 251 | 
            +
                        
         | 
| 252 | 
            +
                        # Clean up response tracker if initialized
         | 
| 253 | 
            +
                        # WHY: Ensure proper cleanup of response tracking resources and
         | 
| 254 | 
            +
                        # finalize any pending response logs.
         | 
| 255 | 
            +
                        if self.response_tracker:
         | 
| 256 | 
            +
                            try:
         | 
| 257 | 
            +
                                # Clear the session ID to stop tracking this session
         | 
| 258 | 
            +
                                if hasattr(self.response_tracker, 'session_logger') and self.response_tracker.session_logger:
         | 
| 259 | 
            +
                                    self.response_tracker.session_logger.set_session_id(None)
         | 
| 260 | 
            +
                                    self.logger.debug("Response tracker session cleared")
         | 
| 261 | 
            +
                            except Exception as e:
         | 
| 262 | 
            +
                                self.logger.debug(f"Error clearing response tracker session: {e}")
         | 
| 216 263 |  | 
| 217 264 | 
             
                    except Exception as e:
         | 
| 218 265 | 
             
                        self.logger.debug(f"Error during cleanup: {e}")
         |