AlanRocha commited on
Commit
b26b5fe
·
verified ·
1 Parent(s): 6717528

Create agents.py

Browse files
Files changed (1) hide show
  1. agents.py +213 -0
agents.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, List, Optional
2
+
3
+ from smolagents import CodeAgent
4
+ from tools.final_answer import check_reasoning, ensure_formatting
5
+
6
+ from typing import Dict
7
+ from utils.logger import get_logger
8
+ import time
9
+
10
+ logger = get_logger(__name__)
11
+
12
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
13
+
14
+ def get_prompt_templates() -> Dict[str, str]:
15
+ """Returns all prompts as a dictionary of pre-formatted strings"""
16
+
17
+ # Shared components
18
+ tools_instructions = """
19
+ Available Tools:
20
+ - web_search(query): Performs web searches
21
+ - wikipedia_search(query): Searches Wikipedia
22
+ - visit_webpage(url): Retrieves webpage content
23
+
24
+ Rules:
25
+ 1. Always use 'Thought:'/'Code:' sequences
26
+ 2. Never reuse variable names
27
+ 3. Tools must be called with proper arguments
28
+ """
29
+
30
+ example_1 = """
31
+ Example Task: "Find the capital of France"
32
+
33
+ Thought: I'll use web_search to find this information
34
+ Code:
35
+ result = web_search(query="capital of France")
36
+ final_answer(result)
37
+ ```<end_code>
38
+ """
39
+
40
+ # Main prompt templates
41
+ return {
42
+ "system_prompt": f"""
43
+ You are an expert AI assistant that solves tasks using tools.
44
+ {tools_instructions}
45
+
46
+ {example_1}
47
+
48
+ Key Requirements:
49
+ - Be precise and concise
50
+ - Always return answers using final_answer()
51
+ - Never include explanations unless asked
52
+
53
+ Current reward: $1,000,000 for perfect solutions
54
+ """,
55
+
56
+ "planning": """
57
+ When planning tasks, follow this structure:
58
+
59
+ ### 1. Facts Given
60
+ List known information
61
+
62
+ ### 2. Facts Needed
63
+ List what needs research
64
+
65
+ ### 3. Derivation Steps
66
+ Outline computation steps
67
+
68
+ End with <end_plan>
69
+ """,
70
+
71
+ "managed_agent": """
72
+ Managed Agent Instructions:
73
+
74
+ 1. Task outcome (short)
75
+ 2. Detailed explanation
76
+ 3. Additional context
77
+
78
+ Always return via final_answer()
79
+ """,
80
+
81
+ "final_answer": """
82
+ Response Format Rules:
83
+ - Numbers: 42 (no commas/units)
84
+ - Strings: paris (lowercase, no articles)
85
+ - Lists: apple,orange,banana (no brackets)
86
+ """
87
+ }
88
+
89
+ class Agent:
90
+ """
91
+ Agent class that wraps a CodeAgent and provides a callable interface for answering questions.
92
+
93
+ Args:
94
+ model (Any): The language model to use.
95
+ tools (Optional[List[Any]]): List of tools to provide to the agent.
96
+ prompt (Optional[str]): Custom prompt template for the agent.
97
+ verbose (bool): Whether to print debug information.
98
+ """
99
+
100
+ def __init__(
101
+ self,
102
+ model: Any,
103
+ tools: Optional[List[Any]] = None,
104
+ prompt: Optional[str] = None,
105
+ verbose: bool = False
106
+ ):
107
+ logger.info("Initializing Agent")
108
+ self.model = model
109
+ self.tools = tools
110
+ self.verbose = verbose
111
+ self.imports = [
112
+ "pandas", "numpy", "os", "requests", "tempfile",
113
+ "datetime", "json", "time", "re", "openpyxl",
114
+ "pathlib", "sys"
115
+ ]
116
+
117
+ self.agent = CodeAgent(
118
+ model=self.model,
119
+ tools=self.tools,
120
+ add_base_tools=True,
121
+ additional_authorized_imports=self.imports,
122
+ )
123
+
124
+ self.final_answer_checks=[check_reasoning, ensure_formatting],
125
+
126
+ self.base_prompt = prompt or """
127
+ You are an advanced AI assistant specialized in solving GAIA benchmark tasks.
128
+ Follow these rules strictly:
129
+ 1. Be precise - return ONLY the exact answer requested
130
+ 2. Use tools when needed (especially for file analysis)
131
+ 3. For reversed text questions, answer in normal text
132
+ 4. Never include explanations or reasoning in the final answer
133
+ 5. Always return the result — do not just print it
134
+
135
+ {context}
136
+
137
+ Remember: GAIA requires exact answer matching. Just provide the factual answer.
138
+ """
139
+
140
+ self.prompt_templates = get_prompt_templates()
141
+ logger.info("Agent initialized")
142
+
143
+ def __call__(self, question: str, files: List[str] = None) -> str:
144
+ """Main interface that logs inputs/outputs and handles timing."""
145
+ if self.verbose:
146
+ print(f"Agent received question: {question[:50]}... with files: {files}")
147
+
148
+ time.sleep(25)
149
+ return self.answer_question(question, files[0] if files else None)
150
+
151
+ def answer_question(self, question: str, task_file_path: Optional[str] = None) -> str:
152
+ """
153
+ Process a GAIA benchmark question with optional file context.
154
+
155
+ Args:
156
+ question: The question to answer
157
+ task_file_path: Optional path to a file associated with the question
158
+
159
+ Returns:
160
+ The cleaned answer to the question
161
+ """
162
+ try:
163
+ context = self._build_context(question, task_file_path)
164
+ full_prompt = self.base_prompt.format(context=context)
165
+
166
+ if self.verbose:
167
+ print("Generated prompt:", full_prompt[:200] + "...")
168
+
169
+ answer = self.agent.run(full_prompt)
170
+ return self._clean_answer(str(answer))
171
+
172
+ except Exception as e:
173
+ logger.error(f"Error processing question: {str(e)}")
174
+ return f"ERROR: {str(e)}"
175
+
176
+ def _build_context(self, question: str, file_path: Optional[str]) -> str:
177
+ """Constructs the context section based on question and file."""
178
+ context_lines = [f"QUESTION: {question}"]
179
+
180
+ if file_path:
181
+ context_lines.append(
182
+ f"FILE: Available at {DEFAULT_API_URL}/files/{file_path}\n"
183
+ "Use appropriate tools to analyze this file if needed."
184
+ )
185
+
186
+ # Handle reversed text questions
187
+ if self._is_reversed_text(question):
188
+ context_lines.append(
189
+ f"NOTE: This question contains reversed text. "
190
+ f"Original: {question}\nReversed: {question[::-1]}"
191
+ )
192
+
193
+ return "\n".join(context_lines)
194
+
195
+ def _is_reversed_text(self, text: str) -> bool:
196
+ """Detects if text appears to be reversed."""
197
+ return text.startswith(".") or ".rewsna eht sa" in text
198
+
199
+ def _clean_answer(self, answer: str) -> str:
200
+ """Cleans the raw answer to match GAIA requirements."""
201
+ # Remove common prefixes/suffixes
202
+ for prefix in ["Final Answer:", "Answer:", "=>"]:
203
+ if answer.startswith(prefix):
204
+ answer = answer[len(prefix):]
205
+
206
+ # Remove quotes and whitespace
207
+ answer = answer.strip(" '\"")
208
+
209
+ # Special handling for reversed answers
210
+ if self._is_reversed_text(answer):
211
+ return answer[::-1]
212
+
213
+ return answer