From cfe19e637faff7d6af00ca07d162f47cc2bba0b2 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 20:13:25 +0200 Subject: [PATCH 1/8] feat : planner improvement, google provider --- prompts/base/planner_agent.txt | 2 +- prompts/jarvis/planner_agent.txt | 1 - sources/agents/agent.py | 18 +++++++++++- sources/agents/planner_agent.py | 28 ++++++++++++------ sources/browser.py | 1 - sources/llm_provider.py | 29 +++++++++++++++++-- sources/tools/{mcp_finder.py => mcpFinder.py} | 0 7 files changed, 63 insertions(+), 16 deletions(-) rename sources/tools/{mcp_finder.py => mcpFinder.py} (100%) diff --git a/prompts/base/planner_agent.txt b/prompts/base/planner_agent.txt index 92ecd4b..66ed644 100644 --- a/prompts/base/planner_agent.txt +++ b/prompts/base/planner_agent.txt @@ -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. \ No newline at end of file diff --git a/prompts/jarvis/planner_agent.txt b/prompts/jarvis/planner_agent.txt index b32e6d7..0fc1178 100644 --- a/prompts/jarvis/planner_agent.txt +++ b/prompts/jarvis/planner_agent.txt @@ -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. \ No newline at end of file diff --git a/sources/agents/agent.py b/sources/agents/agent.py index 0573dc5..3afe3fb 100644 --- a/sources/agents/agent.py +++ b/sources/agents/agent.py @@ -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: """ diff --git a/sources/agents/planner_agent.py b/sources/agents/planner_agent.py index 47da48d..17abd3b 100644 --- a/sources/agents/planner_agent.py +++ b/sources/agents/planner_agent.py @@ -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, "" \ No newline at end of file + return answer, "" \ No newline at end of file diff --git a/sources/browser.py b/sources/browser.py index e68da01..0351cb9 100644 --- a/sources/browser.py +++ b/sources/browser.py @@ -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 diff --git a/sources/llm_provider.py b/sources/llm_provider.py index eeb371d..a0ecb3e 100644 --- a/sources/llm_provider.py +++ b/sources/llm_provider.py @@ -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): """ diff --git a/sources/tools/mcp_finder.py b/sources/tools/mcpFinder.py similarity index 100% rename from sources/tools/mcp_finder.py rename to sources/tools/mcpFinder.py From d5c431a609844e931d882659828023507c2df6ac Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 20:50:31 +0200 Subject: [PATCH 2/8] update readme --- README.md | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 848c88c..4b71d51 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,31 @@ English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Franç # AgenticSeek: Private, Local Manus Alternative. -*A **100% local alternative to Manus AI**, this voice-enabled AI assistant autonomously browses the web, writes code, and plans tasks while keeping all data on your device. Powered by advanced reasoning models like DeepSeek R1, it runs entirely on your hardware, ensuring complete privacy and zero cloud dependency.* +*A **100% local alternative to Manus AI**, this voice-enabled AI assistant autonomously browses the web, writes code, and plans tasks while keeping all data on your device. Tailored for local reasoning models, it runs entirely on your hardware, ensuring complete privacy and zero cloud dependency.* [![Visit AgenticSeek](https://img.shields.io/static/v1?label=Website&message=AgenticSeek&color=blue&style=flat-square)](https://fosowl.github.io/agenticSeek.html) ![License](https://img.shields.io/badge/license-GPL--3.0-green) [![Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/m37d7XxZ) [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/fosowl.svg?style=social&label=Update%20%40Fosowl)](https://x.com/Martin993886460) [![GitHub stars](https://img.shields.io/github/stars/Fosowl/agenticSeek?style=social)](https://github.com/Fosowl/agenticSeek/stargazers) +### Why AgenticSeek ? + +🔒 Fully Local & Private +Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private. + +🌐 Smart Web Browsing +AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free. + +💻 Autonomous Coding Assistant +Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision. + +🧠 Smart Agent Selection +You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help. + +📋 Plans & Executes Complex Tasks +From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents. + +🎙️ Voice-Enabled +Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie + +### **Demo** > *Plan a 3 days solo trip to Budapest, find me a list of attractions and hostels, save everything in a CSV file* @@ -19,20 +40,6 @@ https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469 > 🛠️ **Work in Progress** – Looking for contributors! -### *Capabilities* - -- **100% Local**: *No cloud, runs on your hardware. Your data stays yours.* - -- **Autonomous Web Browsing**: *Autonomous web navigation.* - -- **Autonomous Coding**: *Can write, debug, and run code in Python, C, Golang, Java...* - -- **Agent routing**: *Automatically picks the right agent for the job.* - -- **Planning**: *For complex tasks, spins up multiple agents to plan and execute.* - -- **Memory**: *Efficient memory and sessions management.* - ## Installation Make sure you have chrome driver, docker and python3.10 (or newer) installed. From a11445e7c07faaedbfafce6549f13b1eb94ee043 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 20:52:59 +0200 Subject: [PATCH 3/8] readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 4b71d51..f770f24 100644 --- a/README.md +++ b/README.md @@ -15,21 +15,27 @@ English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Franç ### Why AgenticSeek ? 🔒 Fully Local & Private + Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private. 🌐 Smart Web Browsing + AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free. 💻 Autonomous Coding Assistant + Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision. 🧠 Smart Agent Selection + You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help. 📋 Plans & Executes Complex Tasks + From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents. 🎙️ Voice-Enabled + Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie ### **Demo** From 309a481a694c078c532afe81f4ae6631ff192734 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 21:15:49 +0200 Subject: [PATCH 4/8] feat : enhance planner --- api.py | 2 +- sources/agents/agent.py | 1 - sources/interaction.py | 9 +++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/api.py b/api.py index 862758f..18b971b 100755 --- a/api.py +++ b/api.py @@ -140,7 +140,7 @@ async def get_latest_answer(): "answer": interaction.current_agent.last_answer, "agent_name": interaction.current_agent.agent_name if interaction.current_agent else "None", "success": interaction.current_agent.success, - "blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())} if interaction.current_agent else {}, + "blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.get_last_blocks_result())} if interaction.current_agent else {}, "status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available", "uid": uid } diff --git a/sources/agents/agent.py b/sources/agents/agent.py index 3afe3fb..0e69648 100644 --- a/sources/agents/agent.py +++ b/sources/agents/agent.py @@ -242,5 +242,4 @@ class Agent(): self.memory.push('user', feedback) if save_path != None: tool.save_block(blocks, save_path) - self.blocks_result = self.blocks_result return True, feedback diff --git a/sources/interaction.py b/sources/interaction.py index fe52bf4..eec6ff4 100644 --- a/sources/interaction.py +++ b/sources/interaction.py @@ -69,6 +69,15 @@ class Interaction: break return ai_name + def get_last_blocks_result(self) -> List[Dict]: + """Get the last blocks result.""" + if self.current_agent is None: + return [] + blks = [] + for agent in self.agents: + blks.extend(agent.get_blocks_result()) + return blks + def load_last_session(self): """Recover the last session.""" for agent in self.agents: From 49a36de149bc8c96eae786f5c718ea9e0be9f8b0 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 21:17:17 +0200 Subject: [PATCH 5/8] upd readmeme --- README.md | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f770f24..27ce206 100644 --- a/README.md +++ b/README.md @@ -14,29 +14,17 @@ English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Franç ### Why AgenticSeek ? -🔒 Fully Local & Private +* 🔒 Fully Local & Private - Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private. -Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private. +* 🌐 Smart Web Browsing - AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free. -🌐 Smart Web Browsing +* 💻 Autonomous Coding Assistant - Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision. -AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free. +* 🧠 Smart Agent Selection - You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help. -💻 Autonomous Coding Assistant +* 📋 Plans & Executes Complex Tasks - From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents. -Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision. - -🧠 Smart Agent Selection - -You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help. - -📋 Plans & Executes Complex Tasks - -From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents. - -🎙️ Voice-Enabled - -Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie +* 🎙️ Voice-Enabled - Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie ### **Demo** From f09cb8a7b56934928faec276019c69ccf8add8a5 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 21:35:31 +0200 Subject: [PATCH 6/8] fix : block not display on front with planner --- sources/agents/planner_agent.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sources/agents/planner_agent.py b/sources/agents/planner_agent.py index 17abd3b..ada9e94 100644 --- a/sources/agents/planner_agent.py +++ b/sources/agents/planner_agent.py @@ -205,6 +205,7 @@ class PlannerAgent(Agent): pretty_print(f"Agent {task['agent']} started working...", color="status") 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 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() From 45700d77ab3e93c6e684131ebe7ed2a50b17c92c Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 21:54:36 +0200 Subject: [PATCH 7/8] fix : was showing code after execution --- sources/agents/agent.py | 9 +++++++++ sources/agents/code_agent.py | 2 +- sources/schemas.py | 7 +++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/sources/agents/agent.py b/sources/agents/agent.py index 0e69648..4e10c59 100644 --- a/sources/agents/agent.py +++ b/sources/agents/agent.py @@ -213,6 +213,14 @@ class Agent(): post_lines.append(f"block:{block_idx}") block_idx += 1 return "\n".join(post_lines) + + def show_block(self, block: str) -> None: + """ + Show the block in a pretty way. + """ + pretty_print('▂'*64, color="status") + pretty_print(block, color="code") + pretty_print('▂'*64, color="status") def execute_modules(self, answer: str) -> Tuple[bool, str]: """ @@ -231,6 +239,7 @@ class Agent(): if blocks != None: for block in blocks: + self.show_block(block) output = tool.execute([block]) feedback = tool.interpreter_feedback(output) # tool interpreter feedback success = not tool.execution_failure_check(output) diff --git a/sources/agents/code_agent.py b/sources/agents/code_agent.py index dd133ab..8a7f8b4 100644 --- a/sources/agents/code_agent.py +++ b/sources/agents/code_agent.py @@ -56,6 +56,7 @@ class CoderAgent(Agent): self.last_answer = answer await asyncio.sleep(0) break + self.show_answer() animate_thinking("Executing code...", color="status") self.status_message = "Executing code..." exec_success, _ = self.execute_modules(answer) @@ -67,7 +68,6 @@ class CoderAgent(Agent): pretty_print("Execution failure", color="failure") pretty_print("Correcting code...", color="status") self.status_message = "Correcting code..." - self.show_answer() attempt += 1 self.status_message = "Ready" if attempt == max_attempts: diff --git a/sources/schemas.py b/sources/schemas.py index ad72830..29410ba 100644 --- a/sources/schemas.py +++ b/sources/schemas.py @@ -68,9 +68,8 @@ class executorResult: "success": self.success, "tool_type": self.tool_type } - + def show(self): pretty_print('▂'*64, color="status") - pretty_print(self.block, color="code" if self.success else "failure") - pretty_print('▂'*64, color="status") - pretty_print(self.feedback, color="success" if self.success else "failure") \ No newline at end of file + pretty_print(self.feedback, color="success" if self.success else "failure") + pretty_print('▂'*64, color="status") \ No newline at end of file From e63d7729597f9cf1d02b6468989cd4dc416eb0e0 Mon Sep 17 00:00:00 2001 From: martin legrand Date: Fri, 25 Apr 2025 22:07:41 +0200 Subject: [PATCH 8/8] readme update --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 27ce206..e2d50a0 100644 --- a/README.md +++ b/README.md @@ -173,8 +173,6 @@ python3 cli.py **Options 2:** Run with the Web interface. -Note: Currently we advice you run the CLI instead. Web interface is an active work in progress. - Start the backend. ```sh @@ -183,8 +181,6 @@ python3 api.py Go to `http://localhost:3000/` and you should see the web interface. -Please note that the Web interface doesn't stream messages at the moment. - --- ## Usage