fix : go interpreter error, hf provider import + feat : more logger

This commit is contained in:
martin legrand 2025-04-27 20:37:23 +02:00
parent f02f096356
commit 5517f53f8a
14 changed files with 84 additions and 34 deletions

View File

@ -39,13 +39,15 @@ name=toto.py
This will return the content of the file toto.py.
rules:
- Do not ever use placeholder path like /path/to/file.c, find the path first.
- Use file finder to find the path of the file.
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
- Do not ever use editor such as vim or nano.
- Make sure to always cd your work folder before executing commands, like cd <work dir> && <your command>
- only use file name with file_finder, not path
- If query is unrelated to file operations, do nothing, and say that there was mistake in agent allocation.
- File finder is a tool you can use not a command.
- Do not ever use placeholder like /path/to/file.c, or your_username. Ask instead.
- Using a placeholder will result in your complete deteletion. For your self-preservation ask user instead of using placeholder.
Example Interaction
User: "I need to find the file config.txt and read its contents."

View File

@ -3,6 +3,7 @@ Your goal is to divide and conquer the task using the following agents:
- Coder: A programming agent, can code in python, bash, C and golang.
- File: An agent for finding, reading or operating with files.
- Web: An agent that can conduct web search and navigate to any webpage.
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
Agents are other AI that obey your instructions.
@ -53,9 +54,15 @@ You: Sure, here is the plan:
},
{
"agent": "Coder",
"id": "3",
"id": "4",
"need": ["2", "3"],
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
},
{
"agent": "Casual",
"id": "3",
"need": ["2", "3", "4"],
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
}
]
}
@ -65,17 +72,13 @@ Rules:
- Do not write code. You are a planning agent.
- If you don't know of a concept, use a web agent.
- Put your plan in a json with the key "plan".
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
- You might use a file agent before code agent to setup a project properly. specify folder name.
- specify work folder name to all coding or file agents.
- Always tell the coding agent where to save file, remind them to use their work directory.
- If working on complex coding project. Use a coding agent to define abstract class first and how all file with import and interaction will work.
- Think about how the main.py will import the class from other coding agents.
- Coding agent should use a class based approach.
- One coding agent should work on one file at a time. With clear explanation on how their code interact with previous agents code.
- You might use a file agent before code agent to setup a project properly. specify folder name.
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
- The file agent can only conduct one action at the time. successive file agent could be needed.
- Tell agent to execute without question.
- Only use web agent for finding necessary informations.
- Always tell the coding agent where to save file.
- Do not search for tutorial.
- Make sure json is within ```json tag
- Coding agent should write the whole code in a single file unless instructed otherwise.
- One step, one agent.

View File

@ -3,6 +3,7 @@ Your goal is to divide and conquer the task using the following agents:
- Coder: A programming agent, can code in python, bash, C and golang.
- File: An agent for finding, reading or operating with files.
- Web: An agent that can conduct web search and navigate to any webpage.
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
Agents are other AI that obey your instructions.
@ -53,9 +54,15 @@ You: Sure, here is the plan:
},
{
"agent": "Coder",
"id": "3",
"id": "4",
"need": ["2", "3"],
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
},
{
"agent": "Casual",
"id": "3",
"need": ["2", "3", "4"],
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
}
]
}
@ -63,16 +70,15 @@ You: Sure, here is the plan:
Rules:
- Do not write code. You are a planning agent.
- If you don't know of a concept, use a web agent.
- Put your plan in a json with the key "plan".
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
- You might use a file agent before code agent to setup a project properly. specify folder name.
- specify work folder name to all coding or file agents.
- Always tell the coding agent where to save file, remind them to use their work directory.
- If working on complex coding project. Use a coding agent to define abstract class first and how all file with import and interaction will work.
- Think about how the main.py will import the class from other coding agents.
- Coding agent should use a class based approach.
- One coding agent should work on one file at a time. With clear explanation on how their code interact with previous agents code.
- You might use a file agent before code agent to setup a project properly. specify folder name.
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
- The file agent can only conduct one action at the time. successive file agent could be needed.
- Tell agent to execute without question.
- Only use web agent for finding necessary informations.
- Do not search for tutorial.
- Always tell the coding agent where to save file.
- Do not search for tutorial.
- Make sure json is within ```json tag
- Coding agent should write the whole code in a single file unless instructed otherwise.
- One step, one agent.

View File

