File size: 13,619 Bytes
9a6a4dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
"""
AGNO-Compatible Research Tools
Wrapper tools that integrate the enhanced research capabilities with AGNO framework
"""

import os
import logging
from typing import Dict, List, Any, Optional

try:
    from agno.tools.base import Tool
    AGNO_AVAILABLE = True
except ImportError:
    # Use our simple base tool when AGNO is not available
    from .base_tool import SimpleAGNOTool as Tool
    AGNO_AVAILABLE = False

from .research_orchestrator import ResearchOrchestrator
from .web_research_tool import EnhancedWebSearchTool
from .wikipedia_tool import WikipediaSpecializedTool

logger = logging.getLogger(__name__)


class EnhancedWebResearchTool(Tool):
    """
    AGNO-compatible enhanced web research tool.
    
    This tool integrates with AGNO's orchestration system while providing
    enhanced web research capabilities for GAIA questions.
    """
    
    def __init__(self):
        """Initialize the AGNO-compatible web research tool."""
        super().__init__(
            name="enhanced_web_research",
            description="Enhanced web research with Exa API integration for comprehensive information gathering"
        )
        
        self.orchestrator = ResearchOrchestrator()
        logger.info("βœ… Enhanced Web Research Tool initialized for AGNO")
    
    def search_web(self, query: str, num_results: int = 5) -> str:
        """
        Search the web for information.
        
        Args:
            query: Search query
            num_results: Number of results to return
            
        Returns:
            Formatted search results
        """
        try:
            logger.info(f"πŸ” Enhanced web search: {query}")
            
            result = self.orchestrator.research(query)
            
            if result.confidence > 0.5:
                response = f"Answer: {result.answer}\n"
                response += f"Confidence: {result.confidence:.2f}\n"
                response += f"Sources: {len(result.sources)}\n"
                if result.sources:
                    response += "Top sources:\n"
                    for i, source in enumerate(result.sources[:3], 1):
                        response += f"{i}. {source.get('title', 'Unknown')} ({source.get('type', 'web')})\n"
                return response
            else:
                return f"Search completed but low confidence ({result.confidence:.2f}). Answer: {result.answer}"
                
        except Exception as e:
            logger.error(f"❌ Enhanced web search error: {e}")
            return f"Search failed: {str(e)}"
    
    def research_factual_question(self, question: str) -> str:
        """
        Research a factual question with enhanced capabilities.
        
        Args:
            question: The factual question to research
            
        Returns:
            The answer to the question
        """
        try:
            logger.info(f"πŸ”¬ Researching factual question: {question}")
            
            result = self.orchestrator.quick_factual_search(question)
            return result
            
        except Exception as e:
            logger.error(f"❌ Factual research error: {e}")
            return f"Research failed: {str(e)}"


