This commit is contained in:
CakeCN
2024-12-03 16:21:19 +08:00
commit 4198ca63b1
975 changed files with 333413 additions and 0 deletions

View File

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
"""
Unit tests for agent classes and functions
"""
import unittest
from agentscope.agents import AgentBase
class TestAgent(AgentBase):
"""An agent for test usage"""
def __init__(
self,
name: str,
sys_prompt: str = None,
**kwargs: dict,
) -> None:
super().__init__(
name=name,
sys_prompt=sys_prompt,
model_config_name=(
kwargs["model_config"] if "model_config" in kwargs else None
),
use_memory=(
kwargs["use_memory"] if "use_memory" in kwargs else None
),
memory_config=(
kwargs["memory_config"] if "memory_config" in kwargs else None
),
)
class TestAgentCopy(TestAgent):
"""A copy of testagent"""
class BasicAgentTest(unittest.TestCase):
"""Test cases for basic agents"""
def test_agent_init(self) -> None:
"""Test the init of agentbase sub-class."""
a1 = TestAgent(
"a",
"Hi",
use_memory=False, # type: ignore[arg-type]
attribute_1="hello world", # type: ignore[arg-type]
)
self.assertTupleEqual(
a1._init_settings["args"], # pylint: disable=W0212
(
"a",
"Hi",
),
)
self.assertDictEqual(
a1._init_settings["kwargs"], # pylint: disable=W0212
{"use_memory": False, "attribute_1": "hello world"},
)
a2 = TestAgent(
"b",
sys_prompt="Hello",
attribute_2="Bye", # type: ignore[arg-type]
)
self.assertTupleEqual(
a2._init_settings["args"], # pylint: disable=W0212
("b",),
)
self.assertDictEqual(
a2._init_settings["kwargs"], # pylint: disable=W0212
{"sys_prompt": "Hello", "attribute_2": "Bye"},
)
self.assertNotEqual(a1.agent_id, a2.agent_id)
self.assertTrue(a1.agent_id.startswith("TestAgent"))
self.assertTrue(a2.agent_id.startswith("TestAgent"))
a3 = TestAgentCopy("c")
self.assertTrue(a3.agent_id.startswith("TestAgentCopy"))
a4 = TestAgent(
"d",
)
a4._agent_id = "agent_id_for_d" # pylint: disable=W0212
self.assertEqual(a4.agent_id, "agent_id_for_d")

View File

