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:
- 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.
@ -75,7 +76,6 @@ Rules:
- 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.
- If a task might require user email (eg: api services), do not write plan instead ask for user email.
- Do not search for tutorial.
- Make sure json is within ```json tag
- 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.
- Tell agent to execute without question.
- 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.

View File

@ -159,6 +159,23 @@ class Agent():
def get_last_tool_type(self) -> str:
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):
"""
@ -175,7 +192,6 @@ class Agent():
self.blocks_result[block_idx].show()
else:
pretty_print(line, color="output")
self.blocks_result = []
def remove_blocks(self, text: str) -> str:
"""

View File

@ -69,6 +69,9 @@ class PlannerAgent(Agent):
line_json = json.loads(block)
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()]:
pretty_print(f"Agent {task['agent']} does not exist.", color="warning")
return []
agent = {
'agent': task['agent'],
'id': task['id'],
@ -139,7 +142,7 @@ class PlannerAgent(Agent):
return []
agents_tasks = self.parse_agent_tasks(answer)
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")
continue
self.show_plan(agents_tasks, answer)
@ -160,7 +163,10 @@ class PlannerAgent(Agent):
last_agent_work = agents_work_result[id]
tool_success_str = "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:
# return agents_tasks # we only update the plan if last task failed, for now
update_prompt = f"""
@ -169,10 +175,11 @@ class PlannerAgent(Agent):
The last agent working on task: {id}, did the following work:
{last_agent_work}
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?
If agent work was good: answer "NO_UPDATE"
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.
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.
@ -196,10 +203,14 @@ 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")
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
self.agents[task['agent'].lower()].show_answer()
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
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.
"""
agents_tasks = []
required_infos = None
agents_work_result = dict()
self.status_message = "Making a plan..."
@ -234,14 +246,12 @@ class PlannerAgent(Agent):
if agents_work_result is not None:
required_infos = self.get_work_result_agent(task['need'], agents_work_result)
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:
raise e
agents_work_result[task['id']] = self.last_answer
if i == steps - 1:
break
agents_work_result[task['id']] = answer
agents_tasks = await self.update_plan(goal, agents_tasks, agents_work_result, task['id'], success)
steps = len(agents_tasks)
i += 1
return self.last_answer, ""
return answer, ""

View File

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

View File

@ -29,6 +29,7 @@ class Provider:
"openai": self.openai_fn,
"lm-studio": self.lm_studio_fn,
"huggingface": self.huggingface_fn,
"google": self.google_fn,
"deepseek": self.deepseek_fn,
"together": self.together_fn,
"dsk_deepseek": self.dsk_deepseek,
@ -36,10 +37,10 @@ class Provider:
}
self.logger = Logger("provider.log")
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:
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")
self.api_key = self.get_api_key(self.provider_name)
elif self.provider_name != "ollama":
@ -140,7 +141,6 @@ class Provider:
raise e
return thought
def ollama_fn(self, history, verbose = False):
"""
Use local ollama server to generate text.
@ -206,6 +206,29 @@ class Provider:
return thought
except Exception as 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):
"""