merge
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.
|
||||
|
||||
> 🙏 Please also understand that this project began as a side experiment, with no roadmap and no expectations, we didn't expect to end in Github trending. Financial backing is exactly $1/month (shoutout to my single sponsor). Contributions, feedback, and patience are deeply appreciated.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
+47
-47
@@ -8,23 +8,23 @@
|
||||
[English](./README.md) | 繁體中文 | [日本語](./README_JP.md)
|
||||
|
||||
|
||||
*一个 **100% 本地替代 Manus AI** 的方案,这款支持语音的 AI 助理能够自主浏览网页、编写代码和规划任务,同时将所有数据保留在您的设备上。专为本地推理模型量身打造,完全在您自己的硬件上运行,确保完全的隐私保护和零云端依赖。*
|
||||
*一个 **100% 本地替代 Manus AI** 的方案,這款支持語音的 AI 助理能够自主瀏覽網頁、编寫代码和規劃任務,同时將所有用戶資料保留在您的裝置上。專門為本地推理模型量身打造,完全在您自己的硬體上執行,确保完全的隐私保护和零雲端依賴。*
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460)
|
||||
|
||||
### 为什么选择 AgenticSeek?
|
||||
### 为什么選擇 AgenticSeek?
|
||||
|
||||
* 🔒 完全本地化与隐私保护 - 所有功能都在您的设备上运行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
|
||||
* 🔒 完全本地化與隐私保护 - 所有功能都在您的设备上運行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
|
||||
|
||||
* 🌐 智能网页浏览 - AgenticSeek 能够自主浏览互联网 — 搜索、阅读、提取信息、填写网页表单 — 全程无需人工操作。
|
||||
* 🌐 智能網頁瀏覽 - AgenticSeek 能够自主瀏覽網頁 — 搜索、閱读、提取信息、填寫網页表單 — 全程无需人工操作。
|
||||
|
||||
* 💻 自主编码助手 - 需要代码?它可以编写、调试并运行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
|
||||
* 💻 自主编码助手 - 需要代码?它可以编寫、调试并運行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
|
||||
|
||||
* 🧠 智能代理选择 - 您提问,它会自动选择最适合该任务的代理。就像拥有一个随时待命的专家团队。
|
||||
* 🧠 智能代理选择 - 您提问,它會自动选择最适合该任务的代理。就像拥有一个随时待命的專家团队。
|
||||
|
||||
* 📋 规划与执行复杂任务 - 从旅行规划到复杂项目 — 它能将大型任务分解为步骤,并利用多个 AI 代理完成工作。
|
||||
* 📋 规划與执行复杂任务 - 从旅行规划到复杂项目 — 它能將大型任务分解为步骤,并利用多个 AI 代理完成工作。
|
||||
|
||||
* 🎙️ 语音功能 - 清晰、快速、未来感十足的语音与语音转文本功能,让您能像科幻电影中一样与您的个人 AI 助手对话。
|
||||
* 🎙️ 語音功能 - 清晰、快速、未来感十足的語音與語音轉文本功能,讓您能像科幻电影中一样與您的个人 AI 助手对话。
|
||||
|
||||
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||
|
||||
@@ -36,7 +36,7 @@ https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||
|
||||
確保已安裝了 Chrome driver,Docker 和 Python 3.10(或更新)。
|
||||
|
||||
我们强烈建议您使用 Python 3.10 进行设置,否则可能会发生依赖错误。
|
||||
我们强烈建议您使用 Python 3.10 進行設定,否则可能會发生依赖错误。
|
||||
|
||||
有關於 Chrome driver 的問題,請參見 **Chromedriver** 部分。
|
||||
|
||||
@@ -64,7 +64,7 @@ source agentic_seek_env/bin/activate
|
||||
./install.sh
|
||||
```
|
||||
|
||||
** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):**
|
||||
** 若要將文字轉成語音(TTS)功能支持中文,你需要安装 jieba(中文分詞庫)和 cn2an(中文數字轉換庫):**
|
||||
|
||||
```
|
||||
pip3 install jieba cn2an
|
||||
@@ -73,7 +73,7 @@ pip3 install jieba cn2an
|
||||
**手動安裝:**
|
||||
|
||||
|
||||
**注意:对于任何操作系统,请确保您安装的 ChromeDriver 与您已安装的 Chrome 版本匹配。运行 `google-chrome --version`。如果您的 Chrome 版本 > 135,请参阅已知问题**
|
||||
**注意:對於不同作業系統,請確保已經安装的 ChromeDriver 與您已安装的 Chrome 版本一致。可以執行 `google-chrome --version`。如果您的 Chrome 版本 > 135,請參考已知问题**
|
||||
|
||||
- *Linux*:
|
||||
|
||||
@@ -81,7 +81,7 @@ pip3 install jieba cn2an
|
||||
|
||||
安装依赖项:`sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
|
||||
|
||||
安装与您的 Chrome 浏览器版本匹配的 ChromeDriver:
|
||||
安装與您的 Chrome 瀏覽器版本匹配的 ChromeDriver:
|
||||
`sudo apt install -y chromium-chromedriver`
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
@@ -104,11 +104,11 @@ pip3 install jieba cn2an
|
||||
|
||||
安装 pyreadline3:`pip install pyreadline3`
|
||||
|
||||
手动安装 portaudio(例如,通过 vcpkg 或预编译的二进制文件),然后运行:`pip install pyaudio`
|
||||
手动安装 portaudio(例如,通过 vcpkg 或預編譯的二進制文件),然後運行:`pip install pyaudio`
|
||||
|
||||
从以下网址手动下载并安装 chromedriver:https://sites.google.com/chromium.org/driver/getting-started
|
||||
从以下網址手动下载并安装 chromedriver:https://sites.google.com/chromium.org/driver/getting-started
|
||||
|
||||
将 chromedriver 放置在包含在您的 PATH 中的目录中。
|
||||
將 chromedriver 放置在包含在您的 PATH 中的目录中。
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
@@ -116,45 +116,45 @@ pip3 install jieba cn2an
|
||||
|
||||
**建議至少使用 Deepseek 14B 以上參數的模型,較小的模型難以使用助理功能並且很快就會忘記上下文之間的關係。**
|
||||
|
||||
**本地运行助手**
|
||||
**本地運行助手**
|
||||
|
||||
启动你的本地提供者,例如使用 ollama:
|
||||
啟動你的本地提供者,例如使用 ollama:
|
||||
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
请参阅下方支持的本地提供者列表。
|
||||
请参閱下方支持的本地提供者列表。
|
||||
|
||||
修改 config.ini 文件以设置 provider_name 为支持的提供者,并将 provider_model 设置为该提供者支持的 LLM。我们推荐使用具有推理能力的模型,如 *Qwen* 或 *Deepseek*。
|
||||
修改 config.ini 文件以設定 provider_name 为支持的提供者,并將 provider_model 設定为该提供者支持的 LLM。我们推荐使用具有推理能力的模型,如 *Qwen* 或 *Deepseek*。
|
||||
|
||||
请参见 README 末尾的 **FAQ** 部分了解所需硬件。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True # 无论是在本地运行还是使用远程提供者。
|
||||
is_local = True # 无论是在本地運行还是使用远程提供者。
|
||||
provider_name = ollama # 或 lm-studio, openai 等..
|
||||
provider_model = deepseek-r1:14b # 选择适合您硬件的模型
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Jarvis # 您的 AI 助手的名称
|
||||
recover_last_session = True # 是否恢复之前的会话
|
||||
save_session = True # 是否记住当前会话
|
||||
speak = True # 文本转语音
|
||||
listen = False # 语音转文本,仅适用于命令行界面
|
||||
recover_last_session = True # 是否恢复之前的會话
|
||||
save_session = True # 是否记住当前會话
|
||||
speak = True # 文本轉語音
|
||||
listen = False # 語音轉文本,僅适用于命令行界面
|
||||
work_dir = /Users/mlg/Documents/workspace # AgenticSeek 的工作空间。
|
||||
jarvis_personality = False # 是否使用更"贾维斯"风格的性格,不推荐在小型模型上使用
|
||||
languages = en zh # 语言列表,文本转语音将默认使用列表中的第一种语言
|
||||
languages = en zh # 语言列表,文本轉語音將默认使用列表中的第一种语言
|
||||
[BROWSER]
|
||||
headless_browser = True # 是否使用无头浏览器,只有在使用网页界面时才推荐使用。
|
||||
stealth_mode = True # 使用无法检测的 selenium 来减少浏览器检测
|
||||
headless_browser = True # 是否使用无头瀏覽器,只有在使用網页界面时才推荐使用。
|
||||
stealth_mode = True # 使用无法檢測的 selenium 来减少瀏覽器檢測
|
||||
```
|
||||
|
||||
**本地提供者列表**
|
||||
|
||||
| 提供者 | 本地? | 描述 |
|
||||
|-------------|--------|-------------------------------------------------------|
|
||||
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地运行 LLM |
|
||||
| lm-studio | 是 | 使用 LM Studio 本地运行 LLM(将 `provider_name` 设置为 `lm-studio`)|
|
||||
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地運行 LLM |
|
||||
| lm-studio | 是 | 使用 LM Studio 本地運行 LLM(將 `provider_name` 設定为 `lm-studio`)|
|
||||
| openai | 否 | 使用兼容的 API |
|
||||
|
||||
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
@@ -184,14 +184,14 @@ provider_server_address = 127.0.0.1:5000
|
||||
---
|
||||
|
||||
## Start services and Run
|
||||
(启动服务并运行)
|
||||
(啟動服务并運行)
|
||||
|
||||
如果需要,请激活你的 Python 环境。
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
启动所需的服务。这将启动 `docker-compose.yml` 中的所有服务,包括:
|
||||
啟動所需的服务。这將啟動 `docker-compose.yml` 中的所有服务,包括:
|
||||
- searxng
|
||||
- redis(由 redis 提供支持)
|
||||
- 前端
|
||||
@@ -201,25 +201,25 @@ sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Windows
|
||||
```
|
||||
|
||||
**选项 1:** 使用 CLI 界面运行。
|
||||
**選項 1:** 使用 CLI 界面運行。
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
**选项 2:** 使用 Web 界面运行。
|
||||
**選項 2:** 使用 Web 界面運行。
|
||||
|
||||
注意:目前我們建議您使用 CLI 界面。Web 界面仍在積極開發中。
|
||||
|
||||
启动后端服务。
|
||||
啟動後端服务。
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
访问 `http://localhost:3000/`,你应该会看到 Web 界面。
|
||||
访问 `http://localhost:3000/`,你应该會看到 Web 界面。
|
||||
|
||||
请注意,目前 Web 界面不支持消息流式传输。
|
||||
请注意,目前 Web 界面不支持消息流式傳輸。
|
||||
|
||||
|
||||
*如果你不知道如何開始,請參閱 **Usage** 部分*
|
||||
@@ -228,9 +228,9 @@ python3 api.py
|
||||
|
||||
## Usage (使用方法)
|
||||
|
||||
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中设置语言选项。
|
||||
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中設定语言選項。
|
||||
languages = en zh
|
||||
更多信息请参阅 Config 部分
|
||||
更多信息请参閱 Config 部分
|
||||
|
||||
確定所有的核心檔案都啟用了,也就是執行過這條命令 `./start_services.sh` 然後你就可以使用 `python3 cli.py` 來啟動 AgenticSeek 了!
|
||||
|
||||
@@ -287,11 +287,11 @@ python3 cli.py
|
||||
所以我們希望你在使用時,能明確地表明你希望他要怎麼做,下面給你一個範例!
|
||||
|
||||
你該說:
|
||||
- 进行网络搜索,找出哪些国家最适合独自旅行
|
||||
- 進行網路搜索,找出哪些国家最适合獨自旅行
|
||||
|
||||
|
||||
而不是說:
|
||||
- 你知道哪些国家适合独自旅行?
|
||||
- 你知道哪些国家适合獨自旅行?
|
||||
|
||||
---
|
||||
|
||||
@@ -357,7 +357,7 @@ provider_server_address = x.x.x.x:3333
|
||||
|
||||
## 語音轉文字
|
||||
|
||||
请注意,目前语音转文字功能仅支持英语。
|
||||
请注意,目前語音轉文字功能僅支援英语。
|
||||
|
||||
預設狀況下,語音轉文字功能是停用的。若要啟用它,請在 `config.ini` 檔案中,將 `listen` 選項設為 `True`:
|
||||
|
||||
@@ -538,13 +538,13 @@ https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
**Q: 是否支持中文以外的语言?**
|
||||
|
||||
DeepSeek R1 天生会说中文
|
||||
DeepSeek R1 天生會说中文
|
||||
|
||||
但注意:代理路由系统只懂英文,所以必须通过 config.ini 的 languages 参数(如 languages = en zh)告诉系统:
|
||||
|
||||
如果不设置中文?后果可能是:你让它写代码,结果跳出来个"医生代理"(虽然我们根本没有这个代理... 但系统会一脸懵圈!)
|
||||
如果不設定中文?後果可能是:你讓它寫代码,结果跳出来个"醫生代理"(虽然我们根本没有这个代理... 但系统會一脸懵圈!)
|
||||
|
||||
实际上会下载一个小型翻译模型来协助任务分配
|
||||
实际上會下载一个小型翻译模型来协助任务分配
|
||||
|
||||
## 貢獻
|
||||
|
||||
@@ -556,8 +556,8 @@ DeepSeek R1 天生会说中文
|
||||
|
||||
## 维护者:
|
||||
|
||||
> [Fosowl](https://github.com/Fosowl) | 巴黎时间
|
||||
> [Fosowl](https://github.com/Fosowl) | 巴黎時間 | (有时很忙)
|
||||
|
||||
> [antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time
|
||||
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北時間 | (經常很忙)
|
||||
|
||||
> [steveh8758](https://github.com/steveh8758) | 台北时间
|
||||
> [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:
|
||||
"""
|
||||
|
||||
@@ -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