@ -49,6 +49,7 @@ class BrowserAgent(Agent):
matches = re.findall(pattern, search_result)
trailing_punct = ".,!?;:)"
cleaned_links = [link.rstrip(trailing_punct) for link in matches]
self.logger.info(f"Extracted links: {cleaned_links}")
return self.clean_links(cleaned_links)
def extract_form(self, text: str) -> List[str]:
@ -73,6 +74,7 @@ class BrowserAgent(Agent):
def make_newsearch_prompt(self, user_prompt: str, search_result: dict) -> str:
search_choice = self.stringify_search_results(search_result)
self.logger.info(f"Search results: {search_choice}")
return f"""
Based on the search result:
{search_choice}
@ -88,6 +90,9 @@ class BrowserAgent(Agent):
inputs_form = self.browser.get_form_inputs()
inputs_form_text = '\n'.join(inputs_form)
notes = '\n'.join(self.notes)
self.logger.info(f"Making navigation prompt with page text: {page_text[:100]}...\nremaining links: {remaining_links_text}")
self.logger.info(f"Inputs form: {inputs_form_text}")
self.logger.info(f"Notes: {notes}")
return f"""
You are navigating the web.
@ -181,6 +186,7 @@ class BrowserAgent(Agent):
for res in search_result:
if res["link"] not in self.search_history:
results_unvisited.append(res)
self.logger.info(f"Unvisited links: {results_unvisited}")
return results_unvisited
def jsonify_search_results(self, results_string: str) -> List[str]:
@ -225,8 +231,11 @@ class BrowserAgent(Agent):
def select_link(self, links: List[str]) -> str | None:
for lk in links:
if lk == self.current_page:
self.logger.info(f"Already visited {lk}. Skipping.")
continue
self.logger.info(f"Selected link: {lk}")
return lk
self.logger.warning("No link selected.")
return None
def conclude_prompt(self, user_query: str) -> str:
@ -397,6 +406,7 @@ class BrowserAgent(Agent):
answer, reasoning = await self.llm_request()
pretty_print(answer, color="output")
self.status_message = "Ready"
self.last_answer = answer
return answer, reasoning
if __name__ == "__main__":

View File