class EnhancedWikipediaTool(Tool):
    """
    AGNO-compatible enhanced Wikipedia tool.
    
    This tool provides specialized Wikipedia research capabilities
    that work within AGNO's orchestration framework.
    """
    
    def __init__(self):
        """Initialize the AGNO-compatible Wikipedia tool."""
        super().__init__(
            name="enhanced_wikipedia",
            description="Enhanced Wikipedia research with specialized queries for discography, featured articles, and historical data"
        )
        
        self.wikipedia_tool = WikipediaSpecializedTool()
        logger.info("βœ… Enhanced Wikipedia Tool initialized for AGNO")
    
    def search_wikipedia(self, query: str, limit: int = 5) -> str:
        """
        Search Wikipedia articles.
        
        Args:
            query: Search query
            limit: Maximum number of results
            
        Returns:
            Formatted search results
        """
        try:
            logger.info(f"πŸ“– Enhanced Wikipedia search: {query}")
            
            results = self.wikipedia_tool.search_articles(query, limit)
            
            if results:
                response = f"Found {len(results)} Wikipedia articles:\n"
                for i, result in enumerate(results, 1):
                    response += f"{i}. {result.title}\n"
                    if result.snippet:
                        response += f"   {result.snippet[:100]}...\n"
                return response
            else:
                return "No Wikipedia articles found for the query."
                
        except Exception as e:
            logger.error(f"❌ Wikipedia search error: {e}")
            return f"Wikipedia search failed: {str(e)}"
    
    def get_wikipedia_article(self, title: str) -> str:
        """
        Get detailed Wikipedia article information.
        
        Args:
            title: Article title
            
        Returns:
            Article summary and key information
        """
        try:
            logger.info(f"πŸ“„ Getting Wikipedia article: {title}")
            
            article = self.wikipedia_tool.get_article(title, include_content=False)
            
            if article:
                response = f"Title: {article.title}\n"
                response += f"Summary: {article.summary[:500]}...\n"
                if article.categories:
                    response += f"Categories: {', '.join(article.categories[:5])}\n"
                response += f"URL: {article.url}\n"
                return response
            else:
                return f"Wikipedia article '{title}' not found."
                
        except Exception as e:
            logger.error(f"❌ Wikipedia article error: {e}")
            return f"Failed to get article: {str(e)}"
    
    def search_discography(self, artist_name: str, start_year: int = None, end_year: int = None) -> str:
        """
        Search for artist discography information.
        
        Args:
            artist_name: Name of the artist
            start_year: Start year for filtering (optional)
            end_year: End year for filtering (optional)
            
        Returns:
            Number of studio albums found
        """
        try:
            logger.info(f"🎡 Searching discography for: {artist_name}")
            
            albums = self.wikipedia_tool.extract_discography_info(artist_name, "studio")
            
            # Filter by year range if provided
            if start_year and end_year:
                albums = [album for album in albums if start_year <= album.get('year', 0) <= end_year]
                logger.info(f"Filtered to {start_year}-{end_year}: {len(albums)} albums")
            
            return str(len(albums))
            
        except Exception as e:
            logger.error(f"❌ Discography search error: {e}")
            return "0"
    
    def find_featured_article(self, date: str, topic_keywords: List[str] = None) -> str:
        """
        Find Wikipedia featured article for a specific date.
        
        Args:
            date: Date in YYYY-MM-DD format
            topic_keywords: Keywords to match (optional)
            
        Returns:
            Featured article title or "Not found"
        """
        try:
            logger.info(f"🌟 Finding featured article for {date}")
            
            if topic_keywords is None:
                topic_keywords = []
            
            result = self.wikipedia_tool.find_featured_article_by_date(date, topic_keywords)
            return result or "Not found"
            
        except Exception as e:
            logger.error(f"❌ Featured article search error: {e}")
            return "Not found"


