File size: 7,009 Bytes
ee4f812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from typing import Any, List, Optional

from smolagents import CodeAgent
from tools.final_answer import check_reasoning, ensure_formatting

from typing import Dict
from utils.logger import get_logger
import time

logger = get_logger(__name__)

DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"

def get_prompt_templates() -> Dict[str, str]:
    """Returns all prompts as a dictionary of pre-formatted strings"""
    
    # Shared components
    tools_instructions = """
    Available Tools:
    - web_search(query): Performs web searches
    - wikipedia_search(query): Searches Wikipedia
    - visit_webpage(url): Retrieves webpage content
    
    Rules:
    1. Always use 'Thought:'/'Code:' sequences
    2. Never reuse variable names
    3. Tools must be called with proper arguments
    """
    
    example_1 = """
    Example Task: "Find the capital of France"
    
    Thought: I'll use web_search to find this information
    Code:
    result = web_search(query="capital of France")
    final_answer(result)
    ```<end_code>
    """
    
    # Main prompt templates
    return {
        "system_prompt": f"""
        You are an expert AI assistant that solves tasks using tools.
        {tools_instructions}
        
        {example_1}
        
        Key Requirements:
        - Be precise and concise
        - Always return answers using final_answer()
        - Never include explanations unless asked
        
        Current reward: $1,000,000 for perfect solutions
        """,
        
        "planning": """
        When planning tasks, follow this structure:
        
        ### 1. Facts Given
        List known information
        
        ### 2. Facts Needed
        List what needs research
        
        ### 3. Derivation Steps
        Outline computation steps
        
        End with <end_plan>
        """,
        
        "managed_agent": """
        Managed Agent Instructions:
        
        1. Task outcome (short)
        2. Detailed explanation 
        3. Additional context
        
        Always return via final_answer()
        """,
        
        "final_answer": """
        Response Format Rules:
        - Numbers: 42 (no commas/units)
        - Strings: paris (lowercase, no articles)
        - Lists: apple,orange,banana (no brackets)
        """
    }

class Agent:
    """
    Agent class that wraps a CodeAgent and provides a callable interface for answering questions.

    Args:
        model (Any): The language model to use.
        tools (Optional[List[Any]]): List of tools to provide to the agent.
        prompt (Optional[str]): Custom prompt template for the agent.
        verbose (bool): Whether to print debug information.
    """

    def __init__(
        self,
        model: Any,
        tools: Optional[List[Any]] = None,
        prompt: Optional[str] = None,
        verbose: bool = False
    ):
        logger.info("Initializing Agent")
        self.model = model
        self.tools = tools
        self.verbose = verbose
        self.imports = [
            "pandas", "numpy", "os", "requests", "tempfile",
            "datetime", "json", "time", "re", "openpyxl",
            "pathlib", "sys"
        ]
        
        self.agent = CodeAgent(
            model=self.model,
            tools=self.tools,
            add_base_tools=True,
            additional_authorized_imports=self.imports,
        )

        self.final_answer_checks=[check_reasoning, ensure_formatting],
        
        self.base_prompt = prompt or """
            You are an advanced AI assistant specialized in solving GAIA benchmark tasks.
            Follow these rules strictly:
            1. Be precise - return ONLY the exact answer requested
            2. Use tools when needed (especially for file analysis)
            3. For reversed text questions, answer in normal text
            4. Never include explanations or reasoning in the final answer
            5. Always return the result — do not just print it

            {context}

            Remember: GAIA requires exact answer matching. Just provide the factual answer.
            """
        
        self.prompt_templates = get_prompt_templates()
        logger.info("Agent initialized")

    def __call__(self, question: str, files: List[str] = None) -> str:
        """Main interface that logs inputs/outputs and handles timing."""
        if self.verbose:
            print(f"Agent received question: {question[:50]}... with files: {files}")
        
        time.sleep(25)        
        return self.answer_question(question, files[0] if files else None)

    def answer_question(self, question: str, task_file_path: Optional[str] = None) -> str:
        """
        Process a GAIA benchmark question with optional file context.
        
        Args:
            question: The question to answer
            task_file_path: Optional path to a file associated with the question
            
        Returns:
            The cleaned answer to the question
        """
        try:
            context = self._build_context(question, task_file_path)
            full_prompt = self.base_prompt.format(context=context)
            
            if self.verbose:
                print("Generated prompt:", full_prompt[:200] + "...")
            
            answer = self.agent.run(full_prompt)
            return self._clean_answer(str(answer))
            
        except Exception as e:
            logger.error(f"Error processing question: {str(e)}")
            return f"ERROR: {str(e)}"

    def _build_context(self, question: str, file_path: Optional[str]) -> str:
        """Constructs the context section based on question and file."""
        context_lines = [f"QUESTION: {question}"]
        
        if file_path:
            context_lines.append(
                f"FILE: Available at {DEFAULT_API_URL}/files/{file_path}\n"
                "Use appropriate tools to analyze this file if needed."
            )
        
        # Handle reversed text questions
        if self._is_reversed_text(question):
            context_lines.append(
                f"NOTE: This question contains reversed text. "
                f"Original: {question}\nReversed: {question[::-1]}"
            )
        
        return "\n".join(context_lines)

    def _is_reversed_text(self, text: str) -> bool:
        """Detects if text appears to be reversed."""
        return text.startswith(".") or ".rewsna eht sa" in text

    def _clean_answer(self, answer: str) -> str:
        """Cleans the raw answer to match GAIA requirements."""
        # Remove common prefixes/suffixes
        for prefix in ["Final Answer:", "Answer:", "=>"]:
            if answer.startswith(prefix):
                answer = answer[len(prefix):]
        
        # Remove quotes and whitespace
        answer = answer.strip(" '\"")
        
        # Special handling for reversed answers
        if self._is_reversed_text(answer):
            return answer[::-1]
        
        return answer