Merge branch 'Fosowl:main' into main

This commit is contained in:
Thiago Martins
2025-05-29 17:40:38 -03:00
committed by GitHub
10 changed files with 297 additions and 2781 deletions
+19
View File
@@ -0,0 +1,19 @@
# Python cache files
__pycache__/
*.py[cod]
# Virtual environments
venv/
.venv/
# Environment variables (secrets)
.env
# Git metadata
.git/
# macOS Finder files
.DS_Store
# Log files
*.log
+1
View File
@@ -9,6 +9,7 @@ test_agent.py
config.ini
.voices/
experimental/
chrome_bundle/
.logs/
.screenshots/*.png
.screenshots/*.jpg
+6 -4
View File
@@ -32,7 +32,9 @@ https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.zip), are entirely fictional. We are not a corporation, we seek open-source contributors not candidates.
> 🛠️ **Work in Progress** Looking for contributors!
> 🛠⚠️ **Active Work in Progress** Please note that Code/Bash is not dockerized yet but will be soon (see docker_deployement branch) - Do not deploy over network or production.
> 🙏 This project started as a side-project with zero roadmap and zero funding. It's grown way beyond what I expected by ending in GitHub Trending. Contributions, feedback, and patience are deeply appreciated.
## Installation
@@ -552,8 +554,8 @@ Were looking for developers to improve AgenticSeek! Check out open issues or
## Maintainers:
> [Fosowl](https://github.com/Fosowl) | Paris Time | (Sometime busy)
> [Fosowl](https://github.com/Fosowl) | Paris Time
> [https://github.com/antoineVIVIES](antoineVIVIES) | Taipei Time | (Often busy)
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
> [steveh8758](https://github.com/steveh8758) | Taipei Time | (Always busy)
> [steveh8758](https://github.com/steveh8758) | Taipei Time
+3 -3
View File
@@ -564,8 +564,8 @@ DeepSeek R1 天生会说中文
## 维护者:
> [Fosowl](https://github.com/Fosowl) | 巴黎时间 | (有时很忙)
> [Fosowl](https://github.com/Fosowl) | 巴黎时间
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北时间 | (经常很忙)
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
> [steveh8758](https://github.com/steveh8758) | 台北时间 | (总是很忙)
> [steveh8758](https://github.com/steveh8758) | 台北时间
+1 -1
View File
@@ -495,4 +495,4 @@ Nous recherchons des développeurs pour améliorer AgenticSeek ! Consultez la se
## Mainteneurs:
> [Fosowl](https://github.com/Fosowl)
> [steveh8758](https://github.com/steveh8758)
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES)
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
+1 -1
View File
@@ -565,6 +565,6 @@ AgenticSeekを改善するための開発者を募集しています!オープ
> [Fosowl](https://github.com/Fosowl) | パリ時間
> [https://github.com/antoineVIVIES](antoineVIVIES) | 台北時間
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
> [steveh8758](https://github.com/steveh8758) | 台北時間 |(常に忙しい)
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -140,8 +140,10 @@ class Agent():
Remove the reasoning block of reasoning model like deepseek.
"""
end_tag = "</think>"
end_idx = text.rfind(end_tag)+8
return text[end_idx:]
end_idx = text.rfind(end_tag)
if end_idx == -1:
return text
return text[end_idx+8:]
def extract_reasoning_text(self, text: str) -> None:
"""
+32 -33
View File
@@ -14,7 +14,6 @@ from openai import OpenAI
from sources.logger import Logger
from sources.utility import pretty_print, animate_thinking
class Provider:
def __init__(self, provider_name, model, server_address="127.0.0.1:5000", is_local=False):
self.provider_name = provider_name.lower()
@@ -58,38 +57,6 @@ class Provider:
exit(1)
return api_key
def anthropic_fn(self, history, verbose=False):
"""
Use Anthropic to generate text.
"""
from anthropic import Anthropic
client = Anthropic(api_key=self.api_key)
system_message = None
messages = []
for message in history:
clean_message = {'role': message['role'], 'content': message['content']}
if message['role'] == 'system':
system_message = message['content']
else:
messages.append(clean_message)
try:
response = client.messages.create(
model=self.model,
max_tokens=1024,
messages=messages,
system=system_message
)
if response is None:
raise Exception("Anthropic response is empty.")
thought = response.content[0].text
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"Anthropic API error: {str(e)}") from e
def respond(self, history, verbose=True):
"""
Use the choosen provider to generate text.
@@ -255,6 +222,38 @@ class Provider:
except Exception as e:
raise Exception(f"OpenAI API error: {str(e)}") from e
def anthropic_fn(self, history, verbose=False):
"""
Use Anthropic to generate text.
"""
from anthropic import Anthropic
client = Anthropic(api_key=self.api_key)
system_message = None
messages = []
for message in history:
clean_message = {'role': message['role'], 'content': message['content']}
if message['role'] == 'system':
system_message = message['content']
else:
messages.append(clean_message)
try:
response = client.messages.create(
model=self.model,
max_tokens=1024,
messages=messages,
system=system_message
)
if response is None:
raise Exception("Anthropic response is empty.")
thought = response.content[0].text
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"Anthropic API error: {str(e)}") from e
def google_fn(self, history, verbose=False):
"""
Use google gemini to generate text.
+230
View File
@@ -0,0 +1,230 @@
import unittest
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from sources.tools.tools import Tools
class TestToolsParsing(unittest.TestCase):
"""
Test suite for the Tools class parsing functionality, specifically the load_exec_block method.
This method is responsible for extracting code blocks from LLM-generated text.
"""
def setUp(self):
"""Set up test fixtures before each test method."""
class TestTool(Tools):
def execute(self, blocks, safety=False):
return "test execution"
def execution_failure_check(self, output):
return False
def interpreter_feedback(self, output):
return "test feedback"
self.tool = TestTool()
self.tool.tag = "python" # Set tag for testing
def test_load_exec_block_single_block(self):
"""Test parsing a single code block from LLM text."""
llm_text = """Here's some Python code:
```python
print("Hello, World!")
x = 42
```
That's the code."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\nprint("Hello, World!")\nx = 42\n')
self.assertIsNone(save_path)
def test_load_exec_block_multiple_blocks(self):
"""Test parsing multiple code blocks from LLM text."""
llm_text = """First block:
```python
import os
print("First block")
```
Second block:
```python
import sys
print("Second block")
```
Done."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 2)
self.assertEqual(blocks[0], '\nimport os\nprint("First block")\n')
self.assertEqual(blocks[1], '\nimport sys\nprint("Second block")\n')
self.assertIsNone(save_path)
def test_load_exec_block_with_save_path(self):
"""Test parsing code block with save path specification."""
llm_text = """```python
save_path: test_file.py
import os
print("Hello with save path")
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\nsave_path: test_file.py\nimport os\nprint("Hello with save path")\n')
self.assertIsNone(save_path)
def test_load_exec_block_with_indentation(self):
"""Test parsing code blocks with leading whitespace/indentation."""
llm_text = """ Here's indented code:
```python
def hello():
print("Hello")
return True
```
End of code."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
expected_code = '\ndef hello():\n print("Hello")\n return True\n'
self.assertEqual(blocks[0], expected_code)
def test_load_exec_block_no_blocks(self):
"""Test parsing text with no code blocks."""
llm_text = """This is just regular text with no code blocks.
There are no python blocks here.
Just plain text."""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNone(blocks)
self.assertIsNone(save_path)
def test_load_exec_block_wrong_tag(self):
"""Test parsing text with code blocks but wrong language tag."""
llm_text = """```javascript
console.log("This is JavaScript, not Python");
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNone(blocks)
self.assertIsNone(save_path)
def test_load_exec_block_incomplete_block(self):
"""Test parsing text with incomplete code block (missing closing tag)."""
llm_text = """```python
print("This block has no closing tag")
x = 42"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertEqual(blocks, [])
self.assertIsNone(save_path)
def test_load_exec_block_empty_block(self):
"""Test parsing empty code block."""
llm_text = """```python
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
self.assertEqual(blocks[0], '\n')
def test_load_exec_block_mixed_content(self):
"""Test parsing text with mixed content including code blocks."""
llm_text = """Let me help you with that task.
First, I'll import the necessary modules:
```python
import os
import sys
```
Then I'll define a function:
```python
def process_data(data):
return data.upper()
```
Finally, let's use it:
```python
result = process_data("hello world")
print(result)
```
That should work!"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 3)
self.assertEqual(blocks[0], '\nimport os\nimport sys\n')
self.assertEqual(blocks[1], '\ndef process_data(data):\n return data.upper()\n')
self.assertEqual(blocks[2], '\nresult = process_data("hello world")\nprint(result)\n')
def test_load_exec_block_with_special_characters(self):
"""Test parsing code blocks containing special characters."""
llm_text = """```python
text = "Hello \"world\" with 'quotes'"
regex = r"^\\d+$"
path = "C:\\Users\\test\\file.txt"
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertIsNotNone(blocks)
self.assertEqual(len(blocks), 1)
expected = '\ntext = "Hello "world" with \'quotes\'"\nregex = r"^\\d+$"\npath = "C:\\Users\\test\\file.txt"\n'
self.assertEqual(blocks[0], expected)
def test_load_exec_block_tag_undefined(self):
"""Test that assertion error is raised when tag is undefined."""
self.tool.tag = "undefined"
llm_text = """```python
print("test")
```"""
with self.assertRaises(AssertionError):
self.tool.load_exec_block(llm_text)
def test_found_executable_blocks_flag(self):
"""Test that the executable blocks found flag is set correctly."""
self.assertFalse(self.tool.found_executable_blocks())
llm_text = """```python
print("test")
```"""
blocks, save_path = self.tool.load_exec_block(llm_text)
self.assertTrue(self.tool.found_executable_blocks())
self.assertFalse(self.tool.found_executable_blocks())
def test_get_parameter_value(self):
"""Test the get_parameter_value helper method."""
block = """param1 = value1
param2 = value2
some other text
param3 = value3"""
self.assertEqual(self.tool.get_parameter_value(block, "param1"), "value1")
self.assertEqual(self.tool.get_parameter_value(block, "param2"), "value2")
self.assertEqual(self.tool.get_parameter_value(block, "param3"), "value3")
self.assertIsNone(self.tool.get_parameter_value(block, "nonexistent"))
if __name__ == '__main__':
unittest.main()