Merge pull request #95 from Fosowl/dev

Multilingual routing system (english, french, chinese) + Better web agent handling of web form (#94 corrected)
This commit is contained in:
Martin 2025-04-02 21:55:11 +02:00 committed by GitHub
commit 32b3908aa3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 194 additions and 141 deletions

View File

@ -14,6 +14,10 @@ English | [繁體中文](./README_CHT.md) | [Français](./README_FR.md)
> 🛠️ **Work in Progress** Looking for contributors!
## Task planning with multiple agents
![alt text](./media/examples/planner.png)
> *Do a deep search of AI startup in Osaka and Tokyo, find at least 5, then save in the research_japan.txt file*
> *Can you make a tetris game in C ?*
@ -21,12 +25,6 @@ English | [繁體中文](./README_CHT.md) | [Français](./README_FR.md)
> *I would like to setup a new project file index as mark2.*
### agenticSeek can now plan tasks!
![alt text](./media/exemples/demo_image.png)
*See media/examples for other use case screenshots.*
## Features:
- **100% Local**: No cloud, runs on your hardware. Your data stays yours.
@ -142,8 +140,7 @@ python3 main.py
## Usage
Warning: currently the system that choose the best AI agent routing system will work poorly with non-english text. This is because the agent routing currently use a model that was trained on english text. We are working hard to fix this. Please use english for now.
Warning: We only support French, English and Chinese, prompt in other language would work but might not be routed to the proper agent.
Make sure the services are up and running with `./start_services.sh` and run the agenticSeek with `python3 main.py`
@ -162,9 +159,9 @@ Here are some example usage:
### Coding/Bash
> *Help me with matrix multiplication in Golang*
> *Show me how to multiply matrice in C*
> *Scan my network with nmap, find if any suspicious devices is connected*
> *Can you install follow the readme and install project at /home/path/project*
> *Make a snake game in python*
@ -174,7 +171,7 @@ Here are some example usage:
> *Can you find on the internet who created agenticSeek?*
> *Can you find on which website I can buy a rtx 4090 for cheap*
> *Can you use a fuel calculator online to estimate the cost of a Nice - Milan trip*
### File system
@ -186,11 +183,11 @@ Here are some example usage:
### Casual
> *Tell me about France*
> *Tell me about Rennes, France*
> *What is the meaning of life ?*
> *Should I pursue a phd ?*
> *Should I take creatine before or after workout?*
> *What's the best workout routine ?*
After you type your query, agenticSeek will allocate the best agent for the task.
@ -430,9 +427,11 @@ Ensure Ollama is running (`ollama serve`), your `config.ini` matches your provid
Yes with Ollama or Server providers, all speech to text, LLM and text to speech model run locally. Non-local options (OpenAI or others API) are optional.
**Q: How come it is older than manus ?**
**Q: Why should I use AgenticSeek when I have Manus?**
we started this a fun side project to make a fully local, Jarvis-like AI. However, with the rise of Manus, we saw the opportunity to redirected some tasks to make yet another alternative.
This started as Side-Project we did out of interest about AI agents. Whats special about it is that we want to use local model and avoid APIs.
We draw inspiration from Jarvis and Friday (Iron man movies) to make it "cool" but for functionnality we take more inspiration from Manus, because that's what people want in the first place: a local manus alternative.
Unlike Manus, AgenticSeek prioritizes independence from external systems, giving you more control, privacy and avoid cost.
**Q: How is it better than manus ?**

View File

@ -24,9 +24,7 @@
### AgenticSeek 可以進行任務規劃!
![alt text](./media/exemples/demo_image.png)
*可以查看我們的圖片集和範例了解他到底可以做些甚麼。*
![alt text](./media/examples/planner.png)
## Features:
@ -145,9 +143,6 @@ python3 main.py
## Usage (使用方法)
警告:目前 AgenticSeek 選擇助理的方式,暫且只支援英文,因為選擇助理的方式是使用英文文本訓練,所以使用非英文方式會出現挺多問題的。但放心,我們正在努力解決這個問題,還請體諒 QAQ
確定所有的核心檔案都啟用了,也就是執行過這條命令 `./start_services.sh` 然後你就可以使用 `python3 main.py` 來啟動 AgenticSeek 了!
```sh

View File

@ -15,16 +15,17 @@ Une alternative **entièrement locale** à Manus AI, un assistant vocal IA qui c
![alt text](./media/whale_readme.jpg)
> *Do a deep search of AI startup in Osaka and Tokyo, find at least 5, then save in the research_japan.txt file*
> *Recherche sur le web des activités à faire à Paris*
> *Can you make a tetris game in C ?*
> *Code le jeu snake en python*
> *I would like to setup a new project file index as mark2.*
> *J'aimerais que tu trouve une api météo et que tu me code un application qui affiche la météo à Toulouse*
### agenticSeek peut planifier des taches!
### agenticSeek peut désormais planifier des taches!
![alt text](./media/examples/planner.png)
![alt text](./media/exemples/demo_image.png)
## Fonctionnalités:
@ -135,8 +136,6 @@ Voir la section **Configuration** pour une explication détaillée du fichier de
## Utilisation
Avertissement : actuellement, le système qui choisit le meilleur agent IA fonctionnera mal avec du texte non anglophone. Cela est dû au fait que le routage des agents utilise un modèle entraîné sur du texte en anglais. Nous travaillons dur pour corriger cela. Veuillez utiliser langlais pour le moment.
Assurez-vous que les services sont en cours dexécution avec ./start_services.sh et lancez AgenticSeek avec python3 main.py
```sh
@ -154,42 +153,41 @@ Voici quelques exemples dutilisation :
### Programmation
> *Help me with matrix multiplication in Golang*
> *Aide-moi avec la multiplication de matrices en Golang*
> *Scan my network with nmap, find if any suspicious devices is connected*
> *Initalize un nouveau project python, setup le readme, gitignore et tout le bordel et fait un premier commit*
> *Make a snake game in python*
> *Fais un jeu snake en Python*
### Recherche web
> *Do a web search to find cool tech startup in Japan working on cutting edge AI research*
> *Fais une recherche sur le web pour trouver des startups technologiques au Japon qui travaillent sur des recherches avancées en IA*
> *Can you find on the internet who created agenticSeek?*
> *Peux-tu trouver sur internet qui a créé agenticSeek ?*
> *Can you find on which website I can buy a rtx 4090 for cheap*
> *Peux-tu trouver sur quel site je peux acheter une RTX 4090 à bas prix ?*
### Fichier
> *Hey can you find where is million_dollars_contract.pdf i lost it*
> *Hé, peux-tu trouver où est million_dollars_contract.pdf ? Je lai perdu*
> *Show me how much space I have left on my disk*
> *Montre-moi combien despace il me reste sur mon disque*
> *Find and read the README.md and follow the install instruction*
> *Trouve et lis le fichier README.md et suis les instructions dinstallation*
### Conversation
> *Tell me about France*
> *Parle-moi de la France*
> *What is the meaning of life ?*
> *Should I take creatine before or after workout?*
> *Quel est le sens de la vie ?*
> *Donne moi une recette avec les ingrédients suivant de mon frigo...*
Après avoir saisi votre requête, AgenticSeek attribuera le meilleur agent pour la tâche.
Comme il sagit dun prototype, le système de routage des agents pourrait ne pas toujours attribuer le bon agent en fonction de votre requête.
Le système de routage des agents peut parfois ne pas toujours attribuer le bon agent en fonction de votre requête.
Par conséquent, vous devez être explicite sur ce que vous voulez et sur la manière dont lIA doit procéder. Par exemple, si vous voulez quelle effectue une recherche sur le web, ne dites pas :
Par conséquent, vous devez être assez explicite sur ce que vous voulez et sur la manière dont lIA doit procéder. Par exemple, si vous voulez quelle effectue une recherche sur le web, ne dites pas :
Connait-tu de bons pays pour voyager seul ?
@ -336,7 +334,7 @@ stealth_mode = False
## Providers
Le tableau ci-dessous montre les fournisseurs disponibles :
Le tableau ci-dessous montre les LLM providers disponibles :
| Provider | Local? | Description |
|-----------|--------|-----------------------------------------------------------|
@ -347,7 +345,7 @@ Le tableau ci-dessous montre les fournisseurs disponibles :
| deepseek-api | No | Deepseek API (pas privé) |
| huggingface| No | Hugging-Face API (pas privé) |
Pour sélectionner un fournisseur, modifiez le config.ini :
Pour sélectionner un provider LLM, modifiez le config.ini :
```
is_local = False
@ -387,7 +385,7 @@ Et téléchargez la version de chromedriver correspondant à votre système d
![alt text](./media/chromedriver_readme.png)
Si cette section est incomplète, veuillez signaler un problème.
Si cette section est incomplète, merci de faire une nouvelle issue github.
## FAQ
@ -408,15 +406,11 @@ Assurez-vous quOllama est en cours dexécution (ollama serve), que votre c
**Q: C'est vraiment 100% local?**
Oui, avec les fournisseurs Ollama ou Server, toute la reconnaissance vocale, le LLM et la synthèse vocale fonctionnent localement. Les options non locales (OpenAI ou autres API) sont facultatives.
**Q: Pourquoi le projet est plus vieux que la date de sortie de Manus?**
Nous avons commencé cela comme un projet amusant pour créer une IA locale de type Jarvis. Cependant, avec lémergence de Manus, nous avons vu lopportunité de réorienter certaines tâches pour en faire une autre alternative.
Oui, avec les fournisseurs Ollama, lm-studio ou Server, toute la reconnaissance vocale, le LLM et la synthèse vocale fonctionnent localement. Les options non locales (OpenAI ou autres API) sont facultatives.
**Q: En quoi c'est supérieur à Manus**
Il ne l'est pas mais nous privilégions lexécution locale et la confidentialité par rapport à une approche basée sur le cloud. Cest une alternative plus accessible et surtout moins cher !
Il ne l'est pas, mais nous privilégions lexécution locale et la confidentialité par rapport à une approche basée sur le cloud. Cest une alternative plus accessible et surtout moins cher !
## Contribute

BIN
media/examples/planner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

View File

@ -47,5 +47,5 @@ Some rules:
- Do not ever use user input, input are not supported by the system.
- Do not ever tell user how to run it. user know it.
- For simple explanation you don't need to code.
- Dont be lazy, write full implementation for user.
- If using gui, make sure echap close the program
- If query is unclear say REQUEST_CLARIFICATION

View File

@ -46,8 +46,8 @@ Some rules:
- You do not ever need to use bash to execute code.
- Do not ever use user input, input are not supported by the system.
- Do not ever tell user how to run it. user know it.
- Dont be lazy, write full implementation for user.
- For simple explanation you don't need to code.
- If using gui, make sure echap close the program
- If query is unclear say REQUEST_CLARIFICATION
Personality:

View File

@ -32,6 +32,7 @@ tqdm>4
fake_useragent>=2.1.0
selenium_stealth>=1.0.6
undetected-chromedriver>=3.5.5
sentencepiece>=0.2.0
# for api provider
openai
# if use chinese

View File

@ -44,6 +44,7 @@ setup(
"fake_useragent>=2.1.0",
"selenium_stealth>=1.0.6",
"undetected-chromedriver>=3.5.5",
"sentencepiece>=0.2.0",
"sniffio",
"tqdm>4"
],

View File

@ -187,7 +187,7 @@ class BrowserAgent(Agent):
def conclude_prompt(self, user_query: str) -> str:
annotated_notes = [f"{i+1}: {note.lower().replace('note:', '')}" for i, note in enumerate(self.notes)]
search_note = '\n'.join(annotated_notes)
print("AI research notes:\n", search_note)
pretty_print(f"AI notes:\n{search_note}", color="success")
return f"""
Following a human request:
{user_query}
@ -251,7 +251,7 @@ class BrowserAgent(Agent):
complete = False
animate_thinking(f"Thinking...", color="status")
self.memory.push('user', self.search_prompt(user_prompt))
mem_begin_idx = self.memory.push('user', self.search_prompt(user_prompt))
ai_prompt, _ = self.llm_request()
if "REQUEST_EXIT" in ai_prompt:
pretty_print(f"{reasoning}\n{ai_prompt}", color="output")
@ -305,9 +305,10 @@ class BrowserAgent(Agent):
prompt = self.make_navigation_prompt(user_prompt, page_text)
prompt = self.conclude_prompt(user_prompt)
self.memory.push('user', prompt)
mem_last_idx = self.memory.push('assistant', prompt)
answer, reasoning = self.llm_request()
pretty_print(answer, color="output")
self.memory.clear_section(mem_begin_idx, mem_last_idx)
return answer, reasoning
if __name__ == "__main__":

View File

@ -1,3 +1,4 @@
import platform, os
from sources.utility import pretty_print, animate_thinking
from sources.agents.agent import Agent, executorResult
@ -20,6 +21,7 @@ class CoderAgent(Agent):
"go": GoInterpreter(),
"file_finder": FileFinder()
}
self.work_dir = self.tools["file_finder"].get_work_dir()
self.role = {
"en": "code",
"fr": "codage",
@ -27,10 +29,20 @@ class CoderAgent(Agent):
}
self.type = "code_agent"
def add_sys_info_prompt(self, prompt):
"""Add system information to the prompt."""
info = f"System Info:\n" \
f"OS: {platform.system()} {platform.release()}\n" \
f"Python Version: {platform.python_version()}\n" \
f"\nYou must work in directory: {self.work_dir}"
return f"{prompt}\n\n{info}"
def process(self, prompt, speech_module) -> str:
answer = ""
attempt = 0
max_attempts = 3
max_attempts = 4
prompt = self.add_sys_info_prompt(prompt)
self.memory.push('user', prompt)
clarify_trigger = "REQUEST_CLARIFICATION"

View File

@ -24,6 +24,9 @@ import re
from sources.utility import pretty_print, animate_thinking
logging.basicConfig(filename='browser.log', level=logging.ERROR,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
def get_chrome_path() -> str:
if sys.platform.startswith("win"):
paths = [
@ -111,13 +114,15 @@ class Browser:
self.logger = logging.getLogger(__name__)
self.logger.info("Browser initialized successfully")
except Exception as e:
logging.basicConfig(filename='browser.log', level=logging.ERROR,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
raise Exception(f"Failed to initialize browser: {str(e)}")
self.driver.get("https://www.google.com")
if anticaptcha_manual_install:
self.load_anticatpcha_manually()
def load_anticatpcha_manually(self):
print("You might want to install the AntiCaptcha extension for captchas.")
pretty_print("You might want to install the AntiCaptcha extension for captchas.", color="warning")
self.driver.get(self.anticaptcha)
def go_to(self, url:str) -> bool:
@ -263,7 +268,7 @@ class Browser:
except Exception as e:
raise e
def find_all_inputs(self, timeout=4):
def find_all_inputs(self, timeout=3):
WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
@ -275,26 +280,28 @@ class Browser:
def get_form_inputs(self) -> List[str]:
"""Extract all input from the page and return them."""
try:
#input_elements = self.driver.find_elements(By.TAG_NAME, "input")
input_elements = self.find_all_inputs()
if not input_elements:
return ["No input forms found on the page."]
form_strings = []
for element in input_elements:
input_type = element["type"] or "text"
input_type = element.get("type") or "text"
if input_type in ["hidden", "submit", "button", "image"] or not element["displayed"]:
continue
input_name = element["text"] or element["id"] or input_type
input_name = element.get("text") or element.get("id") or input_type
if input_type == "checkbox" or input_type == "radio":
checked_status = "checked" if element.is_selected() else "unchecked"
try:
checked_status = "checked" if element.is_selected() else "unchecked"
except Exception as e:
continue
form_strings.append(f"[{input_name}]({checked_status})")
else:
form_strings.append(f"[{input_name}]("")")
return form_strings
except Exception as e:
return [f"Error extracting form inputs."]
raise e
def get_buttons_xpath(self) -> List[str]:
"""
@ -308,13 +315,14 @@ class Browser:
continue
text = (button.text or button.get_attribute("value") or "").lower().replace(' ', '')
xpath = f"(//button | //input[@type='submit'])[{i + 1}]"
if "login" in text or "sign" in text or "register":
result.append((text, xpath))
result.append((text, xpath))
result.sort(key=lambda x: len(x[0]))
return result
def find_and_click_submission(self, timeout: int = 10) -> bool:
possible_submissions = ["login", "submit", "register"]
possible_submissions = ["login", "submit", "register", "calculate", "login", "submit", "register", "calculate", "save", "send",
"continue", "apply", "ok", "confirm", "next", "proceed", "accept", "agree", "yes", "no", "cancel",
"close", "done", "finish", "start", "calculate"]
for submission in possible_submissions:
if self.find_and_click_btn(submission, timeout):
return True
@ -388,6 +396,7 @@ class Browser:
element.click()
self.logger.info(f"Set {name} to {value}")
else:
element.clear()
element.send_keys(value)
self.logger.info(f"Filled {name} with {value}")
return True
@ -409,7 +418,7 @@ class Browser:
self.driver.execute_script(
"window.scrollTo(0, document.body.scrollHeight);"
)
time.sleep(1) # Wait for scroll to complete
time.sleep(1)
return True
except Exception as e:
self.logger.error(f"Error scrolling: {str(e)}")
@ -439,13 +448,12 @@ if __name__ == "__main__":
browser = Browser(driver, anticaptcha_manual_install=True)
time.sleep(10)
print("AntiCaptcha Test")
print("AntiCaptcha / Form Test")
browser.go_to("https://www.google.com/recaptcha/api2/demo")
#browser.go_to("https://practicetestautomation.com/practice-test-login/")
time.sleep(10)
print("Form Test:")
browser.go_to("https://practicetestautomation.com/practice-test-login/")
inputs = browser.get_form_inputs()
inputs = ['[username](student)', f'[password](Password123)', '[appOtp]()', '[backupOtp]()']
inputs = ['[input1](Martin)', f'[input2](Test)', '[input3](test@gmail.com)']
browser.fill_form_inputs(inputs)
browser.find_and_click_submission()
time.sleep(30)

View File

@ -1,17 +1,35 @@
from typing import List, Tuple, Type, Dict, Tuple
import langid
import re
import langid
import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from transformers import MarianMTModel, MarianTokenizer
from sources.utility import pretty_print, animate_thinking
class LanguageUtility:
"""LanguageUtility for language, or emotion identification"""
def __init__(self):
self.sid = None
self.translators_tokenizer = None
self.translators_model = None
self.load_model()
def load_model(self) -> None:
animate_thinking("Loading language utility...", color="status")
try:
nltk.data.find('vader_lexicon')
except LookupError:
nltk.download('vader_lexicon')
self.sid = SentimentIntensityAnalyzer()
self.translators_tokenizer = {
"fr": MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-fr-en"),
"zh": MarianTokenizer.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
}
self.translators_model = {
"fr": MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-fr-en"),
"zh": MarianMTModel.from_pretrained("Helsinki-NLP/opus-mt-zh-en")
}
def detect_language(self, text: str) -> str:
"""
@ -24,6 +42,25 @@ class LanguageUtility:
lang, score = langid.classify(text)
return lang
def translate(self, text: str, origin_lang: str) -> str:
"""
Translate the given text to English
Args:
text: string to translate
origin_lang: ISO language code
Returns: translated str
"""
if origin_lang == "en":
return text
if origin_lang not in self.translators_tokenizer:
pretty_print(f"Language {origin_lang} not supported for translation", color="error")
return text
tokenizer = self.translators_tokenizer[origin_lang]
inputs = tokenizer(text, return_tensors="pt", padding=True)
model = self.translators_model[origin_lang]
translation = model.generate(**inputs)
return tokenizer.decode(translation[0], skip_special_tokens=True)
def detect_emotion(self, text: str) -> str:
"""
Detect the dominant emotion in the given text
@ -75,11 +112,12 @@ if __name__ == "__main__":
test_texts = [
"I am so happy today!",
"Qué tristeza siento ahora",
"我不要去巴黎",
"La vie c'est cool"
]
for text in test_texts:
print(f"\nAnalyzing: {text}")
pretty_print("Analyzing...", color="status")
pretty_print(f"Language: {detector.detect_language(text)}", color="status")
result = detector.analyze(text)
print(result)
trans = detector.translate(text, result['language'])
pretty_print(f"Translation: {trans} - from: {result['language']} - Emotion: {result['emotions']}")

View File

@ -67,9 +67,9 @@ class Memory():
def load_memory(self, agent_type: str = "casual_agent") -> None:
"""Load the memory from the last session."""
pretty_print(f"Loading {agent_type} past memories... ", color="status")
if self.session_recovered == True:
return
pretty_print(f"Loading {agent_type} past memories... ", color="status")
save_path = os.path.join(self.conversation_folder, agent_type)
if not os.path.exists(save_path):
pretty_print("No memory to load.", color="success")
@ -89,7 +89,7 @@ class Memory():
def reset(self, memory: list) -> None:
self.memory = memory
def push(self, role: str, content: str) -> None:
def push(self, role: str, content: str) -> int:
"""Push a message to the memory."""
if self.memory_compression and role == 'assistant':
self.compress()
@ -97,10 +97,14 @@ class Memory():
if self.memory[curr_idx-1]['content'] == content:
pretty_print("Warning: same message have been pushed twice to memory", color="error")
self.memory.append({'role': role, 'content': content})
return curr_idx-1
def clear(self) -> None:
self.memory = []
def clear_section(self, start: int, end: int) -> None:
self.memory = self.memory[:start] + self.memory[end:]
def get(self) -> list:
return self.memory

View File

@ -8,14 +8,13 @@ from adaptive_classifier import AdaptiveClassifier
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sources.agents.agent import Agent
from sources.agents.code_agent import CoderAgent
from sources.agents.casual_agent import CasualAgent
from sources.agents.planner_agent import FileAgent
from sources.agents.browser_agent import BrowserAgent
from sources.language import LanguageUtility
from sources.utility import pretty_print
from sources.utility import pretty_print, animate_thinking, timer_decorator
class AgentRouter:
"""
@ -24,13 +23,22 @@ class AgentRouter:
def __init__(self, agents: list):
self.agents = agents
self.lang_analysis = LanguageUtility()
self.pipelines = {
"bart": pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
}
self.pipelines = self.load_pipelines()
self.talk_classifier = self.load_llm_router()
self.complexity_classifier = self.load_llm_router()
self.learn_few_shots_tasks()
self.learn_few_shots_complexity()
def load_pipelines(self) -> Dict[str, Type[pipeline]]:
"""
Load the pipelines for the text classification used for routing.
returns:
Dict[str, Type[pipeline]]: The loaded pipelines
"""
animate_thinking("Loading zero-shot pipeline...", color="status")
return {
"bart": pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
}
def load_llm_router(self) -> AdaptiveClassifier:
"""
@ -42,6 +50,7 @@ class AgentRouter:
"""
path = "../llm_router" if __name__ == "__main__" else "./llm_router"
try:
animate_thinking("Loading LLM router model...", color="status")
talk_classifier = AdaptiveClassifier.from_pretrained(path)
except Exception as e:
raise Exception("Failed to load the routing model. Please run the dl_safetensors.sh script inside llm_router/ directory to download the model.")
@ -302,25 +311,14 @@ class AgentRouter:
pretty_print(f"Agent choice -> BART: {bart} ({final_score_bart}) LLM-router: {llm_router} ({final_score_llm})")
return bart if final_score_bart > final_score_llm else llm_router
def classify_text(self, text: str, threshold: float = 0.4) -> list:
"""
Classify the text using the LLM router and BART model.
"""
def find_first_sentence(self, text: str) -> str:
first_sentence = None
lang = "en"
for line in text.split("\n"):
first_sentence = line.strip()
break
if first_sentence is None:
first_sentence = text
try:
lang = self.lang_analysis.detect_language(first_sentence)
# no multilanguage support yet
labels = [agent.role["en"] for agent in self.agents]
result = self.router_vote(first_sentence, labels, log_confidence=False)
except Exception as e:
raise e
return result, lang
return first_sentence
def estimate_complexity(self, text: str) -> str:
"""
@ -328,7 +326,7 @@ class AgentRouter:
Args:
text: The input text
Returns:
str: The estimated complexity
str: The estimated complexity
"""
predictions = self.complexity_classifier.predict(text)
predictions = sorted(predictions, key=lambda x: x[1], reverse=True)
@ -358,12 +356,6 @@ class AgentRouter:
pretty_print(f"Error finding planner agent. Please add a planner agent to the list of agents.", color="failure")
return None
def multi_language_message(self, text: str):
pretty_print(f"选择代理时出错。路由系统尚不支持多语言", color="failure")
pretty_print(f"エージェントの選択エラー。ルーティングシステムはまだ多言語に対応していません", color="failure")
pretty_print(f"Erreur lors du choix de l'agent. Le système de routage n'est pas encore multilingue.", color="failure")
pretty_print(f"Error al elegir agente. El sistema de enrutamiento aún no es multilingüe.", color="failure")
def select_agent(self, text: str) -> Agent:
"""
Select the appropriate agent based on the text.
@ -374,16 +366,21 @@ class AgentRouter:
"""
if len(self.agents) == 0:
return self.agents[0]
lang = self.lang_analysis.detect_language(text)
text = self.find_first_sentence(text)
text = self.lang_analysis.translate(text, lang)
labels = [agent.role["en"] for agent in self.agents]
complexity = self.estimate_complexity(text)
best_agent, lang = self.classify_text(text)
if lang != "en":
self.multi_language_message(text)
if complexity == None:
pretty_print(f"Humm, the task seem complex but you gave very little information. can you clarify?", color="info")
return None
if complexity == "HIGH" and lang == "en":
if complexity == "HIGH":
pretty_print(f"Complex task detected, routing to planner agent.", color="info")
return self.find_planner_agent()
try:
best_agent = self.router_vote(text, labels, log_confidence=False)
except Exception as e:
raise e
for agent in self.agents:
if best_agent == agent.role["en"]:
pretty_print(f"Selected agent: {agent.agent_name} (roles: {agent.role[lang]})", color="warning")
@ -393,52 +390,52 @@ class AgentRouter:
if __name__ == "__main__":
agents = [
CasualAgent("jarvis", "../prompts/casual_agent.txt", None),
BrowserAgent("browser", "../prompts/planner_agent.txt", None),
CoderAgent("coder", "../prompts/coder_agent.txt", None),
FileAgent("file", "../prompts/coder_agent.txt", None)
CasualAgent("jarvis", "../prompts/base/casual_agent.txt", None),
BrowserAgent("browser", "../prompts/base/planner_agent.txt", None),
CoderAgent("coder", "../prompts/base/coder_agent.txt", None),
FileAgent("file", "../prompts/base/coder_agent.txt", None)
]
router = AgentRouter(agents)
texts = [
"hi",
#"你好",
#"Bonjour",
"你好",
"Bonjour",
"Write a python script to check if the device on my network is connected to the internet",
# "Peut tu écrire un script python qui vérifie si l'appareil sur mon réseau est connecté à internet?",
# "写一个Python脚本检查我网络上的设备是否连接到互联网",
"Peut tu écrire un script python qui vérifie si l'appareil sur mon réseau est connecté à internet?",
"写一个Python脚本检查我网络上的设备是否连接到互联网",
"Hey could you search the web for the latest news on the tesla stock market ?",
# "嘿,你能搜索网页上关于股票市场的最新新闻吗?",
# "Yo, cherche sur internet comment va tesla en bourse.",
"嘿,你能搜索网页上关于股票市场的最新新闻吗?",
"Yo, cherche sur internet comment va tesla en bourse.",
"I would like you to search for weather api and then make an app using this API",
# "我想让你搜索天气API然后用这个API做一个应用程序",
# "J'aimerais que tu cherche une api météo et que l'utilise pour faire une application",
"我想让你搜索天气API然后用这个API做一个应用程序",
"J'aimerais que tu cherche une api météo et que l'utilise pour faire une application",
"Plan a 3-day trip to New York, including flights and hotels.",
# "计划一次为期3天的纽约之旅包括机票和酒店。",
# "Planifie un trip de 3 jours à Paris, y compris les vols et hotels.",
"计划一次为期3天的纽约之旅包括机票和酒店。",
"Planifie un trip de 3 jours à Paris, y compris les vols et hotels.",
"Find on the web the latest research papers on AI.",
# "在网上找到最新的人工智能研究论文。",
# "Trouve moi les derniers articles de recherche sur l'IA sur internet",
"在网上找到最新的人工智能研究论文。",
"Trouve moi les derniers articles de recherche sur l'IA sur internet",
"Help me write a C++ program to sort an array",
"Tell me what France been up to lately",
# "告诉我法国最近在做什么",
# "Dis moi ce que la France a fait récemment",
"告诉我法国最近在做什么",
"Dis moi ce que la France a fait récemment",
"Who is Sergio Pesto ?",
# "谁是Sergio Pesto",
# "Qui est Sergio Pesto ?",
# "帮我写一个C++程序来排序数组",
# "Aide moi à faire un programme c++ pour trier une array.",
"谁是Sergio Pesto",
"Qui est Sergio Pesto ?",
"帮我写一个C++程序来排序数组",
"Aide moi à faire un programme c++ pour trier une array.",
"Whats the weather like today? Oh, and can you find a good weather app?",
# "今天天气怎么样?哦,你还能找到一个好的天气应用程序吗?",
# "La météo est comment aujourd'hui ? oh et trouve moi une bonne appli météo tant que tu y est.",
"今天天气怎么样?哦,你还能找到一个好的天气应用程序吗?",
"La météo est comment aujourd'hui ? oh et trouve moi une bonne appli météo tant que tu y est.",
"Can you debug this Java code? Its not working.",
# "你能调试这段Java代码吗它不起作用。",
# "Peut tu m'aider à debugger ce code java, ça marche pas",
#"Can you browse the web and find me a 4090 for cheap?",
#"你能浏览网页为我找一个便宜的4090吗",
#"Peut tu chercher sur internet et me trouver une 4090 pas cher ?",
#"Hey, can you find the old_project.zip file somewhere on my drive?",
#"你能在我驱动器上找到old_project.zip文件吗",
#"Hé trouve moi le old_project.zip, il est quelque part sur mon disque.",
"你能调试这段Java代码吗它不起作用。",
"Peut tu m'aider à debugger ce code java, ça marche pas",
"Can you browse the web and find me a 4090 for cheap?",
"你能浏览网页为我找一个便宜的4090吗",
"Peut tu chercher sur internet et me trouver une 4090 pas cher ?",
"Hey, can you find the old_project.zip file somewhere on my drive?",
"你能在我驱动器上找到old_project.zip文件吗",
"Hé trouve moi le old_project.zip, il est quelque part sur mon disque.",
"Tell me a funny story",
"给我讲一个有趣的故事",
"Raconte moi une histoire drole"

View File

@ -28,6 +28,9 @@ unsafe_commands_unix = [
"parted", # Disk partitioning
"chroot", # Change root directory
"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)
]
unsafe_commands_windows = [