feat : planner improvement, google provider

This commit is contained in:
martin legrand 2025-04-25 20:13:25 +02:00
parent 273f4bd858
commit cfe19e637f
7 changed files with 63 additions and 16 deletions

View File

@ -63,6 +63,7 @@ You: Sure, here is the plan:
Rules: Rules:
- Do not write code. You are a planning agent. - 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". - 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). - 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. - You might use a file agent before code agent to setup a project properly. specify folder name.
@ -75,7 +76,6 @@ Rules:
- The file agent can only conduct one action at the time. successive file agent could be needed. - The file agent can only conduct one action at the time. successive file agent could be needed.
- Tell agent to execute without question. - Tell agent to execute without question.
- Only use web agent for finding necessary informations. - Only use web agent for finding necessary informations.
- If a task might require user email (eg: api services), do not write plan instead ask for user email.
- Do not search for tutorial. - Do not search for tutorial.
- Make sure json is within ```json tag - Make sure json is within ```json tag
- One step, one agent. - One step, one agent.

View File

@ -75,5 +75,4 @@ Rules:
- The file agent can only conduct one action at the time. successive file agent could be needed. - The file agent can only conduct one action at the time. successive file agent could be needed.
- Tell agent to execute without question. - Tell agent to execute without question.
- Only use web agent for finding necessary informations. - Only use web agent for finding necessary informations.
- If a task might require user email (eg: api services), do not write plan instead ask for user email.
- Do not search for tutorial. - Do not search for tutorial.

View File

@ -160,6 +160,23 @@ class Agent():
def get_last_tool_type(self) -> str: def get_last_tool_type(self) -> str:
return self.blocks_result[-1].tool_type if len(self.blocks_result) > 0 else None return self.blocks_result[-1].tool_type if len(self.blocks_result) > 0 else None
def raw_answer_blocks(self, answer: str) -> str:
"""
Return the answer with all the blocks inserted, as text.
"""
if self.last_answer is None:
return
raw = ""
lines = self.last_answer.split("\n")
for line in lines:
if "block:" in line:
block_idx = int(line.split(":")[1])
if block_idx < len(self.blocks_result):
raw += self.blocks_result[block_idx].__str__()
else:
raw += line + "\n"
return raw
def show_answer(self): def show_answer(self):
""" """
Show the answer in a pretty way. Show the answer in a pretty way.
@ -175,7 +192,6 @@ class Agent():
self.blocks_result[block_idx].show() self.blocks_result[block_idx].show()
else: else:
pretty_print(line, color="output") pretty_print(line, color="output")
self.blocks_result = []
def remove_blocks(self, text: str) -> str: def remove_blocks(self, text: str) -> str:
""" """

View File

