cai/tests/test_core.py

149 lines
4.7 KiB
Python

import pytest
from cai import CAI, Agent
from tests.mock_client import MockOpenAIClient, create_mock_response
from unittest.mock import Mock
import json
DEFAULT_RESPONSE_CONTENT = "sample response content"
@pytest.fixture
def mock_openai_client():
m = MockOpenAIClient()
m.set_response(
create_mock_response(
{"role": "assistant", "content": DEFAULT_RESPONSE_CONTENT})
)
return m
def test_run_with_simple_message(mock_openai_client: MockOpenAIClient):
agent = Agent()
# set up client and run
client = CAI(client=mock_openai_client)
messages = [{"role": "user", "content": "Hello, how are you?"}]
response = client.run(agent=agent, messages=messages)
# assert response content
assert response.messages[-1]["role"] == "assistant"
assert response.messages[-1]["content"] == DEFAULT_RESPONSE_CONTENT
def test_tool_call(mock_openai_client: MockOpenAIClient):
expected_location = "San Francisco"
# set up mock to record function calls
get_weather_mock = Mock()
def get_weather(location):
get_weather_mock(location=location)
return "It's sunny today."
agent = Agent(name="Test Agent", functions=[get_weather])
messages = [
{"role": "user", "content": "What's the weather like in San Francisco?"}
]
# set mock to return a response that triggers function call
mock_openai_client.set_sequential_responses(
[
create_mock_response(
message={"role": "assistant", "content": ""},
function_calls=[
{"name": "get_weather",
"args": {"location": expected_location}}
],
),
create_mock_response(
{"role": "assistant", "content": DEFAULT_RESPONSE_CONTENT}
),
]
)
# set up client and run
client = CAI(client=mock_openai_client)
response = client.run(agent=agent, messages=messages)
get_weather_mock.assert_called_once_with(location=expected_location)
assert response.messages[-1]["role"] == "assistant"
assert response.messages[-1]["content"] == DEFAULT_RESPONSE_CONTENT
def test_execute_tools_false(mock_openai_client: MockOpenAIClient):
expected_location = "San Francisco"
# set up mock to record function calls
get_weather_mock = Mock()
def get_weather(location):
get_weather_mock(location=location)
return "It's sunny today."
agent = Agent(name="Test Agent", functions=[get_weather])
messages = [
{"role": "user", "content": "What's the weather like in San Francisco?"}
]
# set mock to return a response that triggers function call
mock_openai_client.set_sequential_responses(
[
create_mock_response(
message={"role": "assistant", "content": ""},
function_calls=[
{"name": "get_weather",
"args": {"location": expected_location}}
],
),
create_mock_response(
{"role": "assistant", "content": DEFAULT_RESPONSE_CONTENT}
),
]
)
# set up client and run
client = CAI(client=mock_openai_client)
response = client.run(agent=agent, messages=messages, execute_tools=False)
print(response)
# assert function not called
get_weather_mock.assert_not_called()
# assert tool call is present in last response
tool_calls = response.messages[-1].get("tool_calls")
assert tool_calls is not None and len(tool_calls) == 1
tool_call = tool_calls[0]
assert tool_call["function"]["name"] == "get_weather"
assert json.loads(tool_call["function"]["arguments"]) == {
"location": expected_location
}
def test_handoff(mock_openai_client: MockOpenAIClient):
def transfer_to_agent2():
return agent2
agent1 = Agent(name="Test Agent 1", functions=[transfer_to_agent2])
agent2 = Agent(name="Test Agent 2")
# set mock to return a response that triggers the handoff
mock_openai_client.set_sequential_responses(
[
create_mock_response(
message={"role": "assistant", "content": ""},
function_calls=[{"name": "transfer_to_agent2"}],
),
create_mock_response(
{"role": "assistant", "content": DEFAULT_RESPONSE_CONTENT}
),
]
)
# set up client and run
client = CAI(client=mock_openai_client)
messages = [{"role": "user", "content": "I want to talk to agent 2"}]
response = client.run(agent=agent1, messages=messages)
assert response.agent == agent2
assert response.messages[-1]["role"] == "assistant"
assert response.messages[-1]["content"] == DEFAULT_RESPONSE_CONTENT