anderson-ufrj commited on
Commit
4b74da4
·
1 Parent(s): 58073b1

fix: improve Drummond agent import handling and add debug endpoint

Browse files

- Use TYPE_CHECKING to avoid runtime import in factory
- Move CommunicationAgent import to inside get_drummond_agent function
- Add /debug/drummond-status endpoint for diagnostics
- Better error handling and logging for import failures

app.py CHANGED
@@ -641,6 +641,48 @@ async def cache_stats():
641
  "ttl_seconds": api_cache.default_ttl
642
  }
643
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
  if __name__ == "__main__":
645
  port = int(os.getenv("PORT", 7860))
646
  logger.info(f"🚀 Starting Enhanced Cidadão.AI Backend on port {port}")
 
641
  "ttl_seconds": api_cache.default_ttl
642
  }
643
 
644
+ # Debug endpoint for Drummond issue
645
+ @app.get("/debug/drummond-status")
646
+ async def debug_drummond_status():
647
+ """Debug endpoint to check Drummond agent status."""
648
+ import traceback
649
+
650
+ result = {
651
+ "python_version": sys.version,
652
+ "checks": {}
653
+ }
654
+
655
+ # Check if we can import CommunicationAgent
656
+ try:
657
+ from src.agents.drummond import CommunicationAgent
658
+ abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
659
+ result["checks"]["import"] = {
660
+ "status": "success",
661
+ "abstract_methods": list(abstract_methods) if abstract_methods else "none",
662
+ "has_shutdown": hasattr(CommunicationAgent, 'shutdown'),
663
+ "has_initialize": hasattr(CommunicationAgent, 'initialize'),
664
+ "has_process": hasattr(CommunicationAgent, 'process')
665
+ }
666
+
667
+ # Try to instantiate
668
+ try:
669
+ agent = CommunicationAgent()
670
+ result["checks"]["instantiation"] = {"status": "success", "agent_name": agent.name}
671
+ except Exception as e:
672
+ result["checks"]["instantiation"] = {
673
+ "status": "failed",
674
+ "error": str(e),
675
+ "error_type": type(e).__name__
676
+ }
677
+ except Exception as e:
678
+ result["checks"]["import"] = {
679
+ "status": "failed",
680
+ "error": str(e),
681
+ "traceback": traceback.format_exc()[:500] # Limit traceback size
682
+ }
683
+
684
+ return result
685
+
686
  if __name__ == "__main__":
687
  port = int(os.getenv("PORT", 7860))
688
  logger.info(f"🚀 Starting Enhanced Cidadão.AI Backend on port {port}")
