Skip to content
This repository has been archived by the owner on Nov 3, 2024. It is now read-only.

Commit

Permalink
[HN-137/HN-275] feat: added chat history and updated chat endpoint (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
ToJen authored Jun 13, 2024
1 parent 19370aa commit c26b38a
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 37 deletions.
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ To use the `HiveAgentClient` library, you first need to ensure that you have Pyt
1. **Install Poetry**

If you don't have Poetry installed, you can install it using the following commands:
`$ curl -sSL https://install.python-poetry.org | python3 -`
`$ export PATH="$HOME/.local/bin:$PATH"`
```sh
$ curl -sSL https://install.python-poetry.org | python3 -
$ export PATH="$HOME/.local/bin:$PATH"
```

2. **Activate the Virtual Environment**
Activate the virtual environment created by Poetry with the following command:
`$ poetry shell`
```sh
$ poetry shell
```

3. **Install Dependencies**

`$ poetry install --no-root`

```sh
$ poetry install --no-root
```

## Usage

Expand All @@ -36,7 +41,7 @@ client = HiveAgentClient(base_url="http://localhost:8000", timeout=30)
# send a message and receive the response
try:
response = client.chat("Hello, Hive Agent!")
response = await client.chat(user_id="user123", session_id="session123", content="Hello, Hive Agent!")
print(response)
except Exception as e:
print(f"an error occurred: {e}")
Expand Down
2 changes: 1 addition & 1 deletion hive_agent_client/chat/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .chat import send_chat_message
from .chat import send_chat_message, get_chat_history
57 changes: 55 additions & 2 deletions hive_agent_client/chat/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
import sys
from typing import List, Dict


def get_log_level():
Expand All @@ -17,13 +18,15 @@ def get_log_level():


async def send_chat_message(
http_client: httpx.AsyncClient, base_url: str, content: str
http_client: httpx.AsyncClient, base_url: str, user_id: str, session_id: str, content: str
) -> str:
"""
Sends a chat message to the Hive Agent API and returns the response.
:param http_client: An instance of httpx.AsyncClient to make HTTP requests.
:param base_url: The base URL of the Hive Agent API.
:param user_id: The user ID.
:param session_id: The session ID.
:param content: The content of the message to be sent.
:return: The response text from the API.
:raises ValueError: If the content is empty.
Expand All @@ -35,7 +38,11 @@ async def send_chat_message(

endpoint = "/chat"
url = f"{base_url}{endpoint}"
payload = {"messages": [{"role": "user", "content": content}]}
payload = {
"user_id": user_id,
"session_id": session_id,
"chat_data": {"messages": [{"role": "user", "content": content}]}
}

try:
logging.debug(f"Sending chat message to {url}: {content}")
Expand All @@ -62,3 +69,49 @@ async def send_chat_message(
raise Exception(
f"An unexpected error occurred when sending message to the chat API: {e}"
)


async def get_chat_history(
http_client: httpx.AsyncClient, base_url: str, user_id: str, session_id: str
) -> List[Dict]:
"""
Retrieves the chat history from the Hive Agent API.
:param http_client: An instance of httpx.AsyncClient to make HTTP requests.
:param base_url: The base URL of the Hive Agent API.
:param user_id: The user ID.
:param session_id: The session ID.
:return: The chat history as a list of dictionaries.
:raises httpx.HTTPStatusError: If the request fails due to a network error or returns a 4xx/5xx response.
:raises Exception: For other types of errors.
"""
endpoint = "/chat_history"
url = f"{base_url}{endpoint}"
params = {"user_id": user_id, "session_id": session_id}

try:
logging.debug(f"Fetching chat history from {url} with params: {params}")
response = await http_client.get(url, params=params)
response.raise_for_status()
chat_history = response.json()
logger.debug(f"Chat history for user {user_id} and session {session_id}: {chat_history}")
return chat_history
except httpx.HTTPStatusError as e:
logging.error(
f"HTTP error occurred when fetching chat history from {url}: {e.response.status_code} - {e.response.text}"
)
raise Exception(
f"HTTP error occurred when fetching chat history from the chat API: {e.response.status_code} - {e.response.text}"
)
except httpx.RequestError as e:
logging.error(f"Request error occurred when fetching chat history from {url}: {e}")
raise Exception(
f"Request error occurred when fetching chat history from the chat API: {e}"
)
except Exception as e:
logging.error(
f"An unexpected error occurred when fetching chat history from {url}: {e}"
)
raise Exception(
f"An unexpected error occurred when fetching chat history from the chat API: {e}"
)
22 changes: 19 additions & 3 deletions hive_agent_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
from typing import Dict, List

from hive_agent_client.chat import send_chat_message
from hive_agent_client.chat import send_chat_message, get_chat_history
from hive_agent_client.database import (
create_table,
insert_data,
Expand Down Expand Up @@ -34,20 +34,36 @@ def __init__(self, base_url: str, version: str = "v1"):
self.base_url = f"{base_url}/{version}"
self.http_client = httpx.AsyncClient()

async def chat(self, content: str) -> str:
async def chat(self, user_id: str, session_id: str, content: str) -> str:
"""
Send a message to the chat endpoint.
:param user_id: The user ID.
:param session_id: The session ID.
:param content: The content of the message to send.
:return: The response from the chat API as a string.
"""
try:
logger.debug(f"Sending message to chat endpoint: {content}")
return await send_chat_message(self.http_client, self.base_url, content)
return await send_chat_message(self.http_client, self.base_url, user_id, session_id, content)
except Exception as e:
logger.error(f"Failed to send chat message - {content}: {e}")
raise Exception(f"Failed to send chat message: {e}")

async def get_chat_history(self, user_id: str, session_id: str) -> List[Dict]:
"""
Retrieve the chat history for a specified user and session.
:param user_id: The user ID.
:param session_id: The session ID.
:return: The chat history as a list of dictionaries.
"""
try:
return await get_chat_history(self.http_client, self.base_url, user_id, session_id)
except Exception as e:
logger.error(f"Failed to get chat history for user {user_id} and session {session_id}: {e}")
raise Exception(f"Failed to get chat history: {e}")

async def create_table(self, table_name: str, columns: dict) -> Dict:
"""
Create a new table in the database.
Expand Down
70 changes: 55 additions & 15 deletions tests/chat/test_chat.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import httpx
import pytest


from unittest.mock import AsyncMock
from hive_agent_client.chat import send_chat_message
from hive_agent_client.chat import send_chat_message, get_chat_history


@pytest.mark.asyncio
Expand All @@ -15,25 +14,33 @@ async def test_send_chat_message_success():
mock_client.post.return_value = mock_response

base_url = "http://example.com/api/v1"
user_id = "user123"
session_id = "session123"
content = "Hello, how are you?"

result = await send_chat_message(mock_client, base_url, content)
result = await send_chat_message(mock_client, base_url, user_id, session_id, content)

assert result == "Hello, world!"
mock_client.post.assert_called_once_with(
"http://example.com/api/v1/chat",
json={"messages": [{"role": "user", "content": content}]},
json={
"user_id": user_id,
"session_id": session_id,
"chat_data": {"messages": [{"role": "user", "content": content}]}
},
)


@pytest.mark.asyncio
async def test_send_chat_message_empty_content():
mock_client = AsyncMock(spec=httpx.AsyncClient)
base_url = "http://example.com"
user_id = "user123"
session_id = "session123"
content = ""

with pytest.raises(ValueError, match="Content must not be empty"):
await send_chat_message(mock_client, base_url, content)
await send_chat_message(mock_client, base_url, user_id, session_id, content)


@pytest.mark.asyncio
Expand All @@ -42,34 +49,67 @@ async def test_send_chat_message_http_error():
mock_response = AsyncMock(spec=httpx.Response)
mock_response.status_code = 400
mock_response.text = "Bad request"
mock_response.raise_for_status.side_effect = httpx.HTTPStatusError(
message="Bad request", request=mock_response.request, response=mock_response
)
mock_client.post.return_value = mock_response

base_url = "http://example.com"
user_id = "user123"
session_id = "session123"
content = "Hello, how are you?"

with pytest.raises(
Exception,
match="HTTP error occurred when sending message to the chat API: 400 - Bad request",
Exception,
match="HTTP error occurred when sending message to the chat API: 400 - Bad request",
):
await send_chat_message(mock_client, base_url, content)
await send_chat_message(mock_client, base_url, user_id, session_id, content)


@pytest.mark.asyncio
async def test_send_chat_message_http_error():
async def test_get_chat_history_success():
mock_client = AsyncMock(spec=httpx.AsyncClient)
mock_response = AsyncMock(spec=httpx.Response)
mock_response.status_code = 200
expected_history = [
{"user_id": "user123", "session_id": "session123", "message": "Hello", "role": "user",
"timestamp": "2023-01-01T00:00:00Z"},
{"user_id": "user123", "session_id": "session123", "message": "Hi there", "role": "assistant",
"timestamp": "2023-01-01T00:00:01Z"}
]
mock_response.json.return_value = expected_history
mock_client.get.return_value = mock_response

base_url = "http://example.com/api/v1"
user_id = "user123"
session_id = "session123"

result = await get_chat_history(mock_client, base_url, user_id, session_id)

assert result == expected_history
mock_client.get.assert_called_once_with(
f"http://example.com/api/v1/chat_history",
params={"user_id": user_id, "session_id": session_id},
)


@pytest.mark.asyncio
async def test_get_chat_history_failure():
mock_client = AsyncMock(spec=httpx.AsyncClient)
mock_response = AsyncMock(spec=httpx.Response)
mock_response.status_code = 400
mock_response.text = "Bad request"
mock_response.raise_for_status.side_effect = httpx.HTTPStatusError(
message="Bad request", request=mock_response.request, response=mock_response
)
mock_client.post.return_value = mock_response
mock_client.get.return_value = mock_response

base_url = "http://example.com"
content = "Hello, how are you?"
base_url = "http://example.com/api/v1"
user_id = "user123"
session_id = "session123"

with pytest.raises(
Exception,
match="HTTP error occurred when sending message to the chat API: 400 - Bad request",
Exception,
match="HTTP error occurred when fetching chat history from the chat API: 400 - Bad request",
):
await send_chat_message(mock_client, base_url, content)
await get_chat_history(mock_client, base_url, user_id, session_id)
43 changes: 40 additions & 3 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def temp_files():

@pytest.mark.asyncio
async def test_chat_success():
user_id = "user123"
session_id = "session123"
content = "Hello"
expected_response = "Response from chat"

Expand All @@ -39,23 +41,58 @@ async def test_chat_success():
)

