Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

A decentralized, chat-first platform that combines **real-time messaging, token payments, and community-driven funding** into a single seamless experience.



This project reimagines how people coordinate, transact, and build together online by embedding financial actions directly into conversations. Users can send tokens as easily as messages, contribute to shared group treasuries, and fund ideas through lightweight, on-chain proposals—all without leaving the chat interface.

Built on blockchain infrastructure and modern messaging protocols, the platform bridges the gap between Web2 usability and Web3 ownership.
Expand Down
5 changes: 5 additions & 0 deletions apps/ai_agent/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
from pydantic import BaseModel
from weaviate.classes.query import Filter

try:
from openai import OpenAI
except ImportError: # pragma: no cover - exercised when the dependency is absent
OpenAI = None

app = FastAPI(title="AI Agent API")

_SYSTEM_PROMPT = (
Expand Down
77 changes: 77 additions & 0 deletions apps/ai_agent/tests/test_chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Unit tests for POST /chat (issue #144)."""

import pytest
from unittest.mock import MagicMock

_BASE_BODY = {
"message": "What is Clicked?",
"conversation_id": "conv-123",
}


def _fake_chat_reply(content: str = "This is a test reply."):
msg = MagicMock()
msg.content = content
choice = MagicMock()
choice.message = msg
resp = MagicMock()
resp.choices = [choice]
return resp


def test_missing_api_key_returns_500(monkeypatch, client):
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
response = client.post("/chat", json=_BASE_BODY)
assert response.status_code == 500


def test_valid_request_returns_reply(mock_openai, client):
mock_client = mock_openai.return_value
mock_client.chat.completions.create.return_value = _fake_chat_reply(
"Hello from Clicked AI!"
)

response = client.post("/chat", json=_BASE_BODY)
assert response.status_code == 200
data = response.json()
assert "reply" in data
assert data["reply"] == "Hello from Clicked AI!"


def test_system_prompt_contains_context(mock_openai, client):
mock_client = mock_openai.return_value
mock_client.chat.completions.create.return_value = _fake_chat_reply("Sure, I can help!")

response = client.post("/chat", json=_BASE_BODY)
assert response.status_code == 200

call_args = mock_client.chat.completions.create.call_args
messages = call_args[1]["messages"]
system_msg = messages[0]
assert system_msg["role"] == "system"
content = system_msg["content"]
assert "Clicked" in content
assert "Stellar" in content
assert "messaging" in content or "payment" in content


def test_missing_message_returns_422(client):
body = {"conversation_id": "conv-123"}
response = client.post("/chat", json=body)
assert response.status_code == 422


def test_missing_conversation_id_returns_422(client):
body = {"message": "Hello"}
response = client.post("/chat", json=body)
assert response.status_code == 422


def test_correct_model_used(mock_openai, client):
mock_client = mock_openai.return_value
mock_client.chat.completions.create.return_value = _fake_chat_reply("OK")

client.post("/chat", json=_BASE_BODY)

call_args = mock_client.chat.completions.create.call_args
assert call_args[1]["model"] == "gpt-4o-mini"