debug_drummond_import.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Debug script to trace Drummond import issues.
4
+ """
5
+
6
+ import sys
7
+ import traceback
8
+
9
+ def test_import_chain():
10
+ """Test the import chain to find where the error occurs."""
11
+
12
+ print("=== DRUMMOND IMPORT DEBUG ===")
13
+ print(f"Python version: {sys.version}")
14
+ print(f"Python path: {sys.path}")
15
+ print()
16
+
17
+ # Test 1: Import BaseAgent
18
+ print("1. Testing BaseAgent import...")
19
+ try:
20
+ from src.agents.deodoro import BaseAgent
21
+ print(" ✓ BaseAgent imported successfully")
22
+
23
+ # Check if shutdown is abstract
24
+ import inspect
25
+ methods = inspect.getmembers(BaseAgent, predicate=inspect.ismethod)
26
+ for name, method in methods:
27
+ if name == 'shutdown':
28
+ print(f" - shutdown method found: {method}")
29
+ if hasattr(method, '__isabstractmethod__'):
30
+ print(f" - Is abstract: {method.__isabstractmethod__}")
31
+ except Exception as e:
32
+ print(f" ✗ Failed to import BaseAgent: {e}")
33
+ traceback.print_exc()
34
+ return
35
+
36
+ # Test 2: Import CommunicationAgent directly
37
+ print("\n2. Testing CommunicationAgent import...")
38
+ try:
39
+ from src.agents.drummond import CommunicationAgent
40
+ print(" ✓ CommunicationAgent imported successfully")
41
+
42
+ # Check if shutdown is implemented
43
+ if hasattr(CommunicationAgent, 'shutdown'):
44
+ print(" ✓ shutdown method exists in CommunicationAgent")
45
+
46
+ # Check method resolution order
47
+ print(f" - MRO: {[c.__name__ for c in CommunicationAgent.__mro__]}")
48
+
49
+ # Check abstract methods
50
+ abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
51
+ print(f" - Abstract methods: {abstract_methods}")
52
+
53
+ except Exception as e:
54
+ print(f" ✗ Failed to import CommunicationAgent: {e}")
55
+ traceback.print_exc()
56
+ return
57
+
58
+ # Test 3: Try to instantiate
59
+ print("\n3. Testing CommunicationAgent instantiation...")
60
+ try:
61
+ agent = CommunicationAgent()
62
+ print(" ✓ CommunicationAgent instantiated successfully")
63
+ except Exception as e:
64
+ print(f" ✗ Failed to instantiate CommunicationAgent: {e}")
65
+ traceback.print_exc()
66
+
67
+ # Additional diagnostics
68
+ print("\n Additional diagnostics:")
69
+ try:
70
+ from src.agents.drummond import CommunicationAgent
71
+ print(f" - Class type: {type(CommunicationAgent)}")
72
+ print(f" - Base classes: {CommunicationAgent.__bases__}")
73
+
74
+ # List all methods
75
+ print(" - All methods:")
76
+ for attr in dir(CommunicationAgent):
77
+ if not attr.startswith('_'):
78
+ obj = getattr(CommunicationAgent, attr)
79
+ if callable(obj):
80
+ print(f" * {attr}: {type(obj)}")
81
+
82
+ except Exception as e2:
83
+ print(f" - Failed diagnostics: {e2}")
84
+
85
+ # Test 4: Test the factory
86
+ print("\n4. Testing chat_drummond_factory...")
87
+ try:
88
+ from src.api.routes.chat_drummond_factory import get_drummond_agent
89
+ print(" ✓ Factory imported successfully")
90
+ except Exception as e:
91
+ print(f" ✗ Failed to import factory: {e}")
92
+ traceback.print_exc()
93
+
94
+ print("\n=== END DEBUG ===")
95
+
96
+ if __name__ == "__main__":
97
+ test_import_chain()
src/api/routes/chat_drummond_factory.py CHANGED
@@ -2,26 +2,34 @@
2
  Factory for Drummond agent to avoid import-time instantiation issues.
3
  """
4
 
5
- from typing import Optional
6
- from src.agents.drummond import CommunicationAgent
7
  from src.core import get_logger
8
 
 
 
 
 
9
  logger = get_logger(__name__)
10
 
11
  # Global instance cache
12
- _drummond_instance: Optional[CommunicationAgent] = None
13
  _initialized = False
 
14
 
15
 
16
- async def get_drummond_agent() -> Optional[CommunicationAgent]:
17
  """
18
  Get or create Drummond agent instance.
19
  This function handles lazy initialization to avoid import-time issues.
20
  """
21
- global _drummond_instance, _initialized
22
 
23
  if not _initialized:
24
  try:
 
 
 
 
25
  logger.info("Creating Drummond agent instance...")
26
  _drummond_instance = CommunicationAgent()
27
 
@@ -31,11 +39,20 @@ async def get_drummond_agent() -> Optional[CommunicationAgent]:
31
  _initialized = True
32
  logger.info("Drummond agent ready")
33
 
 
 
 
 
 
 
 
 
34
  except Exception as e:
35
  logger.error(f"Failed to create/initialize Drummond: {e}")
36
  import traceback
37
  logger.error(f"Traceback: {traceback.format_exc()}")
38
  _drummond_instance = None
39
  _initialized = False
 
40
 
41
  return _drummond_instance
 
2
  Factory for Drummond agent to avoid import-time instantiation issues.
