grshot commited on
Commit
84ab67c
·
1 Parent(s): 81917a3

GAIA agent

Browse files
Files changed (3) hide show
  1. agent.py +137 -0
  2. app.py +64 -31
  3. requirements.txt +8 -1
agent.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.chat_models import ChatHuggingFace
2
+ from langchain_community.llms import HuggingFaceEndpoint
3
+ from langchain_community.tools.python.tool import PythonREPLTool
4
+
5
+ # --- Custom Tools ---
6
+ from langchain_community.tools.tavily_search import TavilySearchResults
7
+ from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
8
+ from langchain_core.runnables import RunnableLambda
9
+ from langchain_core.tools import tool
10
+ from langgraph.graph import END, START, MessagesState, StateGraph
11
+ from langgraph.graph.message import add_messages
12
+ from langgraph.prebuilt import ToolNode, tools_condition
13
+
14
+
15
+ @tool
16
+ def search_web_sources(query: str) -> str:
17
+ """
18
+ Perform a web search using Tavily and return up to 3 relevant documents.
19
+ This tool is useful for answering research-based queries that require
20
+ up-to-date information from trusted sources.
21
+
22
+ Args:
23
+ query (str): The input search query.
24
+
25
+ Returns:
26
+ str: Formatted web search results with metadata and content.
27
+ """
28
+ search_docs = TavilySearchResults(max_results=3).invoke(query=query)
29
+ formatted_search_docs = "\n\n---\n\n".join(
30
+ [
31
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
32
+ for doc in search_docs
33
+ ]
34
+ )
35
+ return formatted_search_docs
36
+
37
+
38
+ @tool
39
+ def run_python_code(code: str) -> str:
40
+ """Execute Python code and return the result.
41
+ Args:
42
+ code: Python code as a string.
43
+ """
44
+ repl = PythonREPLTool()
45
+ return repl.run(code)
46
+
47
+
48
+ # --- System Prompt ---
49
+ system_prompt = SystemMessage(
50
+ content="""
51
+ You are a helpful and precise assistant. You will receive a question and optionally access tools to help answer it.
52
+
53
+ Your job is to think step-by-step, clearly report your thoughts, and conclude with a formatted response.
54
+
55
+ Use this format strictly:
56
+ FINAL ANSWER: [your concise answer here]
57
+
58
+ Rules for your answer:
59
+ - If the answer is a number, write only the number (no commas, units, or symbols unless asked).
60
+ - If it's a string, avoid articles (a, an, the), don't abbreviate, and use plain text digits.
61
+ - If a list, follow the rules above for each element and separate with a comma and single space (e.g., "apple, orange, banana").
62
+
63
+ Your response must always begin with: FINAL ANSWER:
64
+ """
65
+ )
66
+
67
+
68
+ def build_agent_graph(provider: str = "huggingface"):
69
+ # Define toolset
70
+ tools = [search_web_sources, run_python_code]
71
+
72
+ # Instantiate LLM
73
+ llm = ChatHuggingFace(
74
+ llm=HuggingFaceEndpoint(
75
+ repo_id="TinyLlama/TinyLlama-1.1B-Chat-v1.0",
76
+ task="text-generation",
77
+ max_new_tokens=1024,
78
+ do_sample=False,
79
+ repetition_penalty=1.03,
80
+ temperature=0,
81
+ ),
82
+ verbose=True,
83
+ )
84
+
85
+ # Bind tools to the LLM
86
+ llm_with_tools = llm.bind_tools(tools)
87
+
88
+ # Assistant: reasoning step that plans next action
89
+ def assistant_node(state: MessagesState):
90
+ messages = state["messages"]
91
+ response = llm_with_tools.invoke(messages)
92
+ return {"messages": add_messages(state, [response])}
93
+
94
+ # Stubbed retriever node for future integration
95
+ def retriever_node(state: MessagesState):
96
+ """Retriever node"""
97
+ # Example: use vector_store.similarity_search() in real use
98
+ similar_question = [
99
+ AIMessage(content="This is a mock similar document from the retriever.")
100
+ ]
101
+
102
+ if similar_question:
103
+ example_msg = HumanMessage(
104
+ content=f"Here I provide a similar question and answer for reference: {similar_question[0].content}",
105
+ )
106
+ return {"messages": [system_prompt] + state["messages"] + [example_msg]}
107
+ else:
108
+ return {"messages": [system_prompt] + state["messages"]}
109
+
110
+ # ToolNode wrapper for actual tool use
111
+ tool_node = ToolNode(tools)
112
+
113
+ # Define the graph with ReAct loop
114
+ builder = StateGraph(MessagesState)
115
+ builder.add_node("assistant", RunnableLambda(assistant_node))
116
+ builder.add_node("tools", tool_node)
117
+ builder.add_node("retriever", RunnableLambda(retriever_node))
118
+
119
+ builder.set_entry_point("assistant")
120
+ builder.add_conditional_edges("assistant", tools_condition)
121
+ builder.add_edge("tools", "assistant")
122
+ builder.add_edge("assistant", END)
123
+
124
+ graph = builder.compile()
125
+
126
+ # Optional: test entrypoint to run the graph manually
127
+ test_input = {
128
+ "messages": [
129
+ system_prompt,
130
+ HumanMessage(content="What is the capital of France?"),
131
+ ]
132
+ }
133
+
134
+ # result = graph.invoke(test_input)
135
+ # print("\nFinal output:", result["messages"][-1].content)
136
+
137
+ return graph
app.py CHANGED
@@ -1,34 +1,46 @@
 
