| # π Bug Fixes Applied | |
| ## Issues Identified from Logs | |
| Based on the container logs, three main issues were identified and fixed: | |
| ### 1. β Circular Reference Error in Context Manager | |
| **Error**: `Context update error: Circular reference detected` | |
| **Root Cause**: The context manager was trying to store the entire context object (including itself) in the interactions, causing a circular reference when serializing to JSON. | |
| **Fix Applied** (`context_manager.py`): | |
| - Removed the full context from being stored in each interaction | |
| - Created a clean `session_context` dictionary with only essential fields | |
| - Avoids circular references by storing only necessary data | |
| **Before**: | |
| ```python | |
| new_interaction = { | |
| "user_input": user_input, | |
| "timestamp": datetime.now().isoformat(), | |
| "context": context # β Circular reference! | |
| } | |
| ``` | |
| **After**: | |
| ```python | |
| # Create a clean interaction without circular references | |
| new_interaction = { | |
| "user_input": user_input, | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| # Use a clean context copy for JSON serialization | |
| session_context = { | |
| "interactions": context.get("interactions", []), | |
| "preferences": context.get("preferences", {}), | |
| "active_tasks": context.get("active_tasks", []) | |
| } | |
| ``` | |
| ### 2. β Unhashable Type 'slice' Error in Safety Agent | |
| **Error**: `SAFETY_BIAS_001 error: unhashable type: 'slice'` | |
| **Root Cause**: The safety agent was receiving dictionaries instead of strings, and the `_generate_warnings` method had a bug with list comprehension. | |
| **Fix Applied** (`src/agents/safety_agent.py`): | |
| 1. Made `execute` method accept both string and dict inputs | |
| 2. Fixed the list comprehension that was causing the slice error | |
| 3. Added better error handling with full stack traces | |
| **Changes**: | |
| ```python | |
| # Before: Only accepted strings | |
| async def execute(self, response: str, ...): | |
| # After: Handles both types | |
| async def execute(self, response, ...): | |
| if isinstance(response, dict): | |
| response_text = response.get('final_response', response.get('response', str(response))) | |
| else: | |
| response_text = str(response) | |
| ``` | |
| ```python | |
| # Before: Buggy list comprehension | |
| if category in self.warning_templates and category not in [w.split(":")[1].strip() for w in warnings]: | |
| # After: Clean check | |
| if category and category in self.warning_templates: | |
| category_warning = self.warning_templates[category] | |
| if category_warning not in warnings: | |
| warnings.append(category_warning) | |
| ``` | |
| ### 3. β Empty Response from Synthesis Agent | |
| **Error**: `Orchestrator returned response: ` (empty) | |
| **Root Cause**: When no agent outputs were provided, the synthesis agent returned empty strings, which propagated to a blank response. | |
| **Fix Applied** (`src/agents/synthesis_agent.py`): | |
| - Added fallback responses when content blocks are empty | |
| - Ensured `_structure_conversational_response` always returns something useful | |
| - Added checks in `_template_based_synthesis` to generate a response even with no content | |
| **Changes**: | |
| ```python | |
| # Added fallback in _template_based_synthesis | |
| if not structured_response or len(structured_response.strip()) == 0: | |
| structured_response = f"Thank you for your message: '{user_input}'. I'm working on understanding how to best help you with this." | |
| ``` | |
| ```python | |
| # Added fallback in _structure_conversational_response | |
| if len(combined_content) == 0: | |
| return "I'm here to help. Could you tell me more about what you're looking for?" | |
| ``` | |
| ### 4. β Improved Final Output Formatting | |
| **Enhancement**: Made the orchestrator extract responses from multiple possible locations | |
| **Changes** (`orchestrator_engine.py`): | |
| ```python | |
| # Extracts from multiple possible locations | |
| response_text = ( | |
| response.get("final_response") or | |
| response.get("safety_checked_response") or | |
| response.get("original_response") or | |
| response.get("response") or | |
| str(response.get("result", "")) | |
| ) | |
| # Fallback if all empty | |
| if not response_text: | |
| response_text = "I apologize, but I'm having trouble generating a response right now. Please try again." | |
| ``` | |
| ## Test Results After Fixes | |
| All fixes have been applied and should resolve: | |
| - β No more circular reference errors | |
| - β No more unhashable type errors | |
| - β No more empty responses | |
| - β Better error messages in logs | |
| - β Graceful degradation when components fail | |
| ## Next Steps | |
| The application should now: | |
| 1. Handle requests without crashing | |
| 2. Generate responses even when some agents fail | |
| 3. Log detailed error information for debugging | |
| 4. Persist context without circular references | |
| ## Additional Improvements | |
| - Added `exc_info=True` to all logger.error() calls for full stack traces | |
| - Improved type handling in safety agent | |
| - Better fallback responses throughout the synthesis chain | |
| - More robust error handling in orchestrator | |