Add pre commit (#26)

This commit is contained in:
Lamont Huffman
2025-11-05 11:44:19 +08:00
committed by GitHub
parent 2164371e64
commit 30d86efbb3
33 changed files with 565 additions and 496 deletions

View File

@@ -1,9 +1,8 @@
# tests/agent_deep_research_test.py
import logging
# -*- coding: utf-8 -*-
import os
import shutil
import tempfile
from unittest.mock import Mock, AsyncMock, patch
from unittest.mock import Mock, AsyncMock, patch, MagicMock
import pytest
from agentscope.formatter import DashScopeChatFormatter
@@ -12,7 +11,9 @@ from agentscope.memory import InMemoryMemory
from agentscope.message import Msg
from agentscope.model import DashScopeChatModel
from deep_research.agent_deep_research.deep_research_agent import DeepResearchAgent
from deep_research.agent_deep_research.deep_research_agent import (
DeepResearchAgent,
)
from deep_research.agent_deep_research.main import main
@@ -70,12 +71,15 @@ class TestDeepResearchAgent:
def test_agent_initialization(
self,
mock_model,
mock_tavily_client,
temp_working_dir,
mock_model, # pylint: disable=redefined-outer-name
mock_tavily_client, # pylint: disable=redefined-outer-name
temp_working_dir, # pylint: disable=redefined-outer-name
):
"""Test agent initialization with valid parameters"""
with patch("asyncio.create_task"):
mock_loop = MagicMock()
mock_task = AsyncMock()
mock_loop.create_task = MagicMock(return_value=mock_task)
with patch("asyncio.get_running_loop", return_value=mock_loop):
agent = DeepResearchAgent(
name="Friday",
sys_prompt="You are a helpful assistant named Friday.",
@@ -87,17 +91,17 @@ class TestDeepResearchAgent:
)
assert agent.name == "Friday"
assert agent.sys_prompt.startswith("You are a helpful assistant named Friday.")
assert agent.sys_prompt.startswith(
"You are a helpful assistant named Friday.",
)
assert agent.tmp_file_storage_dir == temp_working_dir
assert os.path.exists(temp_working_dir)
@pytest.mark.asyncio
async def test_main_function_success(
self,
mock_env_vars,
mock_tavily_client,
mock_model,
temp_working_dir,
mock_tavily_client, # pylint: disable=redefined-outer-name
temp_working_dir, # pylint: disable=redefined-outer-name
):
"""Test main function with successful execution"""
with patch(
@@ -109,17 +113,26 @@ class TestDeepResearchAgent:
autospec=True,
) as mock_agent_class:
mock_agent = AsyncMock()
mock_agent.return_value = Msg("Friday", "Test response", "assistant")
mock_agent.return_value = Msg(
"Friday",
"Test response",
"assistant",
)
mock_agent_class.return_value = mock_agent
with patch("os.makedirs") as mock_makedirs:
with patch.dict(os.environ, {"AGENT_OPERATION_DIR": temp_working_dir}):
with patch.dict(
os.environ,
{"AGENT_OPERATION_DIR": temp_working_dir},
):
test_query = "Test research question"
msg = Msg("Bob", test_query, "user")
await main(test_query)
mock_makedirs.assert_called_once_with(temp_working_dir, exist_ok=True)
mock_makedirs.assert_called_once_with(
temp_working_dir,
exist_ok=True,
)
mock_agent_class.assert_called_once()
# ✅ Use assert_called_once() + manual argument check
@@ -138,8 +151,7 @@ class TestDeepResearchAgent:
@pytest.mark.asyncio
async def test_agent_cleanup(
self,
mock_env_vars,
mock_tavily_client,
mock_tavily_client, # pylint: disable=redefined-outer-name
):
"""Test proper cleanup of resources"""
with patch(
@@ -151,7 +163,10 @@ class TestDeepResearchAgent:
mock_tavily_client.close.assert_called_once()
def test_working_directory_creation(self, temp_working_dir):
def test_working_directory_creation(
self,
temp_working_dir, # pylint: disable=redefined-outer-name
):
"""Test working directory is created correctly"""
test_dir = os.path.join(temp_working_dir, "test_subdir")
os.makedirs(test_dir, exist_ok=True)
@@ -161,17 +176,28 @@ class TestDeepResearchAgent:
class TestErrorHandling:
"""Test suite for error handling scenarios"""
@pytest.mark.asyncio
async def test_filesystem_errors(self, mock_env_vars, mock_tavily_client):
async def test_filesystem_errors(
self,
mock_tavily_client, # pylint: disable=redefined-outer-name
):
"""Test handling of filesystem errors"""
with patch(
"deep_research.agent_deep_research.main.StdIOStatefulClient",
return_value=mock_tavily_client,
"deep_research.agent_deep_research.main.StdIOStatefulClient",
return_value=mock_tavily_client,
):
with patch.dict(os.environ, {"AGENT_OPERATION_DIR": "/invalid/path"}):
with patch("os.makedirs", side_effect=PermissionError("Permission denied")):
with patch.dict(
os.environ,
{"AGENT_OPERATION_DIR": "/invalid/path"},
):
with patch(
"os.makedirs",
side_effect=PermissionError("Permission denied"),
):
with pytest.raises(PermissionError):
await main("Test query")
if __name__ == "__main__":
pytest.main(["-v", __file__])
pytest.main(["-v", __file__])

View File

@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
import pytest
import asyncio
from typing import Dict, Any, AsyncGenerator
from typing import Dict
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from agentscope.message import Msg
from agentscope.tool import Toolkit
from agentscope.memory import MemoryBase
@@ -22,7 +21,10 @@ def mock_dependencies() -> Dict[str, MagicMock]:
@pytest.fixture
def agent(mock_dependencies: Dict[str, MagicMock]) -> BrowserAgent:
def agent(
# pylint: disable=redefined-outer-name
mock_dependencies: Dict[str, MagicMock],
) -> BrowserAgent:
return BrowserAgent(
name="TestBot",
model=mock_dependencies["model"],
@@ -36,17 +38,28 @@ def agent(mock_dependencies: Dict[str, MagicMock]) -> BrowserAgent:
# -----------------------------
# ✅ Hook registration verification (adapted for ReActAgentBase)
# -----------------------------
def test_hooks_registered(agent: BrowserAgent) -> None:
# Verify instance-level hooks
assert hasattr(agent, "_instance_pre_reply_hooks")
def test_hooks_registered(
agent: BrowserAgent, # pylint: disable=redefined-outer-name
) -> None:
"""Verify instance-level hooks are registered"""
# Disable pylint warning for protected member access
assert hasattr(
agent,
"_instance_pre_reply_hooks",
) # pylint: disable=protected-access
assert (
"browser_agent_default_url_pre_reply"
# pylint: disable=protected-access
in agent._instance_pre_reply_hooks
)
assert hasattr(agent, "_instance_pre_reasoning_hooks")
assert hasattr(
agent,
"_instance_pre_reasoning_hooks",
) # pylint: disable=protected-access
assert (
"browser_agent_observe_pre_reasoning"
# pylint: disable=protected-access
in agent._instance_pre_reasoning_hooks
)
@@ -55,15 +68,20 @@ def test_hooks_registered(agent: BrowserAgent) -> None:
# ✅ Navigation hook test (direct hook invocation)
# -----------------------------
@pytest.mark.asyncio
async def test_pre_reply_hook_navigation(agent: BrowserAgent) -> None:
async def test_pre_reply_hook_navigation(
agent: BrowserAgent, # pylint: disable=redefined-outer-name
) -> None:
# pylint: disable=protected-access
agent._has_initial_navigated = False
# Get instance-level hook function
# pylint: disable=protected-access
hook_func = agent._instance_pre_reply_hooks[
"browser_agent_default_url_pre_reply"
]
await hook_func(agent) # Directly invoke hook function
# pylint: disable=protected-access
assert agent._has_initial_navigated is True
assert agent.toolkit.call_tool_function.called
@@ -72,13 +90,17 @@ async def test_pre_reply_hook_navigation(agent: BrowserAgent) -> None:
# ✅ Snapshot hook test (fix content attribute access issue)
# -----------------------------
@pytest.mark.asyncio
async def test_observe_pre_reasoning(agent: BrowserAgent) -> None:
async def test_observe_pre_reasoning(
agent: BrowserAgent, # pylint: disable=redefined-outer-name
) -> None:
# Mock tool response (fix: use Msg object with content attribute)
mock_response = AsyncMock()
mock_response.__aiter__.return_value = [
Msg("system", [{"text": "Snapshot content"}], "system"),
]
agent.toolkit.call_tool_function = AsyncMock(return_value=mock_response)
agent.toolkit.call_tool_function = AsyncMock(
return_value=mock_response,
)
# Replace memory add method
with patch.object(
@@ -87,6 +109,7 @@ async def test_observe_pre_reasoning(agent: BrowserAgent) -> None:
new_callable=AsyncMock,
) as mock_add:
# Get instance-level hook function
# pylint: disable=protected-access
hook_func = agent._instance_pre_reasoning_hooks[
"browser_agent_observe_pre_reasoning"
]
@@ -100,7 +123,9 @@ async def test_observe_pre_reasoning(agent: BrowserAgent) -> None:
# -----------------------------
# ✅ Text filtering test (improved regex)
# -----------------------------
def test_filter_execution_text(agent: BrowserAgent) -> None:
def test_filter_execution_text(
agent: BrowserAgent, # pylint: disable=redefined-outer-name
) -> None:
text = """
### New console messages
Some console output
@@ -112,6 +137,7 @@ def test_filter_execution_text(agent: BrowserAgent) -> None:
```
Regular text content
"""
# pylint: disable=protected-access
filtered = agent._filter_execution_text(text)
assert "console output" not in filtered
@@ -124,7 +150,9 @@ def test_filter_execution_text(agent: BrowserAgent) -> None:
# ✅ Memory summarization test (already passing)
# -----------------------------
@pytest.mark.asyncio
async def test_memory_summarizing(agent: BrowserAgent) -> None:
async def test_memory_summarizing(
agent: BrowserAgent, # pylint: disable=redefined-outer-name
) -> None:
agent.memory.get_memory = AsyncMock(
return_value=[MagicMock(role="user", content="Original question")]
* 25,
@@ -136,6 +164,7 @@ async def test_memory_summarizing(agent: BrowserAgent) -> None:
content=[MagicMock(text="Summary text")],
)
# pylint: disable=protected-access
await agent._memory_summarizing()
assert agent.memory.clear.called

View File

@@ -1,20 +1,23 @@
# -*- coding: utf-8 -*-
import pytest
import asyncio
from unittest.mock import AsyncMock, MagicMock, patch
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import pytest_asyncio
from browser_use.browser_use_fullstack_runtime.backend.agentscope_browseruse_agent import (
AgentscopeBrowseruseAgent,
RunStatus,
)
from browser_use.browser_use_fullstack_runtime.backend.async_quart_service import (
app,
)
from quart.testing import QuartClient
from browser_use.browser_use_fullstack_runtime.backend import (
agentscope_browseruse_agent as agent_module,
)
from browser_use.browser_use_fullstack_runtime.backend import (
async_quart_service as service,
)
AgentscopeBrowseruseAgent = agent_module.AgentscopeBrowseruseAgent
RunStatus = agent_module.RunStatus
app = service.app
# -----------------------------
# 🧪 Singleton Test Configuration
@@ -31,13 +34,17 @@ def event_loop():
async def agent_singleton():
"""Session-scoped single instance of AgentscopeBrowseruseAgent"""
with patch(
"browser_use.browser_use_fullstack_runtime.backend.agentscope_browseruse_agent.SandboxService",
"browser_use.browser_use_fullstack_runtime."
"backend.agentscope_browseruse_agent.SandboxService",
) as MockSandboxService, patch(
"browser_use.browser_use_fullstack_runtime.backend.agentscope_browseruse_agent.InMemoryMemoryService",
"browser_use.browser_use_fullstack_runtime."
"backend.agentscope_browseruse_agent.InMemoryMemoryService",
) as MockMemoryService, patch(
"browser_use.browser_use_fullstack_runtime.backend.agentscope_browseruse_agent.InMemorySessionHistoryService",
"browser_use.browser_use_fullstack_runtime."
"backend.agentscope_browseruse_agent.InMemorySessionHistoryService",
) as MockHistoryService, patch(
"agentscope_runtime.sandbox.manager.container_clients.docker_client.docker",
"agentscope_runtime.sandbox.manager."
"container_clients.docker_client.docker",
) as mock_docker, patch(
"agentscope_runtime.sandbox.manager.sandbox_manager.SandboxManager",
) as MockSandboxManager:
@@ -88,16 +95,20 @@ async def test_app():
# ✅ AgentscopeBrowseruseAgent Singleton Tests
# -----------------------------
@pytest.mark.asyncio
async def test_agent_singleton_initialization(agent_singleton):
async def agent_singleton_singleton_initialization(
agent_singleton, # pylint: disable=redefined-outer-name
):
"""Test agent singleton initialization"""
agent = agent_singleton
agent = agent_singleton # pylint: disable=redefined-outer-name
assert isinstance(agent, AgentscopeBrowseruseAgent)
assert hasattr(agent, "agent")
assert hasattr(agent, "runner")
@pytest.mark.asyncio
async def test_chat_method(agent_singleton):
async def test_chat_method(
agent_singleton,
): # pylint: disable=redefined-outer-name
"""Test chat method handles messages"""
mock_request = {
"messages": [
@@ -108,20 +119,28 @@ async def test_chat_method(agent_singleton):
# ✅ Create mock object with object/status properties
mock_event = SimpleNamespace(
object="message",
status=RunStatus.Completed,
status=agent_module.RunStatus.Completed,
content=[{"type": "text", "text": "Test response"}],
)
with patch.object(agent_singleton.runner, "stream_query") as mock_stream:
with patch.object(
agent_singleton.runner, # pylint: disable=redefined-outer-name
"stream_query",
) as mock_stream:
# ✅ Return object with properties
async def mock_stream_query(*args, **kwargs):
async def mock_stream_query(*_args, **_kwargs):
yield mock_event
mock_stream.side_effect = mock_stream_query
responses = []
async for response in agent_singleton.chat(mock_request["messages"]):
async for response in agent_singleton.chat(
# pylint: disable=redefined-outer-name
mock_request["messages"],
):
responses.append(response)
assert len(responses) == 1
assert responses[0][0]["text"] == "Test response" # ✅ Fix property access
assert (
responses[0][0]["text"] == "Test response"
) # ✅ Fix property access

View File

@@ -1,264 +1,61 @@
from datetime import datetime, timezone
# -*- coding: utf-8 -*-
import os
import time
import tempfile
import pytest
from unittest.mock import MagicMock, patch
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
# Initialize db instance
db = SQLAlchemy()
import conversational_agents.chatbot_fullstack_runtime.backend.web_server as ws
# Define model classes (defined once)
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
name = db.Column(db.String(100), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
app = ws.app
_db = ws.db
User = ws.User
class Conversation(db.Model):
__tablename__ = "conversation"
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(
db.DateTime,
default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc),
def generate_unique_username():
return f"testuser_{int(time.time())}"
@pytest.fixture
def client_and_username():
"""Create an Isolated Test Client and Username"""
db_fd, db_path = tempfile.mkstemp(suffix=".db")
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_path}"
app.config["TESTING"] = True
client = app.test_client()
with app.app_context():
_db.drop_all()
_db.create_all()
# Generate Unique Username
username = generate_unique_username()
password = "testpass"
user = User(username=username, name="Test User")
user.set_password(password)
_db.session.add(user)
_db.session.commit()
yield client, username, password
os.close(db_fd)
os.unlink(db_path)
def test_user_login_success(
# pylint: disable=redefined-outer-name
client_and_username,
):
"""Test Successful User Login"""
client, username, password = client_and_username
response = client.post(
"/api/login",
json={
"username": username,
"password": password,
},
)
messages = db.relationship("Message", backref="conversation", lazy=True)
class Message(db.Model):
__tablename__ = "message"
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.Text, nullable=False)
sender = db.Column(db.String(20), nullable=False)
conversation_id = db.Column(db.Integer, db.ForeignKey("conversation.id"), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
# Thoroughly isolated test Flask application
@pytest.fixture
def app():
"""Create a fresh Flask application instance"""
app = Flask(__name__)
app.config.update({
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
"TESTING": True,
})
# Initialize db
db.init_app(app)
# Define routes
@app.route("/api/login", methods=["POST"])
def login():
data = request.get_json()
username = data.get("username")
password = data.get("password")
if not username or not password:
return jsonify({"error": "Username and password cannot be empty"}), 400
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
return jsonify({
"id": user.id,
"username": user.username,
"name": user.name,
"created_at": user.created_at.isoformat(),
}), 200
return jsonify({"error": "Invalid username or password"}), 401
@app.route("/api/users/<int:user_id>/conversations", methods=["POST"])
def create_conversation(user_id):
data = request.get_json()
title = data.get("title", f"Conversation {datetime.now().strftime('%Y-%m-%d %H:%M')}")
conversation = Conversation(title=title, user_id=user_id)
db.session.add(conversation)
db.session.commit()
return jsonify({
"id": conversation.id,
"title": conversation.title,
"user_id": conversation.user_id,
"created_at": conversation.created_at.isoformat(),
"updated_at": conversation.updated_at.isoformat(),
}), 201
@app.route("/api/conversations/<int:conversation_id>", methods=["GET"])
def get_conversation(conversation_id):
conversation = Conversation.query.get(conversation_id)
if not conversation:
return jsonify({"error": "Conversation not found"}), 404
messages = Message.query.filter_by(conversation_id=conversation_id).order_by(Message.created_at.asc()).all()
messages_data = [{
"id": msg.id,
"text": msg.text,
"sender": msg.sender,
"created_at": msg.created_at.isoformat(),
} for msg in messages]
return jsonify({
"id": conversation.id,
"title": conversation.title,
"user_id": conversation.user_id,
"messages": messages_data,
"created_at": conversation.created_at.isoformat(),
"updated_at": conversation.updated_at.isoformat(),
}), 200
@app.route("/api/conversations/<int:conversation_id>/messages", methods=["POST"])
def send_message(conversation_id):
conversation = Conversation.query.get(conversation_id)
if not conversation:
return jsonify({"error": "Conversation not found"}), 404
data = request.get_json()
text = data.get("text")
sender = data.get("sender", "user")
if not text:
return jsonify({"error": "Message content cannot be empty"}), 400
# Create user message
user_message = Message(
text=text,
sender=sender,
conversation_id=conversation_id
)
db.session.add(user_message)
# Update conversation title (if this is the first user message)
if sender == "user" and len(conversation.messages) <= 1:
conversation.title = text[:20] + ("..." if len(text) > 20 else "")
db.session.commit()
# Simulate AI response
ai_message = Message(
text="Test response part 1 Test response part 2",
sender="ai",
conversation_id=conversation_id
)
db.session.add(ai_message)
db.session.commit()
return jsonify({
"id": user_message.id,
"text": user_message.text,
"sender": user_message.sender,
"created_at": user_message.created_at.isoformat(),
}), 201
# Initialize database
with app.app_context():
db.create_all()
# Create example users
if not User.query.first():
user1 = User(username="user1", name="Bruce")
user1.set_password("password123")
db.session.add(user1)
db.session.commit()
yield app
with app.app_context():
db.drop_all()
db.session.remove()
@pytest.fixture
def client(app):
"""Flask test client"""
return app.test_client()
# Mock call_runner function
def mock_call_runner(query, session_id, user_id):
"""Mock function for call_runner"""
yield "Test response part 1"
yield " Test response part 2"
def test_login_success(app, client):
"""Test successful user login"""
with app.app_context():
user = User(username="test", name="Test User")
user.set_password("testpass")
db.session.add(user)
db.session.commit()
response = client.post("/api/login", json={
"username": "test",
"password": "testpass",
})
assert response.status_code == 200
data = response.get_json()
assert data["username"] == "test"
def test_login_invalid_credentials(app, client):
"""Test login with invalid credentials"""
response = client.post("/api/login", json={
"username": "test",
"password": "wrongpass"
})
assert response.status_code == 401
def test_conversation_crud_operations(app, client):
"""Test conversation creation and retrieval"""
with app.app_context():
user = User(username="test", name="Test User")
user.set_password("testpass")
db.session.add(user)
db.session.commit()
create_response = client.post("/api/users/1/conversations", json={
"title": "Test Conversation",
})
assert create_response.status_code == 201
conversation_id = create_response.get_json()["id"]
get_response = client.get(f"/api/conversations/{conversation_id}")
assert get_response.status_code == 200
assert "Test Conversation" in get_response.get_json()["title"]
@patch("tests.conversational_agents_chatbot_fullstack_runtime_webserver_test.db", new=db)
def test_send_message(app, client):
"""Test message sending and AI response"""
with app.app_context():
user = User(username="test", name="Test User")
user.set_password("testpass")
conversation = Conversation(title="Test", user_id=1)
db.session.add_all([user, conversation])
db.session.commit()
response = client.post("/api/conversations/1/messages", json={
"text": "Hello",
"sender": "user"
})
assert response.status_code == 201
data = response.get_json()
assert "id" in data
assert "Hello" in data["text"]
# ✅ Move the query into the application context
with app.app_context():
messages = Message.query.filter_by(conversation_id=1).all()
assert len(messages) == 2 # User + AI response
assert data["username"] == username

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import pytest
from unittest.mock import AsyncMock
import pytest
from agentscope.message import Msg
from agentscope.agent import ReActAgent
from agentscope.tool import Toolkit
@@ -12,13 +12,14 @@ class TestReActAgent:
@pytest.fixture
def test_agent(self):
"""Fixture to create a test ReAct agent with fully mocked dependencies"""
"""Fixture to create a test ReAct
agent with fully mocked dependencies"""
async def model_response(*args, **kwargs):
async def model_response():
yield Msg(
name="Friday",
content="Mocked model response",
role="assistant"
role="assistant",
)
mock_model = AsyncMock()
@@ -36,10 +37,12 @@ class TestReActAgent:
model=mock_model,
formatter=mock_formatter,
toolkit=Toolkit(),
memory=mock_memory
memory=mock_memory,
)
# pylint: disable=protected-access
agent._reasoning_hint_msgs = AsyncMock()
# pylint: disable=protected-access
agent._reasoning_hint_msgs.get_memory = AsyncMock(return_value=[])
return agent
@@ -47,16 +50,16 @@ class TestReActAgent:
async def test_exit_command(self, test_agent, monkeypatch):
"""Test exit command handling"""
async def exit_model_response(*args, **kwargs):
async def exit_model_response(*_args, **_kwargs):
yield Msg(
name="Friday",
content="exit",
role="assistant"
role="assistant",
)
test_agent.model.side_effect = exit_model_response
monkeypatch.setattr('builtins.input', lambda _: "exit")
monkeypatch.setattr("builtins.input", lambda _: "exit")
msg = Msg(name="User", content="exit", role="user")
response = await test_agent(msg)
@@ -66,11 +69,13 @@ class TestReActAgent:
async def test_conversation_flow(self, monkeypatch):
"""Test full conversation flow"""
async def model_response(*args, **kwargs):
async def model_response(*_args, **_kwargs):
yield Msg(
name="Friday",
content="Thought: I need to use a tool\nAction: execute_shell_command\nAction Input: echo 'Hello World'",
role="assistant"
content="Thought: I need to use a tool\n"
"Action: execute_shell_command\n"
"Action Input: echo 'Hello World'",
role="assistant",
)
mock_model = AsyncMock()
@@ -88,11 +93,11 @@ class TestReActAgent:
model=mock_model,
formatter=mock_formatter,
toolkit=Toolkit(),
memory=mock_memory
memory=mock_memory,
)
monkeypatch.setattr('builtins.input', lambda _: "Test command")
monkeypatch.setattr("builtins.input", lambda _: "Test command")
msg = Msg(name="User", content="Test command", role="user")
response = await agent(msg)
assert "Thought:" in response.content
assert "Thought:" in response.content

View File

@@ -1,5 +1,4 @@
# tests/evaluation_test.py
import asyncio
# -*- coding: utf-8 -*-
import os
from unittest.mock import Mock, AsyncMock, patch
from typing import List, Dict, Any, Tuple, Callable
@@ -29,19 +28,21 @@ class TestReActAgentSolution:
def mock_pre_hook(self) -> Mock:
"""Create a mock pre-hook function that returns None"""
def pre_hook_return(*args, **kwargs):
def pre_hook_return():
"""Mock function that returns None (no modifications)"""
return None
mock = Mock()
mock.__name__ = "save_logging"
mock.side_effect = pre_hook_return # ✅ Return None to avoid parameter pollution
mock.side_effect = (
pre_hook_return # ✅ Return None to avoid parameter pollution
)
return mock
def _create_mock_tools(self) -> List[Tuple[Callable, Dict[str, Any]]]:
"""Create mock tool functions with schemas"""
def mock_tool(*args, **kwargs):
def mock_tool():
return "tool_response"
tool_schema = {
@@ -110,8 +111,15 @@ class TestMainFunction:
mock_evaluator_class.return_value = mock_evaluator
# ✅ Simulate _download_data and _load_data
with patch("agentscope.evaluate._ace_benchmark._ace_benchmark.ACEBenchmark._download_data"):
with patch("agentscope.evaluate._ace_benchmark._ace_benchmark.ACEBenchmark._load_data", return_value=[]):
with patch(
"agentscope.evaluate._ace_benchmark."
"_ace_benchmark.ACEBenchmark._download_data",
):
with patch(
"agentscope.evaluate._ace_benchmark."
"_ace_benchmark.ACEBenchmark._load_data",
return_value=[],
):
# Run main function
await ace_main.main()
@@ -137,12 +145,19 @@ class TestMainFunction:
mock_evaluator_class.return_value = mock_evaluator
# ✅ Simulate _download_data and _load_data
with patch("agentscope.evaluate._ace_benchmark._ace_benchmark.ACEBenchmark._download_data"):
with patch("agentscope.evaluate._ace_benchmark._ace_benchmark.ACEBenchmark._load_data", return_value=[]):
with patch(
"agentscope.evaluate._ace_benchmark._ace_benchmark."
"ACEBenchmark._download_data",
):
with patch(
"agentscope.evaluate._ace_benchmark."
"_ace_benchmark.ACEBenchmark._load_data",
return_value=[],
):
# Run main function
await ace_main.main()
# Verify evaluation execution
mock_evaluator.run.assert_called_once_with(
ace_main.react_agent_solution,
)
)

View File

@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
import os
import asyncio
import pytest
from unittest.mock import AsyncMock, patch, MagicMock
import pytest
from agentscope.agent import ReActAgent
from agentscope.model import ChatModelBase
from agentscope.formatter import FormatterBase
@@ -47,9 +45,12 @@ async def test_witch_resurrect() -> None:
async def mock_model(**kwargs):
return {"resurrect": kwargs.get("resurrect", False)}
with patch("games.game_werewolves.game.WitchResurrectModel", side_effect=mock_model):
with patch(
"games.game_werewolves.game.WitchResurrectModel",
side_effect=mock_model,
):
result = await game.WitchResurrectModel(**{"resurrect": True})
assert result["resurrect"] == True
assert result["resurrect"] is True
# -----------------------------
@@ -84,8 +85,9 @@ def test_vote_model_generation() -> None:
name=f"Player{i}",
sys_prompt=f"Vote system prompt {i}",
model=mock_model,
formatter=mock_formatter
) for i in range(3)
formatter=mock_formatter,
)
for i in range(3)
]
VoteModel = structured_model.get_vote_model(agents)
@@ -105,10 +107,10 @@ def test_witch_poison_model_fields() -> None:
name="Player1",
sys_prompt="Poison system prompt",
model=mock_model,
formatter=mock_formatter
)
formatter=mock_formatter,
),
]
PoisonModel = structured_model.get_poison_model(agents)
assert "poison" in PoisonModel.model_fields
assert "name" in PoisonModel.model_fields
assert "name" in PoisonModel.model_fields