chevisli commited on
Commit
bfb26a0
·
1 Parent(s): 0335261

Alpha version app

Browse files
app.py CHANGED
@@ -1,15 +1,10 @@
1
  import os
2
- import base64
3
- import mimetypes
4
- import gradio as gr
5
  import requests
6
- import inspect
7
  import pandas as pd
8
- from dotenv import load_dotenv
9
- from tools import agent_executor
 
10
 
11
- # Load environment variables from .env file
12
- load_dotenv()
13
 
14
  # (Keep Constants as is)
15
  # --- Constants ---
@@ -17,119 +12,26 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
17
 
18
  # --- Basic Agent Definition ---
19
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
20
- class BasicAgent:
21
- def __init__(self):
22
- print("BasicAgent initialized with LangChain tools.")
23
- self.agent_executor = agent_executor
24
-
25
- def __call__(self, question_data: dict) -> str:
26
- """
27
- Process question with optional file attachment
28
- question_data = {
29
- 'text': str,
30
- 'file_path': str (optional),
31
- 'file_name': str (optional)
32
- }
33
- """
34
- question_text = question_data.get('text', '')
35
- file_path = question_data.get('file_path')
36
-
37
- print(f"Agent received question (first 50 chars): {question_text[:50]}...")
38
-
39
- try:
40
- # Prepare input for the agent
41
- if file_path and os.path.exists(file_path):
42
- # Handle file input - check if it's an image or other file type
43
- file_extension = os.path.splitext(file_path)[1].lower()
44
-
45
- if file_extension in ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']:
46
- # Handle image files - use LLM directly for vision, bypass ReAct agent
47
- with open(file_path, 'rb') as img_file:
48
- img_base64 = base64.b64encode(img_file.read()).decode()
49
-
50
- print(f"Processing question with image: {file_path}")
51
-
52
- # Use the LLM directly for vision tasks
53
- from langchain_core.messages import HumanMessage
54
-
55
- # Create image message for direct LLM call
56
- message = HumanMessage(
57
- content=[
58
- {"type": "text", "text": f"{question_text}\n\nPlease analyze this image and provide your answer in the format: FINAL ANSWER: [YOUR ANSWER]"},
59
- {
60
- "type": "image_url",
61
- "image_url": {"url": f"data:image/{file_extension[1:]};base64,{img_base64}"}
62
- }
63
- ]
64
- )
65
-
66
- # Call LLM directly for vision tasks
67
- response = self.agent_executor.llm.invoke([message])
68
- answer = response.content if hasattr(response, 'content') else str(response)
69
- print(f"Agent generated answer: {answer}")
70
- return answer
71
-
72
- else:
73
- # Handle other file types (text, CSV, etc.) - use ReAct agent
74
- try:
75
- with open(file_path, 'r', encoding='utf-8') as f:
76
- file_content = f.read()
77
- combined_input = f"{question_text}\n\nFile content ({os.path.basename(file_path)}):\n{file_content}"
78
- agent_input = {"input": combined_input}
79
- print(f"Processing question with text file: {file_path}")
80
- except UnicodeDecodeError:
81
- # Binary file - provide file info only
82
- file_info = f"Binary file: {os.path.basename(file_path)} ({os.path.getsize(file_path)} bytes)"
83
- combined_input = f"{question_text}\n\nAttached file: {file_info}"
84
- agent_input = {"input": combined_input}
85
- print(f"Processing question with binary file: {file_path}")
86
-
87
- # Use ReAct agent for non-image files
88
- response = self.agent_executor.invoke(agent_input)
89
- answer = response.get('output', 'No answer generated.')
90
- print(f"Agent generated answer: {answer}")
91
- return answer
92
- else:
93
- # Text-only question - use ReAct agent
94
- agent_input = {"input": question_text}
95
- print("Processing text-only question")
96
- response = self.agent_executor.invoke(agent_input)
97
- answer = response.get('output', 'No answer generated.')
98
- print(f"Agent generated answer: {answer}")
99
- return answer
100
-
101
- except Exception as e:
102
- error_msg = f"Agent error: {str(e)}"
103
- print(f"Error in agent execution: {e}")
104
- return error_msg
105
- finally:
106
- # Clean up downloaded file
107
- if file_path and os.path.exists(file_path):
108
- try:
109
- os.remove(file_path)
110
- print(f"Cleaned up file: {file_path}")
111
- except Exception as e:
112
- print(f"Warning: Could not remove file {file_path}: {e}")
113
 