1
  import os
 
2
  import gradio as gr
3
- import requests
4
- import inspect
5
  import pandas as pd
 
 
 
 
 
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
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
  """
24
  Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
 
30
  if profile:
31
- username= f"{profile.username}"
32
  print(f"User logged in: {username}")
33
  else:
34
  print("User not logged in.")
@@ -55,16 +67,16 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
55
  response.raise_for_status()
56
  questions_data = response.json()
57
  if not questions_data:
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
@@ -81,18 +93,36 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
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:
87
- print(f"Error running agent on task {task_id}: {e}")
88
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
89
 
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
 
@@ -162,20 +192,19 @@ with gr.Blocks() as demo:
162
 
163
  run_button = gr.Button("Run Evaluation & Submit All Answers")
164
 
165
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
 
166
  # Removed max_rows=10 from DataFrame constructor
167
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
168
 
169
- run_button.click(
170
- fn=run_and_submit_all,
171
- outputs=[status_output, results_table]
172
- )
173
 
174
  if __name__ == "__main__":
175
- print("\n" + "-"*30 + " App Starting " + "-"*30)
176
  # Check for SPACE_HOST and SPACE_ID at startup for information
177
  space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
 
180
  if space_host_startup:
181
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -183,14 +212,18 @@ if __name__ == "__main__":
183
  else:
184
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
 
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
  print(f"✅ SPACE_ID found: {space_id_startup}")
188
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
 
 
190
  else:
191
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
 
 
192
 
193
- print("-"*(60 + len(" App Starting ")) + "\n")
194
 
195
  print("Launching Gradio Interface for Basic Agent Evaluation...")
196
- demo.launch(debug=True, share=False)
 
1
+ import inspect
2
  import os
3
+
4
  import gradio as gr
 
 
5
  import pandas as pd
6
+ import requests
7
+ from langchain_core.messages import AnyMessage, HumanMessage, SystemMessage
8
+
9
+ # from langgraph.graph import MessagesState
10
+ from agent import build_agent_graph
11
 
12
  # (Keep Constants as is)
13
  # --- Constants ---
14
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
16
+
17
  # --- Basic Agent Definition ---
18
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
19
  class BasicAgent:
20
  def __init__(self):
21
  print("BasicAgent initialized.")
22
+ self.graph = build_agent_graph()
23
+
24
  def __call__(self, question: str) -> str:
25
  print(f"Agent received question (first 50 chars): {question[:50]}...")
26
+ # Wrap the question from HumanMessage from langchain_core
27
+ msgs = [HumanMessage(content=question)]
28
+ # input_state: MessagesState = {"messages": msgs}
29
+ result = self.graph.invoke({"messages": msgs})
30
+ answer = result["messages"][-1].content
31
+ return answer[14:] # skip "FINAL ANSWER: "
32
+
33
 
34
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
35
  """