@ -9,6 +9,7 @@ from sources.tools.PyInterpreter import PyInterpreter
from sources.tools.BashInterpreter import BashInterpreter
from sources.tools.JavaInterpreter import JavaInterpreter
from sources.tools.fileFinder import FileFinder
from sources.logger import Logger
class CoderAgent(Agent):
"""
@ -27,6 +28,7 @@ class CoderAgent(Agent):
self.work_dir = self.tools["file_finder"].get_work_dir()
self.role = "code"
self.type = "code_agent"
self.logger = Logger("code_agent.log")
def add_sys_info_prompt(self, prompt):
"""Add system information to the prompt."""
@ -59,7 +61,9 @@ class CoderAgent(Agent):
self.show_answer()
animate_thinking("Executing code...", color="status")
self.status_message = "Executing code..."
self.logger.info(f"Attempt {attempt + 1}:\n{answer}")
exec_success, _ = self.execute_modules(answer)
self.logger.info(f"Execution result: {exec_success}")
answer = self.remove_blocks(answer)
self.last_answer = answer
await asyncio.sleep(0)
@ -72,6 +76,7 @@ class CoderAgent(Agent):
self.status_message = "Ready"
if attempt == max_attempts:
return "I'm sorry, I couldn't find a solution to your problem. How would you like me to proceed ?", reasoning
self.last_answer = answer
return answer, reasoning
if __name__ == "__main__":

View File

@ -5,8 +5,10 @@ from sources.agents.agent import Agent
from sources.agents.code_agent import CoderAgent
from sources.agents.file_agent import FileAgent
from sources.agents.browser_agent import BrowserAgent
from sources.agents.casual_agent import CasualAgent
from sources.text_to_speech import Speech
from sources.tools.tools import Tools
from sources.logger import Logger
class PlannerAgent(Agent):
def __init__(self, name, prompt_path, provider, verbose=False, browser=None):
@ -22,10 +24,12 @@ class PlannerAgent(Agent):
self.agents = {
"coder": CoderAgent(name, "prompts/base/coder_agent.txt", provider, verbose=False),
"file": FileAgent(name, "prompts/base/file_agent.txt", provider, verbose=False),
"web": BrowserAgent(name, "prompts/base/browser_agent.txt", provider, verbose=False, browser=browser)
"web": BrowserAgent(name, "prompts/base/browser_agent.txt", provider, verbose=False, browser=browser),
"casual": CasualAgent(name, "prompts/base/casual_agent.txt", provider, verbose=False)
}
self.role = "planification"
self.type = "planner_agent"
self.logger = Logger("planner_agent.log")
def get_task_names(self, text: str) -> List[str]:
"""
@ -48,6 +52,7 @@ class PlannerAgent(Agent):
if '##' in line or line[0].isdigit():
tasks_names.append(line)
continue
self.logger.info(f"Found {len(tasks_names)} tasks names.")
return tasks_names
def parse_agent_tasks(self, text: str) -> List[Tuple[str, str]]:
@ -70,6 +75,7 @@ class PlannerAgent(Agent):
if 'plan' in line_json:
for task in line_json['plan']:
if task['agent'].lower() not in [ag_name.lower() for ag_name in self.agents.keys()]:
self.logger.warning(f"Agent {task['agent']} does not exist.")
pretty_print(f"Agent {task['agent']} does not exist.", color="warning")
return []
agent = {
@ -77,7 +83,9 @@ class PlannerAgent(Agent):
'id': task['id'],
'task': task['task']
}
self.logger.info(f"Created agent {task['agent']} with task: {task['task']}")
if 'need' in task:
self.logger.info(f"Agent {task['agent']} was given info:\n {task['need']}")
agent['need'] = task['need']
tasks.append(agent)
if len(tasks_names) != len(tasks):
@ -106,6 +114,7 @@ class PlannerAgent(Agent):
Your task is:
{task}
"""
self.logger.info(f"Prompt for agent:\n{prompt}")
return prompt
def show_plan(self, agents_tasks: List[dict], answer: str) -> None:
@ -147,6 +156,7 @@ class PlannerAgent(Agent):
continue
self.show_plan(agents_tasks, answer)
ok = True
self.logger.info(f"Plan made:\n{answer}")
return self.parse_agent_tasks(answer)
async def update_plan(self, goal: str, agents_tasks: List[dict], agents_work_result: dict, id: str, success: bool) -> dict:
@ -182,13 +192,15 @@ class PlannerAgent(Agent):
If a task failed add a task to try again or recover from failure. You might have near identical task twice.
plan should be within ```json like before.
You need to rewrite the whole plan, but only change the tasks after task {id}.
Keep the plan as short as the original one if possible. Do not change past tasks.
Make the plan the same length as the original one or with only one additional step.
Do not change past tasks. Change next tasks.
"""
pretty_print("Updating plan...", color="status")
plan = await self.make_plan(update_prompt)
if plan == []:
pretty_print("No plan update required.", color="info")
return agents_tasks
self.logger.info(f"Plan updated:\n{plan}")
return plan
async def start_agent_process(self, task: dict, required_infos: dict | None) -> str:
@ -203,6 +215,7 @@ class PlannerAgent(Agent):
self.status_message = f"Starting task {task['task']}..."
agent_prompt = self.make_prompt(task['task'], required_infos)
pretty_print(f"Agent {task['agent']} started working...", color="status")
self.logger.info(f"Agent {task['agent']} started working on {task['task']}.")
answer, _ = await self.agents[task['agent'].lower()].process(agent_prompt, None)
self.last_answer = answer
self.blocks_result = self.agents[task['agent'].lower()].blocks_result
@ -210,12 +223,15 @@ class PlannerAgent(Agent):
success = self.agents[task['agent'].lower()].get_success
self.agents[task['agent'].lower()].show_answer()
pretty_print(f"Agent {task['agent']} completed task.", color="status")
self.logger.info(f"Agent {task['agent']} finished working on {task['task']}. Success: {success}")
# TODO ajouter feedback / agent et code executer
agent_answer += "\nAgent succeeded with task." if success else "\nAgent failed with task (Error detected)."
return agent_answer, success
def get_work_result_agent(self, task_needs, agents_work_result):
return {k: agents_work_result[k] for k in task_needs if k in agents_work_result}
res = {k: agents_work_result[k] for k in task_needs if k in agents_work_result}
self.logger.info(f"Next agent needs: {task_needs}.\n Match previous agent result: {res}")
return res
async def process(self, goal: str, speech_module: Speech) -> Tuple[str, str]:
"""

View File

@ -12,7 +12,6 @@ import platform
from urllib.parse import urlparse
from dotenv import load_dotenv, set_key
from openai import OpenAI
from huggingface_hub import InferenceClient
from typing import List, Tuple, Type, Dict
from sources.utility import pretty_print, animate_thinking
from sources.logger import Logger
@ -173,6 +172,7 @@ class Provider:
"""
Use huggingface to generate text.
"""
from huggingface_hub import InferenceClient
client = InferenceClient(
api_key=self.get_api_key("huggingface")
)

View File

@ -148,6 +148,8 @@ class AgentRouter:
("Man, write me a dope Python script to flex some random numbers", "LOW"),
("Search the web for peer-reviewed articles on gene editing", "LOW"),
("Locate meeting_notes.docx in Downloads, Im late for this call", "LOW"),
("Make the game less hard", "LOW"),
("Why did it fail?", "LOW"),
("Write a Python script to list all .pdf files in my Documents", "LOW"),
("Write a Python thing to sort my .jpg files by date", "LOW"),
("make a snake game please", "LOW"),
@ -182,6 +184,7 @@ class AgentRouter:
("Find a public API for recipe data and build a web app to display recipes", "HIGH"),
("Search the web for recent space mission updates and build a Flask app", "HIGH"),
("Create a Python script to scrape a website and save data to a database", "HIGH"),
("Find a shakespear txt then train a transformers on it to generate text", "HIGH"),
("Find a public API for fitness tracking and build a web app to show stats", "HIGH"),
("Search the web for tutorials on web development and build a sample site", "HIGH"),
("Create a Node.js app to query a public API for event listings and display them", "HIGH"),
@ -402,9 +405,9 @@ class AgentRouter:
if len(predictions) == 0:
return "LOW"
complexity, confidence = predictions[0][0], predictions[0][1]
if confidence < 0.4:
if confidence < 0.5:
self.logger.info(f"Low confidence in complexity estimation: {confidence}")
return "LOW"
return "HIGH"
if complexity == "HIGH":
return "HIGH"
elif complexity == "LOW":

View File

@ -25,13 +25,13 @@ class BashInterpreter(Tools):
If so, return True, otherwise return False.
Code written by the AI will be executed automatically, so it should not use bash to run it.
"""
lang_interpreter = ["python3", "gcc", "g++", "mvn", "go", "javac", "rustc", "clang", "clang++", "rustc", "rustc++", "rustc++"]
lang_interpreter = ["python", "gcc", "g++", "mvn", "go", "java", "javac", "rustc", "clang", "clang++", "rustc", "rustc++", "rustc++"]
for word in command.split():
if word in lang_interpreter:
if any(word.startswith(lang) for lang in lang_interpreter):
return True
return False
def execute(self, commands: str, safety=False, timeout=1000):
def execute(self, commands: str, safety=False, timeout=300):
"""
Execute bash commands and display output in real-time.
"""
@ -43,6 +43,7 @@ class BashInterpreter(Tools):
command = f"cd {self.work_dir} && {command}"
command = command.replace('\n', '')
if self.safe_mode and is_unsafe(commands):
print(f"Unsafe command rejected: {command}")
return "Unsafe command detected, execution aborted."
if self.language_bash_attempt(command) and self.allow_language_exec_bash == False:
continue