client = HiveAgentClient(base_url, version)
response = await client.chat(content)
response = await client.chat(user_id, session_id, content)
assert response == expected_response


@pytest.mark.asyncio
async def test_chat_failure():
user_id = "user123"
session_id = "session123"
content = "Hello"

with respx.mock() as mock:
mock.post(f"{base_url}/v1/chat").mock(return_value=httpx.Response(400))

client = HiveAgentClient(base_url)
client = HiveAgentClient(base_url, version)
with pytest.raises(Exception) as excinfo:
await client.chat(content)
await client.chat(user_id, session_id, content)
assert "Failed to send chat message" in str(excinfo.value)


@pytest.mark.asyncio
async def test_get_chat_history_success():
user_id = "user123"
session_id = "session123"
expected_history = [
{"user_id": user_id, "session_id": session_id, "message": "Hello", "role": "user", "timestamp": "2023-01-01T00:00:00Z"},
{"user_id": user_id, "session_id": session_id, "message": "Hi there", "role": "assistant", "timestamp": "2023-01-01T00:00:01Z"}
]

with respx.mock() as mock:
mock.get(f"{base_url}/v1/chat_history").mock(
return_value=httpx.Response(200, json=expected_history)
)

client = HiveAgentClient(base_url, version)
history = await client.get_chat_history(user_id, session_id)
assert history == expected_history


@pytest.mark.asyncio
async def test_get_chat_history_failure():
user_id = "user123"
session_id = "session123"

with respx.mock() as mock:
mock.get(f"{base_url}/v1/chat_history").mock(return_value=httpx.Response(400))

client = HiveAgentClient(base_url, version)
with pytest.raises(Exception) as excinfo:
await client.get_chat_history(user_id, session_id)
assert "HTTP error occurred when fetching chat history from the chat API: 400" in str(excinfo.value)


@pytest.mark.asyncio
async def test_create_table_success():
table_name = "test_table"
Expand Down
Loading

0 comments on commit c26b38a

Please sign in to comment.