@@ -0,0 +1,308 @@
# -*- coding: utf-8 -*-
"""Dashscope Multi-Modality Service Test."""
import os
import shutil
import unittest
from unittest.mock import patch, MagicMock, mock_open
from agentscope.service import ServiceResponse, ServiceExecStatus
from agentscope.service import (
dashscope_image_to_text,
dashscope_text_to_image,
dashscope_text_to_audio,
)
class TestDashScopeServices(unittest.TestCase):
"""Test DashScope Multi-Modality Services."""
def setUp(self) -> None:
"""Set up the test."""
self.save_dir = "./test_dir/"
def tearDown(self) -> None:
"""Tear down the test."""
# Remove the test directory
if os.path.exists(self.save_dir):
shutil.rmtree(self.save_dir)
@patch(
"agentscope.service.multi_modality.dashscope_services.os.path.abspath",
)
@patch(
"agentscope.service.multi_modality.dashscope_services._download_file",
)
@patch(
"agentscope.service.multi_modality.dashscope_services."
"DashScopeImageSynthesisWrapper",
)
def test_dashscope_text_to_image(
self,
mock_wrapper_cls: MagicMock,
mock_download_file: MagicMock,
mock_abspath: MagicMock,
) -> None:
"""Test DashScope Image to Text Service."""
# Configure the mocks
mock_instance = MagicMock()
mock_wrapper_cls.return_value = mock_instance
mock_response = MagicMock()
mock_response.image_urls = [
"https://xx/RESULT_URL1.png",
"https://xx/RESULT_URL2.png",
"https://xx/RESULT_URL3.png",
"https://xx/RESULT_URL4.png",
]
mock_instance.return_value = mock_response
mock_download_file.return_value = None
mock_abspath.side_effect = lambda x: f"/abc/{x}"
# Call the function under test
prompt = "fake-query-prompt"
api_key = "fake-api"
number_of_images = 4
size = "1024x1024"
model = "fake-model"
save_dir = "./test_dir/"
results = dashscope_text_to_image(
prompt,
api_key,
number_of_images,
size,
model,
save_dir,
)
# Expected result
expected_content = {
"image_urls": [
f"/abc/{self.save_dir[:-1]}/RESULT_URL1.png",
f"/abc/{self.save_dir[:-1]}/RESULT_URL2.png",
f"/abc/{self.save_dir[:-1]}/RESULT_URL3.png",
f"/abc/{self.save_dir[:-1]}/RESULT_URL4.png",
],
}
self.assertEqual(results.status, ServiceExecStatus.SUCCESS)
self.assertEqual(results.content, expected_content)
@patch(
(
"agentscope.service.multi_modality.dashscope_services."
"DashScopeImageSynthesisWrapper"
),
)
@patch("agentscope.service.multi_modality.dashscope_services.os.makedirs")
@patch(
"agentscope.service.multi_modality.dashscope_services.os.path.exists",
)
def test_dashscope_text_to_image_failure(
self,
mock_os_path_exists: MagicMock,
mock_os_makedirs: MagicMock,
mock_wrapper_cls: MagicMock,
) -> None:
"""Test DashScope Image to Text Service failure."""
# Configure the mocks
mock_os_path_exists.return_value = False
mock_instance = mock_wrapper_cls.return_value
mock_instance.return_value.image_urls = (
None # Simulate failure by not returning URLs
)
# Call the function under test
prompt = "fake-query-prompt"
api_key = "fake-api"
results = dashscope_text_to_image(prompt, api_key)
# Verify the wrapper call
mock_wrapper_cls.assert_called_once_with(
config_name="dashscope-text-to-image-service",
model_name="wanx-v1",
api_key=api_key,
)
mock_instance.assert_called_once_with(
prompt=prompt,
n=1,
size="1024*1024",
)
# Verify no directory creation for failure
mock_os_makedirs.assert_not_called()
# Expected result
expected_result = ServiceResponse(
status=ServiceExecStatus.ERROR,
content="Error: Failed to generate images",
)
self.assertEqual(results.status, expected_result.status)
self.assertEqual(results.content, expected_result.content)
@patch(
(
"agentscope.service.multi_modality.dashscope_services."
"DashScopeMultiModalWrapper"
),
)
@patch(
"agentscope.service.multi_modality.dashscope_services.os.path.abspath",
)
def test_dashscope_image_to_text_success(
self,
mock_abspath: MagicMock,
mock_wrapper_cls: MagicMock,
) -> None:
"""Test successful image to text conversion."""
# Configure the mocks
mock_abspath.side_effect = lambda x: f"/abs/path/{x}"
mock_instance = mock_wrapper_cls.return_value
mock_response = MagicMock()
mock_response.text = "A beautiful sunset in the mountains"
mock_instance.return_value = mock_response
# Call the function under test
image_urls = ("image1.jpg", "https://example.com/image2.jpg")
prompt = "Describe the image"
api_key = "fake-api"
model = "qwen-vl-plus"
results = dashscope_image_to_text(image_urls, api_key, prompt, model)
# Verify the wrapper call
mock_wrapper_cls.assert_called_once_with(
config_name="dashscope-image-to-text-service",
model_name=model,
api_key=api_key,
)
mock_instance.assert_called_once()
# Expected result
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content="A beautiful sunset in the mountains",
)
self.assertEqual(results.status, expected_result.status)
self.assertEqual(results.content, expected_result.content)
@patch(
(
"agentscope.service.multi_modality.dashscope_services."
"DashScopeMultiModalWrapper"
),
)
@patch(
"agentscope.service.multi_modality.dashscope_services.os.path.abspath",
)
def test_dashscope_image_to_text_failure(
self,
mock_abspath: MagicMock,
mock_wrapper_cls: MagicMock,
) -> None:
"""Test failure in image to text conversion."""
# Configure the mocks
mock_abspath.side_effect = lambda x: f"/abs/path/{x}"
mock_instance = mock_wrapper_cls.return_value
mock_instance.return_value.text = (
None # Simulate failure by returning None
)
# Call the function under test
image_urls = "image1.jpg"
prompt = "Describe the image"
api_key = "fake-api"
model = "qwen-vl-plus"
results = dashscope_image_to_text(image_urls, api_key, prompt, model)
# Verify the wrapper call
mock_wrapper_cls.assert_called_once_with(
config_name="dashscope-image-to-text-service",
model_name=model,
api_key=api_key,
)
mock_instance.assert_called_once()
# Expected result
expected_result = ServiceResponse(
status=ServiceExecStatus.ERROR,
content="Error: Failed to generate text",
)
self.assertEqual(results.status, expected_result.status)
self.assertEqual(results.content, expected_result.content)
@patch(
(
"agentscope.service.multi_modality.dashscope_services."
"SpeechSynthesizer"
),
)
@patch("agentscope.service.multi_modality.dashscope_services.os.makedirs")
@patch(
"agentscope.service.multi_modality.dashscope_services.os.path.exists",
)
@patch("builtins.open", new_callable=mock_open)
def test_dashscope_text_to_audio_success(
self,
mock_open_func: MagicMock,
mock_os_path_exists: MagicMock,
mock_os_makedirs: MagicMock,
mock_synthesizer_cls: MagicMock,
) -> None:
"""Test successful text to audio conversion."""
# Configure the mocks
mock_os_path_exists.return_value = False
mock_instance = mock_synthesizer_cls.return_value
mock_response = MagicMock()
mock_response.get_audio_data.return_value = b"fake_audio_data"
mock_instance.return_value = mock_response
# Call the function under test
text = "hello?"
api_key = "fake-api-key"
model = "sambert-zhichu-v1"
sample_rate = 48000
saved_dir = "./audio"
results = dashscope_text_to_audio(
text,
api_key,
saved_dir,
model,
sample_rate,
)
# Verify the wrapper call
mock_synthesizer_cls.call.assert_called_once_with(
model=model,
text=text,
sample_rate=sample_rate,
format="wav",
)
# Verify the file operations
mock_os_makedirs.assert_called_once_with(saved_dir, exist_ok=True)
mock_open_func.assert_called_once()
# Expected result
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content={"audio_path": f"{saved_dir}/{text}.wav"},
)
self.assertEqual(results.status, expected_result.status)
self.assertIn(
results.content,
[
{"audio_path": f"{saved_dir}/{text}.wav"},
{"audio_path": f"{saved_dir}\\{text}.wav"}, # For Windows
],
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,350 @@
# -*- coding: utf-8 -*-
"""dashscope test"""
import unittest
from unittest.mock import patch, MagicMock
from agentscope.models import (
ModelResponse,
DashScopeChatWrapper,
DashScopeImageSynthesisWrapper,
DashScopeTextEmbeddingWrapper,
DashScopeMultiModalWrapper,
)
class TestDashScopeChatWrapper(unittest.TestCase):
"""Test DashScope Chat Wrapper"""
def setUp(self) -> None:
self.config_name = "test_config"
self.model_name = "test_model"
self.api_key = "test_api_key"
self.wrapper = DashScopeChatWrapper(
config_name=self.config_name,
model_name=self.model_name,
api_key=self.api_key,
)
@patch("agentscope.models.dashscope_model.dashscope.Generation.call")
def test_call_success(self, mock_generation_call: MagicMock) -> None:
"""Test call success"""
# Set up the mock response for a successful API call
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.request_id = "test_request_id"
mock_response.usage = {
"input_tokens": 3,
"output_tokens": 5,
"total_tokens": 8,
}
mock_response.output = {
"choices": [{"message": {"content": "Hello, world!"}}],
}
mock_generation_call.return_value = mock_response
# Define test input
messages = [
{"role": "user", "content": "Hi!"},
{"role": "assistant", "content": "Hello!"},
]
# Call the wrapper method
response = self.wrapper(messages)
# Verify the response
self.assertIsInstance(response, ModelResponse)
self.assertEqual(response.text, "Hello, world!")
self.assertEqual(response.raw, mock_response)
# Verify call to dashscope.Generation.call
mock_generation_call.assert_called_once_with(
model=self.model_name,
messages=messages,
result_format="message",
)
@patch("agentscope.models.dashscope_model.dashscope.Generation.call")
def test_call_failure(self, mock_generation_call: MagicMock) -> None:
"""test call failure"""
# Set up the mock response for a failed API call
mock_response = MagicMock()
mock_response.status_code = "400"
mock_response.request_id = "Test_request_id"
mock_response.code = "Error Code"
mock_response.message = "Error Message"
mock_generation_call.return_value = mock_response
# Define test input
messages = [
{"role": "user", "content": "Hi!"},
{"role": "assistant", "content": "Hello!"},
]
# Call the wrapper method and expect an exception
with self.assertRaises(RuntimeError) as context:
self.wrapper(messages)
# Assert the expected exception message contains the error details
self.assertIn("Error Code", str(context.exception))
self.assertIn("Error Message", str(context.exception))
self.assertIn("400", str(context.exception))
self.assertIn("Test_request_id", str(context.exception))
# Verify call to dashscope.Generation.call
mock_generation_call.assert_called_once_with(
model=self.model_name,
messages=messages,
result_format="message",
)
class TestDashScopeImageSynthesisWrapper(unittest.TestCase):
"""Test DashScope Image Synthesis Wrapper"""
def setUp(self) -> None:
self.config_name = "config_name"
self.model_name = "test_model"
self.api_key = "test_api_key"
self.wrapper = DashScopeImageSynthesisWrapper(
config_name=self.config_name,
model_name=self.model_name,
api_key=self.api_key,
)
@patch(
"agentscope.file_manager.file_manager.save_image",
side_effect=lambda x: f'/local/path/{x.split("/")[-1]}',
)
@patch("agentscope.models.dashscope_model.dashscope.ImageSynthesis.call")
def test_image_synthesis_wrapper_call_success(
self,
mock_call: MagicMock,
mock_save_image: MagicMock,
) -> None:
"""Test call success"""
# Set up the mock response for a successful API call
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.output = {
"results": [{"url": "http://example.com/image.jpg"}],
}
mock_call.return_value = mock_response
# Call the wrapper with prompt
prompt = "Generate an image of a sunset"
response = self.wrapper(prompt, save_local=False)
# Check if response is an instance of ModelResponse and contains
# expected data
self.assertIsInstance(response, ModelResponse)
self.assertEqual(
response.image_urls,
["http://example.com/image.jpg"],
)
# Call the wrapper method with save_local set to True
response_with_save = self.wrapper(prompt, save_local=True)
# Verify save_image call and local image url in response
mock_save_image.assert_called_with("http://example.com/image.jpg")
self.assertEqual(
response_with_save.image_urls,
["/local/path/image.jpg"],
)
@patch("agentscope.models.dashscope_model.dashscope.ImageSynthesis.call")
def test_image_synthesis_wrapper_call_failure(
self,
mock_call: MagicMock,
) -> None:
"""Test call failure"""
# Set up the mock response for a failed API call
mock_response = MagicMock()
mock_response.status_code = 400
mock_response.request_id = "Test_request_id"
mock_response.code = "Error Code"
mock_response.message = "Error Message"
mock_call.return_value = mock_response
# Call the wrapper with prompt and expect a RuntimeError
prompt = "Generate an image of a sunset"
with self.assertRaises(RuntimeError) as context:
self.wrapper(prompt, save_local=False, n=1)
# Assert the expected exception message
self.assertIn("Error Code", str(context.exception))
self.assertIn("Error Message", str(context.exception))
self.assertIn("Test_request_id", str(context.exception))
self.assertIn("400", str(context.exception))
# Verify call to dashscope.ImageSynthesis.call
mock_call.assert_called_once_with(
model=self.model_name,
prompt=prompt,
n=1, # Assuming this is a default value used to call the API
)
class TestDashScopeTextEmbeddingWrapper(unittest.TestCase):
"""Test DashScope Text Embedding Wrapper"""
def setUp(self) -> None:
# Initialize DashScopeTextEmbeddingWrapper instance
self.wrapper = DashScopeTextEmbeddingWrapper(
config_name="test_config",
model_name="test_model",
api_key="test_key",
)
@patch("agentscope.models.dashscope_model.dashscope.TextEmbedding.call")
def test_call_success(self, mock_call: MagicMock) -> None:
"""Test call success"""
# Mock a successful API response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.usage = {
"total_tokens": 8,
}
mock_response.output = {
"embeddings": [{"embedding": [0.1, 0.2, 0.3]}],
}
mock_call.return_value = mock_response
# Call the wrapper with a mock API
texts = ["Hello, world!"]
response = self.wrapper(texts)
# Assert the API was called correctly
mock_call.assert_called_once_with(
input=texts,
model=self.wrapper.model_name,
**self.wrapper.generate_args,
)
# Assert the response is as expected
self.assertEqual(response.embedding, [[0.1, 0.2, 0.3]])
@patch("agentscope.models.dashscope_model.dashscope.TextEmbedding.call")
def test_call_failure(self, mock_call: MagicMock) -> None:
"""Test call failure"""
# Mock a failed API response
mock_response = MagicMock()
mock_response.status_code = 400
mock_response.request_id = "Test_request_id"
mock_response.code = "Error Code"
mock_response.message = "Error Message"
mock_call.return_value = mock_response
# Call the wrapper with a mock API and expect an exception
texts = ["Hello, world!"]
with self.assertRaises(RuntimeError) as context:
self.wrapper(texts)
# Assert the expected exception message
self.assertIn("Error Code", str(context.exception))
self.assertIn("Error Message", str(context.exception))
self.assertIn("Test_request_id", str(context.exception))
self.assertIn("400", str(context.exception))
# Verify call to dashscope.TextEmbedding.call
mock_call.assert_called_once_with(
input=texts,
model=self.wrapper.model_name,
**self.wrapper.generate_args,
)
class TestDashScopeMultiModalWrapper(unittest.TestCase):
"""Test DashScope MultiModal Wrapper"""
def setUp(self) -> None:
# Initialize DashScopeMultiModalWrapper instance
self.wrapper = DashScopeMultiModalWrapper(
config_name="test_config",
model_name="test_model",
api_key="test_key",
)
@patch(
"agentscope.models.dashscope_model."
"dashscope.MultiModalConversation.call",
)
def test_call_success(self, mock_call: MagicMock) -> None:
"""Test call success"""
# Mocking the response from the API
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.output = {
"choices": [
{"message": {"content": [{"text": "This is the result."}]}},
],
}
mock_response.usage = {
"input_tokens": 23,
"output_tokens": 5,
"image_tokens": 17,
}
mock_call.return_value = mock_response
messages = [
{
"role": "user",
"content": [
{"text": "What does this picture depict?"},
{"image": "http://example.com/image.jpg"},
],
},
]
# Calling the wrapper and validating the response
response = self.wrapper(messages=messages)
self.assertIsInstance(response, ModelResponse)
self.assertEqual(response.text, "This is the result.")
self.assertEqual(response.raw, mock_response)
# Verify call to dashscope.MultiModalConversation.call
mock_call.assert_called_once_with(
model=self.wrapper.model_name,
messages=messages,
)
@patch(
"agentscope.models.dashscope_model."
"dashscope.MultiModalConversation.call",
)
def test_call_failure(self, mock_call: MagicMock) -> None:
"""Test call failure"""
# Simulating a failed API call
mock_response = MagicMock()
mock_response.status_code = 400
mock_response.request_id = "Test_request_id"
mock_response.code = "Error Code"
mock_response.message = "Error Message"
mock_call.return_value = mock_response
messages = [
{
"role": "user",
"content": [
{"text": "What does this picture depict?"},
{"image": "http://example.com/image.jpg"},
],
},
]
# Expecting a RuntimeError to be raised
with self.assertRaises(RuntimeError) as context:
self.wrapper(messages=messages)
# Assert the expected exception message
self.assertIn("Error Code", str(context.exception))
self.assertIn("Error Message", str(context.exception))
self.assertIn("Test_request_id", str(context.exception))
self.assertIn("400", str(context.exception))
# Verify call to dashscope.MultiModalConversation.call
mock_call.assert_called_once_with(
model=self.wrapper.model_name,
messages=messages,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
""" Example for a unit test."""
import unittest
class ExampleTest(unittest.TestCase):
"""
ExampleTest for a unit test.
"""
def setUp(self) -> None:
"""Init for ExampleTest."""
self.num_a = 1
self.num_b = 0
def test_dummy(self) -> None:
"""Dummy test."""
self.assertGreater(self.num_a, self.num_b)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
""" Python code execution test."""
import unittest
import sys
from agentscope.service import execute_python_code
class ExecutePythonCodeTest(unittest.TestCase):
"""
Python code execution test.
"""
def setUp(self) -> None:
"""Init for ExecutePythonCodeTest."""
# Basic expression
self.arg0 = {"code": "print('Hello World')", "timeout": 5}
# Raising Exceptions
self.arg1 = {
"code": "print('Hello World')\nraise ValueError('An intentional "
"error')",
"timeout": 5,
}
# Using External Libraries
self.arg2 = {"code": "import math\nprint(math.sqrt(16))", "timeout": 5}
# Timeout
self.arg3 = {
"code": "import time\nprint('Hello World')\ntime.sleep("
"10)\nprint('This will not print')",
"timeout": 1,
}
# No input code
self.arg4 = {"code": "", "timeout": 5}
def run_test(
self,
args: dict,
expected_output: str,
expected_error_substr: str,
) -> None:
"""A helper function to avoid code repetition"""
response = execute_python_code(
use_docker=False,
**args,
)
self.assertIn(expected_output, response.content)
self.assertIn(expected_error_substr, response.content)
# Uncomment it when test in local
# response = execute_python_code(
# use_docker=True,
# **args,
# )
# self.assertIn(expected_output, response.content)
# self.assertIn(expected_error_substr, response.content)
def test_basic_expression(self) -> None:
"""Execute basic expression test."""
self.run_test(self.arg0, "Hello World\n", "")
def test_raising_exceptions(self) -> None:
"""Execute raising exceptions test."""
self.run_test(
self.arg1,
"Hello World\n",
"ValueError: An intentional error\n",
)
def test_using_external_libs(self) -> None:
"""Execute using external libs test."""
self.run_test(self.arg2, "4.0\n", "")
def test_timeout(self) -> None:
"""Execute timeout test (NOT available in WinOS.)"""
if sys.platform == "win32":
return
self.run_test(self.arg3, "Hello World\n", "timed out\n")
def test_no_input_code(self) -> None:
"""Execute no input code test."""
self.run_test(self.arg4, "", "")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
""" Python code execution test."""
import unittest
import platform
from agentscope.service import execute_shell_command
from agentscope.service import ServiceExecStatus
class ExecuteShellCommandTest(unittest.TestCase):
"""
Python code execution test.
"""
def setUp(self) -> None:
"""Init for ExecuteShellCommandTest."""
# Basic expression
self.arg0 = "touch tmp_a.text"
self.arg1 = "echo 'Helloworld' >> tmp_a.txt"
self.arg2 = "cat tmp_a.txt"
self.arg3 = "rm tmp_a.txt"
def test(self) -> None:
"""test command, skip on windows"""
if platform.system() == "Windows":
return
result = execute_shell_command(
command=self.arg0,
)
assert result.status == ServiceExecStatus.SUCCESS
assert result.content == "Success."
result = execute_shell_command(
command=self.arg1,
)
assert result.status == ServiceExecStatus.SUCCESS
assert result.content == "Success."
result = execute_shell_command(
command=self.arg2,
)
assert result.status == ServiceExecStatus.SUCCESS
assert result.content == "Helloworld"
result = execute_shell_command(
command=self.arg3,
)
assert result.status == ServiceExecStatus.SUCCESS
assert result.content == "Success."
result = execute_shell_command(
command=self.arg3,
)
assert result.status == ServiceExecStatus.ERROR
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,503 @@
# -*- coding: utf-8 -*-
"""Unit test for prompt engineering strategies in format function."""
import unittest
from unittest import mock
from unittest.mock import MagicMock, patch
from agentscope.message import Msg
from agentscope.models import (
OpenAIChatWrapper,
OllamaChatWrapper,
OllamaGenerationWrapper,
GeminiChatWrapper,
ZhipuAIChatWrapper,
DashScopeChatWrapper,
DashScopeMultiModalWrapper,
LiteLLMChatWrapper,
)
class ExampleTest(unittest.TestCase):
"""
ExampleTest for a unit test.
"""
def setUp(self) -> None:
"""Init for ExampleTest."""
self.inputs = [
Msg("system", "You are a helpful assistant", role="system"),
[
Msg("user", "What is the weather today?", role="user"),
Msg("assistant", "It is sunny today", role="assistant"),
],
]
self.inputs_vision = [
Msg("system", "You are a helpful assistant", role="system"),
[
Msg(
"user",
"Describe the images",
role="user",
url="https://fakeweb/test.jpg",
),
Msg(
"user",
"And this images",
"user",
url=[
"/Users/xxx/abc.png",
"/Users/xxx/def.mp3",
],
),
],
]
self.wrong_inputs = [
Msg("system", "You are a helpful assistant", role="system"),
[
"What is the weather today?",
Msg("assistant", "It is sunny today", role="assistant"),
],
]
@patch("builtins.open", mock.mock_open(read_data=b"abcdef"))
@patch("os.path.isfile")
@patch("os.path.exists")
@patch("openai.OpenAI")
def test_openai_chat_vision_with_wrong_model(
self,
mock_client: MagicMock,
mock_exists: MagicMock,
mock_isfile: MagicMock,
) -> None:
"""Unit test for the format function in openai chat api wrapper with
vision models"""
mock_exists.side_effect = lambda url: url == "/Users/xxx/abc.png"
mock_isfile.side_effect = lambda url: url == "/Users/xxx/abc.png"
# Prepare the mock client
mock_client.return_value = "client_dummy"
model = OpenAIChatWrapper(
config_name="",
model_name="gpt-4",
)
# correct format
ground_truth = [
{
"role": "system",
"content": "You are a helpful assistant",
"name": "system",
},
{
"role": "user",
"name": "user",
"content": "Describe the images",
},
{
"role": "user",
"name": "user",
"content": "And this images",
},
]
prompt = model.format(*self.inputs_vision)
self.assertListEqual(prompt, ground_truth)
@patch("builtins.open", mock.mock_open(read_data=b"abcdef"))
@patch("os.path.isfile")
@patch("os.path.exists")
@patch("openai.OpenAI")
def test_openai_chat_vision(
self,
mock_client: MagicMock,
mock_exists: MagicMock,
mock_isfile: MagicMock,
) -> None:
"""Unit test for the format function in openai chat api wrapper with
vision models"""
mock_exists.side_effect = lambda url: url == "/Users/xxx/abc.png"
mock_isfile.side_effect = lambda url: url == "/Users/xxx/abc.png"
# Prepare the mock client
mock_client.return_value = "client_dummy"
model = OpenAIChatWrapper(
config_name="",
model_name="gpt-4o",
)
# correct format
ground_truth = [
{
"role": "system",
"content": "You are a helpful assistant",
"name": "system",
},
{
"role": "user",
"name": "user",
"content": [
{
"type": "text",
"text": "Describe the images",
},
{
"type": "image_url",
"image_url": {
"url": "https://fakeweb/test.jpg",
},
},
],
},
{
"role": "user",
"name": "user",
"content": [
{
"type": "text",
"text": "And this images",
},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,YWJjZGVm",
},
},
],
},
]
prompt = model.format(*self.inputs_vision)
self.assertListEqual(prompt, ground_truth)
@patch("openai.OpenAI")
def test_openai_chat(self, mock_client: MagicMock) -> None:
"""Unit test for the format function in openai chat api wrapper."""
# Prepare the mock client
mock_client.return_value = "client_dummy"
model = OpenAIChatWrapper(
config_name="",
model_name="gpt-4",
)
# correct format
ground_truth = [
{
"role": "system",
"content": "You are a helpful assistant",
"name": "system",
},
{
"role": "user",
"content": "What is the weather today?",
"name": "user",
},
{
"role": "assistant",
"content": "It is sunny today",
"name": "assistant",
},
]
prompt = model.format(*self.inputs) # type: ignore[arg-type]
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_ollama_chat(self) -> None:
"""Unit test for the format function in ollama chat api wrapper."""
model = OllamaChatWrapper(
config_name="",
model_name="llama2",
)
# correct format
ground_truth = [
{
"role": "system",
"content": (
"You are a helpful assistant\n"
"\n"
"## Dialogue History\n"
"user: What is the weather today?\n"
"assistant: It is sunny today"
),
},
]
prompt = model.format(*self.inputs) # type: ignore[arg-type]
self.assertEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_ollama_generation(self) -> None:
"""Unit test for the generation function in ollama chat api wrapper."""
model = OllamaGenerationWrapper(
config_name="",
model_name="llama2",
)
# correct format
ground_truth = (
"You are a helpful assistant\n\n## Dialogue History\nuser: "
"What is the weather today?\nassistant: It is sunny today"
)
prompt = model.format(*self.inputs) # type: ignore[arg-type]
self.assertEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
@patch("google.generativeai.configure")
def test_gemini_chat(self, mock_configure: MagicMock) -> None:
"""Unit test for the format function in gemini chat api wrapper."""
mock_configure.return_value = "client_dummy"
model = GeminiChatWrapper(
config_name="",
model_name="gemini-pro",
api_key="xxx",
)
# correct format
ground_truth = [
{
"role": "user",
"parts": [
"You are a helpful assistant\n\n## Dialogue History\n"
"user: What is the weather today?\nassistant: It is "
"sunny today",
],
},
]
prompt = model.format(*self.inputs) # type: ignore[arg-type]
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_dashscope_chat(self) -> None:
"""Unit test for the format function in dashscope chat api wrapper."""
model = DashScopeChatWrapper(
config_name="",
model_name="qwen-max",
api_key="xxx",
)
ground_truth = [
{
"content": "You are a helpful assistant",
"role": "system",
},
{
"content": (
"## Dialogue History\n"
"user: What is the weather today?\n"
"assistant: It is sunny today"
),
"role": "user",
},
]
prompt = model.format(*self.inputs)
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_zhipuai_chat(self) -> None:
"""Unit test for the format function in zhipu chat api wrapper."""
model = ZhipuAIChatWrapper(
config_name="",
model_name="glm-4",
api_key="xxx",
)
ground_truth = [
{
"content": "You are a helpful assistant",
"role": "system",
},
{
"content": (
"## Dialogue History\n"
"user: What is the weather today?\n"
"assistant: It is sunny today"
),
"role": "user",
},
]
prompt = model.format(*self.inputs)
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_litellm_chat(self) -> None:
"""Unit test for the format function in litellm chat api wrapper."""
model = LiteLLMChatWrapper(
config_name="",
model_name="gpt-3.5-turbo",
api_key="xxx",
)
ground_truth = [
{
"role": "user",
"content": (
"You are a helpful assistant\n\n"
"## Dialogue History\nuser: What is the weather today?\n"
"assistant: It is sunny today"
),
},
]
prompt = model.format(*self.inputs)
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs) # type: ignore[arg-type]
def test_dashscope_multimodal_image(self) -> None:
"""Unit test for the format function in dashscope multimodal
conversation api wrapper for image."""
model = DashScopeMultiModalWrapper(
config_name="",
model_name="qwen-vl-plus",
api_key="xxx",
)
multimodal_input = [
Msg(
"system",
"You are a helpful assistant",
role="system",
url="url1.png",
),
[
Msg(
"user",
"What is the weather today?",
role="user",
url="url2.png",
),
Msg(
"assistant",
"It is sunny today",
role="assistant",
url="url3.png",
),
],
]
ground_truth = [
{
"role": "system",
"content": [
{"image": "url1.png"},
{"text": "You are a helpful assistant"},
],
},
{
"role": "user",
"content": [
{"image": "url2.png"},
{"image": "url3.png"},
{
"text": (
"## Dialogue History\n"
"user: What is the weather today?\n"
"assistant: It is sunny today"
),
},
],
},
]
prompt = model.format(*multimodal_input)
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs)
def test_dashscope_multimodal_audio(self) -> None:
"""Unit test for the format function in dashscope multimodal
conversation api wrapper for audio."""
model = DashScopeMultiModalWrapper(
config_name="",
model_name="qwen-audio-turbo",
api_key="xxx",
)
multimodal_input = [
Msg(
"system",
"You are a helpful assistant",
role="system",
url="url1.mp3",
),
[
Msg(
"user",
"What is the weather today?",
role="user",
url="url2.mp3",
),
Msg(
"assistant",
"It is sunny today",
role="assistant",
url="url3.mp3",
),
],
]
ground_truth = [
{
"role": "system",
"content": [
{"audio": "url1.mp3"},
{"text": "You are a helpful assistant"},
],
},
{
"role": "user",
"content": [
{"audio": "url2.mp3"},
{"audio": "url3.mp3"},
{
"text": (
"## Dialogue History\n"
"user: What is the weather today?\n"
"assistant: It is sunny today"
),
},
],
},
]
prompt = model.format(*multimodal_input)
self.assertListEqual(prompt, ground_truth)
# wrong format
with self.assertRaises(TypeError):
model.format(*self.wrong_inputs)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
"""Unit test for gemini model wrapper."""
import unittest
from unittest.mock import MagicMock, patch
import agentscope
from agentscope.models import load_model_by_config_name
from agentscope._runtime import _Runtime
from agentscope.file_manager import _FileManager
from agentscope.utils.monitor import MonitorFactory
def flush() -> None:
"""
** Only for unittest usage. Don't use this function in your code. **
Clear the runtime dir and destroy all singletons.
"""
_Runtime._flush() # pylint: disable=W0212
_FileManager._flush() # pylint: disable=W0212
MonitorFactory.flush()
class DummyPart:
"""Dummy part for testing."""
text = "Hello! How can I help you?"
class DummyContent:
"""Dummy content for testing."""
parts = [DummyPart()]
class DummyCandidate:
"""Dummy candidate for testing."""
content = DummyContent()
class DummyResponse:
"""Dummy response for testing."""
text = "Hello! How can I help you?"
candidates = [DummyCandidate]
def __str__(self) -> str:
"""Return string representation."""
return str({"text": self.text})
class GeminiModelWrapperTest(unittest.TestCase):
"""Unit test for gemini model wrapper."""
def setUp(self) -> None:
"""Set up for GeminiModelWrapperTest."""
flush()
@patch("google.generativeai.GenerativeModel")
def test_gemini_chat(self, mock_model: MagicMock) -> None:
"""Test for chat API."""
# prepare mock response
mock_counter = MagicMock()
mock_counter.total_tokens = 20
# connect
mock_model.return_value.model_name = "gemini-pro"
mock_model.return_value.generate_content.return_value = DummyResponse()
mock_model.return_value.count_tokens.return_value = mock_counter
agentscope.init(
model_configs={
"config_name": "my_gemini_chat",
"model_type": "gemini_chat",
"model_name": "gemini-pro",
"api_key": "xxx",
},
)
model = load_model_by_config_name("my_gemini_chat")
response = model(contents="Hi!")
self.assertEqual(str(response.raw), str(DummyResponse()))
@patch("google.generativeai.embed_content")
def test_gemini_embedding(self, mock_model: MagicMock) -> None:
"""Test gemini embedding API"""
mock_model.return_value = {
"embedding": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
}
agentscope.init(
model_configs={
"config_name": "my_gemini_embedding",
"model_type": "gemini_embedding",
"model_name": "models/embedding-001",
"api_key": "xxx",
},
)
model = load_model_by_config_name("my_gemini_embedding")
response = model(content="Hi!")
self.assertDictEqual(
response.raw,
{
"embedding": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
},
)
def tearDown(self) -> None:
"""Clean up after each test."""
flush()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""
Unit tests for knowledge (RAG module in AgentScope)
"""
import os
import unittest
from typing import Any
import shutil
from agentscope.rag import LlamaIndexKnowledge
from agentscope.models import OpenAIEmbeddingWrapper, ModelResponse
class DummyModel(OpenAIEmbeddingWrapper):
"""
Dummy model wrapper for testing
"""
def __init__(self) -> None:
"""dummy init"""
def __call__(self, *args: Any, **kwargs: Any) -> ModelResponse:
"""dummy call"""
return ModelResponse(embedding=[[1.0, 2.0]])
class KnowledgeTest(unittest.TestCase):
"""
Test cases for TemporaryMemory
"""
def setUp(self) -> None:
"""set up test data"""
self.data_dir = "tmp_data_dir"
if not os.path.exists(self.data_dir):
os.mkdir(self.data_dir)
self.file_name_1 = "tmp_data_dir/file1.txt"
self.content = "testing file"
with open(self.file_name_1, "w", encoding="utf-8") as f:
f.write(self.content)
def tearDown(self) -> None:
"""Clean up before & after tests."""
try:
if os.path.exists(self.data_dir):
shutil.rmtree(self.data_dir)
if os.path.exists("./runs"):
shutil.rmtree("./runs")
except Exception:
pass
def test_llamaindexknowledge(self) -> None:
"""test llamaindexknowledge"""
dummy_model = DummyModel()
knowledge_config = {
"knowledge_id": "",
"data_processing": [],
}
loader_config = {
"load_data": {
"loader": {
"create_object": True,
"module": "llama_index.core",
"class": "SimpleDirectoryReader",
"init_args": {},
},
},
}
loader_init = {"input_dir": self.data_dir, "required_exts": ".txt"}
loader_config["load_data"]["loader"]["init_args"] = loader_init
knowledge_config["data_processing"].append(loader_config)
knowledge = LlamaIndexKnowledge(
knowledge_id="test_knowledge",
emb_model=dummy_model,
knowledge_config=knowledge_config,
)
retrieved = knowledge.retrieve(
query="testing",
similarity_top_k=2,
to_list_strs=True,
)
self.assertEqual(
retrieved,
[self.content],
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
"""litellm test"""
import unittest
from unittest.mock import patch, MagicMock
import agentscope
from agentscope.models import load_model_by_config_name
class TestLiteLLMChatWrapper(unittest.TestCase):
"""Test LiteLLM Chat Wrapper"""
def setUp(self) -> None:
self.api_key = "test_api_key.secret_key"
self.messages = [
{"role": "user", "content": "Hello, litellm!"},
{"role": "assistant", "content": "How can I assist you?"},
]
@patch("agentscope.models.litellm_model.litellm")
def test_chat(self, mock_litellm: MagicMock) -> None:
"""
Test chat"""
mock_response = MagicMock()
mock_response.model_dump.return_value = {
"choices": [
{"message": {"content": "Hello, this is a mocked response!"}},
],
"usage": {
"prompt_tokens": 100,
"completion_tokens": 5,
"total_tokens": 105,
},
}
mock_response.choices[
0
].message.content = "Hello, this is a mocked response!"
mock_litellm.completion.return_value = mock_response
agentscope.init(
model_configs={
"config_name": "test_config",
"model_type": "litellm_chat",
"model_name": "ollama/llama3:8b",
"api_key": self.api_key,
},
)
model = load_model_by_config_name("test_config")
response = model(
messages=self.messages,
api_base="http://localhost:11434",
)
self.assertEqual(response.text, "Hello, this is a mocked response!")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
""" Unit test for logger chat"""
import os
import shutil
import time
import unittest
from loguru import logger
from agentscope.logging import setup_logger
class LoggerTest(unittest.TestCase):
"""
Unit test for logger.
"""
def setUp(self) -> None:
"""Setup for unit test."""
self.run_dir = "./logger_runs/"
def test_logger_chat(self) -> None:
"""Logger chat."""
setup_logger(self.run_dir, level="INFO")
# str with "\n"
logger.chat("Test\nChat\n\nMessage\n\n")
# dict with "\n"
logger.chat(
{
"name": "Alice",
"content": "Hi!\n",
"url": "https://xxx.png",
},
)
# dict without content
logger.chat({"name": "Alice", "url": "https://xxx.png"})
# dict
logger.chat({"abc": 1})
# html labels
logger.chat({"name": "Bob", "content": "<div>abc</div"})
# To avoid that logging is not finished before the file is read
time.sleep(3)
with open(
os.path.join(self.run_dir, "logging.chat"),
"r",
encoding="utf-8",
) as file:
lines = file.readlines()
ground_truth = [
'"Test\\nChat\\n\\nMessage\\n\\n"\n',
'{"name": "Alice", "content": "Hi!\\n", "url": "https://xxx.png'
'"}\n',
'{"name": "Alice", "url": "https://xxx.png"}\n',
'{"abc": 1}\n',
'{"name": "Bob", "content": "<div>abc</div"}\n',
]
self.assertListEqual(lines, ground_truth)
def tearDown(self) -> None:
"""Tear down for LoggerTest."""
logger.remove()
if os.path.exists(self.run_dir):
shutil.rmtree(self.run_dir)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
"""
Unit tests for memory classes and functions
"""
import os
import unittest
from unittest.mock import patch, MagicMock
from agentscope.message import Msg
from agentscope.memory import TemporaryMemory
class TemporaryMemoryTest(unittest.TestCase):
"""
Test cases for TemporaryMemory
"""
def setUp(self) -> None:
self.memory = TemporaryMemory()
self.file_name_1 = "tmp_mem_file1.txt"
self.file_name_2 = "tmp_mem_file2.txt"
self.msg_1 = Msg("user", "Hello", role="user")
self.msg_2 = Msg(
"agent",
"Hello! How can I help you?",
role="assistant",
)
self.msg_3 = Msg(
"user",
"Translate the following sentence",
role="assistant",
)
self.invalid = {"invalid_key": "invalid_value"}
def tearDown(self) -> None:
"""Clean up before & after tests."""
if os.path.exists(self.file_name_1):
os.remove(self.file_name_1)
if os.path.exists(self.file_name_2):
os.remove(self.file_name_2)
def test_add(self) -> None:
"""Test add different types of object"""
# add msg
self.memory.add(self.msg_1)
self.assertEqual(
self.memory.get_memory(),
[self.msg_1],
)
# add list
self.memory.add([self.msg_2, self.msg_3])
self.assertEqual(
self.memory.get_memory(),
[self.msg_1, self.msg_2, self.msg_3],
)
@patch("loguru.logger.warning")
def test_delete(self, mock_logging: MagicMock) -> None:
"""Test delete operations"""
self.memory.add([self.msg_1, self.msg_2, self.msg_3])
self.memory.delete(index=0)
self.assertEqual(
self.memory.get_memory(),
[self.msg_2, self.msg_3],
)
# test invalid
self.memory.delete(index=100)
mock_logging.assert_called_once_with(
"Skip delete operation for the invalid index [100]",
)
def test_invalid(self) -> None:
"""Test invalid operations for memory"""
# test invalid add
with self.assertRaises(Exception) as context:
self.memory.add(self.invalid)
self.assertTrue(
f"Cannot add {self.invalid} to memory" in str(context.exception),
)
def test_load_export(self) -> None:
"""
Test load and export function of TemporaryMemory
"""
memory = TemporaryMemory()
user_input = Msg(name="user", content="Hello")
agent_input = Msg(
name="agent",
content="Hello! How can I help you?",
)
memory.load([user_input, agent_input])
retrieved_mem = memory.export(to_mem=True)
self.assertEqual(
retrieved_mem,
[user_input, agent_input],
)
memory.export(file_path=self.file_name_1)
memory.clear()
self.assertEqual(
memory.get_memory(),
[],
)
memory.load(self.file_name_1)
self.assertEqual(
memory.get_memory(),
[user_input, agent_input],
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""
Unit tests for model wrapper classes and functions
"""
from typing import Any, Union, List, Sequence
import unittest
from unittest.mock import patch, MagicMock
from agentscope.message import Msg
from agentscope.models import (
ModelResponse,
ModelWrapperBase,
OpenAIChatWrapper,
PostAPIModelWrapperBase,
_get_model_wrapper,
read_model_configs,
load_model_by_config_name,
clear_model_configs,
)
class TestModelWrapperSimple(ModelWrapperBase):
"""A simple model wrapper class for test usage"""
def __call__(self, *args: Any, **kwargs: Any) -> ModelResponse:
return ModelResponse(text=self.config_name)
def format(
self,
*args: Union[Msg, Sequence[Msg]],
) -> Union[List[dict], str]:
return ""
class BasicModelTest(unittest.TestCase):
"""Test cases for basic model wrappers"""
def test_model_registry(self) -> None:
"""Test the automatic registration mechanism of model wrapper."""
# get model wrapper class by class name
self.assertEqual(
_get_model_wrapper(model_type="TestModelWrapperSimple"),
TestModelWrapperSimple,
)
# get model wrapper class by model type
self.assertEqual(
_get_model_wrapper(model_type="openai_chat"),
OpenAIChatWrapper,
)
# return PostAPIModelWrapperBase if model_type is not supported
self.assertEqual(
_get_model_wrapper(model_type="unknown_model_wrapper"),
PostAPIModelWrapperBase,
)
@patch("loguru.logger.warning")
def test_load_model_configs(self, mock_logging: MagicMock) -> None:
"""Test to load model configs"""
configs = [
{
"model_type": "openai_chat",
"config_name": "gpt-4",
"model_name": "gpt-4",
"api_key": "xxx",
"organization": "xxx",
"generate_args": {"temperature": 0.5},
},
{
"model_type": "post_api",
"config_name": "my_post_api",
"api_url": "https://xxx",
"headers": {},
"json_args": {},
},
]
# load a list of configs
read_model_configs(configs=configs, clear_existing=True)
model = load_model_by_config_name("gpt-4")
self.assertEqual(model.config_name, "gpt-4")
model = load_model_by_config_name("my_post_api")
self.assertEqual(model.config_name, "my_post_api")
self.assertRaises(
ValueError,
load_model_by_config_name,
"non_existent_id",
)
# load a single config
read_model_configs(configs=configs[0], clear_existing=True)
model = load_model_by_config_name("gpt-4")
self.assertEqual(model.config_name, "gpt-4")
self.assertRaises(ValueError, load_model_by_config_name, "my_post_api")
# load model with the same id
read_model_configs(configs=configs[0], clear_existing=False)
mock_logging.assert_called_once_with(
"config_name [gpt-4] already exists.",
)
read_model_configs(
configs={
"model_type": "TestModelWrapperSimple",
"config_name": "test_model_wrapper",
"args": {},
},
)
test_model = load_model_by_config_name("test_model_wrapper")
response = test_model()
self.assertEqual(response.text, "test_model_wrapper")
clear_model_configs()
self.assertRaises(
ValueError,
load_model_by_config_name,
"test_model_wrapper",
)