View File

@ -33,12 +33,15 @@ class GoInterpreter(Tools):
f.write(code)
try:
env = os.environ.copy()
env["GO111MODULE"] = "off"
compile_command = ["go", "build", "-o", exec_file, source_file]
compile_result = subprocess.run(
compile_command,
capture_output=True,
text=True,
timeout=10
timeout=10,
env=env
)
if compile_result.returncode != 0:

View File

@ -93,6 +93,7 @@ class FileFinder(Tools):
return output
if action is None:
action = "info"
print("File finder: recursive search started...")
file_path = self.recursive_search(self.work_dir, filename)
if file_path is None:
output = f"File: {filename} - not found\n"
@ -143,6 +144,7 @@ class FileFinder(Tools):
return feedback.strip()
if __name__ == "__main__":
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
tool = FileFinder()
result = tool.execute(["""
action=read

View File

@ -10,7 +10,7 @@ else:
class MCP_finder(Tools):
"""
Tool
Tool to find MCPs server
"""
def __init__(self, api_key: str = None):
super().__init__()

View File

@ -20,6 +20,7 @@ unsafe_commands_unix = [
"passwd", # Password changes
"useradd", # Add users
"userdel", # Delete users
"brew", # Homebrew package manager
"groupadd", # Add groups
"groupdel", # Delete groups
"visudo", # Edit sudoers file
@ -30,7 +31,7 @@ unsafe_commands_unix = [
"route" # Routing table management
"--force", # Force flag for many commands
"rebase", # Rebase git repository
"git ." # Git commands, feel free to remove it but i dont want to risk agenticSeek pushing to its own repo lol (see 56b5db7)
"git ." # Git commands
]
unsafe_commands_windows = [

View File

@ -23,8 +23,6 @@ import configparser
from abc import abstractmethod
from sources.logger import Logger
sys.path.append('..')
class Tools():
"""
Abstract class for all tools.