114
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
115
  """
116
  Fetches all questions, runs the BasicAgent on them, submits all answers,
117
  and displays the results.
118
  """
119
  # --- Determine HF Space Runtime URL and Repo URL ---
120
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
 
121
 
122
  if profile:
123
- username= f"{profile.username}"
124
  print(f"User logged in: {username}")
125
  else:
126
  print("User not logged in.")
127
  return "Please Login to Hugging Face with the button.", None
128
 
129
  api_url = DEFAULT_API_URL
130
- questions_url = f"{api_url}/questions"
131
  submit_url = f"{api_url}/submit"
132
- file_url = f"{api_url}/files"
133
 
134
  # 1. Instantiate Agent ( modify this part to create your agent)
135
  try:
@@ -142,25 +44,10 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
142
  print(agent_code)
143
 
144
  # 2. Fetch Questions
145
- print(f"Fetching questions from: {questions_url}")
146
- try:
147
- response = requests.get(questions_url, timeout=15)
148
- response.raise_for_status()
149
- questions_data = response.json()
150
- if not questions_data:
151
- print("Fetched questions list is empty.")
152
- return "Fetched questions list is empty or invalid format.", None
153
- print(f"Fetched {len(questions_data)} questions.")
154
- except requests.exceptions.RequestException as e:
155
- print(f"Error fetching questions: {e}")
156
- return f"Error fetching questions: {e}", None
157
- except requests.exceptions.JSONDecodeError as e:
158
- print(f"Error decoding JSON response from questions endpoint: {e}")
159
- print(f"Response text: {response.text[:500]}")
160
- return f"Error decoding server response for questions: {e}", None
161
- except Exception as e:
162
- print(f"An unexpected error occurred fetching questions: {e}")
163
- return f"An unexpected error occurred fetching questions: {e}", None
164
 
165
  # 3. Run your Agent
166
  results_log = []
@@ -168,63 +55,34 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
168
  print(f"Running agent on {len(questions_data)} questions...")
169
  for item in questions_data:
170
  task_id = item.get("task_id")
171
- question_text = item.get("question")
172
- file_name = item.get("file_name")
173
-
174
  if not task_id or question_text is None:
175
  print(f"Skipping item with missing task_id or question: {item}")
176
  continue
177
-
178
- # Prepare question data for the agent
179
- question_data = {
180
- 'text': question_text,
181
- 'file_path': None,
182
- 'file_name': file_name
183
- }
184
-
185
- # Download file if present
186
- if file_name:
187
- try:
188
- print(f"Downloading file for task {task_id}: {file_name}")
189
- file_response = requests.get(f"{file_url}/{task_id}", timeout=30) # Increased timeout
190
- file_response.raise_for_status()
191
-
192
- # Save file with a safe path
193
- safe_file_path = os.path.join(os.getcwd(), f"temp_{task_id}_{file_name}")
194
- with open(safe_file_path, "wb") as f:
195
- f.write(file_response.content)
196
-
197
- question_data['file_path'] = safe_file_path
198
- print(f"File downloaded successfully: {safe_file_path}")
199
-
200
- except requests.exceptions.Timeout:
201
- print(f"Timeout downloading file for task {task_id}: {file_name}")
202
- question_data['file_path'] = None
203
- except Exception as e:
204
- print(f"Error downloading file for task {task_id}: {e}")
205
- # Continue processing without file
206
- question_data['file_path'] = None
207
-
208
  # Process question with agent
209
  try:
210
- submitted_answer = agent(question_data)
211
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
212
-
 
213
  # Log result with file info
214
  file_info = f" (with file: {file_name})" if file_name else ""
215
  results_log.append({
216
- "Task ID": task_id,
217
- "Question": question_text + file_info,
218
  "Submitted Answer": submitted_answer
219
  })
220
  print(f"Task {task_id} completed successfully{file_info}")
221
-
222
  except Exception as e:
223
  print(f"Error running agent on task {task_id}: {e}")
224
  file_info = f" (with file: {file_name})" if file_name else ""
225
  results_log.append({
226
- "Task ID": task_id,
227
- "Question": question_text + file_info,
228
  "Submitted Answer": f"AGENT ERROR: {e}"
229
  })
230
 
@@ -232,8 +90,9 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
232
  print("Agent did not produce any answers to submit.")
233
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
234
 
235
- # 4. Prepare Submission
236
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
 