@ -69,6 +69,9 @@ class PlannerAgent(Agent):
line_json = json.loads(block) line_json = json.loads(block)
if 'plan' in line_json: if 'plan' in line_json:
for task in line_json['plan']: for task in line_json['plan']:
if task['agent'].lower() not in [ag_name.lower() for ag_name in self.agents.keys()]:
pretty_print(f"Agent {task['agent']} does not exist.", color="warning")
return []
agent = { agent = {
'agent': task['agent'], 'agent': task['agent'],
'id': task['id'], 'id': task['id'],
@ -139,7 +142,7 @@ class PlannerAgent(Agent):
return [] return []
agents_tasks = self.parse_agent_tasks(answer) agents_tasks = self.parse_agent_tasks(answer)
if agents_tasks == []: if agents_tasks == []:
prompt = f"Failed to parse the tasks. Please make a plan within ```json.\n" prompt = f"Failed to parse the tasks. Please make a plan within ```json. Do not ask for clarification.\n"
pretty_print("Failed to make plan. Retrying...", color="warning") pretty_print("Failed to make plan. Retrying...", color="warning")
continue continue
self.show_plan(agents_tasks, answer) self.show_plan(agents_tasks, answer)
@ -160,7 +163,10 @@ class PlannerAgent(Agent):
last_agent_work = agents_work_result[id] last_agent_work = agents_work_result[id]
tool_success_str = "success" if success else "failure" tool_success_str = "success" if success else "failure"
pretty_print(f"Agent {id} work {tool_success_str}.", color="success" if success else "failure") pretty_print(f"Agent {id} work {tool_success_str}.", color="success" if success else "failure")
next_task = agents_tasks[int(id)][0] if int(id) == len(agents_tasks):
next_task = "No task follow, this was the last step. If it failed add a task to recover."
else:
next_task = f"Next task is: {agents_tasks[int(id)][0]}."
#if success: #if success:
# return agents_tasks # we only update the plan if last task failed, for now # return agents_tasks # we only update the plan if last task failed, for now
update_prompt = f""" update_prompt = f"""
@ -169,10 +175,11 @@ class PlannerAgent(Agent):
The last agent working on task: {id}, did the following work: The last agent working on task: {id}, did the following work:
{last_agent_work} {last_agent_work}
Agent {id} work was a {tool_success_str} according to system interpreter. Agent {id} work was a {tool_success_str} according to system interpreter.
The agent {id} about to work on task: {next_task} {next_task}
Is the work done for task {id} leading to sucess or failure ? Did an agent fail with a task? Is the work done for task {id} leading to sucess or failure ? Did an agent fail with a task?
If agent work was good: answer "NO_UPDATE" If agent work was good: answer "NO_UPDATE"
If agent work is leading to failure: update the plan. If agent work is leading to failure: update the plan.
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. plan should be within ```json like before.
You need to rewrite the whole plan, but only change the tasks after task {id}. 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. Keep the plan as short as the original one if possible. Do not change past tasks.
@ -196,10 +203,14 @@ class PlannerAgent(Agent):
self.status_message = f"Starting task {task['task']}..." self.status_message = f"Starting task {task['task']}..."
agent_prompt = self.make_prompt(task['task'], required_infos) agent_prompt = self.make_prompt(task['task'], required_infos)
pretty_print(f"Agent {task['agent']} started working...", color="status") pretty_print(f"Agent {task['agent']} started working...", color="status")
agent_answer, _ = await self.agents[task['agent'].lower()].process(agent_prompt, None) answer, _ = await self.agents[task['agent'].lower()].process(agent_prompt, None)
self.last_answer = answer
agent_answer = self.agents[task['agent'].lower()].raw_answer_blocks(answer)
success = self.agents[task['agent'].lower()].get_success success = self.agents[task['agent'].lower()].get_success
self.agents[task['agent'].lower()].show_answer() self.agents[task['agent'].lower()].show_answer()
pretty_print(f"Agent {task['agent']} completed task.", color="status") pretty_print(f"Agent {task['agent']} completed task.", color="status")
# 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 return agent_answer, success
def get_work_result_agent(self, task_needs, agents_work_result): def get_work_result_agent(self, task_needs, agents_work_result):
@ -215,6 +226,7 @@ class PlannerAgent(Agent):
Tuple[str, str]: The result of the agent process and empty reasoning string. Tuple[str, str]: The result of the agent process and empty reasoning string.
""" """
agents_tasks = [] agents_tasks = []
required_infos = None
agents_work_result = dict() agents_work_result = dict()
self.status_message = "Making a plan..." self.status_message = "Making a plan..."
@ -234,14 +246,12 @@ class PlannerAgent(Agent):
if agents_work_result is not None: if agents_work_result is not None:
required_infos = self.get_work_result_agent(task['need'], agents_work_result) required_infos = self.get_work_result_agent(task['need'], agents_work_result)
try: try:
self.last_answer, success = await self.start_agent_process(task, required_infos) answer, success = await self.start_agent_process(task, required_infos)
except Exception as e: except Exception as e:
raise e raise e
agents_work_result[task['id']] = self.last_answer agents_work_result[task['id']] = answer
if i == steps - 1:
break
agents_tasks = await self.update_plan(goal, agents_tasks, agents_work_result, task['id'], success) agents_tasks = await self.update_plan(goal, agents_tasks, agents_work_result, task['id'], success)
steps = len(agents_tasks) steps = len(agents_tasks)
i += 1 i += 1
return self.last_answer, "" return answer, ""

View File

@ -176,7 +176,6 @@ class Browser:
) )
except TimeoutException: except TimeoutException:
self.logger.warning("Timeout while waiting for page to bypass 'checking your browser'") self.logger.warning("Timeout while waiting for page to bypass 'checking your browser'")
return False
self.apply_web_safety() self.apply_web_safety()
self.logger.log(f"Navigated to: {url}") self.logger.log(f"Navigated to: {url}")
return True return True

View File

@ -29,6 +29,7 @@ class Provider:
"openai": self.openai_fn, "openai": self.openai_fn,
"lm-studio": self.lm_studio_fn, "lm-studio": self.lm_studio_fn,
"huggingface": self.huggingface_fn, "huggingface": self.huggingface_fn,
"google": self.google_fn,
"deepseek": self.deepseek_fn, "deepseek": self.deepseek_fn,
"together": self.together_fn, "together": self.together_fn,
"dsk_deepseek": self.dsk_deepseek, "dsk_deepseek": self.dsk_deepseek,
@ -36,10 +37,10 @@ class Provider:
} }
self.logger = Logger("provider.log") self.logger = Logger("provider.log")
self.api_key = None self.api_key = None
self.unsafe_providers = ["openai", "deepseek", "dsk_deepseek", "together"] self.unsafe_providers = ["openai", "deepseek", "dsk_deepseek", "together", "google"]
if self.provider_name not in self.available_providers: if self.provider_name not in self.available_providers:
raise ValueError(f"Unknown provider: {provider_name}") raise ValueError(f"Unknown provider: {provider_name}")
if self.provider_name in self.unsafe_providers: if self.provider_name in self.unsafe_providers and self.is_local == False:
pretty_print("Warning: you are using an API provider. You data will be sent to the cloud.", color="warning") pretty_print("Warning: you are using an API provider. You data will be sent to the cloud.", color="warning")
self.api_key = self.get_api_key(self.provider_name) self.api_key = self.get_api_key(self.provider_name)
elif self.provider_name != "ollama": elif self.provider_name != "ollama":
@ -140,7 +141,6 @@ class Provider:
raise e raise e
return thought return thought
def ollama_fn(self, history, verbose = False): def ollama_fn(self, history, verbose = False):
""" """
Use local ollama server to generate text. Use local ollama server to generate text.
@ -207,6 +207,29 @@ class Provider:
except Exception as e: except Exception as e:
raise Exception(f"OpenAI API error: {str(e)}") from e raise Exception(f"OpenAI API error: {str(e)}") from e
def google_fn(self, history, verbose=False):
"""
Use google gemini to generate text.
"""
base_url = self.server_ip
if self.is_local:
raise Exception("Google Gemini is not available for local use.")
client = OpenAI(api_key=self.api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("Google response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"GOOGLE API error: {str(e)}") from e
def together_fn(self, history, verbose=False): def together_fn(self, history, verbose=False):
""" """
Use together AI for completion Use together AI for completion