View File

@@ -0,0 +1,285 @@
# -*- coding: utf-8 -*-
"""
Unit tests for Monitor classes
"""
import unittest
import uuid
import os
import shutil
from loguru import logger
import agentscope
from agentscope.utils import MonitorBase, QuotaExceededError, MonitorFactory
from agentscope.utils.monitor import SqliteMonitor, DummyMonitor
class MonitorFactoryTest(unittest.TestCase):
"Test class for MonitorFactory"
def setUp(self) -> None:
MonitorFactory._instance = None # pylint: disable=W0212
self.db_path = f"test-{uuid.uuid4()}.db"
def test_get_monitor(self) -> None:
"""Test get monitor method of MonitorFactory."""
_ = MonitorFactory.get_monitor(db_path=self.db_path)
monitor1 = MonitorFactory.get_monitor()
monitor2 = MonitorFactory.get_monitor()
self.assertEqual(monitor1, monitor2)
self.assertTrue(
monitor1.register("token_num", metric_unit="token", quota=200),
)
self.assertTrue(monitor2.exists("token_num"))
self.assertTrue(monitor2.remove("token_num"))
self.assertFalse(monitor1.exists("token_num"))
def test_monitor_type(self) -> None:
"""Test get different type of monitor"""
monitor = MonitorFactory.get_monitor(impl_type="dummy")
self.assertTrue(isinstance(monitor, DummyMonitor))
MonitorFactory._instance = None # pylint: disable=W0212
monitor = MonitorFactory.get_monitor(
impl_type="sqlite",
db_path=self.db_path,
)
self.assertTrue(isinstance(monitor, SqliteMonitor))
def tearDown(self) -> None:
MonitorFactory._instance = None # pylint: disable=W0212
os.remove(self.db_path)
class DummyMonitorTest(unittest.TestCase):
"""Test class for DummyMonitor"""
def setUp(self) -> None:
MonitorFactory._instance = None # pylint: disable=W0212
agentscope.init(
project="test",
name="monitor",
save_dir="./test_runs",
save_log=True,
use_monitor=False,
)
def test_dummy_monitor(self) -> None:
"""test dummy monitor"""
monitor = MonitorFactory.get_monitor()
self.assertTrue(
monitor.register_budget(
model_name="qwen",
value=100.0,
prefix="xxx",
),
)
self.assertTrue(
monitor.register(
"prompt_tokens",
metric_unit="token",
),
)
monitor.update({"call_counter": 1})
def tearDown(self) -> None:
MonitorFactory._instance = None # pylint: disable=W0212
logger.remove()
shutil.rmtree("./test_runs")
class MonitorTestBase(unittest.TestCase):
"""An abstract test class for MonitorBase interface"""
def setUp(self) -> None:
if self.__class__ is MonitorTestBase:
raise unittest.SkipTest("Base test class")
self.monitor = self.get_monitor_instance()
def get_monitor_instance(self) -> MonitorBase:
"""Implement this method for your Monitorbase implementation."""
raise NotImplementedError
def test_register_exists_remove(self) -> None:
"""Test register and remove of monitor"""
# register token_num
self.assertTrue(
self.monitor.register(
"token_num",
metric_unit="token",
quota=1000,
),
)
# register an existing metric (ignore this operation and return false)
self.assertFalse(
self.monitor.register(
"token_num",
metric_unit="token",
quota=2000,
),
)
# exists
self.assertTrue(self.monitor.exists("token_num"))
# not exists
self.assertFalse(self.monitor.exists("communication"))
# metric content
metric = self.monitor.get_metric("token_num")
self.assertIsNotNone(metric)
self.assertEqual(metric["unit"], "token") # type: ignore[index]
self.assertEqual(metric["quota"], 1000) # type:ignore[index]
# remove a registered metric
self.assertTrue(self.monitor.remove("token_num"))
self.assertFalse(self.monitor.exists("token_num"))
# remove an not existed metric
self.assertFalse(self.monitor.remove("cost"))
def test_add_clear_set_quota(self) -> None:
"""Test add and clear of monitor"""
self.monitor.register("token_num", metric_unit="token", quota=100)
# add to an existing metric
self.assertTrue(self.monitor.add("token_num", 10))
# add to a not existing metric
self.assertFalse(self.monitor.add("communication", 20))
# add and exceed quota
self.assertRaises(
QuotaExceededError,
self.monitor.add,
"token_num",
91,
)
# set quota of not exists metric
self.assertFalse(self.monitor.set_quota("communication", 200))
# update quota
self.assertTrue(self.monitor.set_quota("token_num", 200))
# add success and check new value
self.assertTrue(self.monitor.add("token_num", 10))
self.assertEqual(self.monitor.get_value("token_num"), 20)
# clear an existing metric
self.assertTrue(self.monitor.clear("token_num"))
# clear an not existing metric
self.assertFalse(self.monitor.clear("communication"))
self.assertTrue(self.monitor.remove("token_num"))
def test_get(self) -> None:
"""Test get method of monitor"""
self.assertTrue(
self.monitor.register(
"agentA.token_num",
metric_unit="token",
quota=200,
),
)
self.assertTrue(
self.monitor.register(
"agentB.token_num",
metric_unit="token",
quota=100,
),
)
self.assertTrue(
self.monitor.register(
"agentA.communication",
metric_unit="KB",
quota=500,
),
)
self.assertTrue(
self.monitor.register(
"agentB.communication",
metric_unit="KB",
quota=600,
),
)
self.assertTrue(
self.monitor.register(
"agentC.token_num",
metric_unit="token",
quota=600,
),
)
self.monitor.add("agentA.token_num", 10)
self.assertEqual(self.monitor.get_value("agentA.token_num"), 10)
self.assertEqual(self.monitor.get_unit("agentA.token_num"), "token")
self.assertEqual(self.monitor.get_quota("agentA.token_num"), 200)
self.assertIsNone(self.monitor.get_value("token_num"))
self.assertIsNone(self.monitor.get_unit("token_num"))
self.assertIsNone(self.monitor.get_quota("token_num"))
self.assertIsNone(self.monitor.get_metric("token_num"))
metric = self.monitor.get_metric("agentB.token_num")
self.assertIsNotNone(metric)
self.assertEqual(metric["value"], 0) # type: ignore[index]
self.assertEqual(metric["unit"], "token") # type: ignore[index]
self.assertEqual(metric["quota"], 100) # type: ignore[index]
self.assertEqual(self.monitor.get_metrics(r"cost"), {})
agenta_metrics = self.monitor.get_metrics("agentA")
self.assertEqual(len(agenta_metrics.keys()), 2)
comm_metrics = self.monitor.get_metrics("communication")
self.assertEqual(len(comm_metrics.keys()), 2)
agentc_metrics = self.monitor.get_metrics("agentC")
self.assertEqual(len(agentc_metrics.keys()), 1)
self.assertEqual(
agenta_metrics["agentA.token_num"],
{"value": 10.0, "unit": "token", "quota": 200},
)
class SqliteMonitorTest(MonitorTestBase):
"""Test class for SqliteMonitor"""
def get_monitor_instance(self) -> MonitorBase:
self.db_path = f"test-{uuid.uuid4()}.db"
return SqliteMonitor(self.db_path)
def tearDown(self) -> None:
os.remove(self.db_path)
def test_register_budget(self) -> None:
"""Test register_budget method of monitor"""
self.assertTrue(
self.monitor.register_budget(
model_name="gpt-4",
value=5,
prefix="agent_A.gpt-4",
),
)
# register an existing model with different prefix is ok
self.assertTrue(
self.monitor.register_budget(
model_name="gpt-4",
value=15,
prefix="agent_B.gpt-4",
),
)
gpt_4_3d = {
"prompt_tokens": 50000,
"completion_tokens": 25000,
"total_tokens": 750000,
}
# agentA uses 3 dollors
self.monitor.update(gpt_4_3d, prefix="agent_A.gpt-4")
# agentA uses another 3 dollors and exceeds quota
self.assertRaises(
QuotaExceededError,
self.monitor.update,
gpt_4_3d,
"agent_A.gpt-4",
)
self.assertLess(
self.monitor.get_value( # type: ignore[arg-type]
"agent_A.gpt-4.cost",
),
5,
)
# register an existing model with existing prefix is wrong
self.assertFalse(
self.monitor.register_budget(
model_name="gpt-4",
value=5,
prefix="agent_A.gpt-4",
),
)
self.assertEqual(
self.monitor.get_value( # type: ignore[arg-type]
"agent_A.gpt-4.cost",
),
3,
)

