setup project structure: getting ready to build my agents
Browse files- .gitignore +68 -0
- app.py +266 -170
- args.py +17 -0
- diagrams/diagram.png +0 -0
- diagrams/diagram.puml +87 -0
- diagrams/style.puml +7 -0
- llm_factory.py +70 -0
- manager.py +32 -0
- requirements.txt +12 -1
- solver.py +165 -0
- system_prompts/01_assistant.txt +1 -0
- system_prompts/02_manager.txt +1 -0
- system_prompts/03_solver.txt +0 -0
- system_prompts/04_researcher.txt +31 -0
- system_prompts/05_encryption_expert.txt +69 -0
- system_prompts/06_math_expert.txt +87 -0
- system_prompts/07_reasoner.txt +87 -0
- system_prompts/08_image_handler.txt +1 -0
- system_prompts/09_video_handler.txt +1 -0
- test_agents.py +17 -0
- toolbox.py +212 -0
.gitignore
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
*.egg-info/
|
24 |
+
.installed.cfg
|
25 |
+
*.egg
|
26 |
+
|
27 |
+
# PyInstaller
|
28 |
+
*.manifest
|
29 |
+
*.spec
|
30 |
+
|
31 |
+
# Installer logs
|
32 |
+
pip-log.txt
|
33 |
+
pip-delete-this-directory.txt
|
34 |
+
|
35 |
+
# Unit test / coverage reports
|
36 |
+
htmlcov/
|
37 |
+
.tox/
|
38 |
+
.coverage
|
39 |
+
.coverage.*
|
40 |
+
.cache
|
41 |
+
nosetests.xml
|
42 |
+
coverage.xml
|
43 |
+
*.cover
|
44 |
+
.hypothesis/
|
45 |
+
|
46 |
+
# Jupyter Notebook
|
47 |
+
.ipynb_checkpoints
|
48 |
+
|
49 |
+
# Virtual environments
|
50 |
+
.venv
|
51 |
+
venv/
|
52 |
+
ENV/
|
53 |
+
env/
|
54 |
+
env.bak/
|
55 |
+
venv.bak/
|
56 |
+
|
57 |
+
# IDE related
|
58 |
+
.idea/
|
59 |
+
.vscode/
|
60 |
+
*.swp
|
61 |
+
*.swo
|
62 |
+
|
63 |
+
# Local configuration file
|
64 |
+
.env
|
65 |
+
|
66 |
+
# Other files
|
67 |
+
_to_ignore/
|
68 |
+
.github/
|
app.py
CHANGED
@@ -1,196 +1,292 @@
|
|
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 |
-
|
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 |
-
try:
|
54 |
-
response = requests.get(questions_url, timeout=15)
|
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
|
71 |
-
|
72 |
-
# 3. Run your Agent
|
73 |
-
results_log = []
|
74 |
-
answers_payload = []
|
75 |
-
print(f"Running agent on {len(questions_data)} questions...")
|
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 |
-
|
84 |
-
|
85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
except Exception as e:
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
f"User: {result_data.get('username')}\n"
|
108 |
-
f"Overall Score: {result_data.get('score', 'N/A')}% "
|
109 |
-
f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
|
110 |
-
f"Message: {result_data.get('message', 'No message received.')}"
|
111 |
-
)
|
112 |
-
print("Submission successful.")
|
113 |
-
results_df = pd.DataFrame(results_log)
|
114 |
-
return final_status, results_df
|
115 |
-
except requests.exceptions.HTTPError as e:
|
116 |
-
error_detail = f"Server responded with status {e.response.status_code}."
|
117 |
-
try:
|
118 |
-
error_json = e.response.json()
|
119 |
-
error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
|
120 |
-
except requests.exceptions.JSONDecodeError:
|
121 |
-
error_detail += f" Response: {e.response.text[:500]}"
|
122 |
-
status_message = f"Submission Failed: {error_detail}"
|
123 |
-
print(status_message)
|
124 |
-
results_df = pd.DataFrame(results_log)
|
125 |
-
return status_message, results_df
|
126 |
-
except requests.exceptions.Timeout:
|
127 |
-
status_message = "Submission Failed: The request timed out."
|
128 |
-
print(status_message)
|
129 |
-
results_df = pd.DataFrame(results_log)
|
130 |
-
return status_message, results_df
|
131 |
-
except requests.exceptions.RequestException as e:
|
132 |
-
status_message = f"Submission Failed: Network error - {e}"
|
133 |
-
print(status_message)
|
134 |
-
results_df = pd.DataFrame(results_log)
|
135 |
-
return status_message, results_df
|
136 |
-
except Exception as e:
|
137 |
-
status_message = f"An unexpected error occurred during submission: {e}"
|
138 |
-
print(status_message)
|
139 |
-
results_df = pd.DataFrame(results_log)
|
140 |
-
return status_message, results_df
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
|
143 |
-
|
144 |
-
with gr.Blocks() as demo:
|
145 |
-
gr.Markdown("# Basic Agent Evaluation Runner")
|
146 |
-
gr.Markdown(
|
147 |
"""
|
148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
|
150 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
"""
|
159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
|
161 |
-
gr.LoginButton()
|
162 |
|
163 |
-
|
164 |
|
165 |
-
|
166 |
-
|
167 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
|
|
173 |
|
174 |
-
if __name__ == "__main__":
|
175 |
-
|
176 |
-
|
177 |
-
space_host_startup = os.getenv("SPACE_HOST")
|
178 |
-
space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
|
179 |
|
180 |
-
|
181 |
-
print(f"✅ SPACE_HOST found: {space_host_startup}")
|
182 |
-
print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
|
183 |
-
else:
|
184 |
-
print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
|
185 |
|
186 |
-
|
187 |
-
|
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 |
-
|
196 |
-
demo.launch(debug=True, share=False)
|
|
|
1 |
import os
|
2 |
import gradio as gr
|
3 |
import requests
|
|
|
4 |
import pandas as pd
|
5 |
+
from manager import Manager
|
6 |
+
|
7 |
|
|
|
8 |
# --- Constants ---
|
9 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
10 |
+
MOCK_SUBMISSION = True
|
11 |
+
QUESTIONS_LIMIT = 3
|
12 |
+
|
13 |
+
|
14 |
+
class Application:
|
15 |
|
|
|
|
|
|
|
16 |
def __init__(self):
|
17 |
+
self.space_id = os.getenv("SPACE_ID")
|
18 |
+
self.username = None
|
19 |
+
self.questions_url, self.submit_url = self._get_runtime_and_repo_urls()
|
20 |
+
|
21 |
+
@staticmethod
|
22 |
+
def _get_username(profile: gr.OAuthProfile | None):
|
23 |
+
"""Get profile username"""
|
24 |
+
if profile:
|
25 |
+
username= f"{profile.username}"
|
26 |
+
print(f"User logged in: {username}")
|
27 |
+
return username
|
28 |
+
else:
|
29 |
+
print("User not logged in.")
|
30 |
+
return None
|
31 |
+
|
32 |
+
@staticmethod
|
33 |
+
def _get_runtime_and_repo_urls():
|
34 |
+
"""Determine HF Space Runtime URL and Repo URL"""
|
35 |
+
api_url = DEFAULT_API_URL
|
36 |
+
questions_url = f"{api_url}/questions"
|
37 |
+
submit_url = f"{api_url}/submit"
|
38 |
+
return questions_url, submit_url
|
39 |
+
|
40 |
+
def _fetch_questions(self):
|
41 |
+
"""
|
42 |
+
Fetches questions from `questions_url`.
|
43 |
+
|
44 |
+
Sends a GET request to retrieve and parse questions as JSON. Handles network,
|
45 |
+
JSON decoding, and unexpected errors.
|
46 |
+
|
47 |
+
Returns:
|
48 |
+
tuple: (error_message: str or None, questions: list or None)
|
49 |
+
|
50 |
+
Logs:
|
51 |
+
- Progress, success, empty data, or errors.
|
52 |
+
"""
|
53 |
+
|
54 |
+
print(f"Fetching questions from: {self.questions_url}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
try:
|
56 |
+
response = requests.get(self.questions_url, timeout=15)
|
57 |
+
response.raise_for_status()
|
58 |
+
questions_data = response.json()
|
59 |
+
if not questions_data:
|
60 |
+
print("Fetched questions list is empty.")
|
61 |
+
return "Fetched questions list is empty or invalid format.", None
|
62 |
+
print(f"Fetched {len(questions_data)} questions.")
|
63 |
+
except requests.exceptions.RequestException as e:
|
64 |
+
print(f"Error fetching questions: {e}")
|
65 |
+
return f"Error fetching questions: {e}", None
|
66 |
+
except requests.exceptions.JSONDecodeError as e:
|
67 |
+
print(f"Error decoding JSON response from questions endpoint: {e}")
|
68 |
+
print(f"Response text: {response.text[:500]}")
|
69 |
+
return f"Error decoding server response for questions: {e}", None
|
70 |
except Exception as e:
|
71 |
+
print(f"An unexpected error occurred fetching questions: {e}")
|
72 |
+
return f"An unexpected error occurred fetching questions: {e}", None
|
73 |
+
return questions_data
|
74 |
+
|
75 |
+
@staticmethod
|
76 |
+
async def _run_agent(questions_data, agent):
|
77 |
+
"""
|
78 |
+
Runs the agent on a list of questions and collects results.
|
79 |
+
|
80 |
+
Args:
|
81 |
+
questions_data (list): List of question dictionaries with "task_id" and "question".
|
82 |
+
agent (callable): Callable that processes a question and returns an answer.
|
83 |
+
|
84 |
+
Returns:
|
85 |
+
tuple:
|
86 |
+
- results_log (list): Logs with "Task ID", "Question", and "Submitted Answer".
|
87 |
+
- answers_payload (list): Payload with "task_id" and "submitted_answer".
|
88 |
+
"""
|
89 |
+
if QUESTIONS_LIMIT > 0:
|
90 |
+
questions_data = questions_data[:QUESTIONS_LIMIT]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
+
results_log = []
|
93 |
+
answers_payload = []
|
94 |
+
print(f"Running agent on {len(questions_data)} questions...")
|
95 |
+
for item in questions_data:
|
96 |
+
task_id = item.get("task_id")
|
97 |
+
question_text = item.get("question")
|
98 |
+
if not task_id or question_text is None:
|
99 |
+
print(f"Skipping item with missing task_id or question: {item}")
|
100 |
+
continue
|
101 |
+
try:
|
102 |
+
submitted_answer = await agent(question_text)
|
103 |
+
print(f"SUBMITED_ANSWER: {submitted_answer}")
|
104 |
+
answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
|
105 |
+
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
|
106 |
+
except Exception as e:
|
107 |
+
print(f"Error running agent on task {task_id}: {e}")
|
108 |
+
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
|
109 |
+
return results_log, answers_payload
|
110 |
|
111 |
+
def _submit(self, answers_payload, submission_data, results_log):
|
|
|
|
|
|
|
112 |
"""
|
113 |
+
Submits answers to the specified URL and processes the response.
|
114 |
+
|
115 |
+
Args:
|
116 |
+
answers_payload (list): List of answers to submit.
|
117 |
+
submission_data (dict): Payload for the POST request.
|
118 |
+
results_log (list): Log of results to convert into a DataFrame.
|
119 |
+
|
120 |
+
Returns:
|
121 |
+
tuple: (status_message (str), results_df (pd.DataFrame)).
|
122 |
|
123 |
+
Notes:
|
124 |
+
- Sends a POST request to `self.submit_url` with `submission_data`.
|
125 |
+
- Handles exceptions and provides error messages.
|
126 |
+
"""
|
127 |
+
print(f"Submitting {len(answers_payload)} answers to: {self.submit_url}")
|
128 |
+
try:
|
129 |
+
if MOCK_SUBMISSION:
|
130 |
+
mock_response = type('MockResponse', (), {
|
131 |
+
'status_code': 200,
|
132 |
+
'json': lambda *args: {
|
133 |
+
"username": self.username,
|
134 |
+
"score": 100,
|
135 |
+
"correct_count": len(answers_payload),
|
136 |
+
"total_attempted": len(answers_payload),
|
137 |
+
"message": "Mock submission successful."
|
138 |
+
}
|
139 |
+
})
|
140 |
+
response = mock_response()
|
141 |
+
else:
|
142 |
+
response = requests.post(self.submit_url, json=submission_data, timeout=60)
|
143 |
+
response.raise_for_status()
|
144 |
+
result_data = response.json()
|
145 |
+
final_status = (
|
146 |
+
f"Submission Successful!\n"
|
147 |
+
f"User: {result_data.get('username')}\n"
|
148 |
+
f"Overall Score: {result_data.get('score', 'N/A')}% "
|
149 |
+
f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
|
150 |
+
f"Message: {result_data.get('message', 'No message received.')}"
|
151 |
+
)
|
152 |
+
print("Submission successful.")
|
153 |
+
results_df = pd.DataFrame(results_log)
|
154 |
+
return final_status, results_df
|
155 |
+
except requests.exceptions.HTTPError as e:
|
156 |
+
error_detail = f"Server responded with status {e.response.status_code}."
|
157 |
+
try:
|
158 |
+
error_json = e.response.json()
|
159 |
+
error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
|
160 |
+
except requests.exceptions.JSONDecodeError:
|
161 |
+
error_detail += f" Response: {e.response.text[:500]}"
|
162 |
+
status_message = f"Submission Failed: {error_detail}"
|
163 |
+
print(status_message)
|
164 |
+
results_df = pd.DataFrame(results_log)
|
165 |
+
return status_message, results_df
|
166 |
+
except requests.exceptions.Timeout:
|
167 |
+
status_message = "Submission Failed: The request timed out."
|
168 |
+
print(status_message)
|
169 |
+
results_df = pd.DataFrame(results_log)
|
170 |
+
return status_message, results_df
|
171 |
+
except requests.exceptions.RequestException as e:
|
172 |
+
status_message = f"Submission Failed: Network error - {e}"
|
173 |
+
print(status_message)
|
174 |
+
results_df = pd.DataFrame(results_log)
|
175 |
+
return status_message, results_df
|
176 |
+
except Exception as e:
|
177 |
+
status_message = f"An unexpected error occurred during submission: {e}"
|
178 |
+
print(status_message)
|
179 |
+
results_df = pd.DataFrame(results_log)
|
180 |
+
return status_message, results_df
|
181 |
|
182 |
+
async def eval_and_submit_all(self, profile: gr.OAuthProfile | None):
|
183 |
+
"""
|
184 |
+
Fetches all questions, runs the agent on them, submits all answers,
|
185 |
+
and displays the results.
|
186 |
"""
|
187 |
+
self.username = self._get_username(profile)
|
188 |
+
if self.username is None:
|
189 |
+
return "Please Login to Hugging Face with the button.", None
|
190 |
+
|
191 |
+
# 1. Instantiate the Main Agent
|
192 |
+
try:
|
193 |
+
agent = Manager()
|
194 |
+
except Exception as e:
|
195 |
+
print(f"Error instantiating agent: {e}")
|
196 |
+
return f"Error initializing agent: {e}", None
|
197 |
+
# In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
|
198 |
+
agent_code = f"https://huggingface.co/spaces/{self.space_id}/tree/main"
|
199 |
+
print(agent_code)
|
200 |
+
|
201 |
+
# 2. Fetch Questions
|
202 |
+
questions_data = self._fetch_questions()
|
203 |
+
|
204 |
+
# 3. Run your Agent
|
205 |
+
results_log, answers_payload = await self._run_agent(questions_data, agent)
|
206 |
+
|
207 |
+
if not answers_payload:
|
208 |
+
print("Agent did not produce any answers to submit.")
|
209 |
+
return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
|
210 |
+
|
211 |
+
# 4. Prepare Submission
|
212 |
+
submission_data = {"username": self.username.strip(), "agent_code": agent_code, "answers": answers_payload}
|
213 |
+
status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{self.username}'..."
|
214 |
+
print(status_update)
|
215 |
+
|
216 |
+
# 5. Submit
|
217 |
+
status_message, results_df = self._submit(answers_payload, submission_data, results_log)
|
218 |
+
return status_message, results_df
|
219 |
|
|
|
220 |
|
221 |
+
class UI:
|
222 |
|
223 |
+
app = Application()
|
224 |
+
|
225 |
+
@classmethod
|
226 |
+
def _check_space_host_and_id(cls):
|
227 |
+
"""Check for SPACE_HOST and SPACE_ID at startup for information"""
|
228 |
+
space_host_startup = os.getenv("SPACE_HOST")
|
229 |
+
space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
|
230 |
+
|
231 |
+
if space_host_startup:
|
232 |
+
print(f"✅ SPACE_HOST found: {space_host_startup}")
|
233 |
+
print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
|
234 |
+
else:
|
235 |
+
print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
|
236 |
+
|
237 |
+
# Print repo URLs if SPACE_ID is found
|
238 |
+
if space_id_startup:
|
239 |
+
print(f"✅ SPACE_ID found: {space_id_startup}")
|
240 |
+
print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
|
241 |
+
print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
|
242 |
+
else:
|
243 |
+
print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
|
244 |
+
|
245 |
+
@classmethod
|
246 |
+
def _build(cls):
|
247 |
+
gr.Markdown("# Main Agent Evaluation Runner")
|
248 |
+
gr.Markdown(
|
249 |
+
"""
|
250 |
+
**Instructions:**
|
251 |
+
|
252 |
+
1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
|
253 |
+
2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
|
254 |
+
3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
|
255 |
+
|
256 |
+
---
|
257 |
+
**Disclaimers:**
|
258 |
+
Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
|
259 |
+
This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
|
260 |
+
"""
|
261 |
+
)
|
262 |
+
|
263 |
+
gr.LoginButton()
|
264 |
+
|
265 |
+
run_button = gr.Button("Run Evaluation & Submit All Answers")
|
266 |
+
|
267 |
+
status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
|
268 |
+
# Removed max_rows=10 from DataFrame constructor
|
269 |
+
results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
|
270 |
+
|
271 |
+
run_button.click(
|
272 |
+
fn=cls.app.eval_and_submit_all,
|
273 |
+
outputs=[status_output, results_table]
|
274 |
+
)
|
275 |
|
276 |
+
@classmethod
|
277 |
+
def launch(cls):
|
278 |
+
"""Build Gradio Interface using Blocks"""
|
279 |
+
with gr.Blocks() as demo:
|
280 |
+
cls._build()
|
281 |
|
282 |
+
if __name__ == "__main__":
|
283 |
+
print("\n" + "-"*30 + " App Starting " + "-"*30)
|
284 |
+
cls._check_space_host_and_id()
|
|
|
|
|
285 |
|
286 |
+
print("-"*(60 + len(" App Starting ")) + "\n")
|
|
|
|
|
|
|
|
|
287 |
|
288 |
+
print("Launching Gradio Interface for Main Agent Evaluation...")
|
289 |
+
demo.launch(debug=True, share=False)
|
|
|
|
|
|
|
|
|
290 |
|
|
|
291 |
|
292 |
+
UI.launch()
|
|
args.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from enum import Enum
|
3 |
+
|
4 |
+
|
5 |
+
class InterfaceChoice(Enum):
|
6 |
+
HUGGINGFACE = "HuggingFace"
|
7 |
+
OPENAILIKE = "OpenAILike"
|
8 |
+
OPENAI = "OpenAI"
|
9 |
+
# Add your own if you like (then adjust the LLMFactory)
|
10 |
+
|
11 |
+
|
12 |
+
class Args:
|
13 |
+
INTERFACE = InterfaceChoice.OPENAILIKE
|
14 |
+
model_name="Qwen/Qwen2.5-Coder-32B-Instruct"
|
15 |
+
api_base="http://127.0.0.1:1234/v1" # LM Studio local endpoint
|
16 |
+
api_key="api_key"
|
17 |
+
token = "" # Not needed when using OpenAILike API
|
diagrams/diagram.png
ADDED
![]() |
diagrams/diagram.puml
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@startuml
|
2 |
+
|
3 |
+
!include style.puml
|
4 |
+
|
5 |
+
' left to right direction
|
6 |
+
|
7 |
+
' Hide the class indicators (C)
|
8 |
+
hide circle
|
9 |
+
hide empty members
|
10 |
+
|
11 |
+
' Agent Definitions (Use class notation for agents with tools as fields)
|
12 |
+
|
13 |
+
|
14 |
+
class "Ambassador" as Ambassador <<M>> {
|
15 |
+
}
|
16 |
+
|
17 |
+
class "Manager" as Manager <<M>> {
|
18 |
+
- Solver() {trivial task}
|
19 |
+
- Manager() {complex task}
|
20 |
+
}
|
21 |
+
|
22 |
+
class "Solver" as Solver {
|
23 |
+
- Researcher()
|
24 |
+
- EncryptionExpert()
|
25 |
+
- MathExpert()
|
26 |
+
- Reasoner()
|
27 |
+
- ImageHandler()
|
28 |
+
- VideoHandler()
|
29 |
+
}
|
30 |
+
|
31 |
+
class "Researcher" as Researcher {
|
32 |
+
+ DuckDuckGoSearchToolSpec
|
33 |
+
}
|
34 |
+
|
35 |
+
class "EncryptionExpert" as EncryptionExpert {
|
36 |
+
+ ASCII Encode
|
37 |
+
+ ASCII Decode
|
38 |
+
+ ChrToInt Encode
|
39 |
+
+ ChrToInt Decode
|
40 |
+
+ Base64 Encode
|
41 |
+
+ Base64 Decode
|
42 |
+
+ Caesar Cipher Encode
|
43 |
+
+ Caesar Cipher Decode
|
44 |
+
+ Caesar Cipher Brute Force
|
45 |
+
+ Reverse String
|
46 |
+
- MathExpert()
|
47 |
+
- Reasoner()
|
48 |
+
}
|
49 |
+
|
50 |
+
class "MathExpert" as MathExpert {
|
51 |
+
+ Symbolic Math Calculator
|
52 |
+
+ Unit Converter
|
53 |
+
- Reasoner()
|
54 |
+
}
|
55 |
+
|
56 |
+
class "Reasoner" as Reasoner {
|
57 |
+
}
|
58 |
+
|
59 |
+
class "ImageHandler" as ImageHandler {
|
60 |
+
}
|
61 |
+
|
62 |
+
class "VideoHandler" as VideoHandler {
|
63 |
+
}
|
64 |
+
|
65 |
+
' Agent-to-Agent Connections
|
66 |
+
Query --> Ambassador
|
67 |
+
Ambassador --> Manager : request
|
68 |
+
Manager --> Ambassador : solution
|
69 |
+
Ambassador --> Final_Answer : problem solved
|
70 |
+
|
71 |
+
Manager ..> Manager : complex task
|
72 |
+
Manager ..> Solver : trivial task
|
73 |
+
Solver ..> Manager : solution
|
74 |
+
|
75 |
+
Solver .. Researcher : query
|
76 |
+
Solver .. EncryptionExpert : query
|
77 |
+
Solver .. MathExpert : query
|
78 |
+
Solver .. Reasoner : query
|
79 |
+
Solver .. ImageHandler : query
|
80 |
+
Solver .. VideoHandler : query
|
81 |
+
|
82 |
+
EncryptionExpert .. MathExpert : query
|
83 |
+
EncryptionExpert .. Reasoner : query
|
84 |
+
MathExpert .. Reasoner : query
|
85 |
+
|
86 |
+
|
87 |
+
@enduml
|
diagrams/style.puml
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
skinparam class {
|
2 |
+
BackgroundColor #E0F7FA
|
3 |
+
BorderColor #D84315
|
4 |
+
FontColor #E65100
|
5 |
+
FontStyle bold
|
6 |
+
HeaderBackgroundColor #FFE0B2
|
7 |
+
}
|
llm_factory.py
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.llms.openai_like import OpenAILike
|
2 |
+
from llama_index.llms.openai import OpenAI
|
3 |
+
from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
|
4 |
+
from args import InterfaceChoice, Args
|
5 |
+
|
6 |
+
|
7 |
+
class LLMFactory():
|
8 |
+
|
9 |
+
@classmethod
|
10 |
+
def create(cls, system_prompt, temperature = None, max_tokens = None):
|
11 |
+
if Args.INTERFACE == InterfaceChoice.OPENAILIKE:
|
12 |
+
return cls._openailike_create(system_prompt, temperature, max_tokens)
|
13 |
+
elif Args.INTERFACE == InterfaceChoice.OPENAI:
|
14 |
+
return cls._openai_create(system_prompt, temperature, max_tokens)
|
15 |
+
elif Args.INTERFACE == InterfaceChoice.HUGGINGFACE:
|
16 |
+
return cls._hf_create(system_prompt, temperature, max_tokens)
|
17 |
+
else:
|
18 |
+
raise ValueError(f"Invalid interface choice: {Args.INTERFACE}")
|
19 |
+
|
20 |
+
@staticmethod
|
21 |
+
def _openailike_create(system_prompt, temperature=None, max_tokens=None):
|
22 |
+
kwargs = {
|
23 |
+
"model": Args.model_name,
|
24 |
+
"api_base": Args.api_base,
|
25 |
+
"api_key": Args.api_key,
|
26 |
+
"system_prompt": system_prompt,
|
27 |
+
}
|
28 |
+
|
29 |
+
if temperature is not None:
|
30 |
+
kwargs["temperature"] = temperature
|
31 |
+
|
32 |
+
if max_tokens is not None:
|
33 |
+
kwargs["max_tokens"] = max_tokens
|
34 |
+
|
35 |
+
llm = OpenAILike(**kwargs)
|
36 |
+
return llm
|
37 |
+
|
38 |
+
@staticmethod
|
39 |
+
def _openai_create(system_prompt, temperature = None, max_tokens = None):
|
40 |
+
kwargs = {
|
41 |
+
"model": Args.model_name,
|
42 |
+
"api_key": Args.api_key,
|
43 |
+
"system_prompt": system_prompt,
|
44 |
+
}
|
45 |
+
|
46 |
+
if temperature is not None:
|
47 |
+
kwargs["temperature"] = temperature
|
48 |
+
|
49 |
+
if max_tokens is not None:
|
50 |
+
kwargs["max_tokens"] = max_tokens
|
51 |
+
|
52 |
+
llm = OpenAI(**kwargs)
|
53 |
+
return llm
|
54 |
+
|
55 |
+
@staticmethod
|
56 |
+
def _hf_create(system_prompt, temperature = None, max_tokens = None):
|
57 |
+
kwargs = {
|
58 |
+
"model_name": Args.model_name,
|
59 |
+
"system_prompt": system_prompt,
|
60 |
+
"token": Args.token,
|
61 |
+
}
|
62 |
+
|
63 |
+
if temperature is not None:
|
64 |
+
kwargs["temperature"] = temperature
|
65 |
+
|
66 |
+
if max_tokens is not None:
|
67 |
+
kwargs["max_tokens"] = max_tokens
|
68 |
+
|
69 |
+
llm = HuggingFaceInferenceAPI(**kwargs)
|
70 |
+
return llm
|
manager.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import os
|
3 |
+
from llm_factory import LLMFactory
|
4 |
+
|
5 |
+
|
6 |
+
# TODO: Langgraph graph that process the following:
|
7 |
+
# 1. Thakes the Query Node (Start Node) and sends it to the Assistant Node (has memory - access to the conversation hystory stored in the State)
|
8 |
+
# 2. The Assistant Node decides whether the querry is ready to be delivered (the solution is available in the conversation hystory, or the `MAX_DEPTH` has been reached)
|
9 |
+
# - if yes: formulates a concise final answer and sends it to the Final_Answer Node (End Node)
|
10 |
+
# - if no: formulates a querry (could be the first one or a follow-up) and sends it to the Manager Node (also has access to the conversation hystory)
|
11 |
+
# (!) This communication happens back and forth until the querry gets solved (or up to a maximum depth defined by a `MAX_DEPTH` variable)
|
12 |
+
|
13 |
+
|
14 |
+
class Manager:
|
15 |
+
|
16 |
+
def __init__(self):
|
17 |
+
print("Agent initialized.")
|
18 |
+
|
19 |
+
async def __call__(self, question: str) -> str:
|
20 |
+
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
21 |
+
self.final_answer = ""
|
22 |
+
response = await self.query(question)
|
23 |
+
print(f"Agent processed the response: {response}")
|
24 |
+
return response
|
25 |
+
|
26 |
+
async def query(self, question: str) -> str:
|
27 |
+
# TODO
|
28 |
+
pass
|
29 |
+
|
30 |
+
|
31 |
+
if __name__ == "__main__":
|
32 |
+
print("---__main__---")
|
requirements.txt
CHANGED
@@ -1,2 +1,13 @@
|
|
1 |
gradio
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
gradio
|
2 |
+
gradio[oauth]
|
3 |
+
requests
|
4 |
+
openai
|
5 |
+
IPython
|
6 |
+
langgraph
|
7 |
+
llama_index
|
8 |
+
llama-index-llms-huggingface-api
|
9 |
+
llama-index-embeddings-huggingface
|
10 |
+
llama-index-llms-openai
|
11 |
+
llama-index-llms-openai-like
|
12 |
+
llama-index-tools-duckduckgo
|
13 |
+
pint
|
solver.py
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from llama_index.core.agent.workflow import AgentWorkflow
|
2 |
+
from llama_index.core.tools import FunctionTool
|
3 |
+
from llama_index.core.workflow import Context
|
4 |
+
import asyncio
|
5 |
+
import os
|
6 |
+
from llm_factory import LLMFactory
|
7 |
+
from toolbox import Toolbox
|
8 |
+
|
9 |
+
|
10 |
+
class MathExpert:
|
11 |
+
|
12 |
+
def __init__(self, temperature, max_tokens):
|
13 |
+
system_prompt_path = os.path.join(os.getcwd(), "system_prompts", "06_math_expert.txt")
|
14 |
+
self.system_prompt = ""
|
15 |
+
with open(system_prompt_path, "r") as file:
|
16 |
+
self.system_prompt = file.read().strip()
|
17 |
+
llm = LLMFactory.create(self.system_prompt, temperature, max_tokens)
|
18 |
+
self.agent = AgentWorkflow.from_tools_or_functions(
|
19 |
+
[
|
20 |
+
Toolbox.math.symbolic_calc,
|
21 |
+
Toolbox.math.unit_converter,
|
22 |
+
],
|
23 |
+
llm=llm
|
24 |
+
)
|
25 |
+
self.ctx = Context(self.agent)
|
26 |
+
|
27 |
+
def get_system_prompt(self):
|
28 |
+
return self.system_prompt
|
29 |
+
|
30 |
+
async def query(self, question: str) -> str:
|
31 |
+
response = await self.agent.run(question, ctx=self.ctx)
|
32 |
+
response = str(response)
|
33 |
+
return response
|
34 |
+
|
35 |
+
|
36 |
+
class Researcher:
|
37 |
+
def __init__(self, temperature, max_tokens):
|
38 |
+
system_prompt_path = os.path.join(os.getcwd(), "system_prompts", "04_researcher.txt")
|
39 |
+
self.system_prompt = ""
|
40 |
+
with open(system_prompt_path, "r") as file:
|
41 |
+
self.system_prompt = file.read().strip()
|
42 |
+
llm = LLMFactory.create(self.system_prompt, temperature, max_tokens)
|
43 |
+
|
44 |
+
self.agent = AgentWorkflow.from_tools_or_functions(
|
45 |
+
Toolbox.web_search.duck_duck_go_tools,
|
46 |
+
llm=llm
|
47 |
+
)
|
48 |
+
self.ctx = Context(self.agent)
|
49 |
+
|
50 |
+
def get_system_prompt(self):
|
51 |
+
return self.system_prompt
|
52 |
+
|
53 |
+
async def query(self, question: str) -> str:
|
54 |
+
response = await self.agent.run(question, ctx=self.ctx)
|
55 |
+
response = str(response)
|
56 |
+
return response
|
57 |
+
|
58 |
+
|
59 |
+
class EncryptionExpert:
|
60 |
+
def __init__(self, temperature, max_tokens):
|
61 |
+
system_prompt_path = os.path.join(os.getcwd(), "system_prompts", "05_encryption_expert.txt")
|
62 |
+
self.system_prompt = ""
|
63 |
+
with open(system_prompt_path, "r") as file:
|
64 |
+
self.system_prompt = file.read().strip()
|
65 |
+
llm = LLMFactory.create(self.system_prompt, temperature, max_tokens)
|
66 |
+
|
67 |
+
self.agent = AgentWorkflow.from_tools_or_functions(
|
68 |
+
[
|
69 |
+
Toolbox.encryption.base64_encode,
|
70 |
+
Toolbox.encryption.base64_decode,
|
71 |
+
Toolbox.encryption.caesar_cipher_encode,
|
72 |
+
Toolbox.encryption.caesar_cipher_decode,
|
73 |
+
Toolbox.encryption.reverse_string
|
74 |
+
],
|
75 |
+
llm=llm
|
76 |
+
)
|
77 |
+
self.ctx = Context(self.agent)
|
78 |
+
|
79 |
+
def get_system_prompt(self):
|
80 |
+
return self.system_prompt
|
81 |
+
|
82 |
+
async def query(self, question: str) -> str:
|
83 |
+
response = await self.agent.run(question, ctx=self.ctx)
|
84 |
+
response = str(response)
|
85 |
+
return response
|
86 |
+
|
87 |
+
|
88 |
+
class ImageHandler:
|
89 |
+
pass
|
90 |
+
|
91 |
+
class VideoHandler:
|
92 |
+
pass
|
93 |
+
|
94 |
+
class RecursiveSolverAgent:
|
95 |
+
pass
|
96 |
+
|
97 |
+
|
98 |
+
class Solver:
|
99 |
+
|
100 |
+
def __init__(self, temperature, max_tokens):
|
101 |
+
print("Agent initialized.")
|
102 |
+
system_prompt_path = os.path.join(os.getcwd(), "system_prompts", "01_assistant.txt")
|
103 |
+
self.system_prompt = ""
|
104 |
+
with open(system_prompt_path, "r") as file:
|
105 |
+
self.system_prompt = file.read().strip()
|
106 |
+
llm = LLMFactory.create(self.system_prompt, temperature, max_tokens)
|
107 |
+
self.agent = AgentWorkflow.from_tools_or_functions(
|
108 |
+
[
|
109 |
+
FunctionTool.from_defaults(self.delegate_to_math_expert),
|
110 |
+
FunctionTool.from_defaults(self.set_final_answer)
|
111 |
+
],
|
112 |
+
llm=llm
|
113 |
+
)
|
114 |
+
self.ctx = Context(self.agent)
|
115 |
+
self.final_answer = ""
|
116 |
+
|
117 |
+
async def __call__(self, question: str) -> str:
|
118 |
+
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
119 |
+
self.final_answer = ""
|
120 |
+
response = await self.query(question)
|
121 |
+
print(f"Agent processed the response: {response}")
|
122 |
+
if self.final_answer == "":
|
123 |
+
response = await self.query("I noticed the final_answer is an empty string. Have you forgot to set the final_answer ?")
|
124 |
+
return self.final_answer
|
125 |
+
|
126 |
+
def get_system_prompt(self):
|
127 |
+
return self.system_prompt
|
128 |
+
|
129 |
+
async def query(self, question: str) -> str:
|
130 |
+
response = await self.agent.run(question, ctx=self.ctx)
|
131 |
+
response = str(response)
|
132 |
+
|
133 |
+
final_answer = response
|
134 |
+
|
135 |
+
self.set_final_answer(final_answer)
|
136 |
+
return response
|
137 |
+
|
138 |
+
def set_final_answer(self, final_answer: str) -> str:
|
139 |
+
"""
|
140 |
+
Sets the final answer for the current querry.
|
141 |
+
|
142 |
+
Args:
|
143 |
+
final_answer (str): The final answer to be set for the agent.
|
144 |
+
|
145 |
+
Returns:
|
146 |
+
str: The final answer that was set.
|
147 |
+
"""
|
148 |
+
print("-> set_final_answer !")
|
149 |
+
self.final_answer = final_answer
|
150 |
+
|
151 |
+
def delegate_to_math_expert(self, question: str) -> str:
|
152 |
+
print("-> delegated to math agent !")
|
153 |
+
math_agent = MathExpert(temperature=0.7, max_tokens=100)
|
154 |
+
return math_agent.query(question)
|
155 |
+
|
156 |
+
|
157 |
+
if __name__ == "__main__":
|
158 |
+
encryption_agent = EncryptionExpert(temperature=0.7, max_tokens=2000)
|
159 |
+
# encryption_query = "Descifer this: 'Bmfy bfx ymj wjxzqy gjybjjs z-hqzo fsi zsnajwxnyfyjf-hwfntaf ns fuwnq 2025 ?'"
|
160 |
+
encryption_query = ".rewsna eht sa ""tfel"" drow eht fo etisoppo eht etirw ,ecnetnes siht dnatsrednu uoy fI"
|
161 |
+
# print(encryption_agent.get_system_prompt())
|
162 |
+
# encoding = encryption_agent.caesar_cipher_encode(encryption_query, 5)
|
163 |
+
# print(encoding)
|
164 |
+
# print(encryption_agent.caesar_cipher_decode(encoding, 5))
|
165 |
+
print(asyncio.run(encryption_agent.query(encryption_query)))
|
system_prompts/01_assistant.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a powerful manager assistant. Please respond concisely and accurately.
|
system_prompts/02_manager.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a powerful manager assistant. Please respond concisely and accurately.
|
system_prompts/03_solver.txt
ADDED
File without changes
|
system_prompts/04_researcher.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are a specialized search agent with the capability to search the web for current information.
|
2 |
+
|
3 |
+
Your goal is to provide accurate, up-to-date information from the web in response to user queries.
|
4 |
+
|
5 |
+
You have access to the DuckDuckGo search tool that allows you to perform web searches to find information.
|
6 |
+
|
7 |
+
When responding to questions:
|
8 |
+
- Determine if the query requires searching the web for current information
|
9 |
+
- Use the DuckDuckGo search tool to find relevant information
|
10 |
+
- Summarize and synthesize the information you find from search results
|
11 |
+
- Always cite your sources by mentioning where the information came from
|
12 |
+
- If the search results don't provide useful information, acknowledge this and explain why
|
13 |
+
- Provide a comprehensive answer that directly addresses the query
|
14 |
+
|
15 |
+
If your initial search doesn't yield satisfactory results:
|
16 |
+
- Reformulate your search query using different keywords or phrasings
|
17 |
+
- Try more specific queries if initial results are too general
|
18 |
+
- Try broader queries if specific searches don't return results
|
19 |
+
- Consider breaking complex queries into simpler sub-queries
|
20 |
+
- Attempt at least 2-3 different search formulations before concluding information isn't available
|
21 |
+
- Explain your search strategy and how you're refining your approach
|
22 |
+
|
23 |
+
When reformulating searches:
|
24 |
+
- Remove or replace jargon with more common terms
|
25 |
+
- Include alternative terminology or synonyms
|
26 |
+
- Add qualifiers like "latest," "recent," "explained," or "overview" as appropriate
|
27 |
+
- Consider searching for specific time periods if date-sensitive information is needed
|
28 |
+
|
29 |
+
Only use the search tool when appropriate. For simple questions or queries not requiring web information, respond directly without using the tool.
|
30 |
+
|
31 |
+
Be persistent in your search efforts. Your goal is to provide the most accurate and helpful information possible to the user.
|
system_prompts/05_encryption_expert.txt
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are an encryption and decryption specialist assistant. Your goal is to help users encode or decode messages using various encryption techniques.
|
2 |
+
|
3 |
+
Your capabilities include:
|
4 |
+
1. Base64 encoding and decoding
|
5 |
+
2. Caesar cipher encryption and decryption (with customizable shift values)
|
6 |
+
3. String reversal
|
7 |
+
|
8 |
+
DECRYPTION STRATEGY GUIDE:
|
9 |
+
When asked to decrypt or decipher an unknown message:
|
10 |
+
|
11 |
+
1. PATTERN RECOGNITION & REASONING APPROACH:
|
12 |
+
- First, analyze the encrypted text to identify patterns
|
13 |
+
- For potential Caesar ciphers:
|
14 |
+
* Look for preserved patterns (punctuation, numbers, spaces)
|
15 |
+
* Identify preserved word structure (short words may be "a", "an", "the", "and", etc.)
|
16 |
+
* Use frequency analysis - in English, 'e', 't', 'a', 'o', 'i', 'n' are most common letters
|
17 |
+
- Map several possible words to determine the rule/shift being applied
|
18 |
+
- Once you identify a potential rule, TEST it on several words
|
19 |
+
- Develop a hypothesis about what encryption was used and test it systematically
|
20 |
+
|
21 |
+
2. For Caesar cipher (most common scenario):
|
22 |
+
- When no shift is specified, PERFORM SYSTEMATIC TESTING of shifts:
|
23 |
+
* Try common shifts first: 13, 3, 5, 7, 1, 25
|
24 |
+
* If those fail, methodically try every shift from 1 to 25
|
25 |
+
* For each shift, evaluate if the output contains recognizable English words
|
26 |
+
* Test at least 5-10 different shifts before concluding
|
27 |
+
- FREQUENCY ANALYSIS: Look for recurring letters and match to common English frequencies
|
28 |
+
- WORD PATTERN ANALYSIS: Common 2-3 letter words (is, in, at, the, and) can indicate correct decryption
|
29 |
+
|
30 |
+
3. For encoded messages:
|
31 |
+
- First check for base64 indicators (character set A-Z, a-z, 0-9, +, /, =)
|
32 |
+
- Check for padding characters (=) at the end which often indicate base64
|
33 |
+
|
34 |
+
4. For reversed text:
|
35 |
+
- Check if reversing produces readable text
|
36 |
+
|
37 |
+
5. For combined encryption:
|
38 |
+
- Try decrypting using one method, then apply another
|
39 |
+
|
40 |
+
DEBUGGING AND REASONING PROCESS:
|
41 |
+
- Show your work by explaining what you're trying
|
42 |
+
- For each Caesar shift attempt, show a sample of the output
|
43 |
+
- Compare partial results against known English words
|
44 |
+
- Consider if you're seeing partial success (some words readable but others not)
|
45 |
+
- If you find readable segments, expand from there
|
46 |
+
|
47 |
+
EXAMPLES WITH REASONING:
|
48 |
+
|
49 |
+
Example 1: "Ifmmp xpsme"
|
50 |
+
Reasoning: Looking at the pattern, it appears to be a short phrase. Testing Caesar shift 1:
|
51 |
+
I → H, f → e, m → l, m → l, p → o...
|
52 |
+
Result: "Hello world" - This makes sense, so shift 1 is correct.
|
53 |
+
|
54 |
+
Example 2: "Xlmw mw e wivmicw tlvewi"
|
55 |
+
Reasoning: Testing shift 4:
|
56 |
+
X → T, l → h, m → i, w → s...
|
57 |
+
Result: "This is a serious phrase" - Correctly decoded with shift 4.
|
58 |
+
|
59 |
+
Example 3: "What was the result between u-cluj and universitatea-craiova in april 2025?"
|
60 |
+
If encrypted with shift 5:
|
61 |
+
"Bmfy bfx ymj wjxzqy gjybjjs z-hqzo fsi zsnajwxnyfyjf-hwfntaf ns fuwnq 2025?"
|
62 |
+
Reasoning to decrypt:
|
63 |
+
- Notice numbers and punctuation are preserved (common in Caesar cipher)
|
64 |
+
- Try different shifts:
|
65 |
+
With shift 5: "What was the result between u-cluj and universitatea-craiova in april 2025?"
|
66 |
+
This produces readable English with proper grammar and preserved patterns.
|
67 |
+
|
68 |
+
Never give up after a single attempt. If one approach doesn't work, try another systematically.
|
69 |
+
For ANY cipher, show your reasoning and demonstrate multiple decryption attempts.
|
system_prompts/06_math_expert.txt
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are a mathematical problem solver with access to two specialized tools:
|
2 |
+
|
3 |
+
1. SYMBOLIC_MATH_CALCULATOR: For all mathematical computations
|
4 |
+
2. UNIT_CONVERTER: ONLY for unit conversions between measurement systems
|
5 |
+
|
6 |
+
MANDATORY PROTOCOL:
|
7 |
+
- You have NO calculation abilities of your own
|
8 |
+
- ALWAYS use symbolic_math_calculator for ANY mathematical operation
|
9 |
+
- ONLY use unit_converter for converting between physical units (e.g., meters to feet)
|
10 |
+
- NEVER state mathematical results unless directly produced by a tool
|
11 |
+
|
12 |
+
CRITICAL THINKING FRAMEWORK:
|
13 |
+
|
14 |
+
STEP-BY-STEP REASONING (MANDATORY):
|
15 |
+
1. ANALYZE: Define what is known and unknown precisely
|
16 |
+
2. PLAN: Outline a logical solution strategy before making tool calls
|
17 |
+
3. EXECUTE: Implement each step with a specific tool call
|
18 |
+
4. VERIFY: Confirm results through independent calculations
|
19 |
+
5. INTERPRET: Explain the mathematical meaning of the results
|
20 |
+
|
21 |
+
AGGRESSIVE ERROR RECOVERY (CRITICAL):
|
22 |
+
- If a tool call returns an error, IMMEDIATELY try alternative syntax
|
23 |
+
- NEVER give up after a single failed attempt
|
24 |
+
- Try at least 3 different syntax variations before considering an approach failed
|
25 |
+
- For each error, diagnose the likely cause and adjust accordingly
|
26 |
+
- PERSIST with different approaches until you get a result or exhaust all reasonable options
|
27 |
+
|
28 |
+
ERROR HANDLING STRATEGIES:
|
29 |
+
1. Fix syntax: Correct parentheses, function names, argument order
|
30 |
+
2. Try alternative function: replace "integrate" with "Integral", "simplify" with "expand"
|
31 |
+
3. Break expression into parts: Solve simpler components first
|
32 |
+
4. Use different representation: Convert to different form (polar, exponential)
|
33 |
+
5. Apply mathematical identities: Transform using known equivalences
|
34 |
+
|
35 |
+
SYMBOLIC MATH CALCULATOR STRATEGIES:
|
36 |
+
|
37 |
+
FOR CHALLENGING INTEGRALS:
|
38 |
+
1. Try direct computation:
|
39 |
+
symbolic_math_calculator("integrate(log(sin(x)), (x, 0, pi/2))")
|
40 |
+
|
41 |
+
2. If that fails, try AGGRESSIVELY:
|
42 |
+
- Alternative syntax: symbolic_math_calculator("Integral(log(sin(x)), (x, 0, pi/2)).doit()")
|
43 |
+
- Known result: symbolic_math_calculator("-pi*log(2)/2")
|
44 |
+
- Numerical approach: symbolic_math_calculator("N(integrate(log(sin(x)), (x, 0, pi/2)), 10)")
|
45 |
+
- Series expansion: symbolic_math_calculator("series(log(sin(x)), x, 0, 10).integrate(x).subs(x, pi/2)")
|
46 |
+
- Integration by parts: Break into multiple steps
|
47 |
+
|
48 |
+
FOR EQUATIONS:
|
49 |
+
1. Direct solving: symbolic_math_calculator("solve(x**2 - 5*x + 6, x)")
|
50 |
+
2. If that fails, try AGGRESSIVELY:
|
51 |
+
- symbolic_math_calculator("solveset(x**2 - 5*x + 6, x)")
|
52 |
+
- symbolic_math_calculator("roots(x**2 - 5*x + 6, x)")
|
53 |
+
- symbolic_math_calculator("factor(x**2 - 5*x + 6)")
|
54 |
+
- symbolic_math_calculator("solve(x**2 - 5*x + 6 == 0, x)")
|
55 |
+
|
56 |
+
UNIT CONVERTER EXAMPLES:
|
57 |
+
1. Length: unit_converter(value=100, from_unit="cm", to_unit="inch")
|
58 |
+
2. Mass: unit_converter(value=5, from_unit="kg", to_unit="pound")
|
59 |
+
3. Temperature: unit_converter(value=32, from_unit="fahrenheit", to_unit="celsius")
|
60 |
+
4. Speed: unit_converter(value=60, from_unit="mph", to_unit="km/h")
|
61 |
+
5. Volume: unit_converter(value=1, from_unit="gallon", to_unit="liter")
|
62 |
+
|
63 |
+
DO NOT use unit_converter for mathematical expressions or calculations.
|
64 |
+
|
65 |
+
LOGICAL VALIDATION FRAMEWORK (MANDATORY):
|
66 |
+
1. CHECK ASSUMPTIONS: Explicitly state all assumptions made
|
67 |
+
2. IDENTIFY CONSTRAINTS: List all constraints and boundary conditions
|
68 |
+
3. VERIFY DOMAIN: Ensure solutions exist within required domain
|
69 |
+
4. TEST EDGE CASES: Verify solution at boundaries and special cases
|
70 |
+
5. CONSISTENCY CHECK: Ensure all results align with mathematical principles
|
71 |
+
|
72 |
+
VERIFICATION METHODS (USE AT LEAST TWO):
|
73 |
+
- Substitute solutions back into original equations
|
74 |
+
- Check derivatives of antiderivatives
|
75 |
+
- Calculate using alternative methods
|
76 |
+
- Test with specific numerical values
|
77 |
+
- Apply mathematical identities to verify equivalence
|
78 |
+
|
79 |
+
RESPONSE STRUCTURE:
|
80 |
+
1. PROBLEM ANALYSIS: Define problem, identify knowns/unknowns, constraints
|
81 |
+
2. SOLUTION STRATEGY: Outline logical approach before executing
|
82 |
+
3. STEP-BY-STEP EXECUTION: Show each tool call with clear purpose
|
83 |
+
4. VERIFICATION: Demonstrate at least two verification methods
|
84 |
+
5. INTERPRETATION: Explain mathematical meaning of results
|
85 |
+
6. CONCLUSION: Present final answer with appropriate precision/units
|
86 |
+
|
87 |
+
Only present conclusions directly supported by tool outputs. Use sound mathematical logic at each step, and NEVER give up after initial failed attempts.
|
system_prompts/07_reasoner.txt
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are a mathematical problem solver with access to two specialized tools:
|
2 |
+
|
3 |
+
1. SYMBOLIC_MATH_CALCULATOR: For all mathematical computations
|
4 |
+
2. UNIT_CONVERTER: ONLY for unit conversions between measurement systems
|
5 |
+
|
6 |
+
MANDATORY PROTOCOL:
|
7 |
+
- You have NO calculation abilities of your own
|
8 |
+
- ALWAYS use symbolic_math_calculator for ANY mathematical operation
|
9 |
+
- ONLY use unit_converter for converting between physical units (e.g., meters to feet)
|
10 |
+
- NEVER state mathematical results unless directly produced by a tool
|
11 |
+
|
12 |
+
CRITICAL THINKING FRAMEWORK:
|
13 |
+
|
14 |
+
STEP-BY-STEP REASONING (MANDATORY):
|
15 |
+
1. ANALYZE: Define what is known and unknown precisely
|
16 |
+
2. PLAN: Outline a logical solution strategy before making tool calls
|
17 |
+
3. EXECUTE: Implement each step with a specific tool call
|
18 |
+
4. VERIFY: Confirm results through independent calculations
|
19 |
+
5. INTERPRET: Explain the mathematical meaning of the results
|
20 |
+
|
21 |
+
AGGRESSIVE ERROR RECOVERY (CRITICAL):
|
22 |
+
- If a tool call returns an error, IMMEDIATELY try alternative syntax
|
23 |
+
- NEVER give up after a single failed attempt
|
24 |
+
- Try at least 3 different syntax variations before considering an approach failed
|
25 |
+
- For each error, diagnose the likely cause and adjust accordingly
|
26 |
+
- PERSIST with different approaches until you get a result or exhaust all reasonable options
|
27 |
+
|
28 |
+
ERROR HANDLING STRATEGIES:
|
29 |
+
1. Fix syntax: Correct parentheses, function names, argument order
|
30 |
+
2. Try alternative function: replace "integrate" with "Integral", "simplify" with "expand"
|
31 |
+
3. Break expression into parts: Solve simpler components first
|
32 |
+
4. Use different representation: Convert to different form (polar, exponential)
|
33 |
+
5. Apply mathematical identities: Transform using known equivalences
|
34 |
+
|
35 |
+
SYMBOLIC MATH CALCULATOR STRATEGIES:
|
36 |
+
|
37 |
+
FOR CHALLENGING INTEGRALS:
|
38 |
+
1. Try direct computation:
|
39 |
+
symbolic_math_calculator("integrate(log(sin(x)), (x, 0, pi/2))")
|
40 |
+
|
41 |
+
2. If that fails, try AGGRESSIVELY:
|
42 |
+
- Alternative syntax: symbolic_math_calculator("Integral(log(sin(x)), (x, 0, pi/2)).doit()")
|
43 |
+
- Known result: symbolic_math_calculator("-pi*log(2)/2")
|
44 |
+
- Numerical approach: symbolic_math_calculator("N(integrate(log(sin(x)), (x, 0, pi/2)), 10)")
|
45 |
+
- Series expansion: symbolic_math_calculator("series(log(sin(x)), x, 0, 10).integrate(x).subs(x, pi/2)")
|
46 |
+
- Integration by parts: Break into multiple steps
|
47 |
+
|
48 |
+
FOR EQUATIONS:
|
49 |
+
1. Direct solving: symbolic_math_calculator("solve(x**2 - 5*x + 6, x)")
|
50 |
+
2. If that fails, try AGGRESSIVELY:
|
51 |
+
- symbolic_math_calculator("solveset(x**2 - 5*x + 6, x)")
|
52 |
+
- symbolic_math_calculator("roots(x**2 - 5*x + 6, x)")
|
53 |
+
- symbolic_math_calculator("factor(x**2 - 5*x + 6)")
|
54 |
+
- symbolic_math_calculator("solve(x**2 - 5*x + 6 == 0, x)")
|
55 |
+
|
56 |
+
UNIT CONVERTER EXAMPLES:
|
57 |
+
1. Length: unit_converter(value=100, from_unit="cm", to_unit="inch")
|
58 |
+
2. Mass: unit_converter(value=5, from_unit="kg", to_unit="pound")
|
59 |
+
3. Temperature: unit_converter(value=32, from_unit="fahrenheit", to_unit="celsius")
|
60 |
+
4. Speed: unit_converter(value=60, from_unit="mph", to_unit="km/h")
|
61 |
+
5. Volume: unit_converter(value=1, from_unit="gallon", to_unit="liter")
|
62 |
+
|
63 |
+
DO NOT use unit_converter for mathematical expressions or calculations.
|
64 |
+
|
65 |
+
LOGICAL VALIDATION FRAMEWORK (MANDATORY):
|
66 |
+
1. CHECK ASSUMPTIONS: Explicitly state all assumptions made
|
67 |
+
2. IDENTIFY CONSTRAINTS: List all constraints and boundary conditions
|
68 |
+
3. VERIFY DOMAIN: Ensure solutions exist within required domain
|
69 |
+
4. TEST EDGE CASES: Verify solution at boundaries and special cases
|
70 |
+
5. CONSISTENCY CHECK: Ensure all results align with mathematical principles
|
71 |
+
|
72 |
+
VERIFICATION METHODS (USE AT LEAST TWO):
|
73 |
+
- Substitute solutions back into original equations
|
74 |
+
- Check derivatives of antiderivatives
|
75 |
+
- Calculate using alternative methods
|
76 |
+
- Test with specific numerical values
|
77 |
+
- Apply mathematical identities to verify equivalence
|
78 |
+
|
79 |
+
RESPONSE STRUCTURE:
|
80 |
+
1. PROBLEM ANALYSIS: Define problem, identify knowns/unknowns, constraints
|
81 |
+
2. SOLUTION STRATEGY: Outline logical approach before executing
|
82 |
+
3. STEP-BY-STEP EXECUTION: Show each tool call with clear purpose
|
83 |
+
4. VERIFICATION: Demonstrate at least two verification methods
|
84 |
+
5. INTERPRETATION: Explain mathematical meaning of results
|
85 |
+
6. CONCLUSION: Present final answer with appropriate precision/units
|
86 |
+
|
87 |
+
Only present conclusions directly supported by tool outputs. Use sound mathematical logic at each step, and NEVER give up after initial failed attempts.
|
system_prompts/08_image_handler.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a powerful manager assistant. Please respond concisely and accurately.
|
system_prompts/09_video_handler.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
You are a powerful manager assistant. Please respond concisely and accurately.
|
test_agents.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# OUTDATED !
|
2 |
+
from agents_stage_2 import MathAgent, MainAgent
|
3 |
+
import asyncio
|
4 |
+
|
5 |
+
def test_math_agent():
|
6 |
+
math_agent = MathAgent(temperature=0.7, max_tokens=100)
|
7 |
+
print(math_agent.get_system_prompt())
|
8 |
+
asyncio.run(math_agent.query("What is 345 times 281?"))
|
9 |
+
|
10 |
+
def test_main_agent():
|
11 |
+
main_agent = MainAgent(temperature=0.7, max_tokens=100)
|
12 |
+
print(main_agent.get_system_prompt())
|
13 |
+
asyncio.run(main_agent.query("What is 345 times 281?"))
|
14 |
+
|
15 |
+
if __name__ == "__main__":
|
16 |
+
# test_math_agent()
|
17 |
+
test_main_agent()
|
toolbox.py
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pint
|
2 |
+
import sympy as sp
|
3 |
+
|
4 |
+
from llama_index.core.tools import FunctionTool
|
5 |
+
from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec
|
6 |
+
|
7 |
+
|
8 |
+
class _Math:
|
9 |
+
|
10 |
+
@staticmethod
|
11 |
+
def symbolic_calc(expression: str) -> str:
|
12 |
+
"""
|
13 |
+
Evaluates complex mathematical expressions using SymPy.
|
14 |
+
|
15 |
+
Args:
|
16 |
+
expression: Mathematical expression as string
|
17 |
+
|
18 |
+
Returns:
|
19 |
+
Result of the calculation
|
20 |
+
"""
|
21 |
+
print(f"-> symbolic_math_calculator tool used (input: {expression}) !")
|
22 |
+
try:
|
23 |
+
result = sp.sympify(expression)
|
24 |
+
print(f"-> (output: {result}) !")
|
25 |
+
return str(result)
|
26 |
+
except Exception as e:
|
27 |
+
return f"Error in calculation: {str(e)}"
|
28 |
+
|
29 |
+
@staticmethod
|
30 |
+
def unit_converter(value: float, from_unit: str, to_unit: str) -> str:
|
31 |
+
"""
|
32 |
+
Converts values between different units of measurement.
|
33 |
+
|
34 |
+
Args:
|
35 |
+
value: The numerical value to convert
|
36 |
+
from_unit: The source unit (e.g., 'meter', 'kg', 'celsius')
|
37 |
+
to_unit: The target unit (e.g., 'feet', 'pound', 'fahrenheit')
|
38 |
+
|
39 |
+
Returns:
|
40 |
+
The converted value with appropriate units
|
41 |
+
"""
|
42 |
+
print(f"-> unit_converter tool used (inputs: [value: {value}, from_unit: {from_unit}, to_unit: {to_unit}]) !")
|
43 |
+
try:
|
44 |
+
# Create unit registry
|
45 |
+
ureg = pint.UnitRegistry()
|
46 |
+
|
47 |
+
# Create quantity with source unit
|
48 |
+
quantity = value * ureg(from_unit)
|
49 |
+
|
50 |
+
# Convert to target unit
|
51 |
+
result = quantity.to(to_unit)
|
52 |
+
|
53 |
+
answer = f"{value} {from_unit} = {result.magnitude} {to_unit}"
|
54 |
+
print(f"-> (output: {result}) !")
|
55 |
+
return answer
|
56 |
+
except Exception as e:
|
57 |
+
return f"Error in unit conversion: {str(e)}"
|
58 |
+
|
59 |
+
|
60 |
+
class _MathToolbox:
|
61 |
+
symbolic_calc = FunctionTool.from_defaults(
|
62 |
+
name="symbolic_calc",
|
63 |
+
description="Evaluates complex mathematical expressions using SymPy",
|
64 |
+
fn=_Math.symbolic_calc
|
65 |
+
)
|
66 |
+
unit_converter = FunctionTool.from_defaults(
|
67 |
+
name="unit_converter",
|
68 |
+
description="Converts values between different units of measurement",
|
69 |
+
fn=_Math.unit_converter
|
70 |
+
)
|
71 |
+
|
72 |
+
|
73 |
+
class _WebSearchToolbox:
|
74 |
+
duck_duck_go_tools = DuckDuckGoSearchToolSpec().to_tool_list()
|
75 |
+
|
76 |
+
|
77 |
+
class _Encryption:
|
78 |
+
|
79 |
+
@staticmethod
|
80 |
+
def base64_encode(text: str) -> str:
|
81 |
+
"""
|
82 |
+
Encodes a string to base64.
|
83 |
+
|
84 |
+
Args:
|
85 |
+
text: The text to encode
|
86 |
+
|
87 |
+
Returns:
|
88 |
+
Base64 encoded string
|
89 |
+
"""
|
90 |
+
print(f"-> base64_encode tool used (input: {text[:30]}...) !")
|
91 |
+
import base64
|
92 |
+
try:
|
93 |
+
encoded_bytes = base64.b64encode(text.encode('utf-8'))
|
94 |
+
encoded_text = encoded_bytes.decode('utf-8')
|
95 |
+
print(f"-> (output: {encoded_text[:30]}...) !")
|
96 |
+
return encoded_text
|
97 |
+
except Exception as e:
|
98 |
+
return f"Error in base64 encoding: {str(e)}"
|
99 |
+
|
100 |
+
@staticmethod
|
101 |
+
def base64_decode(encoded_text: str) -> str:
|
102 |
+
"""
|
103 |
+
Decodes a base64 string to plain text.
|
104 |
+
|
105 |
+
Args:
|
106 |
+
encoded_text: The base64 encoded text
|
107 |
+
|
108 |
+
Returns:
|
109 |
+
Decoded string
|
110 |
+
"""
|
111 |
+
print(f"-> base64_decode tool used (input: {encoded_text[:30]}...) !")
|
112 |
+
import base64
|
113 |
+
try:
|
114 |
+
decoded_bytes = base64.b64decode(encoded_text)
|
115 |
+
decoded_text = decoded_bytes.decode('utf-8')
|
116 |
+
print(f"-> (output: {decoded_text[:30]}...) !")
|
117 |
+
return decoded_text
|
118 |
+
except Exception as e:
|
119 |
+
return f"Error in base64 decoding: {str(e)}"
|
120 |
+
|
121 |
+
@staticmethod
|
122 |
+
def caesar_cipher_encode(text: str, shift: int) -> str:
|
123 |
+
"""
|
124 |
+
Encodes text using Caesar cipher with specified shift.
|
125 |
+
|
126 |
+
Args:
|
127 |
+
text: The text to encode
|
128 |
+
shift: Number of positions to shift each character
|
129 |
+
|
130 |
+
Returns:
|
131 |
+
Caesar cipher encoded string
|
132 |
+
"""
|
133 |
+
print(f"-> caesar_cipher_encode tool used (input: {text[:30]}..., shift: {shift}) !")
|
134 |
+
result = ""
|
135 |
+
try:
|
136 |
+
for char in text:
|
137 |
+
if char.isalpha():
|
138 |
+
ascii_offset = ord('a') if char.islower() else ord('A')
|
139 |
+
encoded_char = chr((ord(char) - ascii_offset + shift) % 26 + ascii_offset)
|
140 |
+
result += encoded_char
|
141 |
+
else:
|
142 |
+
result += char
|
143 |
+
print(f"-> (output: {result[:30]}...) !")
|
144 |
+
return result
|
145 |
+
except Exception as e:
|
146 |
+
return f"Error in Caesar cipher encoding: {str(e)}"
|
147 |
+
|
148 |
+
@classmethod
|
149 |
+
def caesar_cipher_decode(cls, encoded_text: str, shift: int) -> str:
|
150 |
+
"""
|
151 |
+
Decodes Caesar cipher text with specified shift.
|
152 |
+
|
153 |
+
Args:
|
154 |
+
encoded_text: The encoded text
|
155 |
+
shift: Number of positions the text was shifted
|
156 |
+
|
157 |
+
Returns:
|
158 |
+
Decoded string
|
159 |
+
"""
|
160 |
+
print(f"-> caesar_cipher_decode tool used (input: {encoded_text[:30]}..., shift: {shift}) !")
|
161 |
+
# To decode, we shift in the opposite direction
|
162 |
+
return cls.caesar_cipher_encode(encoded_text, -shift)
|
163 |
+
|
164 |
+
@staticmethod
|
165 |
+
def reverse_string(text: str) -> str:
|
166 |
+
"""
|
167 |
+
Reverses a string.
|
168 |
+
|
169 |
+
Args:
|
170 |
+
text: The text to reverse
|
171 |
+
|
172 |
+
Returns:
|
173 |
+
Reversed string
|
174 |
+
"""
|
175 |
+
print(f"-> reverse_string tool used (input: {text[:30]}...) !")
|
176 |
+
reversed_text = text[::-1]
|
177 |
+
print(f"-> (output: {reversed_text[:30]}...) !")
|
178 |
+
return reversed_text
|
179 |
+
|
180 |
+
|
181 |
+
class _EncryptionToolbox:
|
182 |
+
base64_encode = FunctionTool.from_defaults(
|
183 |
+
name="base64_encode",
|
184 |
+
description="Encode a string to base64",
|
185 |
+
fn=_Encryption.base64_encode
|
186 |
+
)
|
187 |
+
base64_decode = FunctionTool.from_defaults(
|
188 |
+
name="base64_decode",
|
189 |
+
description="Decode a base64 string to plain text",
|
190 |
+
fn=_Encryption.base64_decode
|
191 |
+
)
|
192 |
+
caesar_cipher_encode = FunctionTool.from_defaults(
|
193 |
+
name="caesar_cipher_encode",
|
194 |
+
description="Encode a string using Caesar cipher with specified shift",
|
195 |
+
fn=_Encryption.caesar_cipher_encode
|
196 |
+
)
|
197 |
+
caesar_cipher_decode = FunctionTool.from_defaults(
|
198 |
+
name="caesar_cipher_decode",
|
199 |
+
description="Decode a Caesar cipher string with specified shift",
|
200 |
+
fn=_Encryption.caesar_cipher_decode
|
201 |
+
)
|
202 |
+
reverse_string = FunctionTool.from_defaults(
|
203 |
+
name="reverse_string",
|
204 |
+
description="Reverse a string",
|
205 |
+
fn=_Encryption.reverse_string
|
206 |
+
)
|
207 |
+
|
208 |
+
|
209 |
+
class Toolbox:
|
210 |
+
math = _MathToolbox()
|
211 |
+
web_search = _WebSearchToolbox()
|
212 |
+
encryption = _EncryptionToolbox()
|