Skip to content

Commit a52f96a

Browse files
authored
Merge pull request #3 from balureddy003/codex/add-chat-api-endpoint-and-tests
Add chat endpoint and tests
2 parents bcdd45f + 8410284 commit a52f96a

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

src/backend/app_kernel.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from fastapi import FastAPI, HTTPException, Query, Request
2121
from fastapi.middleware.cors import CORSMiddleware
2222
from kernel_agents.agent_factory import AgentFactory
23+
from pydantic import BaseModel
2324

2425
# Local imports
2526
from middleware.health_check import HealthCheckMiddleware
@@ -168,6 +169,55 @@ async def user_browser_language_endpoint(
168169
return {"status": "Language received successfully"}
169170

170171

172+
class ChatRequest(BaseModel):
173+
"""Request model for the simple chat endpoint."""
174+
175+
session_id: str
176+
user_message: str
177+
178+
179+
@app.post("/api/chat")
180+
async def chat_endpoint(chat_request: ChatRequest, request: Request):
181+
"""Handle a simple chat message from the user."""
182+
183+
authenticated_user = get_authenticated_user_details(request_headers=request.headers)
184+
user_id = authenticated_user["user_principal_id"]
185+
186+
if not user_id:
187+
track_event_if_configured(
188+
"UserIdNotFound", {"status_code": 400, "detail": "no user"}
189+
)
190+
raise HTTPException(status_code=400, detail="no user")
191+
192+
kernel, memory_store = await initialize_runtime_and_context(
193+
chat_request.session_id, user_id
194+
)
195+
196+
client = None
197+
try:
198+
client = config.get_ai_project_client()
199+
except Exception as client_exc: # pylint: disable=broad-except
200+
logging.error(f"Error creating AIProjectClient: {client_exc}")
201+
202+
simple_chat_agent = await AgentFactory.create_agent(
203+
agent_type=AgentType.GENERIC,
204+
session_id=chat_request.session_id,
205+
user_id=user_id,
206+
memory_store=memory_store,
207+
client=client,
208+
)
209+
210+
reply = await simple_chat_agent.handle_user_message(chat_request.user_message)
211+
212+
if client:
213+
try:
214+
client.close()
215+
except Exception as e: # pylint: disable=broad-except
216+
logging.error(f"Error sending to AIProjectClient: {e}")
217+
218+
return {"reply": reply}
219+
220+
171221
@app.post("/api/input_task")
172222
async def input_task_endpoint(input_task: InputTask, request: Request):
173223
"""
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""Tests for the simple chat API endpoint."""
2+
3+
import os
4+
import sys
5+
from unittest.mock import AsyncMock, MagicMock, patch
6+
7+
import pytest
8+
from fastapi.testclient import TestClient
9+
10+
# Mock Azure dependencies to avoid import errors during tests
11+
sys.modules["azure.monitor"] = MagicMock()
12+
sys.modules["azure.monitor.events.extension"] = MagicMock()
13+
sys.modules["azure.monitor.opentelemetry"] = MagicMock()
14+
15+
# Set required environment variables before importing the app
16+
os.environ["COSMOSDB_ENDPOINT"] = "https://mock-endpoint"
17+
os.environ["COSMOSDB_KEY"] = "mock-key"
18+
os.environ["COSMOSDB_DATABASE"] = "mock-database"
19+
os.environ["COSMOSDB_CONTAINER"] = "mock-container"
20+
os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"] = (
21+
"InstrumentationKey=mock;IngestionEndpoint=https://mock"
22+
)
23+
os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"] = "mock-deployment-name"
24+
os.environ["AZURE_OPENAI_API_VERSION"] = "2023-01-01"
25+
os.environ["AZURE_OPENAI_ENDPOINT"] = "https://mock-openai-endpoint"
26+
os.environ["FRONTEND_SITE_NAME"] = "http://localhost"
27+
28+
with patch("azure.monitor.opentelemetry.configure_azure_monitor", MagicMock()):
29+
from src.backend.app_kernel import app
30+
31+
32+
client = TestClient(app)
33+
34+
35+
@pytest.fixture(autouse=True)
36+
def mock_dependencies(monkeypatch):
37+
"""Mock dependencies used by the chat endpoint."""
38+
39+
# Mock authentication helper
40+
monkeypatch.setattr(
41+
"src.backend.app_kernel.get_authenticated_user_details",
42+
lambda request_headers: {"user_principal_id": "mock-user"},
43+
)
44+
45+
# Mock runtime initialization
46+
async def mock_initialize_runtime_and_context(session_id, user_id):
47+
return None, MagicMock()
48+
49+
monkeypatch.setattr(
50+
"src.backend.app_kernel.initialize_runtime_and_context",
51+
mock_initialize_runtime_and_context,
52+
)
53+
54+
# Mock config client creation
55+
monkeypatch.setattr(
56+
"src.backend.app_kernel.config.get_ai_project_client",
57+
lambda: MagicMock(close=MagicMock()),
58+
)
59+
60+
# Mock AgentFactory.create_agent to return an agent with handle_user_message
61+
async def mock_create_agent(*args, **kwargs):
62+
agent = MagicMock()
63+
agent.handle_user_message = AsyncMock(return_value="mock response")
64+
return agent
65+
66+
monkeypatch.setattr(
67+
"src.backend.app_kernel.AgentFactory.create_agent",
68+
mock_create_agent,
69+
)
70+
71+
72+
def test_chat_endpoint_returns_reply():
73+
"""Ensure the chat endpoint returns the agent's reply."""
74+
75+
payload = {"session_id": "123", "user_message": "Hello"}
76+
77+
response = client.post("/api/chat", json=payload)
78+
79+
assert response.status_code == 200
80+
assert response.json() == {"reply": "mock response"}
81+

0 commit comments

Comments
 (0)