This commit is contained in:
tcsenpai 2025-05-02 23:41:55 +02:00
commit f79c3f10da
21 changed files with 123 additions and 70 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: [Fosowl ]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]

View File

@ -159,9 +159,9 @@ Set the desired provider in the `config.ini`. See below for a list of API provid
```sh
[MAIN]
is_local = False
provider_name = openai
provider_model = gpt-4o
provider_server_address = 127.0.0.1:5000
provider_name = google
provider_model = gemini-2.0-flash
provider_server_address = 127.0.0.1:5000 # doesn't matter
```
Warning: Make sure there is not trailing space in the config.
@ -179,6 +179,10 @@ Example: export `TOGETHER_API_KEY="xxxxx"`
| togetherAI | No | Use together AI API (non-private) |
| google | No | Use google gemini API (non-private) |
*We advice against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning.
Please also note that coding/bash might fail with gemini, it seem to ignore our prompt for format to respect, which are optimized for deepseek r1.
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
*See the **Known issues** section if you are having issues*

View File

@ -1,9 +1,9 @@
[MAIN]
is_local = True
provider_name = openai
provider_model = gpt-4o
provider_server_address = 192.168.1.6:11434/v1
agent_name = Joey
provider_name = ollama
provider_model = deepseek-r1:14b
provider_server_address = 127.0.0.1:11434
agent_name = Friday
recover_last_session = False
save_session = False
speak = False

View File

@ -1,3 +1,5 @@
kokoro==0.9.4
certifi==2025.4.26
fastapi>=0.115.12
flask>=3.1.0
celery>=5.5.1
@ -18,10 +20,10 @@ torch>=2.4.1
python-dotenv>=1.0.0
ollama>=0.4.7
scipy>=1.9.3
kokoro>=0.7.12
soundfile>=0.13.1
protobuf>=3.20.3
termcolor>=2.4.0
pypdf>=5.4.0
ipython>=8.13.0
pyaudio>=0.2.14
librosa>=0.10.2.post1
@ -39,6 +41,7 @@ fake_useragent>=2.1.0
selenium_stealth>=1.0.6
undetected-chromedriver>=3.5.5
sentencepiece>=0.2.0
tqdm>4
openai
sniffio
tqdm>4
@ -46,5 +49,3 @@ python-dotenv>=1.0.0
# if use chinese
ordered_set
pypinyin
cn2an
jieba

View File