View File

@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
""" Unit test for msghub."""
import unittest
from typing import Optional, Union, Sequence
from agentscope.agents import AgentBase
from agentscope import msghub
from agentscope.message import Msg
class TestAgent(AgentBase):
"""Test agent class for msghub."""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
"""Reply function for agent."""
if x is not None:
self.memory.add(x)
return x
else:
return {}
class MsgHubTest(unittest.TestCase):
"""
Test for MsgHub
"""
def setUp(self) -> None:
"""Init for ExampleTest."""
self.wisper = TestAgent("wisper")
self.agent1 = TestAgent("agent1")
self.agent2 = TestAgent("agent2")
self.agent3 = TestAgent("agent3")
def test_msghub_operation(self) -> None:
"""Test add, delete and broadcast operations"""
msg1 = Msg(name="a1", content="msg1")
msg2 = Msg(name="a2", content="msg2")
msg3 = Msg(name="a3", content="msg3")
msg4 = Msg(name="a4", content="msg4")
with msghub(participants=[self.agent1, self.agent2]) as hub:
self.agent1(msg1)
self.agent2(msg2)
hub.delete(self.agent1)
hub.add(self.agent3)
self.agent3(msg3)
hub.broadcast(msg4)
self.assertListEqual(
self.agent2.memory.get_memory(),
[
msg1,
msg2,
msg3,
msg4,
],
)
self.assertListEqual(self.agent1.memory.get_memory(), [msg1, msg2])
self.assertListEqual(self.agent3.memory.get_memory(), [msg3, msg4])
def test_msghub(self) -> None:
"""msghub test."""
ground_truth = [
Msg(
name="w1",
content="This secret that my password is 123456 can't be"
" leaked!",
role="wisper",
),
]
with msghub(participants=[self.wisper, self.agent1, self.agent2]):
self.wisper(ground_truth)
# agent1 and agent2 heard wisper's secret!
self.assertListEqual(
self.agent1.memory.get_memory(),
ground_truth,
)
self.assertListEqual(
self.agent2.memory.get_memory(),
ground_truth,
)
# agent3 didn't hear wisper's secret!
self.assertListEqual(
self.agent3.memory.get_memory(),
[],
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,173 @@
# -*- coding: utf-8 -*-
"""Unit test for Ollama model APIs."""
import unittest
from unittest.mock import patch, MagicMock
import agentscope
from agentscope.models import load_model_by_config_name
from agentscope._runtime import _Runtime
from agentscope.file_manager import _FileManager
from agentscope.utils.monitor import MonitorFactory
def flush() -> None:
"""
** Only for unittest usage. Don't use this function in your code. **
Clear the runtime dir and destroy all singletons.
"""
_Runtime._flush() # pylint: disable=W0212
_FileManager._flush() # pylint: disable=W0212
MonitorFactory.flush()
class OllamaModelWrapperTest(unittest.TestCase):
"""Unit test for Ollama model APIs."""
def setUp(self) -> None:
"""Init for OllamaModelWrapperTest."""
self.dummy_response = {
"model": "llama2",
"created_at": "2024-03-12T04:16:48.911377Z",
"message": {
"role": "assistant",
"content": (
"Hello! It's nice to meet you. Is there something I can "
"help you with or would you like to chat?",
),
},
"done": True,
"total_duration": 20892900042,
"load_duration": 20019679292,
"prompt_eval_count": 22,
"prompt_eval_duration": 149094000,
"eval_count": 26,
"eval_duration": 721982000,
}
self.dummy_embedding = {
"embedding": [1.0, 2.0, 3.0],
}
self.dummy_generate = {
"model": "llama2",
"created_at": "2024-03-12T03:42:19.621919Z",
"response": "\n1 + 1 = 2",
"done": True,
"context": [
518,
25580,
29962,
3532,
14816,
29903,
29958,
5299,
829,
14816,
29903,
6778,
13,
13,
29896,
29974,
29896,
29922,
518,
29914,
25580,
29962,
13,
13,
29896,
718,
29871,
29896,
353,
29871,
29906,
],
"total_duration": 6146120041,
"load_duration": 6677375,
"prompt_eval_count": 9,
"prompt_eval_duration": 5913554000,
"eval_count": 9,
"eval_duration": 223689000,
}
flush()
@patch("ollama.chat")
def test_ollama_chat(self, mock_chat: MagicMock) -> None:
"""Unit test for ollama chat API."""
# prepare the mock
mock_chat.return_value = self.dummy_response
# run test
agentscope.init(
model_configs={
"config_name": "my_ollama_chat",
"model_type": "ollama_chat",
"model_name": "llama2",
"options": {
"temperature": 0.5,
},
"keep_alive": "5m",
},
)
model = load_model_by_config_name("my_ollama_chat")
response = model(messages=[{"role": "user", "content": "Hi!"}])
self.assertEqual(response.raw, self.dummy_response)
@patch("ollama.embeddings")
def test_ollama_embedding(self, mock_embeddings: MagicMock) -> None:
"""Unit test for ollama embeddings API."""
# prepare the mock
mock_embeddings.return_value = self.dummy_embedding
# run test
agentscope.init(
model_configs={
"config_name": "my_ollama_embedding",
"model_type": "ollama_embedding",
"model_name": "llama2",
"options": {
"temperature": 0.5,
},
"keep_alive": "5m",
},
)
model = load_model_by_config_name("my_ollama_embedding")
response = model(prompt="Hi!")
self.assertEqual(response.raw, self.dummy_embedding)
@patch("ollama.generate")
def test_ollama_generate(self, mock_generate: MagicMock) -> None:
"""Unit test for ollama generate API."""
# prepare the mock
mock_generate.return_value = self.dummy_generate
# run test
agentscope.init(
model_configs={
"config_name": "my_ollama_generate",
"model_type": "ollama_generate",
"model_name": "llama2",
"options": None,
"keep_alive": "5m",
},
)
model = load_model_by_config_name("my_ollama_generate")
response = model(prompt="1+1=")
self.assertEqual(response.raw, self.dummy_generate)
def tearDown(self) -> None:
"""Clean up after each test."""
flush()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,547 @@
# -*- coding: utf-8 -*-
"""OpenAI services test module."""
import unittest
from unittest.mock import patch, MagicMock, mock_open
import os
import shutil
from openai._types import NOT_GIVEN
from agentscope.service.multi_modality.openai_services import (
openai_audio_to_text,
openai_text_to_audio,
openai_text_to_image,
openai_image_to_text,
openai_edit_image,
openai_create_image_variation,
)
from agentscope.service import ServiceExecStatus
from agentscope.service.multi_modality.openai_services import _audio_filename
class TestOpenAIServices(unittest.TestCase):
"""Test the OpenAI services functions."""
def setUp(self) -> None:
"""Set up the test"""
self.save_dir = os.path.join(os.path.dirname(__file__), "test_dir")
os.makedirs(self.save_dir, exist_ok=True)
self.maxDiff = None
def tearDown(self) -> None:
"""Tear down the test"""
if os.path.exists(self.save_dir):
shutil.rmtree(self.save_dir)
@patch(
"agentscope.service.multi_modality.openai_services.OpenAIDALLEWrapper",
)
@patch("agentscope.service.multi_modality.openai_services._download_file")
def test_openai_text_to_image_success(
self,
_: MagicMock,
mock_dalle_wrapper: MagicMock,
) -> None:
"""Test the openai_text_to_image function with a valid prompt."""
# Mock the OpenAIDALLEWrapper response
mock_response = MagicMock()
mock_response.image_urls = [
"https://example.com/image1.png",
"https://example.com/image2.png",
]
mock_instance = MagicMock()
mock_instance.return_value = mock_response
mock_dalle_wrapper.return_value = mock_instance
# Call the function with a valid prompt
result = openai_text_to_image(
prompt="A futuristic city skyline at sunset",
api_key="fake_api_key",
n=2,
model="dall-e-2",
size="256x256",
quality="standard",
style="vivid",
save_dir=self.save_dir,
)
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
expected_urls = [
os.path.join(self.save_dir, "image1.png"),
os.path.join(self.save_dir, "image2.png"),
]
self.assertEqual(result.content, {"image_urls": expected_urls})
# Ensure the wrapper and response methods are called correctly
mock_dalle_wrapper.assert_called_once_with(
config_name="text_to_image_service_call",
model_name="dall-e-2",
api_key="fake_api_key",
)
mock_instance.assert_called_once_with(
prompt="A futuristic city skyline at sunset",
n=2,
size="256x256",
quality="standard",
style="vivid",
)
@patch(
"agentscope.service.multi_modality.openai_services.OpenAIDALLEWrapper",
)
def test_openai_text_to_image_api_error(
self,
mock_dalle_wrapper: MagicMock,
) -> None:
"""Test the openai_text_to_image function with an API error."""
# Mock an API failure response
mock_instance = MagicMock()
mock_instance.side_effect = Exception("API Error: Invalid request")
mock_dalle_wrapper.return_value = mock_instance
# Call the function with a prompt that causes an API error
result = openai_text_to_image(
prompt="An invalid prompt",
api_key="fake_api_key",
n=1,
model="dall-e-2",
size="256x256",
quality="standard",
style="vivid",
)
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertIn("API Error", result.content)
# Ensure the wrapper and response methods are called correctly
mock_dalle_wrapper.assert_called_once_with(
config_name="text_to_image_service_call",
model_name="dall-e-2",
api_key="fake_api_key",
)
mock_instance.assert_called_once_with(
prompt="An invalid prompt",
n=1,
size="256x256",
quality="standard",
style="vivid",
)
@patch(
"agentscope.service.multi_modality.openai_services.OpenAIDALLEWrapper",
)
@patch("agentscope.service.multi_modality.openai_services._download_file")
def test_openai_text_to_image_service_error(
self,
mock_download_file: MagicMock,
mock_dalle_wrapper: MagicMock,
) -> None:
"""Test the openai_text_to_image function with a service error."""
mock_response = MagicMock()
mock_response.image_urls = None
mock_instance = MagicMock()
mock_instance.return_value = mock_response
mock_dalle_wrapper.return_value = mock_instance
# Call the function with a valid prompt but simulate an internal error
result = openai_text_to_image(
prompt="A futuristic city skyline at sunset",
api_key="fake_api_key",
n=2,
model="dall-e-2",
size="256x256",
quality="standard",
style="vivid",
save_dir=self.save_dir,
)
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertIn("Error: Failed to generate images", result.content)
# Ensure the wrapper and response methods are called correctly
mock_dalle_wrapper.assert_called_once_with(
config_name="text_to_image_service_call",
model_name="dall-e-2",
api_key="fake_api_key",
)
mock_instance.assert_called_once_with(
prompt="A futuristic city skyline at sunset",
n=2,
size="256x256",
quality="standard",
style="vivid",
)
# Ensure _download_file is not called in case of service error
mock_download_file.assert_not_called()
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch(
"builtins.open",
new_callable=mock_open,
read_data=b"mock_audio_data",
)
def test_openai_audio_to_text_success(
self,
_: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_audio_to_text function with a valid audio file."""
# Mocking the OpenAI API response
mock_transcription = (
mock_openai.return_value.audio.transcriptions.create.return_value
)
mock_transcription.text = "This is a test transcription."
# Test audio file path within the save_dir
audio_file_url = os.path.join(self.save_dir, "test_audio.mp3")
# Create the test file in the save_dir
with open(audio_file_url, "wb") as f:
f.write(b"mock_audio_data")
# Call the function
result = openai_audio_to_text(audio_file_url, "mock_api_key")
# Assertions
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
self.assertEqual(
result.content,
{"transcription": "This is a test transcription."},
)
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch("builtins.open", new_callable=mock_open)
def test_openai_audio_to_text_error(
self,
_: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_audio_to_text function with an API error."""
# Mocking an OpenAI API error
mock_openai.return_value.audio.transcriptions.create.side_effect = (
Exception("API Error")
)
# Test audio file path within the save_dir
audio_file_url = os.path.join(self.save_dir, "test_audio.mp3")
# Call the function (the mock_file_open will handle the file opening)
result = openai_audio_to_text(audio_file_url, "mock_api_key")
# Assertions
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertIn(
"Error: Failed to transcribe audio API Error",
result.content,
)
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
def test_successful_audio_generation(self, mock_openai: MagicMock) -> None:
"""Test the openai_text_to_audio function with a valid text."""
# Mocking the OpenAI API response
mock_response = (
mock_openai.return_value.audio.speech.create.return_value
)
# Sample text and expected audio path
text = "Hello, this is a test."
save_dir = self.save_dir
expected_audio_path = os.path.join(
save_dir,
f"{_audio_filename(text)}.mp3",
)
# Call the function
result = openai_text_to_audio(text, "mock_api_key", save_dir)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
self.assertEqual(result.content["audio_path"], expected_audio_path)
mock_response.stream_to_file.assert_called_once_with(
expected_audio_path,
) # Check file save
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
def test_api_error_text_to_audio(self, mock_openai: MagicMock) -> None:
"""Test the openai_text_to_audio function with an API error."""
# Mocking an OpenAI API error
mock_openai.return_value.audio.speech.create.side_effect = Exception(
"API Error",
)
# Call the function
result = openai_text_to_audio(
"Hello, this is a test.",
"mock_api_key",
self.save_dir,
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertIn(
"Error: Failed to generate audio. API Error",
result.content,
)
@patch(
"agentscope.service.multi_modality.openai_services.OpenAIChatWrapper",
)
def test_openai_image_to_text_success(
self,
mock_openai_chat_wrapper: MagicMock,
) -> None:
"""Test the openai_image_to_text function with a valid image URL."""
# Mock the OpenAIChatWrapper
mock_wrapper_instance = MagicMock()
mock_openai_chat_wrapper.return_value = mock_wrapper_instance
# Mock the response
mock_response = MagicMock()
mock_response.text = "This is a description of the image."
mock_wrapper_instance.return_value = mock_response
# Test with single image URL
result = openai_image_to_text(
"https://example.com/image.jpg",
"fake_api_key",
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
self.assertEqual(result.content, "This is a description of the image.")
mock_openai_chat_wrapper.assert_called_once_with(
config_name="image_to_text_service_call",
model_name="gpt-4o",
api_key="fake_api_key",
)
mock_wrapper_instance.format.assert_called_once()
formatted_message = mock_wrapper_instance.format.call_args[0][0]
self.assertEqual(formatted_message.name, "service_call")
self.assertEqual(formatted_message.role, "user")
self.assertEqual(formatted_message.content, "Describe the image")
self.assertEqual(
formatted_message.url,
"https://example.com/image.jpg",
)
@patch(
"agentscope.service.multi_modality.openai_services.OpenAIChatWrapper",
)
def test_openai_image_to_text_error(
self,
mock_openai_chat_wrapper: MagicMock,
) -> None:
"""Test the openai_image_to_text function with an API error."""
# Mock the OpenAIChatWrapper to raise an exception
mock_wrapper_instance = MagicMock()
mock_openai_chat_wrapper.return_value = mock_wrapper_instance
mock_wrapper_instance.side_effect = Exception("API Error")
# Test with single image URL
result = openai_image_to_text(
"https://example.com/image.jpg",
"fake_api_key",
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertEqual(result.content, "API Error")
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch("agentscope.service.multi_modality.openai_services._parse_url")
@patch(
(
"agentscope.service.multi_modality.openai_services"
"._handle_openai_img_response"
),
)
def test_openai_edit_image_success(
self,
mock_handle_response: MagicMock,
mock_parse_url: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_edit_image function with a valid image URL."""
# Mock OpenAI client
mock_client = MagicMock()
mock_openai.return_value = mock_client
mock_response = MagicMock()
mock_client.images.edit.return_value = mock_response
# Mock _parse_url function
mock_parse_url.side_effect = lambda x: f"parsed_{x}"
# Mock _handle_openai_img_response function
mock_handle_response.return_value = [
"edited_image_url1",
"edited_image_url2",
]
# Call the function
result = openai_edit_image(
image_url="original_image.png",
prompt="Add a sun to the sky",
api_key="fake_api_key",
mask_url="mask_image.png",
n=2,
size="512x512",
save_dir=None,
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
self.assertEqual(
result.content,
{"image_urls": ["edited_image_url1", "edited_image_url2"]},
)
# Check if OpenAI client was called correctly
mock_client.images.edit.assert_called_once_with(
model="dall-e-2",
image="parsed_original_image.png",
mask="parsed_mask_image.png",
prompt="Add a sun to the sky",
n=2,
size="512x512",
)
# Check if _handle_openai_img_response was called
mock_handle_response.assert_called_once_with(mock_response, None)
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch("agentscope.service.multi_modality.openai_services._parse_url")
def test_openai_edit_image_error(
self,
mock_parse_url: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_edit_image function with an API error."""
# Mock OpenAI client to raise an exception
mock_client = MagicMock()
mock_openai.return_value = mock_client
mock_client.images.edit.side_effect = Exception("API Error")
# Mock _parse_url function
mock_parse_url.side_effect = lambda x: f"parsed_{x}"
# Call the function
result = openai_edit_image(
image_url="original_image.png",
prompt="Add a sun to the sky",
api_key="fake_api_key",
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertEqual(result.content, "API Error")
# Check if OpenAI client was called
mock_client.images.edit.assert_called_once_with(
model="dall-e-2",
image="parsed_original_image.png",
mask=NOT_GIVEN,
prompt="Add a sun to the sky",
n=1,
size="256x256",
)
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch("agentscope.service.multi_modality.openai_services._parse_url")
@patch(
(
"agentscope.service.multi_modality.openai_services"
"._handle_openai_img_response"
),
)
def test_openai_create_image_variation_success(
self,
mock_handle_response: MagicMock,
mock_parse_url: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_create_image_variation swith a valid image URL."""
# Mock OpenAI client
mock_client = MagicMock()
mock_openai.return_value = mock_client
mock_response = MagicMock()
mock_client.images.create_variation.return_value = mock_response
# Mock _parse_url function
mock_parse_url.return_value = "parsed_image.png"
# Mock _handle_openai_img_response function
mock_handle_response.return_value = [
"variation_url1",
"variation_url2",
]
# Call the function
result = openai_create_image_variation(
image_url="original_image.png",
api_key="fake_api_key",
n=2,
size="512x512",
save_dir=None,
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.SUCCESS)
self.assertEqual(
result.content,
{"image_urls": ["variation_url1", "variation_url2"]},
)
# Check if OpenAI client was called correctly
mock_client.images.create_variation.assert_called_once_with(
model="dall-e-2",
image="parsed_image.png",
n=2,
size="512x512",
)
# Check if _handle_openai_img_response was called
mock_handle_response.assert_called_once_with(mock_response, None)
@patch("agentscope.service.multi_modality.openai_services.OpenAI")
@patch("agentscope.service.multi_modality.openai_services._parse_url")
def test_openai_create_image_variation_error(
self,
mock_parse_url: MagicMock,
mock_openai: MagicMock,
) -> None:
"""Test the openai_create_image_variation with an API error."""
# Mock OpenAI client to raise an exception
mock_client = MagicMock()
mock_openai.return_value = mock_client
mock_client.images.create_variation.side_effect = Exception(
"API Error",
)
# Mock _parse_url function
mock_parse_url.return_value = "parsed_image.png"
# Call the function
result = openai_create_image_variation(
image_url="original_image.png",
api_key="fake_api_key",
)
# Assertions
self.assertEqual(result.status, ServiceExecStatus.ERROR)
self.assertEqual(result.content, "API Error")
# Check if OpenAI client was called
mock_client.images.create_variation.assert_called_once_with(
model="dall-e-2",
image="parsed_image.png",
n=1,
size="256x256",
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
""" Operate file test."""
import os
import shutil
import unittest
from agentscope.service import (
create_file,
delete_file,
move_file,
create_directory,
delete_directory,
move_directory,
read_text_file,
write_text_file,
read_json_file,
write_json_file,
list_directory_content,
get_current_directory,
)
from agentscope.service.service_status import ServiceExecStatus
class OperateFileTest(unittest.TestCase):
"""
Operate file test.
"""
def setUp(self) -> None:
"""Set up test variables."""
self.file_name = "tmp_file.txt"
self.moved_file_name = "moved_tmp_file.txt"
self.dir_name = "tmp_dir"
self.moved_dir_name = "moved_tmp_dir"
self.txt_file_name = "tmp_txt_file.txt"
self.json_file_name = "tmp_json_file.json"
self.tearDown()
def tearDown(self) -> None:
"""Clean up before & after tests."""
if os.path.exists(self.file_name):
os.remove(self.file_name)
if os.path.exists(self.moved_file_name):
os.remove(self.moved_file_name)
if os.path.exists(self.dir_name):
shutil.rmtree(self.dir_name)
if os.path.exists(self.moved_dir_name):
shutil.rmtree(self.moved_dir_name)
if os.path.exists(self.txt_file_name):
os.remove(self.txt_file_name)
def test_file(self) -> None:
"""Execute file test."""
is_success = create_file(self.file_name, "This is a test").status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = move_file(self.file_name, self.moved_file_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = delete_file(self.moved_file_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
def test_dir(self) -> None:
"""Execute dir test."""
is_success = get_current_directory().status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = create_directory(self.dir_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = move_directory(self.dir_name, self.moved_dir_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = list_directory_content(self.moved_dir_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
is_success = delete_directory(self.moved_dir_name).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
def test_txt(self) -> None:
"""Execute txt test."""
is_success = write_text_file(
self.txt_file_name,
"This is a test",
True,
).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
info = read_text_file(self.txt_file_name).content
self.assertEqual(info, "This is a test")
def test_json(self) -> None:
"""Execute json test."""
data = {"test": "This is a test"}
is_success = write_json_file(self.json_file_name, data, True).status
self.assertEqual(is_success, ServiceExecStatus.SUCCESS)
info = read_json_file(self.json_file_name).content
self.assertEqual(info, f"{data}")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
"""Unit test for model response parser."""
import unittest
from pydantic import BaseModel, Field
from agentscope.models import ModelResponse
from agentscope.parsers import (
MarkdownJsonDictParser,
MarkdownJsonObjectParser,
MarkdownCodeBlockParser,
MultiTaggedContentParser,
TaggedContent,
)
from agentscope.parsers.parser_base import DictFilterMixin
class ModelResponseParserTest(unittest.TestCase):
"""Unit test for model response parser."""
def setUp(self) -> None:
"""Init for ExampleTest."""
self.res_dict_1 = ModelResponse(
text=(
"```json\n"
'{"speak": "Hello, world!", '
'"thought": "xxx", '
'"end_discussion": true}\n```'
),
)
self.instruction_dict_1 = (
"Respond a JSON dictionary in a markdown's fenced code block "
"as follows:\n"
"```json\n"
'{"speak": "what you speak", '
'"thought": "what you thought", '
'"end_discussion": true/false}\n'
"```"
)
self.res_dict_2 = ModelResponse(
text="[SPEAK]Hello, world![/SPEAK]\n"
"[THOUGHT]xxx[/THOUGHT]\n"
"[END_DISCUSSION]true[/END_DISCUSSION]",
)
self.instruction_dict_2 = (
"Respond with specific tags as outlined below, and the content "
"between [END_DISCUSSION] and [/END_DISCUSSION] MUST be a JSON "
"object:\n"
"[SPEAK]what you speak[/SPEAK]\n"
"[THOUGHT]what you thought[/THOUGHT]\n"
"[END_DISCUSSION]true/false[/END_DISCUSSION]"
)
self.gt_dict = {
"speak": "Hello, world!",
"thought": "xxx",
"end_discussion": True,
}
self.hint_dict = (
'{"speak": "what you speak", '
'"thought": "what you thought", '
'"end_discussion": true/false}'
)
self.instruction_dict_3 = (
"Respond a JSON dictionary in a markdown's fenced code block as "
"follows:\n"
"```json\n"
"{a_JSON_dictionary}\n"
"```\n"
"The generated JSON dictionary MUST follow this schema: \n"
"{'properties': {'speak': {'description': 'what you speak', "
"'title': 'Speak', 'type': 'string'}, 'thought': {'description': "
"'what you thought', 'title': 'Thought', 'type': 'string'}, "
"'end_discussion': {'description': 'whether the discussion "
"reached an agreement or not', 'title': 'End Discussion', "
"'type': 'boolean'}}, 'required': ['speak', 'thought', "
"'end_discussion'], 'title': 'Schema', 'type': 'object'}"
)
self.gt_to_memory = {"speak": "Hello, world!", "thought": "xxx"}
self.gt_to_content = "Hello, world!"
self.gt_to_metadata = {"end_discussion": True}
self.res_list = ModelResponse(text="""```json\n[1,2,3]\n```""")
self.instruction_list = (
"You should respond a json object in a json fenced code block as "
"follows:\n"
"```json\n"
"{Your generated list of numbers}\n"
"```"
)
self.gt_list = [1, 2, 3]
self.hint_list = "{Your generated list of numbers}"
self.res_float = ModelResponse(text="""```json\n3.14\n```""")
self.instruction_float = (
"You should respond a json object in a json fenced code block as "
"follows:\n"
"```json\n"
"{Your generated float number}\n"
"```"
)
self.gt_float = 3.14
self.hint_float = "{Your generated float number}"
self.res_code = ModelResponse(
text="""```python\nprint("Hello, world!")\n```""",
)
self.instruction_code = (
"You should generate python code in a python fenced code block as "
"follows: \n"
"```python\n"
"${your_python_code}\n"
"```"
)
self.instruction_code_with_hint = (
"You should generate python code in a python fenced code block as "
"follows: \n"
"```python\n"
"abc\n"
"```"
)
self.gt_code = """\nprint("Hello, world!")\n"""
def test_markdownjsondictparser_with_schema(self) -> None:
"""Test for MarkdownJsonDictParser with schema"""
class Schema(BaseModel): # pylint: disable=missing-class-docstring
speak: str = Field(description="what you speak")
thought: str = Field(description="what you thought")
end_discussion: bool = Field(
description="whether the discussion reached an agreement or "
"not",
)
parser = MarkdownJsonDictParser(
content_hint=Schema,
keys_to_memory=["speak", "thought"],
keys_to_content="speak",
keys_to_metadata=["end_discussion"],
)
self.assertEqual(parser.format_instruction, self.instruction_dict_3)
res = parser.parse(self.res_dict_1)
self.assertDictEqual(res.parsed, self.gt_dict)
res = parser.parse(
ModelResponse(
text="""```json
{
"speak" : "Hello, world!",
"thought" : "xxx",
"end_discussion" : "true"
}
```""",
),
)
self.assertDictEqual(res.parsed, self.gt_dict)
def test_markdownjsondictparser(self) -> None:
"""Test for MarkdownJsonDictParser"""
parser = MarkdownJsonDictParser(
content_hint=self.hint_dict,
keys_to_memory=["speak", "thought"],
keys_to_content="speak",
keys_to_metadata=["end_discussion"],
)
self.assertEqual(parser.format_instruction, self.instruction_dict_1)
res = parser.parse(self.res_dict_1)
self.assertDictEqual(res.parsed, self.gt_dict)
# test filter functions
self.assertDictEqual(parser.to_memory(res.parsed), self.gt_to_memory)
self.assertEqual(parser.to_content(res.parsed), self.gt_to_content)
self.assertDictEqual(
parser.to_metadata(res.parsed),
self.gt_to_metadata,
)
def test_markdownjsonobjectparser(self) -> None:
"""Test for MarkdownJsonObjectParser"""
# list
parser_list = MarkdownJsonObjectParser(content_hint=self.hint_list)
self.assertEqual(parser_list.format_instruction, self.instruction_list)
res_list = parser_list.parse(self.res_list)
self.assertListEqual(res_list.parsed, self.gt_list)
# float
parser_float = MarkdownJsonObjectParser(content_hint=self.hint_float)
self.assertEqual(
parser_float.format_instruction,
self.instruction_float,
)
res_float = parser_float.parse(self.res_float)
self.assertEqual(res_float.parsed, self.gt_float)
def test_markdowncodeblockparser(self) -> None:
"""Test for MarkdownCodeBlockParser"""
parser = MarkdownCodeBlockParser(language_name="python")
self.assertEqual(parser.format_instruction, self.instruction_code)
res = parser.parse(self.res_code)
self.assertEqual(res.parsed, self.gt_code)
def test_markdowncodeblockparser_with_hint(self) -> None:
"""Test for MarkdownCodeBlockParser"""
parser = MarkdownCodeBlockParser(
language_name="python",
content_hint="abc",
)
self.assertEqual(
parser.format_instruction,
self.instruction_code_with_hint,
)
res = parser.parse(self.res_code)
self.assertEqual(res.parsed, self.gt_code)
def test_multitaggedcontentparser(self) -> None:
"""Test for MultiTaggedContentParser"""
parser = MultiTaggedContentParser(
TaggedContent(
"speak",
tag_begin="[SPEAK]",
content_hint="what you speak",
tag_end="[/SPEAK]",
),
TaggedContent(
"thought",
tag_begin="[THOUGHT]",
content_hint="what you thought",
tag_end="[/THOUGHT]",
),
TaggedContent(
"end_discussion",
tag_begin="[END_DISCUSSION]",
content_hint="true/false",
tag_end="[/END_DISCUSSION]",
parse_json=True,
),
keys_to_memory=["speak", "thought"],
keys_to_content="speak",
keys_to_metadata=["end_discussion"],
)
self.assertEqual(parser.format_instruction, self.instruction_dict_2)
res = parser.parse(self.res_dict_2)
self.assertDictEqual(res.parsed, self.gt_dict)
# test filter functions
self.assertDictEqual(parser.to_memory(res.parsed), self.gt_to_memory)
self.assertEqual(parser.to_content(res.parsed), self.gt_to_content)
self.assertDictEqual(
parser.to_metadata(res.parsed),
self.gt_to_metadata,
)
def test_DictFilterMixin_default_value(self) -> None:
"""Test the default value of the DictFilterMixin class"""
mixin = DictFilterMixin(
keys_to_memory=True,
keys_to_content=True,
keys_to_metadata=False,
)
self.assertDictEqual(mixin.to_memory(self.gt_dict), self.gt_dict)
self.assertDictEqual(mixin.to_content(self.gt_dict), self.gt_dict)
self.assertEqual(mixin.to_metadata(self.gt_dict), None)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,259 @@
# -*- coding: utf-8 -*-
"""
Unit tests for pipeline classes and functions
"""
import unittest
import random
from agentscope.pipelines import (
SequentialPipeline,
IfElsePipeline,
SwitchPipeline,
ForLoopPipeline,
WhileLoopPipeline,
sequentialpipeline,
ifelsepipeline,
)
from agentscope.agents import AgentBase
class Add(AgentBase):
"""Operator for adding a value"""
def __init__(self, name: str, value: int) -> None:
self.name = name
self.value = value
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
x["value"] += self.value
return x
class Mult(AgentBase):
"""Operator for multiplying a value"""
def __init__(self, name: str, value: int) -> None:
self.name = name
self.value = value
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
x["value"] *= self.value
return x
class If_agent(AgentBase):
"""Operator for If condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, _: dict = None) -> dict:
return {"operation": "A"}
class Else_agent(AgentBase):
"""Operator for Else condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, _: dict = None) -> dict:
return {"operation": "B"}
class Case_agent(AgentBase):
"""Operator for Switch condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
return {"operation": x["text"].strip()}
class Default_agent(AgentBase):
"""Operator for Switch default condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
return {"operation": "IDLE"}
class Loop_for_agent(AgentBase):
"""Operator for Loop condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
x["value"] += 1
return x
class Loop_while_agent(AgentBase):
"""Operator for Loop condition"""
def __init__(self, name: str) -> None:
self.name = name
super().__init__(name=name)
def __call__(self, x: dict = None) -> dict:
x["token_num"] += random.randint(1, 100)
x["round"] += 1
return x
class BasicPipelineTest(unittest.TestCase):
"""Test cases for Basic Pipelines"""
def test_sequential_pipeline(self) -> None:
"""Test SequentialPipeline executes agents sequentially"""
add1 = Add("add1", 1)
add2 = Add("add2", 2)
mult3 = Mult("mult3", 3)
x = {"value": 0}
pipeline = SequentialPipeline([add1, add2, mult3])
self.assertEqual(pipeline(x)["value"], 9)
x = {"value": 0}
pipeline = SequentialPipeline([add1, mult3, add2])
self.assertEqual(pipeline(x)["value"], 5)
x = {"value": 0}
pipeline = SequentialPipeline([mult3, add1, add2])
self.assertEqual(pipeline(x)["value"], 3)
def test_if_else_pipeline(self) -> None:
"""Test IfElsePipeline executes if or else agent based on condition"""
if_x = {"text": "xxxx [PASS]"}
else_x = {"text": "xxxx"}
if_agent = If_agent("if_agent")
else_agent = Else_agent("else_agent")
p = IfElsePipeline(
condition_func=lambda x: "[PASS]" in x["text"],
if_body_operators=if_agent,
else_body_operators=else_agent,
)
x = p(if_x)
self.assertEqual(x["operation"], "A")
x = p(else_x)
self.assertEqual(x["operation"], "B")
def test_switch_pipeline(self) -> None:
"""Test SwitchPipeline executes one of the case agents or the default
agent
"""
tool_types = ["A", "B", "C", "D"]
case_agent = Case_agent(name="case_agent")
default_agent = Default_agent("default_agent")
case_agents = {k: case_agent for k in tool_types}
p = SwitchPipeline(
condition_func=lambda x: x["text"].strip(),
case_operators=case_agents,
default_operators=default_agent,
)
for tool in tool_types:
x = {"text": f"\n\n{tool}\n\n"}
x = p(x)
self.assertEqual(x["operation"], tool)
x = p({"text": "hello"})
self.assertEqual(x["operation"], "IDLE")
def test_for_pipeline(self) -> None:
"""Test ForLoopPipeline"""
loop_agent = Loop_for_agent("loop_agent")
# test max loop
x = {"value": 0}
p = ForLoopPipeline(loop_body_operators=loop_agent, max_loop=10)
x = p(x)
self.assertEqual(x["value"], 10)
x = {"value": 0}
p = ForLoopPipeline(
loop_body_operators=loop_agent,
max_loop=10,
break_func=lambda x: x["value"] > 5,
)
x = p(x)
self.assertEqual(x["value"], 6)
def test_while_pipeline(self) -> None:
"""Test WhileLoopPipeline"""
loop_agent = Loop_while_agent("loop_agent")
p = WhileLoopPipeline(
loop_body_operators=loop_agent,
condition_func=lambda i, x: i < 10 and not x["token_num"] > 500,
)
for _ in range(50):
x = {"token_num": 0, "round": 0}
x = p(x)
self.assertTrue(x["round"] >= 10 or x["token_num"] > 500)
class FunctionalPipelineTest(unittest.TestCase):
"""Test cases for Functional Pipelines"""
def test_sequential_pipeline(self) -> None:
"""Test SequentialPipeline executes agents sequentially"""
add1 = Add("add1", 1)
add2 = Add("add2", 2)
mult3 = Mult("mult3", 3)
x = {"value": 0}
x = sequentialpipeline(x=x, operators=[add1, add2, mult3])
self.assertEqual(x["value"], 9)
x = {"value": 0}
x = sequentialpipeline(x=x, operators=[add1, mult3, add2])
self.assertEqual(x["value"], 5)
x = {"value": 0}
x = sequentialpipeline(x=x, operators=[mult3, add1, add2])
self.assertEqual(x["value"], 3)
def test_if_else_pipeline(self) -> None:
"""Test ifelsepipeline executes if or else agent based on condition"""
if_x = {"text": "xxxx [PASS]"}
else_x = {"text": "xxxx"}
if_agent = If_agent("if_agent")
else_agent = Else_agent("else_agent")
if_x = ifelsepipeline(
x=if_x,
condition_func=lambda x: "[PASS]" in x["text"],
if_body_operators=if_agent,
else_body_operators=else_agent,
)
else_x = ifelsepipeline(
x=else_x,
condition_func=lambda x: "[PASS]" in x["text"],
if_body_operators=if_agent,
else_body_operators=else_agent,
)
self.assertEqual(if_x["operation"], "A")
self.assertEqual(else_x["operation"], "B")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
"""Unit test for prompt engine."""
import unittest
from typing import Any
from agentscope.models import read_model_configs, ModelResponse
from agentscope.models import load_model_by_config_name
from agentscope.models import OpenAIWrapperBase
from agentscope.prompt import PromptEngine
class PromptEngineTest(unittest.TestCase):
"""Unit test for prompt engine."""
def setUp(self) -> None:
"""Init for PromptEngineTest."""
self.name = "white"
self.sys_prompt = (
"You're a player in a chess game, and you are playing {name}."
)
self.dialog_history = [
{"name": "white player", "content": "Move to E4."},
{"name": "black player", "content": "Okay, I moved to F4."},
{"name": "white player", "content": "Move to F5."},
]
self.hint = "Now decide your next move."
self.prefix = "{name} player: "
read_model_configs(
[
{
"model_type": "post_api",
"config_name": "open-source",
"api_url": "http://xxx",
"headers": {"Autherization": "Bearer {API_TOKEN}"},
"parameters": {
"temperature": 0.5,
},
},
{
"model_type": "openai_chat",
"config_name": "gpt-4",
"model_name": "gpt-4",
"api_key": "xxx",
"organization": "xxx",
},
],
clear_existing=True,
)
def test_list_prompt(self) -> None:
"""Test for list prompt."""
class TestModelWrapperBase(OpenAIWrapperBase):
"""Test model wrapper."""
def __init__(self) -> None:
self.max_length = 1000
def __call__(
self,
*args: Any,
**kwargs: Any,
) -> ModelResponse:
return ModelResponse(text="")
def _register_default_metrics(self) -> None:
pass
model = TestModelWrapperBase()
engine = PromptEngine(model)
prompt = engine.join(
self.sys_prompt,
self.dialog_history,
self.hint,
format_map={"name": self.name},
)
self.assertEqual(
[
{
"role": "assistant",
"content": "You're a player in a chess game, and you are "
"playing white.",
},
{
"name": "white player",
"role": "assistant",
"content": "Move to E4.",
},
{
"name": "black player",
"role": "assistant",
"content": "Okay, I moved to F4.",
},
{
"name": "white player",
"role": "assistant",
"content": "Move to F5.",
},
{
"role": "assistant",
"content": "Now decide your next move.",
},
],
prompt,
)
def test_str_prompt(self) -> None:
"""Test for string prompt."""
model = load_model_by_config_name("open-source")
engine = PromptEngine(model)
prompt = engine.join(
self.sys_prompt,
self.dialog_history,
self.hint,
self.prefix,
format_map={"name": self.name},
)
self.assertEqual(
"""You're a player in a chess game, and you are playing white.
white player: Move to E4.
black player: Okay, I moved to F4.
white player: Move to F5.
Now decide your next move.
white player: """,
prompt,
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
""" Test for record api invocation."""
import json
import os
import unittest
from unittest.mock import patch, MagicMock
import agentscope
from agentscope.models import OpenAIChatWrapper
from agentscope._runtime import _Runtime
from agentscope.file_manager import _FileManager, file_manager
from agentscope.utils.monitor import MonitorFactory
def flush() -> None:
"""
** Only for unittest usage. Don't use this function in your code. **
Clear the runtime dir and destroy all singletons.
"""
_Runtime._flush() # pylint: disable=W0212
_FileManager._flush() # pylint: disable=W0212
MonitorFactory.flush()
class RecordApiInvocation(unittest.TestCase):
"""
Test for record api invocation.
"""
def setUp(self) -> None:
"""Init for RecordApiInvocation."""
self.dummy_response = {"content": "dummy_response"}
flush()
@patch("openai.OpenAI")
def test_record_model_invocation_with_init(
self,
mock_client: MagicMock,
) -> None:
"""Test record model invocation with calling init function."""
# prepare mock response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.model_dump.return_value = self.dummy_response
mock_response.usage.model_dump.return_value = {}
# link mock response to mock client
mock_openai_instance = mock_client.return_value
mock_openai_instance.chat.completions.create.return_value = (
mock_response
)
# test
agentscope.init(save_api_invoke=True)
model = OpenAIChatWrapper(
config_name="gpt-4",
api_key="xxx",
organization="xxx",
)
_ = model(messages=[])
# assert
self.assert_invocation_record()
def assert_invocation_record(self) -> None:
"""Assert invocation record."""
run_dir = file_manager.dir_root
records = [
_
for _ in os.listdir(
os.path.join(run_dir, "invoke"),
)
if _.startswith("model_OpenAIChatWrapper_")
]
# only one record is here
self.assertEqual(len(records), 1)
filename = records[0]
timestamp = filename.split("_")[2]
with open(
os.path.join(run_dir, "invoke", filename),
"r",
encoding="utf-8",
) as file:
self.assertEqual(
json.load(file),
{
"model_class": "OpenAIChatWrapper",
"timestamp": timestamp,
"arguments": {
"model": "gpt-4",
"messages": [],
},
"response": {
"content": "dummy_response",
},
},
)
def tearDown(self) -> None:
"""Tear down for RecordApiInvocation."""
flush()

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
""" Python web search test."""
from datetime import datetime
import unittest
from typing import Any
from agentscope.service import retrieve_from_list, cos_sim
from agentscope.service.service_status import ServiceExecStatus
from agentscope.message import MessageBase, Msg
from agentscope.memory.temporary_memory import TemporaryMemory
from agentscope.models import OpenAIEmbeddingWrapper, ModelResponse
class TestRetrieval(unittest.TestCase):
"""TestMemRetrieval for memory retrieval unit test."""
def test_retrieval_from_list(self) -> None:
"""test memory retrieval"""
class DummyModel(OpenAIEmbeddingWrapper):
"""
Dummy model wrapper for testing
"""
def __init__(self) -> None:
pass
def __call__(self, *args: Any, **kwargs: Any) -> ModelResponse:
print(*args, **kwargs)
return ModelResponse(raw={})
dummy_model = DummyModel()
query = Msg(name="Lora", content="test query", role="assistant")
query.embedding = [0, 1]
query.timestamp = "2023-12-18 21:40:59"
m1 = Msg(name="env", content="test", role="assistant")
m1.embedding = [1, 0]
m1.timestamp = "2023-12-18 21:45:59"
m2 = Msg(name="env", content="test2", role="assistant")
m2.embedding = [0.5, 0.5]
m2.timestamp = "2023-12-18 21:50:59"
memory = TemporaryMemory(config={}, embedding_model=dummy_model)
memory.add(m1)
memory.add(m2)
def score_func(m1: MessageBase, m2: MessageBase) -> float:
relevance = cos_sim(m1.embedding, m2.embedding).content
time_gap = (
datetime.strptime(m1.timestamp, "%Y-%m-%d %H:%M:%S")
- datetime.strptime(m2.timestamp, "%Y-%m-%d %H:%M:%S")
).total_seconds() / 60
recency = 0.99**time_gap
return recency + relevance
retrieved = retrieve_from_list(
query,
list(memory.get_memory()),
score_func,
embedding_model=dummy_model,
preserve_order=False,
)
self.assertEqual(retrieved.status, ServiceExecStatus.SUCCESS)
self.assertEqual(retrieved.content[0][2], m2)
self.assertEqual(retrieved.content[1][2], m1)
retrieved = retrieve_from_list(
query,
list(memory.get_memory(recent_n=2)),
score_func,
top_k=2,
embedding_model=None,
preserve_order=True,
)
self.assertEqual(retrieved.status, ServiceExecStatus.SUCCESS)
self.assertEqual(retrieved.content[0][2], m1)
# This allows the tests to be run from the command line
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,610 @@
# -*- coding: utf-8 -*-
"""
Unit tests for rpc agent classes
"""
import unittest
import time
import os
import shutil
from typing import Optional, Union, Sequence
from loguru import logger
import agentscope
from agentscope.agents import AgentBase, DistConf
from agentscope.server import RpcAgentServerLauncher
from agentscope.message import Msg
from agentscope.message import PlaceholderMessage
from agentscope.message import deserialize
from agentscope.msghub import msghub
from agentscope.pipelines import sequentialpipeline
from agentscope.utils import MonitorFactory, QuotaExceededError
class DemoRpcAgent(AgentBase):
"""A demo Rpc agent for test usage."""
def __init__(self, **kwargs) -> None: # type: ignore[no-untyped-def]
super().__init__(**kwargs)
self.id = 0
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
"""Response after 2s"""
x.id = self.id
self.id += 1
time.sleep(2)
return x
class DemoRpcAgentAdd(AgentBase):
"""A demo Rpc agent for test usage"""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
"""add the value, wait 1s"""
x.content["value"] += 1
time.sleep(1)
return x
class DemoLocalAgentAdd(AgentBase):
"""A demo local agent for test usage"""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
"""add the value, wait 1s"""
x.content["value"] += 1
time.sleep(1)
return x
class DemoRpcAgentWithMemory(AgentBase):
"""A demo Rpc agent that count its memory"""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
self.memory.add(x)
msg = Msg(
name=self.name,
content={"mem_size": self.memory.size()},
role="assistant",
)
self.memory.add(msg)
time.sleep(1)
return msg
class DemoRpcAgentWithMonitor(AgentBase):
"""A demo Rpc agent that use monitor"""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
monitor = MonitorFactory.get_monitor()
try:
monitor.update({"msg_num": 1})
except QuotaExceededError:
x.content["quota_exceeded"] = True
logger.chat(
{
"name": self.name,
"content": "quota_exceeded",
},
)
return x
x.content["msg_num"] = monitor.get_value("msg_num")
logger.chat(
{
"name": self.name,
"content": f"msg_num {x.content['msg_num']}",
},
)
time.sleep(0.2)
return x
class DemoGeneratorAgent(AgentBase):
"""A demo agent to generate a number"""
def __init__(self, name: str, value: int) -> None:
super().__init__(name)
self.value = value
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
time.sleep(1)
return Msg(
name=self.name,
role="assistant",
content={
"value": self.value,
},
)
class DemoGatherAgent(AgentBase):
"""A demo agent to gather value"""
def __init__(
self,
name: str,
agents: list[DemoGeneratorAgent],
to_dist: dict = None,
) -> None:
super().__init__(name, to_dist=to_dist)
self.agents = agents
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
result = []
stime = time.time()
for agent in self.agents:
result.append(agent())
value = 0
for r in result:
value += r.content["value"]
etime = time.time()
return Msg(
name=self.name,
role="assistant",
content={
"value": value,
"time": etime - stime,
},
)
class DemoErrorAgent(AgentBase):
"""A demo Rpc agent that raise Error"""
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
raise RuntimeError("Demo Error")
class BasicRpcAgentTest(unittest.TestCase):
"Test cases for Rpc Agent"
def setUp(self) -> None:
"""Init for Rpc Agent Test"""
agentscope.init(
project="test",
name="rpc_agent",
save_dir="./.unittest_runs",
save_log=True,
)
self.assertTrue(os.path.exists("./.unittest_runs"))
def tearDown(self) -> None:
MonitorFactory._instance = None # pylint: disable=W0212
logger.remove()
shutil.rmtree("./.unittest_runs")
def test_single_rpc_agent_server(self) -> None:
"""test setup a single rpc agent"""
agent_a = DemoRpcAgent(
name="a",
to_dist=True,
)
self.assertIsNotNone(agent_a)
msg = Msg(
name="System",
content={"text": "hello world"},
role="system",
)
result = agent_a(msg)
# get name without waiting for the server
self.assertEqual(result.name, "a")
self.assertEqual(result["name"], "a")
js_placeholder_result = result.serialize()
self.assertTrue(result._is_placeholder) # pylint: disable=W0212
placeholder_result = deserialize(js_placeholder_result)
self.assertTrue(isinstance(placeholder_result, PlaceholderMessage))
self.assertEqual(placeholder_result.name, "a")
self.assertEqual(
placeholder_result["name"], # type: ignore[call-overload]
"a",
)
self.assertTrue(
placeholder_result._is_placeholder, # pylint: disable=W0212
)
# wait to get content
self.assertEqual(result.content, msg.content)
self.assertFalse(result._is_placeholder) # pylint: disable=W0212
self.assertEqual(result.id, 0)
self.assertTrue(
placeholder_result._is_placeholder, # pylint: disable=W0212
)
self.assertEqual(placeholder_result.content, msg.content)
self.assertFalse(
placeholder_result._is_placeholder, # pylint: disable=W0212
)
self.assertEqual(placeholder_result.id, 0)
# check msg
js_msg_result = result.serialize()
msg_result = deserialize(js_msg_result)
self.assertTrue(isinstance(msg_result, Msg))
self.assertEqual(msg_result.content, msg.content)
self.assertEqual(msg_result.id, 0)
# check id increase
msg = agent_a(msg_result) # type: ignore[arg-type]
self.assertEqual(msg.id, 1)
def test_connect_to_an_existing_rpc_server(self) -> None:
"""test connecting to an existing server"""
launcher = RpcAgentServerLauncher(
# choose port automatically
host="127.0.0.1",
port=12010,
local_mode=False,
custom_agents=[DemoRpcAgent],
)
launcher.launch()
agent_a = DemoRpcAgent(
name="a",
).to_dist(
host="127.0.0.1",
port=launcher.port,
)
msg = Msg(
name="System",
content={"text": "hello world"},
role="system",
)
result = agent_a(msg)
# get name without waiting for the server
self.assertEqual(result.name, "a")
# waiting for server
self.assertEqual(result.content, msg.content)
# test dict usage
msg = Msg(
name="System",
content={"text": "hi world"},
role="system",
)
result = agent_a(msg)
# get name without waiting for the server
self.assertEqual(result["name"], "a")
# waiting for server
self.assertEqual(result["content"], msg.content)
# test to_str
msg = Msg(
name="System",
content={"text": "test"},
role="system",
)
result = agent_a(msg)
self.assertEqual(result.to_str(), "a: {'text': 'test'}")
launcher.shutdown()
def test_multi_rpc_agent(self) -> None:
"""test setup multi rpc agent"""
agent_a = DemoRpcAgentAdd(
name="a",
).to_dist(
lazy_launch=False,
)
agent_b = DemoRpcAgentAdd(
name="b",
).to_dist(
lazy_launch=False,
)
agent_c = DemoRpcAgentAdd(
name="c",
).to_dist(
lazy_launch=False,
)
# test sequential
msg = Msg(
name="System",
content={"value": 0},
role="system",
)
start_time = time.time()
msg = agent_a(msg)
self.assertTrue(isinstance(msg, PlaceholderMessage))
msg = agent_b(msg)
self.assertTrue(isinstance(msg, PlaceholderMessage))
msg = agent_c(msg)
self.assertTrue(isinstance(msg, PlaceholderMessage))
return_time = time.time()
# should return directly
self.assertTrue((return_time - start_time) < 1)
self.assertEqual(msg.content["value"], 3)
end_time = time.time()
# need at least 3s to finish
self.assertTrue((end_time - start_time) >= 3)
# test parallel
msg = Msg(
name="System",
content={"value": -1},
role="system",
)
start_time = time.time()
msg_a = agent_a(msg)
msg_b = agent_b(msg)
msg_c = agent_c(msg)
self.assertEqual(msg_a.content["value"], 0)
self.assertEqual(msg_b.content["value"], 0)
self.assertEqual(msg_c.content["value"], 0)
end_time = time.time()
# need 1s to finish
self.assertTrue((end_time - start_time) < 1.5)
def test_mix_rpc_agent_and_local_agent(self) -> None:
"""test to use local and rpc agent simultaneously"""
agent_a = DemoRpcAgentAdd(
name="a",
).to_dist(
lazy_launch=False,
)
# local agent b
agent_b = DemoLocalAgentAdd(
name="b",
)
# rpc agent c
agent_c = DemoRpcAgentAdd( # pylint: disable=E1123
name="c",
to_dist=DistConf(
lazy_launch=False,
),
)
msg = Msg(
name="System",
content={"value": 0},
role="system",
)
while msg.content["value"] < 4:
msg = agent_a(msg)
msg = agent_b(msg)
msg = agent_c(msg)
self.assertEqual(msg.content["value"], 6)
def test_msghub_compatibility(self) -> None:
"""test compatibility with msghub"""
agent_a = DemoRpcAgentWithMemory(
name="a",
).to_dist()
agent_b = DemoRpcAgentWithMemory(
name="b",
).to_dist()
agent_c = DemoRpcAgentWithMemory(
name="c",
to_dist=True,
)
participants = [agent_a, agent_b, agent_c]
annonuncement_msgs = [
Msg(name="System", content="Announcement 1", role="system"),
Msg(name="System", content="Announcement 2", role="system"),
]
with msghub(
participants=participants,
announcement=annonuncement_msgs,
):
x_a = agent_a()
x_b = agent_b(x_a)
x_c = agent_c(x_b)
self.assertEqual(x_a.content["mem_size"], 2)
self.assertEqual(x_b.content["mem_size"], 3)
self.assertEqual(x_c.content["mem_size"], 4)
x_a = agent_a(x_c)
self.assertEqual(x_a.content["mem_size"], 5)
x_b = agent_b(x_a)
self.assertEqual(x_b.content["mem_size"], 6)
x_c = agent_c(x_b)
self.assertEqual(x_c.content["mem_size"], 7)
x_c = sequentialpipeline(participants, x_c)
self.assertEqual(x_c.content["mem_size"], 10)
def test_standalone_multiprocess_init(self) -> None:
"""test compatibility with agentscope.init"""
monitor = MonitorFactory.get_monitor()
monitor.register("msg_num", quota=10)
# rpc agent a
agent_a = DemoRpcAgentWithMonitor(
name="a",
).to_dist(
lazy_launch=False,
)
# local agent b
agent_b = DemoRpcAgentWithMonitor(
name="b",
).to_dist(
lazy_launch=False,
)
msg = Msg(name="System", content={"msg_num": 0}, role="system")
j = 0
for _ in range(5):
msg = agent_a(msg)
self.assertEqual(msg["content"]["msg_num"], j + 1)
msg = agent_b(msg)
self.assertEqual(msg["content"]["msg_num"], j + 2)
j += 2
msg = agent_a(msg)
logger.chat(msg)
self.assertTrue(msg["content"]["quota_exceeded"])
msg = agent_b(msg)
logger.chat(msg)
self.assertTrue(msg["content"]["quota_exceeded"])
def test_multi_agent_in_same_server(self) -> None:
"""test agent server with multi agent"""
launcher = RpcAgentServerLauncher(
host="127.0.0.1",
port=12010,
local_mode=False,
custom_agents=[DemoRpcAgentWithMemory],
)
launcher.launch()
# although agent1 and agent2 connect to the same server
# they are different instances with different memories
agent1 = DemoRpcAgentWithMemory(
name="a",
)
oid = agent1.agent_id
agent1 = agent1.to_dist(
host="127.0.0.1",
port=launcher.port,
)
self.assertEqual(oid, agent1.agent_id)
self.assertEqual(oid, agent1.client.agent_id)
agent2 = DemoRpcAgentWithMemory( # pylint: disable=E1123
name="a",
to_dist={
"host": "127.0.0.1",
"port": launcher.port,
},
)
# agent3 has the same agent id as agent1
# so it share the same memory with agent1
agent3 = DemoRpcAgentWithMemory(
name="a",
).to_dist(
host="127.0.0.1",
port=launcher.port,
)
agent3._agent_id = agent1.agent_id # pylint: disable=W0212
agent3.client.agent_id = agent1.client.agent_id
msg1 = Msg(name="System", content="First Msg for agent1")
res1 = agent1(msg1)
self.assertEqual(res1.content["mem_size"], 1)
msg2 = Msg(name="System", content="First Msg for agent2")
res2 = agent2(msg2)
self.assertEqual(res2.content["mem_size"], 1)
msg3 = Msg(name="System", content="First Msg for agent3")
res3 = agent3(msg3)
self.assertEqual(res3.content["mem_size"], 3)
msg4 = Msg(name="System", content="Second Msg for agent2")
res4 = agent2(msg4)
self.assertEqual(res4.content["mem_size"], 3)
# delete existing agent
agent2.client.delete_agent()
msg2 = Msg(name="System", content="First Msg for agent2")
res2 = agent2(msg2)
self.assertRaises(ValueError, res2.__getattr__, "content")
# should override remote default parameter(e.g. name field)
agent4 = DemoRpcAgentWithMemory(
name="b",
).to_dist(
host="127.0.0.1",
port=launcher.port,
)
msg5 = Msg(name="System", content="Second Msg for agent4")
res5 = agent4(msg5)
self.assertEqual(res5.name, "b")
self.assertEqual(res5.content["mem_size"], 1)
launcher.shutdown()
def test_clone_instances(self) -> None:
"""Test the clone_instances method of RpcAgent"""
agent = DemoRpcAgentWithMemory(
name="a",
).to_dist()
# lazy launch will not init client
self.assertIsNone(agent.client)
# generate two agents (the first is it self)
agents = agent.clone_instances(2)
self.assertEqual(len(agents), 2)
agent1 = agents[0]
agent2 = agents[1]
self.assertTrue(agent1.agent_id.startswith("DemoRpcAgentWithMemory"))
self.assertTrue(agent2.agent_id.startswith("DemoRpcAgentWithMemory"))
self.assertTrue(
agent1.client.agent_id.startswith("DemoRpcAgentWithMemory"),
)
self.assertTrue(
agent2.client.agent_id.startswith("DemoRpcAgentWithMemory"),
)
self.assertNotEqual(agent1.agent_id, agent2.agent_id)
self.assertEqual(agent1.agent_id, agent1.client.agent_id)
self.assertEqual(agent2.agent_id, agent2.client.agent_id)
# clone instance will init client
self.assertIsNotNone(agent.client)
self.assertEqual(agent.agent_id, agent1.agent_id)
self.assertNotEqual(agent1.agent_id, agent2.agent_id)
self.assertIsNotNone(agent.server_launcher)
self.assertIsNotNone(agent1.server_launcher)
self.assertIsNone(agent2.server_launcher)
msg1 = Msg(name="System", content="First Msg for agent1")
res1 = agent1(msg1)
self.assertEqual(res1.content["mem_size"], 1)
msg2 = Msg(name="System", content="First Msg for agent2")
res2 = agent2(msg2)
self.assertEqual(res2.content["mem_size"], 1)
new_agents = agent.clone_instances(2, including_self=False)
agent3 = new_agents[0]
agent4 = new_agents[1]
self.assertEqual(len(new_agents), 2)
self.assertNotEqual(agent3.agent_id, agent.agent_id)
self.assertNotEqual(agent4.agent_id, agent.agent_id)
self.assertIsNone(agent3.server_launcher)
self.assertIsNone(agent4.server_launcher)
msg3 = Msg(name="System", content="First Msg for agent3")
res3 = agent3(msg3)
self.assertEqual(res1.content["mem_size"], 1)
msg4 = Msg(name="System", content="First Msg for agent4")
res4 = agent4(msg4)
self.assertEqual(res3.content["mem_size"], 1)
self.assertEqual(res4.content["mem_size"], 1)
def test_error_handling(self) -> None:
"""Test error handling"""
agent = DemoErrorAgent(name="a").to_dist()
x = agent()
self.assertRaises(RuntimeError, x.__getattr__, "content")
def test_agent_nesting(self) -> None:
"""Test agent nesting"""
host = "localhost"
launcher1 = RpcAgentServerLauncher(
# choose port automatically
host=host,
port=12010,
local_mode=False,
custom_agents=[DemoGatherAgent, DemoGeneratorAgent],
)
launcher2 = RpcAgentServerLauncher(
# choose port automatically
host=host,
port=12011,
local_mode=False,
custom_agents=[DemoGatherAgent, DemoGeneratorAgent],
)
launcher1.launch()
launcher2.launch()
agents = []
for i in range(8):
if i % 2:
agents.append(
DemoGeneratorAgent(name=f"a_{i}", value=i).to_dist(
host=host,
port=launcher1.port,
),
)
else:
agents.append(
DemoGeneratorAgent(name=f"a_{i}", value=i).to_dist(
host=host,
port=launcher2.port,
),
)
gather1 = DemoGatherAgent( # pylint: disable=E1123
name="g1",
agents=agents[:4],
to_dist=DistConf(
host=host,
port=launcher1.port,
),
)
gather2 = DemoGatherAgent( # pylint: disable=E1123
name="g2",
agents=agents[4:],
to_dist={
"host": host,
"port": launcher2.port,
},
)
r1 = gather1()
r2 = gather2()
self.assertEqual(r1.content["value"], 6)
self.assertEqual(r2.content["value"], 22)
self.assertTrue(0.5 < r1.content["time"] < 2)
self.assertTrue(0.5 < r2.content["time"] < 2)
launcher1.shutdown()
launcher2.shutdown()

69
AlgoriAgent/tests/run.py Normal file
View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# Copyright (c) Alibaba, Inc. and its affiliates.
# This file is licensed under the terms of the Apache 2.0 license. Some
# codes of this file is modified from
# https://github.com/alibaba/FederatedScope/blob/master/tests/run.py, which
# is also licensed under the terms of the Apache 2.0.
""" This module provides a test runner for unittest cases."""
import argparse
import os
import sys
import unittest
file_dir = os.path.join(os.path.dirname(__file__), "..")
sys.path.append(file_dir)
parser = argparse.ArgumentParser("test runner")
parser.add_argument("--list_tests", action="store_true", help="list all tests")
parser.add_argument("--pattern", default="*_test.py", help="test file pattern")
parser.add_argument(
"--test_dir",
default="tests",
help="directory to be tested",
)
args = parser.parse_args()
def gather_test_cases(
test_dir: str,
pattern: str,
list_tests: bool,
) -> unittest.TestSuite:
"""Gathers all the test cases that match the given pattern and
directory."""
test_suite = unittest.TestSuite()
discover = unittest.defaultTestLoader.discover(
test_dir,
pattern=pattern,
top_level_dir=None,
)
for suite_discovered in discover:
for test_case in suite_discovered:
test_suite.addTest(test_case)
if hasattr(test_case, "__iter__"):
for subcase in test_case:
if list_tests:
print(subcase)
else:
if list_tests:
print(test_case)
return test_suite
def main() -> None:
"""Main func for the runner for unittest cases."""
runner = unittest.TextTestRunner()
test_suite = gather_test_cases(
os.path.abspath(args.test_dir),
args.pattern,
args.list_tests,
)
if not args.list_tests:
res = runner.run(test_suite)
if not res.wasSuccessful():
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,380 @@
# -*- coding: utf-8 -*-
""" Unit test for service toolkit. """
import json
import unittest
from typing import Literal
from agentscope.models import ModelWrapperBase, ModelResponse
from agentscope.parsers import MultiTaggedContentParser, TaggedContent
from agentscope.service import (
bing_search,
execute_python_code,
retrieve_from_list,
query_mysql,
summarization,
)
from agentscope.service import ServiceToolkit
class ServiceToolkitTest(unittest.TestCase):
"""
Unit test for service toolkit.
"""
def setUp(self) -> None:
"""Init for ExampleTest."""
self.json_schema_bing_search1 = {
"type": "function",
"function": {
"name": "bing_search",
"description": (
"Search question in Bing Search API and "
"return the searching results"
),
"parameters": {
"type": "object",
"properties": {
"num_results": {
"type": "number",
"description": (
"The number of search " "results to return."
),
"default": 10,
},
"question": {
"type": "string",
"description": "The search query string.",
},
},
"required": [
"question",
],
},
},
}
self.json_schema_bing_search2 = {
"type": "function",
"function": {
"name": "bing_search",
"description": (
"Search question in Bing Search API and "
"return the searching results"
),
"parameters": {
"type": "object",
"properties": {
"question": {
"type": "string",
"description": "The search query string.",
},
},
"required": ["question"],
},
},
}
self.json_schema_func = {
"type": "function",
"function": {
"name": "func",
"description": None,
"parameters": {
"type": "object",
"properties": {
"c": {"default": "test"},
"d": {
"type": "typing.Literal",
"enum": [1, "abc", "d"],
"default": 1,
},
"b": {},
"a": {"type": "string"},
},
"required": ["a", "b"],
},
},
}
self.json_schema_execute_python_code = {
"type": "function",
"function": {
"name": "execute_python_code",
"description": "Execute a piece of python code.",
"parameters": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": (
"The Python code to be " "executed."
),
},
},
"required": ["code"],
},
},
}
self.json_schema_retrieve_from_list = {
"type": "function",
"function": {
"name": "retrieve_from_list",
"description": "Retrieve data in a list.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "Any",
"description": "A message to be retrieved.",
},
},
"required": [
"query",
],
},
},
}
self.json_schema_query_mysql = {
"type": "function",
"function": {
"name": "query_mysql",
"description": "Execute query within MySQL database.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "SQL query to execute.",
},
},
"required": [
"query",
],
},
},
}
self.json_schema_summarization = {
"type": "function",
"function": {
"name": "summarization",
"description": "Summarize the input text.",
"parameters": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": (
"Text to be summarized by " "the model."
),
},
},
"required": [
"text",
],
},
},
}
def test_bing_search(self) -> None:
"""Test bing_search."""
# api_key is specified by developer, while question and num_results
# are specified by model
_, doc_dict = ServiceToolkit.get(bing_search, api_key="xxx")
print(json.dumps(doc_dict, indent=4))
self.assertDictEqual(
doc_dict,
self.json_schema_bing_search1,
)
# Set num_results by developer rather than model
_, doc_dict = ServiceToolkit.get(
bing_search,
num_results=3,
api_key="xxx",
)
self.assertDictEqual(
doc_dict,
self.json_schema_bing_search2,
)
def test_enum(self) -> None:
"""Test enum in service toolkit."""
def func( # type: ignore
a: str,
b,
c="test",
d: Literal[1, "abc", "d"] = 1,
) -> None:
print(a, b, c, d)
_, doc_dict = ServiceToolkit.get(func)
self.assertDictEqual(
doc_dict,
self.json_schema_func,
)
def test_exec_python_code(self) -> None:
"""Test execute_python_code in service toolkit."""
_, doc_dict = ServiceToolkit.get(
execute_python_code,
timeout=300,
use_docker=True,
maximum_memory_bytes=None,
)
self.assertDictEqual(
doc_dict,
self.json_schema_execute_python_code,
)
def test_retrieval(self) -> None:
"""Test retrieval in service toolkit."""
_, doc_dict = ServiceToolkit.get(
retrieve_from_list,
knowledge=[1, 2, 3],
score_func=lambda x, y: 1.0,
top_k=10,
embedding_model=10,
preserve_order=True,
)
self.assertDictEqual(
doc_dict,
self.json_schema_retrieve_from_list,
)
def test_sql_query(self) -> None:
"""Test sql_query in service toolkit."""
_, doc_dict = ServiceToolkit.get(
query_mysql,
database="test",
host="localhost",
user="root",
password="xxx",
port=3306,
allow_change_data=False,
maxcount_results=None,
)
self.assertDictEqual(
doc_dict,
self.json_schema_query_mysql,
)
def test_summary(self) -> None:
"""Test summarization in service toolkit."""
_, doc_dict = ServiceToolkit.get(
summarization,
model=ModelWrapperBase("abc"),
system_prompt="",
summarization_prompt="",
max_return_token=-1,
token_limit_prompt="",
)
print(json.dumps(doc_dict, indent=4))
self.assertDictEqual(
doc_dict,
self.json_schema_summarization,
)
def test_service_toolkit(self) -> None:
"""Test the object of ServiceToolkit."""
service_toolkit = ServiceToolkit()
service_toolkit.add(bing_search, api_key="xxx", num_results=3)
service_toolkit.add(
execute_python_code,
timeout=300,
use_docker=True,
maximum_memory_bytes=None,
)
self.assertEqual(
service_toolkit.tools_instruction,
"""## Tool Functions:
The following tool functions are available in the format of
```
{index}. {function name}: {function description}
{argument1 name} ({argument type}): {argument description}
{argument2 name} ({argument type}): {argument description}
...
```
1. bing_search: Search question in Bing Search API and return the searching results
question (string): The search query string.
2. execute_python_code: Execute a piece of python code.
code (string): The Python code to be executed.
""", # noqa
)
self.assertDictEqual(
service_toolkit.json_schemas,
{
"bing_search": self.json_schema_bing_search2,
"execute_python_code": self.json_schema_execute_python_code,
},
)
def test_multi_tagged_content(self) -> None:
"""Test multi tagged content"""
parser = MultiTaggedContentParser(
TaggedContent(
"thought",
"[THOUGHT]",
"what you think",
"[/THOUGHT]",
),
TaggedContent("speak", "[SPEAK]", "what you speak", "[/SPEAK]"),
TaggedContent(
"function",
"[FUNCTION]",
'{"function name": "xxx", "args": {"arg name": "xxx"}}',
"[/FUNCTION]",
parse_json=True,
),
)
target_format_instruction = (
"Respond with specific tags as outlined below, and the content "
"between [FUNCTION] and [/FUNCTION] MUST be a JSON object:\n"
"[THOUGHT]what you think[/THOUGHT]\n"
"[SPEAK]what you speak[/SPEAK]\n"
'[FUNCTION]{"function name": "xxx", "args": {"arg name": "xxx"}}'
"[/FUNCTION]"
)
self.assertEqual(parser.format_instruction, target_format_instruction)
response = ModelResponse(
text=(
"This is a test\n[THOUGHT]I think this is a good idea"
"[/THOUGHT]\n[SPEAK]I am speaking now[/SPEAK]\n[FUNCTION]"
'{"function name": "bing_search", "args": {"query": "news of '
'today"}}[/FUNCTION]'
),
)
res = parser.parse(response)
self.assertDictEqual(
res.parsed,
{
"thought": "I think this is a good idea",
"speak": "I am speaking now",
"function": {
"function name": "bing_search",
"args": {"query": "news of today"},
},
},
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,175 @@
# -*- coding: utf-8 -*-
""" Python sql query test."""
import unittest
from unittest.mock import MagicMock, patch
from agentscope.service.sql_query.mongodb import query_mongodb
from agentscope.service.sql_query.mysql import query_mysql
from agentscope.service.service_response import ServiceExecStatus
from agentscope.service.sql_query.sqlite import query_sqlite
class TestSQLQueries(unittest.TestCase):
"""ExampleTest for a unit test."""
@patch("agentscope.service.sql_query.mysql.pymysql.connect")
def test_query_mysql_success(self, mock_connect: MagicMock) -> None:
"""Test query mysql success"""
# Set up a mock connection and cursor
mock_cursor = mock_connect.return_value.cursor.return_value
mock_cursor.fetchall.return_value = [("data1",), ("data2",)]
# Call the query_mysql function
response = query_mysql(
database="test_mysql_db",
query="SELECT * FROM my_table",
host="localhost",
user="user",
password="pass",
port=3306,
allow_change_data=False,
maxcount_results=10,
)
# Assert that the query_mysql function returned the expected results
self.assertEqual(response.status, ServiceExecStatus.SUCCESS)
self.assertEqual(response.content, [("data1",), ("data2",)])
# Ensure that the SQL query was executed correctly
mock_cursor.execute.assert_called_once_with(
"SELECT * FROM my_table LIMIT 10",
)
# Ensure that all results were fetched
mock_cursor.fetchall.assert_called_once()
@patch("agentscope.service.sql_query.mysql.pymysql.connect")
def test_query_mysql_failure(self, mock_connect: MagicMock) -> None:
"""Test query mysql failure"""
# Set up pymysql.connect to raise an exception
mock_connect.side_effect = Exception("Connection Error")
# Call the query_mysql function
response = query_mysql(
database="test_mysql_db",
query="SELECT * FROM my_table",
host="localhost",
user="user",
password="pass",
port=3306,
)
# Assert that the query_mysql function handled the exception
self.assertEqual(response.status, ServiceExecStatus.ERROR)
self.assertIn("Connection Error", str(response.content))
# Test for mongodb
@patch("agentscope.service.sql_query.mongodb.pymongo.MongoClient")
def test_query_mongodb_success(self, mock_mongo_client: MagicMock) -> None:
"""Test query mongodb success"""
# Set up a mock connection
mock_collection = MagicMock()
mock_collection.find.return_value.limit.return_value = [
{"_id": 1, "data": "test"},
]
mock = MagicMock()
mock_db = MagicMock()
mock.__getitem__.return_value = mock_db
mock_db.__getitem__.return_value = mock_collection
mock_client = MagicMock()
mock_mongo_client.return_value.__enter__.return_value = mock_client
mock_client.__getitem__.return_value = mock_db
# Call the query_mongodb function
response = query_mongodb(
database="db_name",
collection="collection_name",
query={"data": "test"},
host="localhost",
port=27017,
maxcount_results=10,
)
# Ensure that the query_mongodb returned the expected results
self.assertEqual(response.status, ServiceExecStatus.SUCCESS)
self.assertEqual(response.content, [{"_id": 1, "data": "test"}])
# Ensure that the query was executed correctly
mock_db.__getitem__.assert_called_with("collection_name")
mock_collection.find.assert_called_with({"data": "test"})
mock_collection.find.return_value.limit.assert_called_with(10)
@patch("agentscope.service.sql_query.mongodb.pymongo.MongoClient")
def test_query_mongodb_failure(self, mock_mongo_client: MagicMock) -> None:
"""Test query mongodb failure"""
# Configure the mock to raise a connection error
mock_mongo_client.side_effect = Exception("Connection Error")
# Call the query_mongodb function
response = query_mongodb(
database="test_db",
collection="test_collection",
query={"name": "Test Data"},
host="localhost",
port=27017,
)
# Assert that the function handled the exception
self.assertEqual(response.status, ServiceExecStatus.ERROR)
self.assertIn("Connection Error", str(response.content))
# Test for sqlite
@patch("agentscope.service.sql_query.sqlite.sqlite3.connect")
def test_query_sqlite_success(self, mock_connect: MagicMock) -> None:
"""Test successful SELECT query without data modification"""
# Mock sqlite connection and cursor
mock_cursor = MagicMock()
mock_cursor.fetchall.return_value = [("data1",), ("data2",)]
mock_connection = MagicMock()
mock_connection.cursor.return_value = mock_cursor
mock_connect.return_value = mock_connection
# Execute the query_sqlite function
response = query_sqlite(
database="test_db.sqlite",
query="SELECT * FROM my_table",
allow_change_data=False,
maxcount_results=10,
)
# Assert the query_sqlite function returned expected results
self.assertEqual(response.status, ServiceExecStatus.SUCCESS)
self.assertEqual(response.content, [("data1",), ("data2",)])
# Verify the correct SQL query was executed
mock_cursor.execute.assert_called_with(
"SELECT * FROM my_table LIMIT 10",
)
# Ensure all results were fetched
mock_cursor.fetchall.assert_called_once()
@patch("agentscope.service.sql_query.sqlite.sqlite3.connect")
def test_query_sqlite_exception_handling(
self,
mock_connect: MagicMock,
) -> None:
"""Test exception handling within the query_sqlite function"""
# Configure the mock to raise an exception during connection
mock_connect.side_effect = Exception("Connection Error")
# Execute the query_sqlite function
response = query_sqlite(
database="test_db.sqlite",
query="SELECT * FROM my_table",
)
# Assert that the function handled the exception
self.assertEqual(response.status, ServiceExecStatus.ERROR)
self.assertIn("Connection Error", str(response.content))
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
""" Unit test for token_utils."""
import unittest
from agentscope.utils.token_utils import get_openai_max_length
from agentscope.utils.token_utils import count_openai_token
class TokenUtilsTest(unittest.TestCase):
"""Token utils test."""
def test_get_openai_max_length(self) -> None:
"""Test the function get_openai_max_length."""
self.assertEqual(get_openai_max_length("gpt-4"), 8192)
self.assertEqual(get_openai_max_length("gpt-3.5-turbo"), 4096)
with self.assertRaises(KeyError):
get_openai_max_length("non-existing-model")
def test_count_openai_token(self) -> None:
"""Test the function count_openai_token."""
test_model_1 = "text-davinci-003"
test_content_str = "This is a test string."
self.assertEqual(
count_openai_token(test_content_str, test_model_1),
6,
)
test_content_list = [
{
"role": "system",
"content": "This is a system content.",
},
{
"role": "user",
"name": "example_user",
"content": "This is a user content.",
},
]
test_model_2 = "gpt-4"
self.assertEqual(
count_openai_token(test_content_list, test_model_2),
26,
)
# Test unsupported model
unsupported_model = "unsupported-model"
with self.assertRaises(NotImplementedError):
count_openai_token(test_content_str, unsupported_model)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
""" Python web digest test."""
import unittest
from typing import Union, Sequence, List
from unittest.mock import patch, MagicMock, Mock
from agentscope.service import ServiceResponse
from agentscope.service import load_web, digest_webpage
from agentscope.service.service_status import ServiceExecStatus
from agentscope.models import ModelWrapperBase, ModelResponse
from agentscope.message import Msg
class TestWebDigest(unittest.TestCase):
"""Tests for web loading and digesting."""
@patch("requests.get")
def test_web_load(self, mock_get: MagicMock) -> None:
"""test web_load function loading html"""
# Set up the mock response
mock_response = Mock()
mock_return_text = """
<!DOCTYPE html>
<html>
<body>
<div>
<h1>Hello World!</h1>
<div>
Testing!
<p>
Some intro text about Foo. <a href="xxx">Examples</a>
<ol>
<li>Test list.</li>
</ol>
</div>
</div>
<ol>
<li>Test list again.</li>
</ol>
</body>
</html>
"""
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content={
"raw": bytes(mock_return_text, "utf-8"),
"html_to_text": "Hello World! Testing! Some intro text "
"about Foo. Test list.Test list again.",
},
)
mock_response.text = mock_return_text
mock_response.content = bytes(mock_return_text, "utf-8")
mock_response.status_code = 200
mock_response.headers = {"Content-Type": "text/html"}
mock_get.return_value = mock_response
# set parameters
fake_url = "fake-url"
results = load_web(
url=fake_url,
keep_raw=True,
html_selected_tags=["p", "div", "h1", "li"],
)
self.assertEqual(
results,
expected_result,
)
def test_web_digest(self) -> None:
"""test web_digest function"""
# test the case with dummy model
class DummyModel(ModelWrapperBase):
"""Dummy model for testing"""
def __init__(self) -> None:
self.max_length = 1000
def __call__(self, messages: list[Msg]) -> ModelResponse:
return ModelResponse(text="model return")
def format(
self,
*args: Union[Msg, Sequence[Msg]],
) -> Union[List[dict], str]:
return str(args)
dummy_model = DummyModel()
response = digest_webpage("testing", dummy_model)
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content="model return",
)
self.assertEqual(
response,
expected_result,
)
# This allows the tests to be run from the command line
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
""" Python web search test."""
import unittest
from unittest.mock import Mock, patch, MagicMock
from agentscope.service import ServiceResponse, arxiv_search
from agentscope.service import bing_search, google_search
from agentscope.service.service_status import ServiceExecStatus
from agentscope.service.web.arxiv import _reformat_query
class TestWebSearches(unittest.TestCase):
"""ExampleTest for a unit test."""
@patch("agentscope.utils.common.requests.get")
def test_search_bing(self, mock_get: MagicMock) -> None:
"""test bing search"""
# Set up the mock response
mock_response = Mock()
mock_dict = {
"webPages": {
"value": [
{
"name": "Test name from Bing",
"url": "Test url from Bing",
"snippet": "Test snippet from Bing",
},
],
},
}
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content=[
{
"title": "Test name from Bing",
"link": "Test url from Bing",
"snippet": "Test snippet from Bing",
},
],
)
mock_response.json.return_value = mock_dict
mock_get.return_value = mock_response
# set parameters
bing_api_key = "fake-bing-api-key"
test_question = "test test_question"
num_results = 1
params = {"q": test_question, "count": num_results}
headers = {"Ocp-Apim-Subscription-Key": bing_api_key}
# Call the function
results = bing_search(
test_question,
api_key=bing_api_key,
num_results=num_results,
)
# Assertions
mock_get.assert_called_once_with(
"https://api.bing.microsoft.com/v7.0/search",
params=params,
headers=headers,
)
self.assertEqual(
results,
expected_result,
)
@patch("agentscope.utils.common.requests.get")
def test_search_google(self, mock_get: MagicMock) -> None:
"""test google search"""
# Set up the mock response
mock_response = Mock()
mock_dict = {
"items": [
{
"title": "Test title from Google",
"link": "Test link from Google",
"snippet": "Test snippet from Google",
},
],
}
expected_result = ServiceResponse(
status=ServiceExecStatus.SUCCESS,
content=[
{
"title": "Test title from Google",
"link": "Test link from Google",
"snippet": "Test snippet from Google",
},
],
)
mock_response.json.return_value = mock_dict
mock_get.return_value = mock_response
# set parameter
test_question = "test test_question"
google_api_key = "fake-google-api-key"
google_cse_id = "fake-google-cse-id"
num_results = 1
params = {
"q": test_question,
"key": google_api_key,
"cx": google_cse_id,
"num": num_results,
}
# Call the function
results = google_search(
test_question,
api_key=google_api_key,
cse_id=google_cse_id,
num_results=num_results,
)
# Assertions
mock_get.assert_called_once_with(
"https://www.googleapis.com/customsearch/v1",
params=params,
)
self.assertEqual(results, expected_result)
def test_arxiv_search(self) -> None:
"""test arxiv search"""
res = arxiv_search(
search_query="ti:Agentscope",
id_list=["2402.14034"],
max_results=1,
)
self.assertEqual(
res.content["entries"][0]["title"],
"AgentScope: A Flexible yet Robust Multi-Agent Platform",
)
def test_arxiv_query_format(self) -> None:
"""Test arxiv query format."""
res = _reformat_query(
'ti: "Deep Learning" ANDau:LeCun OR (ti: machine learning '
"ANDNOT au:John Doe)",
)
ground_truth = (
"ti:%22Deep+Learning%22+AND+au:%22LeCun%22+OR+%28ti:"
"%22machine+learning%22+ANDNOT+au:%22John+Doe%22%29"
)
self.assertEqual(ground_truth, res)
# This allows the tests to be run from the command line
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""zhipuai test"""
import unittest
from unittest.mock import patch, MagicMock
import agentscope
from agentscope.models import load_model_by_config_name
class TestZhipuAIChatWrapper(unittest.TestCase):
"""Test ZhipuAI Chat Wrapper"""
def setUp(self) -> None:
self.api_key = "test_api_key.secret_key"
self.messages = [
{"role": "user", "content": "Hello, ZhipuAI!"},
{"role": "assistant", "content": "How can I assist you?"},
]
@patch("agentscope.models.zhipu_model.zhipuai")
def test_chat(self, mock_zhipuai: MagicMock) -> None:
"""
Test chat"""
mock_response = MagicMock()
mock_response.model_dump.return_value = {
"choices": [
{"message": {"content": "Hello, this is a mocked response!"}},
],
"usage": {
"prompt_tokens": 100,
"completion_tokens": 5,
"total_tokens": 105,
},
}
mock_response.choices[
0
].message.content = "Hello, this is a mocked response!"
mock_zhipuai_client = MagicMock()
mock_zhipuai.ZhipuAI.return_value = mock_zhipuai_client
mock_zhipuai_client.chat.completions.create.return_value = (
mock_response
)
agentscope.init(
model_configs={
"config_name": "test_config",
"model_type": "zhipuai_chat",
"model_name": "glm-4",
"api_key": self.api_key,
},
)
model = load_model_by_config_name("test_config")
response = model(messages=self.messages)
self.assertEqual(response.text, "Hello, this is a mocked response!")
mock_zhipuai_client.chat.completions.create.assert_called_once()
class TestZhipuAIEmbeddingWrapper(unittest.TestCase):
"""Test ZhipuAI Embedding Wrapper"""
def setUp(self) -> None:
self.api_key = "test_api_key"
self.model_name = "embedding-2"
self.text_to_embed = "This is a test sentence for embedding."
@patch("agentscope.models.zhipu_model.zhipuai")
def test_embedding(self, mock_zhipuai: MagicMock) -> None:
"""Test embedding API"""
mock_embedding_response = MagicMock()
mock_embedding_response.model_dump.return_value = {
"data": [
{"embedding": [0.1, 0.2, 0.3]},
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 2,
"total_tokens": 12,
},
}
mock_zhipuai_client = MagicMock()
mock_zhipuai.ZhipuAI.return_value = mock_zhipuai_client
mock_zhipuai_client.embeddings.create.return_value = (
mock_embedding_response
)
agentscope.init(
model_configs={
"config_name": "test_embedding",
"model_type": "zhipuai_embedding",
"model_name": self.model_name,
"api_key": self.api_key,
},
)
model = load_model_by_config_name("test_embedding")
response = model(self.text_to_embed)
expected_embedding = [[0.1, 0.2, 0.3]]
self.assertEqual(response.embedding, expected_embedding)
mock_zhipuai_client.embeddings.create.assert_called_once_with(
input=self.text_to_embed,
model=self.model_name,
**{},
)
if __name__ == "__main__":
unittest.main()