3
  """
4
 
5
+ from typing import Optional, TYPE_CHECKING
 
6
  from src.core import get_logger
7
 
8
+ # Use TYPE_CHECKING to avoid import at runtime
9
+ if TYPE_CHECKING:
10
+ from src.agents.drummond import CommunicationAgent
11
+
12
  logger = get_logger(__name__)
13
 
14
  # Global instance cache
15
+ _drummond_instance: Optional['CommunicationAgent'] = None
16
  _initialized = False
17
+ _import_error = None
18
 
19
 
20
+ async def get_drummond_agent() -> Optional['CommunicationAgent']:
21
  """
22
  Get or create Drummond agent instance.
23
  This function handles lazy initialization to avoid import-time issues.
24
  """
25
+ global _drummond_instance, _initialized, _import_error
26
 
27
  if not _initialized:
28
  try:
29
+ # Lazy import to avoid module-level import errors
30
+ logger.info("Attempting to import CommunicationAgent...")
31
+ from src.agents.drummond import CommunicationAgent
32
+
33
  logger.info("Creating Drummond agent instance...")
34
  _drummond_instance = CommunicationAgent()
35
 
 
39
  _initialized = True
40
  logger.info("Drummond agent ready")
41
 
42
+ except ImportError as e:
43
+ logger.error(f"Import error for Drummond agent: {e}")
44
+ import traceback
45
+ logger.error(f"Import traceback: {traceback.format_exc()}")
46
+ _drummond_instance = None
47
+ _initialized = False
48
+ _import_error = str(e)
49
+
50
  except Exception as e:
51
  logger.error(f"Failed to create/initialize Drummond: {e}")
52
  import traceback
53
  logger.error(f"Traceback: {traceback.format_exc()}")
54
  _drummond_instance = None
55
  _initialized = False
56
+ _import_error = str(e)
57
 
58
  return _drummond_instance
src/api/routes/debug.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Debug routes for diagnosing issues in production.
3
+ """
4
+
5
+ from fastapi import APIRouter
6
+ from fastapi.responses import JSONResponse
7
+ import sys
8
+ import os
9
+ import importlib
10
+ import traceback
11
+ from typing import Dict, Any
12
+
13
+ router = APIRouter(
14
+ prefix="/debug",
15
+ tags=["debug"]
16
+ )
17
+
18
+
19
+ @router.get("/drummond-status")
20
+ async def drummond_status() -> Dict[str, Any]:
21
+ """Check the status of Drummond agent and diagnose import issues."""
22
+
23
+ result = {
24
+ "python_version": sys.version,
25
+ "working_dir": os.getcwd(),
26
+ "sys_path": sys.path[:5], # First 5 paths
27
+ "checks": {}
28
+ }
29
+
30
+ # Check 1: Can we import BaseAgent?
31
+ try:
32
+ from src.agents.deodoro import BaseAgent
33
+ result["checks"]["base_agent_import"] = {
34
+ "status": "success",
35
+ "abstract_methods": list(getattr(BaseAgent, '__abstractmethods__', []))
36
+ }
37
+ except Exception as e:
38
+ result["checks"]["base_agent_import"] = {
39
+ "status": "failed",
40
+ "error": str(e),
41
+ "traceback": traceback.format_exc()
42
+ }
43
+
44
+ # Check 2: Can we import CommunicationAgent?
45
+ try:
46
+ from src.agents.drummond import CommunicationAgent
47
+ abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', set())
48
+ result["checks"]["communication_agent_import"] = {
49
+ "status": "success",
50
+ "type": str(type(CommunicationAgent)),
51
+ "base_classes": [str(base) for base in CommunicationAgent.__bases__],
52
+ "abstract_methods": list(abstract_methods) if abstract_methods else "none",
53
+ "has_shutdown": hasattr(CommunicationAgent, 'shutdown'),
54
+ "has_initialize": hasattr(CommunicationAgent, 'initialize'),
55
+ "has_process": hasattr(CommunicationAgent, 'process')
56
+ }
57
+ except Exception as e:
58
+ result["checks"]["communication_agent_import"] = {
59
+ "status": "failed",
60
+ "error": str(e),
61
+ "traceback": traceback.format_exc()
62
+ }
63
+
64
+ # Check 3: Can we instantiate?
65
+ try:
66
+ from src.agents.drummond import CommunicationAgent
67
+ agent = CommunicationAgent()
68
+ result["checks"]["instantiation"] = {
69
+ "status": "success",
70
+ "agent_name": agent.name
71
+ }
72
+ except Exception as e:
73
+ result["checks"]["instantiation"] = {
74
+ "status": "failed",
75
+ "error": str(e),
76
+ "error_type": type(e).__name__,
77
+ "traceback": traceback.format_exc()
78
+ }
79
+
80
+ # Check 4: Factory status
81
+ try:
82
+ from src.api.routes.chat_drummond_factory import get_drummond_agent, _initialized, _import_error
83
+ agent = await get_drummond_agent()
84
+ result["checks"]["factory"] = {
85
+ "status": "success" if agent else "failed",
86
+ "initialized": _initialized,
87
+ "import_error": _import_error,
88
+ "agent_available": agent is not None
89
+ }
90
+ except Exception as e:
91
+ result["checks"]["factory"] = {
92
+ "status": "failed",
93
+ "error": str(e),
94
+ "traceback": traceback.format_exc()
95
+ }
96
+
97
+ return result
98
+
99
+
100
+ @router.get("/module-info/{module_path}")
101
+ async def module_info(module_path: str) -> Dict[str, Any]:
102
+ """Get information about a specific module."""
103
+
104
+ try:
105
+ module = importlib.import_module(module_path)
106
+
107
+ return {
108
+ "module": module_path,
109
+ "file": getattr(module, '__file__', 'unknown'),
110
+ "attributes": [attr for attr in dir(module) if not attr.startswith('_')],
111
+ "status": "loaded"
112
+ }
113
+ except Exception as e:
114
+ return {
115
+ "module": module_path,
116
+ "status": "error",
117
+ "error": str(e),
118
+ "traceback": traceback.format_exc()
119
+ }
test_drummond_minimal.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Minimal test to verify CommunicationAgent can be imported and instantiated.
4
+ This simulates what happens on HuggingFace Spaces.
5
+ """
6
+
7
+ import sys
8
+ import os
9
+
10
+ # Add src to path like HuggingFace does
11
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
12
+
13
+ def test_minimal_import():
14
+ print("=== MINIMAL DRUMMOND TEST ===")
15
+
16
+ # Step 1: Try importing just the class
17
+ try:
18
+ print("1. Importing CommunicationAgent class...")
19
+ from src.agents.drummond import CommunicationAgent
20
+ print(" ✓ Import successful")
21
+ except Exception as e:
22
+ print(f" ✗ Import failed: {e}")
23
+ import traceback
24
+ traceback.print_exc()
25
+ return False
26
+
27
+ # Step 2: Check if it's a proper class
28
+ print("\n2. Checking class structure...")
29
+ print(f" - Type: {type(CommunicationAgent)}")
30
+ print(f" - Base classes: {CommunicationAgent.__bases__}")
31
+ print(f" - Module: {CommunicationAgent.__module__}")
32
+
33
+ # Check abstract methods
34
+ abstract_methods = getattr(CommunicationAgent, '__abstractmethods__', None)
35
+ if abstract_methods:
36
+ print(f" - Abstract methods remaining: {abstract_methods}")
37
+ else:
38
+ print(" - No abstract methods remaining")
39
+
40
+ # Step 3: Try instantiation without any dependencies
41
+ print("\n3. Testing instantiation...")
42
+ try:
43
+ # Mock the logger to avoid dependency issues
44
+ import logging
45
+ logging.basicConfig(level=logging.INFO)
46
+
47
+ # Try to create instance
48
+ agent = CommunicationAgent()
49
+ print(" ✓ Instantiation successful")
50
+ return True
51
+ except Exception as e:
52
+ print(f" ✗ Instantiation failed: {e}")
53
+ import traceback
54
+ traceback.print_exc()
55
+ return False
56
+
57
+ if __name__ == "__main__":
58
+ success = test_minimal_import()
59
+ print(f"\n=== TEST {'PASSED' if success else 'FAILED'} ===")
60
+ sys.exit(0 if success else 1)