Test_Run_with_CodeAgent

#1
by KoRiF - opened
Files changed (4) hide show
  1. answering.py +0 -17
  2. app.py +13 -31
  3. requirements.txt +1 -16
  4. workflow.py +0 -316
answering.py DELETED
@@ -1,17 +0,0 @@
1
- import os
2
-
3
- from smolagents import CodeAgent, InferenceClientModel, FinalAnswerTool, DuckDuckGoSearchTool, WikipediaSearchTool, PythonInterpreterTool
4
-
5
- from dotenv import load_dotenv
6
- load_dotenv()
7
-
8
-
9
- def gen_question_answer(question: str) -> str:
10
- duck_duck_go_search_tool = DuckDuckGoSearchTool()
11
- wikipedia_search_tool = WikipediaSearchTool()
12
- final_answer_tool = FinalAnswerTool()
13
- python_interpreter_tool = PythonInterpreterTool()
14
- agent = CodeAgent(tools=[duck_duck_go_search_tool, wikipedia_search_tool, python_interpreter_tool, final_answer_tool], model=InferenceClientModel(), add_base_tools=True, additional_authorized_imports=["pandas"])
15
-
16
- response = agent.run(question) # Use run() instead of query()
17
- return str(response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -3,11 +3,6 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
6
- from workflow import GAIAAnsweringWorkflow
7
-
8
-
9
- from dotenv import load_dotenv
10
- load_dotenv()
11
 
12
  # (Keep Constants as is)
13
  # --- Constants ---
@@ -15,16 +10,14 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
16
  # --- Basic Agent Definition ---
17
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
- class JeSaisToutAgent(GAIAAnsweringWorkflow):
19
  def __init__(self):
20
- super().__init__()
21
- print("Agentics Workflow initialized.")
22
- def __call__(self, question: str, context) -> str:
23
  print(f"Agent received question (first 50 chars): {question[:50]}...")
24
- answer = "This is a default answer."
25
- answer=super().__call__(question, context)
26
- print(f"Agent returning answer: {answer}")
27
- return answer
28
 
29
  def run_and_submit_all( profile: gr.OAuthProfile | None):
30
  """
@@ -47,7 +40,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
47
 
48
  # 1. Instantiate Agent ( modify this part to create your agent)
49
  try:
50
- agent = JeSaisToutAgent()
51
  except Exception as e:
52
  print(f"Error instantiating agent: {e}")
53
  return f"Error initializing agent: {e}", None
@@ -65,13 +58,13 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
65
  print("Fetched questions list is empty.")
66
  return "Fetched questions list is empty or invalid format.", None
67
  print(f"Fetched {len(questions_data)} questions.")
 
 
 
68
  except requests.exceptions.JSONDecodeError as e:
69
  print(f"Error decoding JSON response from questions endpoint: {e}")
70
  print(f"Response text: {response.text[:500]}")
71
  return f"Error decoding server response for questions: {e}", None
72
- except requests.exceptions.RequestException as e:
73
- print(f"Error fetching questions: {e}")
74
- return f"Error fetching questions: {e}", None
75
  except Exception as e:
76
  print(f"An unexpected error occurred fetching questions: {e}")
77
  return f"An unexpected error occurred fetching questions: {e}", None
@@ -83,15 +76,11 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
83
  for item in questions_data:
84
  task_id = item.get("task_id")
85
  question_text = item.get("question")
86
- question_context = item
87
- print(f"=== item[{task_id}]===")
88
- print(item)
89
- print("\n")
90
  if not task_id or question_text is None:
91
  print(f"Skipping item with missing task_id or question: {item}")
92
  continue
93
  try:
94
- submitted_answer = agent(question_text, question_context)
95
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
96
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
97
  except Exception as e:
@@ -101,19 +90,12 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
101
  if not answers_payload:
102
  print("Agent did not produce any answers to submit.")
103
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
104
- if os.getenv("TESTRUN"):
105
- print("Skipping submission in test environment.")
106
- return "Skipping submission in test environment.", pd.DataFrame(results_log)
107
-
108
  # 4. Prepare Submission
109
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
110
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
111
  print(status_update)
112
-
113
- if os.getenv("TESTRUN"):
114
- print(f"Skipping submission in test environment. \n{submission_data}")
115
- return "Skipping submission in test environment.", pd.DataFrame(submission_data)
116
-
117
  # 5. Submit
118
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
119
  try:
 
3
  import requests
4
  import inspect
5
  import pandas as pd
 
 
 
 
 
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
 
10
 
11
  # --- Basic Agent Definition ---
12
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
+ class BasicAgent:
14
  def __init__(self):
15
+ print("BasicAgent initialized.")
16
+ def __call__(self, question: str) -> str:
 
17
  print(f"Agent received question (first 50 chars): {question[:50]}...")
18
+ fixed_answer = "This is a default answer."
19
+ print(f"Agent returning fixed answer: {fixed_answer}")
20
+ return fixed_answer
 
21
 
22
  def run_and_submit_all( profile: gr.OAuthProfile | None):
23
  """
 
40
 
41
  # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
+ agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
 
58
  print("Fetched questions list is empty.")
59
  return "Fetched questions list is empty or invalid format.", None
60
  print(f"Fetched {len(questions_data)} questions.")
61
+ except requests.exceptions.RequestException as e:
62
+ print(f"Error fetching questions: {e}")
63
+ return f"Error fetching questions: {e}", None
64
  except requests.exceptions.JSONDecodeError as e:
65
  print(f"Error decoding JSON response from questions endpoint: {e}")
66
  print(f"Response text: {response.text[:500]}")
67
  return f"Error decoding server response for questions: {e}", None
 
 
 
68
  except Exception as e:
69
  print(f"An unexpected error occurred fetching questions: {e}")
70
  return f"An unexpected error occurred fetching questions: {e}", None
 
76
  for item in questions_data:
77
  task_id = item.get("task_id")
78
  question_text = item.get("question")
 
 
 
 
79
  if not task_id or question_text is None:
80
  print(f"Skipping item with missing task_id or question: {item}")
81
  continue
82
  try:
83
+ submitted_answer = agent(question_text)
84
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
  except Exception as e:
 
90
  if not answers_payload:
91
  print("Agent did not produce any answers to submit.")
92
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
93
+
 
 
 
94
  # 4. Prepare Submission
95
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
96
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
97
  print(status_update)
98
+
 
 
 
 
99
  # 5. Submit
100
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
101
  try:
requirements.txt CHANGED
@@ -1,17 +1,2 @@
1
  gradio
2
- requests
3
- pandas
4
- langgraph
5
- smolagents
6
- transformers
7
- torch
8
- huggingface_hub
9
- python-dotenv
10
- pillow
11
- duckduckgo-search
12
- wikipedia-api
13
- markdownify
14
- langchain_huggingface
15
- langchain-community
16
- llama-index
17
- sseclient-py
 
1
  gradio
2
+ requests
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
workflow.py DELETED
@@ -1,316 +0,0 @@
1
- from typing import List, Dict, TypedDict, Annotated, Callable, Optional, Any
2
- from huggingface_hub.inference._generated.types import question_answering
3
- from langgraph.graph import StateGraph, END
4
- from langchain_core.messages import HumanMessage
5
- #from langchain_community.chat_models import ChatHuggingFace
6
- from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
7
- from answering import gen_question_answer
8
-
9
- import requests
10
- import os
11
- from dotenv import load_dotenv
12
- load_dotenv()
13
-
14
-
15
- class AgentState(TypedDict):
16
- context: Dict[str, str]
17
- question: str
18
- answer: Annotated[str, lambda x, y: y] # Overwrite with new value
19
- formatted_answer: Annotated[str, lambda x, y: y]
20
- format_requirement: str
21
- uris: List[str]
22
- reasoning: List[str]
23
-
24
- class GAIAAnsweringWorkflow:
25
- def __init__(
26
- self,
27
- qa_function: Optional[Callable[[str], str]] = None,
28
- formatter: Optional[Callable[[str], str]] = None
29
- ):
30
- """
31
- Initialize the GAIA agent workflow
32
-
33
- Args:
34
- qa_function: Core question answering function (gen_question_answer)
35
- formatter: Answer formatting function (default: GAIA boxed format)
36
- """
37
- self.qa_function = gen_question_answer #qa_function or self.default_qa_function
38
- self.formatter = formatter or self.default_formatter
39
- self.workflow = self.build_workflow()
40
- # Initialize model with HF Inference API
41
- llm_endpoint = HuggingFaceEndpoint(
42
- model="deepseek-ai/DeepSeek-R1",#endpoint_url="https://api-inference.huggingface.co/models/cortexso/deepseek-r1:7b",
43
- huggingfacehub_api_token=os.getenv("HF_TOKEN"),
44
- task="text-generation",
45
- #max_tokens=1024
46
- )
47
- self.reasoning_llm = ChatHuggingFace(llm=llm_endpoint)
48
-
49
- self.llm = ChatHuggingFace(
50
- llm=HuggingFaceEndpoint(
51
- model="mistralai/Mistral-7B-Instruct-v0.3",
52
- huggingfacehub_api_token=os.getenv("HF_TOKEN"),
53
- task="text-generation",
54
- )
55
-
56
- )
57
-
58
-
59
-
60
- def ask_llm(self, question: str, do_reasoning=False)->str:
61
- prompt = question
62
- messages = [HumanMessage(content=prompt)]
63
- response = self.llm.invoke(messages)
64
- answer = str(response.content)
65
- return answer
66
-
67
-
68
- def extract_noted_urls_with_llm(self, question: str) -> List[str]:
69
- """Use LLM to extract URLs specifically noted in the question"""
70
- prompt = f"""
71
- Analyze the following question and extract ONLY URLs that are explicitly noted or referenced.
72
- Return each URL on a separate line. If no URLs are noted, return an empty string.
73
-
74
- QUESTION: {question}
75
-
76
- Respond ONLY with the URLs, one per line, with no additional text or formatting.
77
- """
78
-
79
- try:
80
- # Use your LLM to generate the response
81
- response = self.ask_llm(prompt)
82
-
83
- # Parse the response to extract URLs
84
- urls = []
85
- for line in response.split('\n'):
86
- line = line.strip()
87
- #if line.startswith(('http://', 'https://', 'www.')):
88
- urls.append(line)
89
-
90
- return urls
91
- except Exception as e:
92
- print(f"LLM-based URL extraction failed: {str(e)}")
93
- return []
94
-
95
- def download_file(self, task_id: str, file_name: str) -> str:
96
- """Download file from API and return local path"""
97
- try:
98
- #os.makedirs("files", exist_ok=True)
99
- file_path = f"./{file_name}"#files/{file_id}"
100
- api_base_url: str = "https://agents-course-unit4-scoring.hf.space"
101
- api_endpoint = f"{api_base_url}/files/{task_id}"
102
- response = requests.get(api_endpoint)
103
- response.raise_for_status()
104
-
105
- with open(file_path, "wb") as f:
106
- f.write(response.content)
107
-
108
- print(f"File saved: {file_path}")
109
- return file_path
110
- except Exception as e:
111
- print(f"File download failed: {str(e)}")
112
- return ""
113
-
114
-
115
- def check_context_independent(self, state: AgentState)->bool:
116
- if ctx := state.get("context"):
117
- if ctx.get("filename"):
118
- return False
119
- prompt = f"""
120
-
121
- I have a CodeAgent based on the text-to-text model that can use Internet search and parse the information found.
122
- If this approach is enough to successfully cope with the task, then we will call such a task an "easy question"
123
-
124
- AS AN ERUDITE PERSON YOU must analyze how difficult it will be to solve the next question
125
- <<{state["question"]}>>
126
-
127
- If you think that the question is easy, then return an empty string. Important! You should NOT add any symbols to the output in this case!
128
- If the question concerns the use of additional resources such as complex analysis of downloaded files or resources on the Internet, then return an action plan
129
-
130
- """
131
- reply = self.ask_llm(prompt, True)
132
- prompt = f""" The reasonings from other LLM is provided: <<{reply}>>
133
- You have to Summarize:
134
- output either empty string ('') for easy question
135
- or extract action plan for non-easy question
136
- """
137
- reply = self.ask_llm(prompt, False)
138
- if reply:
139
- state["reasoning"].append(reply)
140
- return False
141
- return True
142
-
143
- def preparations_node(self, state: AgentState) -> dict:
144
- if not state["context"]:
145
- return {}
146
- """Node to prepare resources"""
147
- context = state["context"]
148
- question = state["question"]
149
- uris = state["uris"]
150
-
151
- # 1. Handle file_id in context
152
- if file_name:= context.get("file_name"):
153
- file_path = self.download_file(context["task_id"], file_name)
154
- if file_path:
155
- uris.append(file_path)
156
-
157
- # 2. Extract URLs from question
158
- found_urls = self.extract_noted_urls_with_llm(question)
159
- if found_urls:
160
- uris.extend(found_urls)
161
- print(f"Added {len(found_urls)} URL(s) from question")
162
-
163
- return {"uris": uris}
164
-
165
-
166
- def triage_node(self, state: AgentState) -> dict:
167
- return {}
168
-
169
- def deep_processing_node(self, state: AgentState) -> dict:
170
- question = f"""
171
- question: \n <<{state["question"]}>> \n
172
- resources: {str(state["uris"])} \n
173
- reasoning: <<{state["reasoning"]}>>
174
- """
175
- answer = gen_question_answer(question)
176
- return {state["answer"]: answer}
177
-
178
- def generate_answer_node(self, state: AgentState) -> dict:
179
- """Node that executes the question answering tool"""
180
- try:
181
- answer = self.qa_function(state["question"])
182
- return {"answer": answer}
183
- except Exception as e:
184
- print(str(e))
185
- return {"answer": f"Error: {str(e)}"}
186
-
187
- def format_output_node(self, state: AgentState) -> dict:
188
- """Node that formats the answer for GAIA benchmark"""
189
- prompt = f"""
190
-
191
- As a very smart person, you should formulate what should be the output format of the answer to the question:
192
- <<{state["question"]}>>
193
-
194
- You must formulate it very briefly and clearly!
195
- The common requirements is:
196
- <<
197
- OUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
198
-
199
- If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise, and don't include additional text.
200
- If the answer is a number, represent it with digits.
201
- If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
202
- If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
203
- >>
204
- But you have to figure out how the answer should looks like in the given case and reformulate requirement according to the specified question
205
-
206
- """
207
- format_requirement = self.ask_llm(prompt, True)
208
-
209
- prompt = f"""
210
- Your attentiveness and responsibility are very much needed! We are solving a strict test that is automatically checked, so we must formulate the answer in strict accordance with the task and the required format! Even one incorrect symbol in the answer can fail the task! Pull yourself together!
211
-
212
- You will be required to produce an output of the answer, but formatted in accordance with the task
213
-
214
- Received answer: <<{state['answer']}>>
215
-
216
- Format requirements: <<{format_requirement}>>
217
-
218
- Do NOT include << >> in your answer! Don't use full answer formulations! If you are asked about a number it MUST be just a number, nothing more! Each time it should be a clear answer (checked automatically)
219
- """
220
- try:
221
- formatted = self.ask_llm(prompt)
222
- return {"formatted_answer": formatted.strip()}
223
- except Exception as e:
224
- return {"formatted_answer": f"\\boxed{{\\text{{Formatting error: {str(e)}}}}}"}
225
-
226
- def build_workflow(self) -> Any:
227
- """Construct and compile the LangGraph workflow"""
228
- # Create graph
229
- workflow = StateGraph(AgentState)
230
-
231
- # Add nodes
232
- workflow.add_node("preparations", self.preparations_node)
233
- workflow.add_node("triage", self.triage_node)
234
- workflow.add_node("deep_processing", self.deep_processing_node)
235
- workflow.add_node("generate_answer", self.generate_answer_node)
236
- workflow.add_node("format_output", self.format_output_node)
237
-
238
- # Define edges
239
- workflow.set_entry_point("preparations")
240
- workflow.add_edge("preparations", "triage")
241
- workflow.add_conditional_edges("triage"
242
- , self.check_context_independent
243
- , {
244
- True: "generate_answer",
245
- False: "deep_processing"
246
- })
247
- workflow.add_edge("deep_processing", "format_output")
248
-
249
- workflow.add_edge("generate_answer", "format_output")
250
- workflow.add_edge("format_output", END)
251
-
252
- return workflow.compile()
253
-
254
-
255
-
256
- def __call__(self, question: str, context: Dict|None=None) -> str:
257
- """
258
- Execute the agent workflow for a given question
259
-
260
- Args:
261
- question: Input question string
262
-
263
- Returns:
264
- Formatted GAIA answer
265
- """
266
- # Initialize state
267
- initial_state = {
268
- "context": context,
269
- "question": question,
270
- "answer": "",
271
- "formatted_answer": "",
272
- "format_requirement": "",
273
- "uris": [],
274
- "reasoning": []
275
- }
276
-
277
- # Execute workflow
278
- result = self.workflow.invoke(initial_state)
279
- return result["answer"]#["formatted_answer"]
280
-
281
- @staticmethod
282
- def default_qa_function(question: str) -> str:
283
- """Placeholder QA function (override with your CodeAgent)"""
284
- return "42"
285
-
286
- @staticmethod
287
- def default_formatter(answer: str) -> str:
288
- """Default GAIA formatting"""
289
- return answer #f"\\boxed{{{answer}}}"
290
-
291
- # Example usage with custom QA function
292
- if __name__ == "__main__":
293
- # Custom QA function (replace with your CodeAgent integration)
294
- def custom_qa(question: str) -> str:
295
- if "life" in question:
296
- return "42"
297
- elif "prime" in question:
298
- return "101"
299
- return "unknown"
300
-
301
- # Create agent instance
302
- agent = GAIAAnsweringWorkflow(
303
- qa_function=gen_question_answer,
304
- formatter=lambda ans: ans #f"ANSWER: \\boxed{{{ans}}}" # Custom formatting
305
- )
306
-
307
- # Test cases
308
- questions = [
309
- "What is the answer to life, the universe, and everything?",
310
- "What is the smallest 3-digit prime number?",
311
- "Unknown question type?"
312
- ]
313
-
314
- for q in questions:
315
- result = agent(q)
316
- print(f"Question: {q}\nAnswer: {result}\n")