class GAIAResearchOrchestrator(Tool):
    """
    AGNO-compatible research orchestrator for GAIA questions.
    
    This tool provides high-level research coordination that works
    seamlessly with AGNO's existing orchestration capabilities.
    """
    
    def __init__(self):
        """Initialize the AGNO-compatible research orchestrator."""
        super().__init__(
            name="gaia_research_orchestrator",
            description="Intelligent research orchestrator for complex GAIA questions with multi-tool coordination"
        )
        
        self.orchestrator = ResearchOrchestrator()
        logger.info("βœ… GAIA Research Orchestrator initialized for AGNO")
    
    def research_question(self, question: str, expected_answer_type: str = "text") -> str:
        """
        Research a complex question using multiple tools and strategies.
        
        Args:
            question: The research question
            expected_answer_type: Expected type of answer (text, number, date, list)
            
        Returns:
            Research result with confidence information
        """
        try:
            logger.info(f"πŸ”¬ Orchestrated research: {question}")
            
            result = self.orchestrator.research(
                question, 
                expected_answer_type=expected_answer_type
            )
            
            if result.confidence > 0.7:
                return result.answer
            elif result.confidence > 0.4:
                return f"{result.answer} (confidence: {result.confidence:.2f})"
            else:
                return f"Low confidence result: {result.answer}"
                
        except Exception as e:
            logger.error(f"❌ Orchestrated research error: {e}")
            return f"Research failed: {str(e)}"
    
    def answer_mercedes_sosa_question(self) -> str:
        """
        Specific method to answer the Mercedes Sosa studio albums question.
        This directly addresses one of the failing GAIA questions.
        """
        try:
            logger.info("🎡 Answering Mercedes Sosa studio albums question (2000-2009)")
            return self.orchestrator.research_mercedes_sosa_albums(2000, 2009)
        except Exception as e:
            logger.error(f"❌ Mercedes Sosa question error: {e}")
            return "0"
    
    def answer_dinosaur_featured_article_question(self) -> str:
        """
        Specific method to answer the dinosaur featured article question.
        This directly addresses one of the failing GAIA questions.
        """
        try:
            logger.info("πŸ¦• Answering dinosaur featured article question (November 2016)")
            return self.orchestrator.research_featured_article("2016-11-15", "dinosaur")
        except Exception as e:
            logger.error(f"❌ Dinosaur featured article error: {e}")
            return "Not found"


# Factory function to create all enhanced research tools
def create_enhanced_research_tools() -> List[Tool]:
    """
    Create all enhanced research tools for AGNO integration.
    
    Returns:
        List of AGNO-compatible research tools
    """
    tools = []
    
    try:
        # Create enhanced web research tool
        web_tool = EnhancedWebResearchTool()
        tools.append(web_tool)
        
        # Create enhanced Wikipedia tool
        wiki_tool = EnhancedWikipediaTool()
        tools.append(wiki_tool)
        
        # Create research orchestrator
        orchestrator_tool = GAIAResearchOrchestrator()
        tools.append(orchestrator_tool)
        
        logger.info(f"βœ… Created {len(tools)} enhanced research tools for AGNO")
        
    except Exception as e:
        logger.error(f"❌ Error creating enhanced research tools: {e}")
    
    return tools


# Integration helper functions
def integrate_with_existing_agno_tools(existing_tools: List[Tool]) -> List[Tool]:
    """
    Integrate enhanced research tools with existing AGNO tools.
    
    Args:
        existing_tools: List of existing AGNO tools
        
    Returns:
        Combined list of tools with enhanced research capabilities
    """
    enhanced_tools = create_enhanced_research_tools()
    
    # Add enhanced tools to existing tools
    all_tools = existing_tools + enhanced_tools
    
    logger.info(f"βœ… Integrated {len(enhanced_tools)} enhanced research tools with {len(existing_tools)} existing tools")
    
    return all_tools


def get_research_tool_status() -> Dict[str, Any]:
    """
    Get status of all research tools for debugging.
    
    Returns:
        Status information for research tools
    """
    status = {
        'enhanced_web_research': False,
        'enhanced_wikipedia': False,
        'gaia_research_orchestrator': False,
        'exa_api_available': bool(os.getenv('EXA_API_KEY')),
        'firecrawl_api_available': bool(os.getenv('FIRECRAWL_API_KEY')),
        'errors': []
    }
    
    try:
        # Test web research tool
        web_tool = EnhancedWebResearchTool()
        status['enhanced_web_research'] = True
    except Exception as e:
        status['errors'].append(f"Web research tool error: {str(e)}")
    
    try:
        # Test Wikipedia tool
        wiki_tool = EnhancedWikipediaTool()
        status['enhanced_wikipedia'] = True
    except Exception as e:
        status['errors'].append(f"Wikipedia tool error: {str(e)}")
    
    try:
        # Test orchestrator
        orchestrator_tool = GAIAResearchOrchestrator()
        status['gaia_research_orchestrator'] = True
    except Exception as e:
        status['errors'].append(f"Orchestrator error: {str(e)}")
    
    return status