@ -123,6 +123,8 @@ class Agent():
"""
start_tag = "<think>"
end_tag = "</think>"
if text is None:
return None
start_idx = text.find(start_tag)
end_idx = text.rfind(end_tag)+8
return text[start_idx:end_idx]

View File

@ -151,7 +151,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. Do not ask for clarification.\n"
prompt = f"Failed to parse the tasks. Please write down your task followed by a json 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)

View File

@ -13,6 +13,8 @@ from fake_useragent import UserAgent
from selenium_stealth import stealth
import undetected_chromedriver as uc
import chromedriver_autoinstaller
import certifi
import ssl
import time
import random
import os
@ -28,6 +30,7 @@ from sources.utility import pretty_print, animate_thinking
from sources.logger import Logger
def get_chrome_path() -> str:
"""Get the path to the Chrome executable."""
if sys.platform.startswith("win"):

View File

@ -72,6 +72,8 @@ class Provider:
except ModuleNotFoundError as e:
raise ModuleNotFoundError(f"{str(e)}\nA import related to provider {self.provider_name} was not found. Is it installed ?")
except Exception as e:
if "try again later" in str(e).lower():
return f"{self.provider_name} server is overloaded. Please try again later."
if "refused" in str(e):
return f"Server {self.server_ip} seem offline. Unable to answer."
raise Exception(f"Provider {self.provider_name} failed: {str(e)}") from e
@ -214,7 +216,7 @@ class Provider:
"""
base_url = self.server_ip
if self.is_local:
raise Exception("Google Gemini is not available for local use.")
raise Exception("Google Gemini is not available for local use. Change config.ini")
client = OpenAI(api_key=self.api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
try:
@ -237,6 +239,8 @@ class Provider:
"""
from together import Together
client = Together(api_key=self.api_key)
if self.is_local:
raise Exception("Together AI is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
@ -257,6 +261,8 @@ class Provider:
Use deepseek api to generate text.
"""
client = OpenAI(api_key=self.api_key, base_url="https://api.deepseek.com")
if self.is_local:
raise Exception("Deepseek (API) is not available for local use. Change config.ini")
try:
response = client.chat.completions.create(
model="deepseek-chat",

View File

@ -9,7 +9,10 @@ from kokoro import KPipeline
from IPython.display import display, Audio
import soundfile as sf
from sources.utility import pretty_print, animate_thinking
if __name__ == "__main__":
from utility import pretty_print, animate_thinking
else:
from sources.utility import pretty_print, animate_thinking
class Speech():
"""
@ -140,6 +143,7 @@ class Speech():
return sentence
if __name__ == "__main__":
# TODO add info message for cn2an, jieba chinese related import
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
speech = Speech()
tosay_en = """

View File

@ -1,15 +1,14 @@
import sys
import os, sys
import re
from io import StringIO
import subprocess
if __name__ == "__main__":
from tools import Tools
from safety import is_unsafe
else:
from sources.tools.tools import Tools
from sources.tools.safety import is_unsafe
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
from sources.tools.safety import is_unsafe
class BashInterpreter(Tools):
"""

View File

@ -1,12 +1,12 @@
import subprocess
import os
import os, sys
import tempfile
import re
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class CInterpreter(Tools):
"""

View File

@ -1,12 +1,12 @@
import subprocess
import os
import os, sys
import tempfile
import re
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class GoInterpreter(Tools):
"""

View File

@ -1,12 +1,12 @@
import subprocess
import os
import os, sys
import tempfile
import re
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class JavaInterpreter(Tools):
"""

View File

@ -4,10 +4,10 @@ import os
import re
from io import StringIO
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class PyInterpreter(Tools):
"""

View File

@ -1,13 +1,12 @@
import os
import os, sys
import stat
import mimetypes
import configparser
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class FileFinder(Tools):
"""
@ -30,14 +29,46 @@ class FileFinder(Tools):
return file.read()
except Exception as e:
return f"Error reading file: {e}"
def read_arbitrary_file(self, file_path: str, file_type: str) -> str:
"""
Reads the content of a file with arbitrary encoding.
Args:
file_path (str): The path to the file to read
Returns:
str: The content of the file in markdown format
"""
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type:
if mime_type.startswith(('image/', 'video/', 'audio/')):
return "can't read file type: image, video, or audio files are not supported."
content_raw = self.read_file(file_path)
if "text" in file_type:
content = content_raw
elif "pdf" in file_type:
from pypdf import PdfReader
reader = PdfReader(file_path)
content = '\n'.join([pt.extract_text() for pt in reader.pages])
elif "binary" in file_type:
content = content_raw.decode('utf-8', errors='replace')
else:
content = content_raw
return content
def get_file_info(self, file_path: str) -> str:
"""
Gets information about a file, including its name, path, type, content, and permissions.
Args:
file_path (str): The path to the file
Returns:
str: A dictionary containing the file information
"""
if os.path.exists(file_path):
stats = os.stat(file_path)
permissions = oct(stat.S_IMODE(stats.st_mode))
file_type, _ = mimetypes.guess_type(file_path)
file_type = file_type if file_type else "Unknown"
content = self.read_file(file_path)
content = self.read_arbitrary_file(file_path, file_type)
result = {
"filename": os.path.basename(file_path),

View File

@ -1,13 +1,13 @@
import os
import os, sys
import requests
import dotenv
dotenv.load_dotenv()
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class FlightSearch(Tools):
def __init__(self, api_key: str = None):

View File

@ -1,12 +1,13 @@
import os
import os, sys
import requests
from urllib.parse import urljoin
from typing import Dict, Any, Optional
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
class MCP_finder(Tools):
"""

View File

@ -2,10 +2,10 @@ import requests
from bs4 import BeautifulSoup
import os
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from sources.tools.tools import Tools
class searxSearch(Tools):
def __init__(self, base_url: str = None):

View File

@ -14,13 +14,17 @@ For example:
print("Hello world")
```
This is then executed by the tool with its own class implementation of execute().
A tool is not just for code tool but also API, internet, etc..
A tool is not just for code tool but also API, internet search, MCP, etc..
"""
import sys
import os
import configparser
from abc import abstractmethod
if __name__ == "__main__": # if running as a script for individual testing
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from sources.logger import Logger
class Tools():

View File

@ -5,14 +5,8 @@ import dotenv
dotenv.load_dotenv()
if __name__ == "__main__":
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utility import animate_thinking, pretty_print
from tools import Tools
else:
from sources.tools.tools import Tools
from sources.utility import animate_thinking, pretty_print
from sources.tools.tools import Tools
from sources.utility import animate_thinking, pretty_print
"""
WARNING

View File

@ -17,13 +17,13 @@ class TestBrowserAgentParsing(unittest.TestCase):
# Test various link formats
test_text = """
Check this out: https://thriveonai.com/15-ai-startups-in-japan-to-take-note-of, and www.google.com!
Also try https://test.org/about?page=1, hey this one as well bro https://weatherstack.com/documentation.
Also try https://test.org/about?page=1, hey this one as well bro https://weatherstack.com/documentation/.
"""
expected = [
"https://thriveonai.com/15-ai-startups-in-japan-to-take-note-of",
"www.google.com",
"https://test.org/about?page=1",
"https://weatherstack.com/documentation"
"https://weatherstack.com/documentation",
]
result = self.agent.extract_links(test_text)
self.assertEqual(result, expected)