237
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
238
  print(status_update)
239
 
@@ -303,9 +162,11 @@ with gr.Blocks() as demo:
303
 
304
  run_button = gr.Button("Run Evaluation & Submit All Answers")
305
 
306
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
307
  # Removed max_rows=10 from DataFrame constructor
308
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
 
309
 
310
  run_button.click(
311
  fn=run_and_submit_all,
@@ -316,22 +177,24 @@ if __name__ == "__main__":
316
  print("\n" + "-"*30 + " App Starting " + "-"*30)
317
  # Check for SPACE_HOST and SPACE_ID at startup for information
318
  space_host_startup = os.getenv("SPACE_HOST")
319
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
320
 
321
  if space_host_startup:
322
  print(f"✅ SPACE_HOST found: {space_host_startup}")
323
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
 
324
  else:
325
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
326
 
327
- if space_id_startup: # Print repo URLs if SPACE_ID is found
328
  print(f"✅ SPACE_ID found: {space_id_startup}")
329
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
330
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
 
331
  else:
332
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
333
 
334
  print("-"*(60 + len(" App Starting ")) + "\n")
335
 
336
  print("Launching Gradio Interface for Basic Agent Evaluation...")
337
- demo.launch(debug=True, share=False)
 
1
  import os
 
 
 
2
  import requests
 
3
  import pandas as pd
4
+ import gradio as gr
5
+ from basic_agent import BasicAgent
6
+ from utils.question_manager import QuestionManager
7
 
 
 
8
 
9
  # (Keep Constants as is)
10
  # --- Constants ---
 
12
 
13
  # --- Basic Agent Definition ---
14
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+
17
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
18
  """
19
  Fetches all questions, runs the BasicAgent on them, submits all answers,
20
  and displays the results.
21
  """
22
  # --- Determine HF Space Runtime URL and Repo URL ---
23
+ # Get the SPACE_ID for sending link to the code
24
+ space_id = os.getenv("SPACE_ID")
25
 
26
  if profile:
27
+ username = f"{profile.username}"
28
  print(f"User logged in: {username}")
29
  else:
30
  print("User not logged in.")
31
  return "Please Login to Hugging Face with the button.", None
32
 
33
  api_url = DEFAULT_API_URL
 
34
  submit_url = f"{api_url}/submit"
 
35
 
36
  # 1. Instantiate Agent ( modify this part to create your agent)
37
  try:
 
44
  print(agent_code)
45
 
46
  # 2. Fetch Questions
47
+ question_manager = QuestionManager(api_url)
48
+ questions = question_manager.fetch_questions()
49
+ # questions = question_manager.fetch_random_question()
50
+ questions_data = question_manager.prepare_questions_data(questions)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  # 3. Run your Agent
53
  results_log = []
 
55
  print(f"Running agent on {len(questions_data)} questions...")
56
  for item in questions_data:
57
  task_id = item.get("task_id")
58
+ question_text = item.get("text")
59
+ file_name = item.get("file_url")
60
+
61
  if not task_id or question_text is None:
62
  print(f"Skipping item with missing task_id or question: {item}")
63
  continue
64
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  # Process question with agent
66
  try:
67
+ submitted_answer = agent(item)
68
+ answers_payload.append(
69
+ {"task_id": task_id, "submitted_answer": submitted_answer})
70
+
71
  # Log result with file info
72
  file_info = f" (with file: {file_name})" if file_name else ""
73
  results_log.append({
74
+ "Task ID": task_id,
75
+ "Question": question_text + file_info,
76
  "Submitted Answer": submitted_answer
77
  })
78
  print(f"Task {task_id} completed successfully{file_info}")
79
+
80
  except Exception as e:
81
  print(f"Error running agent on task {task_id}: {e}")
82
  file_info = f" (with file: {file_name})" if file_name else ""
83
  results_log.append({
84
+ "Task ID": task_id,
85
+ "Question": question_text + file_info,
86
  "Submitted Answer": f"AGENT ERROR: {e}"
87
  })
88
 
 
90
  print("Agent did not produce any answers to submit.")
91
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
92
 
93
+ # 4. Prepare Submission
94
+ submission_data = {"username": username.strip(
95
+ ), "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
 
163
  run_button = gr.Button("Run Evaluation & Submit All Answers")
164
 
165
+ status_output = gr.Textbox(
166
+ label="Run Status / Submission Result", lines=5, interactive=False)
167
  # Removed max_rows=10 from DataFrame constructor
168
+ results_table = gr.DataFrame(
169
+ label="Questions and Agent Answers", wrap=True)
170
 
171
  run_button.click(
172
  fn=run_and_submit_all,
 
177
  print("\n" + "-"*30 + " App Starting " + "-"*30)
178
  # Check for SPACE_HOST and SPACE_ID at startup for information
179
  space_host_startup = os.getenv("SPACE_HOST")
180
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
181
 
182
  if space_host_startup:
183
  print(f"✅ SPACE_HOST found: {space_host_startup}")
184
+ print(
185
+ f" Runtime URL should be: https://{space_host_startup}.hf.space")
186
  else:
187
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
188
 
189
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
190
  print(f"✅ SPACE_ID found: {space_id_startup}")
191
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
192
+ print(
193
+ f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
194
  else:
195
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
196
 
197
  print("-"*(60 + len(" App Starting ")) + "\n")
198
 
199
  print("Launching Gradio Interface for Basic Agent Evaluation...")
200
+ demo.launch(debug=True, share=False)
basic_agent.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils.agent_executor import create_agent_executor
2
+
3
+
4
+ class BasicAgent:
5
+ def __init__(self):
6
+ print("BasicAgent initialized with LangChain tools.")
7
+ self.agent_executor = create_agent_executor()
8
+
9
+ def __call__(self, question_data: dict) -> str:
10
+ question_text = question_data.get('text', '')
11
+ file_url = question_data.get('file_url')
12
+ print(
13
+ f"Agent received question (task_id: {question_data.get('task_id')}) (first 50 chars): {question_text[:50]}...")
14
+ if file_url:
15
+ print(f"With attached file URL: {file_url}")
16
+
17
+ print(
18
+ f"Start processing question (task_id: {question_data.get('task_id')})")
19
+ response = self.agent_executor.invoke(
20
+ {"input": question_text, "file_url": file_url})
21
+ answer = response.get('output', 'No answer generated.')
22
+ print(
23
+ f"Agent generated answer (task_id: {question_data.get('task_id')}): {answer}")
24
+ return answer
utils/agent_executor.py CHANGED
@@ -1,6 +1,7 @@
1
  from langchain.agents import AgentExecutor, create_react_agent
2
  from langchain_openai import ChatOpenAI
3
- from prompt import prompt_default
 
4
 
5
 
6
  def create_agent_executor(
@@ -22,7 +23,7 @@ def create_agent_executor(
22
  )
23
 
24
  if tools is None:
25
- tools = []
26
 
27
  if prompt is None:
28
  prompt = prompt_default
 
1
  from langchain.agents import AgentExecutor, create_react_agent
2
  from langchain_openai import ChatOpenAI
3
+ from utils.prompt import prompt_default
4
+ from utils.tools import tools_default
5
 
6
 
7
  def create_agent_executor(
 
23
  )
24
 
25
  if tools is None:
26
+ tools = tools_default
27
 
28
  if prompt is None:
29
  prompt = prompt_default
utils/document_parser_tool.py CHANGED
@@ -2,8 +2,7 @@ import os
2
  import pandas as pd
3
  from langchain_community.document_loaders import PyPDFLoader
4
  from langchain.tools import Tool
5
- from agent_executor import create_agent_executor
6
- from file_downloader import FileDownloader
7
  from dotenv import load_dotenv
8
 
9
  load_dotenv()
@@ -174,6 +173,9 @@ document_parser_url_tool = Tool(
174
 
175
  if __name__ == "__main__":
176
  print("Start testing document parser tool with file downloader integration")
 
 
 
177
 
178
  # Initialize file downloader
179
  downloader = FileDownloader()
 
2
  import pandas as pd
3
  from langchain_community.document_loaders import PyPDFLoader
4
  from langchain.tools import Tool
5
+ from utils.file_downloader import FileDownloader
 
6
  from dotenv import load_dotenv
7
 
8
  load_dotenv()
 
173
 
174
  if __name__ == "__main__":
175
  print("Start testing document parser tool with file downloader integration")
176
+
177
+ # Import here to avoid circular import
178
+ from utils.agent_executor import create_agent_executor
179
 
180
  # Initialize file downloader
181
  downloader = FileDownloader()
utils/question_manager.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+
3
+
4
+ class QuestionManager:
5
+ def __init__(self, api_url: str):
6
+ self.api_url = api_url
7
+ self.questions_url = f"{api_url}/questions"
8
+ self.random_question_url = f"{api_url}/random_question"
9
+ self.files_url = f"{api_url}/files"
10
+ self.submit_url = f"{api_url}/submit"
11
+
12
+ def fetch_random_question(self):
13
+ print("Fetching random question")
14
+ try:
15
+ response = requests.get(self.random_question_url, timeout=15)
16
+ response.raise_for_status()
17
+ question_data = response.json()
18
+ return question_data
19
+ except requests.exceptions.RequestException as e:
20
+ print(f"Error fetching random question: {e}")
21
+ except requests.exceptions.JSONDecodeError as e:
22
+ print(
23
+ f"Error decoding JSON response from random question endpoint: {e}")
24
+ print(f"Response text: {response.text[:500]}")
25
+ return None
26
+ except Exception as e:
27
+ print(
28
+ f"An unexpected error occurred fetching random question: {e}")
29
+ return None
30
+
31
+ def fetch_question_by_id(self, question_id: str) -> dict | None:
32
+ print(f"Fetching question by id: {question_id}")
33
+ questions = self.fetch_questions()
34
+ for question in questions:
35
+ if question.get("task_id") == question_id:
36
+ return question
37
+ return None
38
+
39
+ def fetch_questions(self) -> list[dict]:
40
+ print(f"Fetching questions from: {self.questions_url}")
41
+ try:
42
+ response = requests.get(self.questions_url, timeout=15)
43
+ response.raise_for_status()
44
+ questions_data = response.json()
45
+ if not questions_data:
46
+ print("Fetched questions list is empty.")
47
+ return "Fetched questions list is empty or invalid format.", None
48
+ print(f"Fetched {len(questions_data)} questions.")
49
+ return questions_data
50
+ except requests.exceptions.RequestException as e:
51
+ print(f"Error fetching questions: {e}")
52
+ return []
53
+ except requests.exceptions.JSONDecodeError as e:
54
+ print(f"Error decoding JSON response from questions endpoint: {e}")
55
+ print(f"Response text: {response.text[:500]}")
56
+ return []
57
+ except Exception as e:
58
+ print(f"An unexpected error occurred fetching questions: {e}")
59
+ return []
60
+
61
+ def prepare_questions_data(self, questions: list[dict]) -> list[dict]:
62
+ print(f"Preparing question data for: {questions}")
63
+ questions_data = []
64
+ for item in questions:
65
+ task_id = item.get("task_id")
66
+ question_text = item.get("question")
67
+ file_url = f"{self.files_url}/{task_id}"
68
+ if not task_id or question_text is None:
69
+ print(
70
+ f"Skipping item with missing task_id or question: {item}")
71
+ continue
72
+ question_data = {
73
+ 'task_id': task_id,
74
+ 'text': question_text,
75
+ 'file_url': file_url
76
+ }
77
+ questions_data.append(question_data)
78
+ return questions_data
utils/search_tool.py CHANGED
@@ -1,6 +1,5 @@
1
  from langchain_google_community import GoogleSearchRun, GoogleSearchAPIWrapper
2
  from dotenv import load_dotenv
3
- from agent_executor import create_agent_executor
4
 
5
  load_dotenv()
6
 
@@ -9,6 +8,9 @@ search_tool = GoogleSearchRun(api_wrapper=search_wrapper)
9
 
10
  if __name__ == "__main__":
11
  print("Start testing search tool with an example question")
 
 
 
12
 
13
  tools = [search_tool]
14
  agent_executor = create_agent_executor(tools=tools)
 
1
  from langchain_google_community import GoogleSearchRun, GoogleSearchAPIWrapper
2
  from dotenv import load_dotenv
 
3
 
4
  load_dotenv()
5
 
 
8
 
9
  if __name__ == "__main__":
10
  print("Start testing search tool with an example question")
11
+
12
+ # Import here to avoid circular import
13
+ from utils.agent_executor import create_agent_executor
14
 
15
  tools = [search_tool]
16
  agent_executor = create_agent_executor(tools=tools)
utils/tools.py CHANGED
@@ -1,4 +1,4 @@
1
- from search_tool import search_tool
2
- from document_parser_tool import document_parser_tool
3
 
4
- tools = [search_tool, document_parser_tool]
 
1
+ from utils.search_tool import search_tool
2
+ from utils.document_parser_tool import document_parser_tool
3
 
4
+ tools_default = [search_tool, document_parser_tool]