36
  Fetches all questions, runs the BasicAgent on them, submits all answers,
37
  and displays the results.
38
  """
39
  # --- Determine HF Space Runtime URL and Repo URL ---
40
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
41
 
42
  if profile:
43
+ username = f"{profile.username}"
44
  print(f"User logged in: {username}")
45
  else:
46
  print("User not logged in.")
 
67
  response.raise_for_status()
68
  questions_data = response.json()
69
  if not questions_data:
70
+ print("Fetched questions list is empty.")
71
+ return "Fetched questions list is empty or invalid format.", None
72
  print(f"Fetched {len(questions_data)} questions.")
73
  except requests.exceptions.RequestException as e:
74
  print(f"Error fetching questions: {e}")
75
  return f"Error fetching questions: {e}", None
76
  except requests.exceptions.JSONDecodeError as e:
77
+ print(f"Error decoding JSON response from questions endpoint: {e}")
78
+ print(f"Response text: {response.text[:500]}")
79
+ return f"Error decoding server response for questions: {e}", None
80
  except Exception as e:
81
  print(f"An unexpected error occurred fetching questions: {e}")
82
  return f"An unexpected error occurred fetching questions: {e}", None
 
93
  continue
94
  try:
95
  submitted_answer = agent(question_text)
96
+ answers_payload.append(
97
+ {"task_id": task_id, "submitted_answer": submitted_answer}
98
+ )
99
+ results_log.append(
100
+ {
101
+ "Task ID": task_id,
102
+ "Question": question_text,
103
+ "Submitted Answer": submitted_answer,
104
+ }
105
+ )
106
  except Exception as e:
107
+ print(f"Error running agent on task {task_id}: {e}")
108
+ results_log.append(
109
+ {
110
+ "Task ID": task_id,
111
+ "Question": question_text,
112
+ "Submitted Answer": f"AGENT ERROR: {e}",
113
+ }
114
+ )
115
 
116
  if not answers_payload:
117
  print("Agent did not produce any answers to submit.")
118
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
119
 
120
+ # 4. Prepare Submission
121
+ submission_data = {
122
+ "username": username.strip(),
123
+ "agent_code": agent_code,
124
+ "answers": answers_payload,
125
+ }
126
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
127
  print(status_update)
128
 
 
192
 
193
  run_button = gr.Button("Run Evaluation & Submit All Answers")
194
 
195
+ status_output = gr.Textbox(
196
+ label="Run Status / Submission Result", lines=5, interactive=False
197
+ )
198
  # Removed max_rows=10 from DataFrame constructor
199
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
200
 
201
+ run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
 
 
 
202
 
203
  if __name__ == "__main__":
204
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
205
  # Check for SPACE_HOST and SPACE_ID at startup for information
206
  space_host_startup = os.getenv("SPACE_HOST")
207
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
208
 
209
  if space_host_startup:
210
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
212
  else:
213
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
214
 
215
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
216
  print(f"✅ SPACE_ID found: {space_id_startup}")
217
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
218
+ print(
219
+ f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main"
220
+ )
221
  else:
222
+ print(
223
+ "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined."
224
+ )
225
 
226
+ print("-" * (60 + len(" App Starting ")) + "\n")
227
 
228
  print("Launching Gradio Interface for Basic Agent Evaluation...")
229
+ demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -1,2 +1,9 @@
1
  gradio
2
- requests
 
 
 
 
 
 
 
 
1
  gradio
2
+ requests
3
+ langchain
4
+ langchain-core
5
+ langgraphlangchain
6
+ langchain-community
7
+ langchain-tavily
8
+ langgraph
9
+ tavily-python