Merge branch 'Fosowl:main' into main
This commit is contained in:
@@ -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
|
||||
@@ -9,6 +9,7 @@ test_agent.py
|
||||
config.ini
|
||||
.voices/
|
||||
experimental/
|
||||
chrome_bundle/
|
||||
.logs/
|
||||
.screenshots/*.png
|
||||
.screenshots/*.jpg
|
||||
|
||||
@@ -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 @@ We’re 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user