i forgot too commit
All checks were successful
Enterprise AI Code Review / ai-review (pull_request) Successful in 38s
All checks were successful
Enterprise AI Code Review / ai-review (pull_request) Successful in 38s
This commit is contained in:
185
cli/client.py
Normal file
185
cli/client.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""HTTP client for Loyal Companion Web API."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
|
||||
class APIError(Exception):
|
||||
"""API request error."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class LoyalCompanionClient:
|
||||
"""HTTP client for Loyal Companion API."""
|
||||
|
||||
def __init__(self, base_url: str, auth_token: str | None = None):
|
||||
"""Initialize client.
|
||||
|
||||
Args:
|
||||
base_url: API base URL
|
||||
auth_token: Optional authentication token
|
||||
"""
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.auth_token = auth_token
|
||||
self.client = httpx.Client(timeout=60.0)
|
||||
|
||||
def _get_headers(self) -> dict[str, str]:
|
||||
"""Get request headers.
|
||||
|
||||
Returns:
|
||||
dict: Request headers
|
||||
"""
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
if self.auth_token:
|
||||
headers["Authorization"] = f"Bearer {self.auth_token}"
|
||||
|
||||
return headers
|
||||
|
||||
def request_token(self, email: str) -> dict[str, Any]:
|
||||
"""Request an authentication token.
|
||||
|
||||
Args:
|
||||
email: User email
|
||||
|
||||
Returns:
|
||||
dict: Token response
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.post(
|
||||
f"{self.base_url}/api/auth/token",
|
||||
json={"email": email},
|
||||
headers={"Content-Type": "application/json"},
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise APIError(f"Failed to request token: {e}")
|
||||
|
||||
def send_message(self, session_id: str, message: str) -> dict[str, Any]:
|
||||
"""Send a chat message.
|
||||
|
||||
Args:
|
||||
session_id: Session identifier
|
||||
message: User message
|
||||
|
||||
Returns:
|
||||
dict: Chat response with AI's reply and metadata
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.post(
|
||||
f"{self.base_url}/api/chat",
|
||||
json={"session_id": session_id, "message": message},
|
||||
headers=self._get_headers(),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
if hasattr(e, "response") and e.response is not None:
|
||||
try:
|
||||
error_detail = e.response.json().get("detail", str(e))
|
||||
except Exception:
|
||||
error_detail = str(e)
|
||||
raise APIError(f"Chat request failed: {error_detail}")
|
||||
raise APIError(f"Chat request failed: {e}")
|
||||
|
||||
def get_history(self, session_id: str, limit: int = 50) -> dict[str, Any]:
|
||||
"""Get conversation history.
|
||||
|
||||
Args:
|
||||
session_id: Session identifier
|
||||
limit: Maximum number of messages
|
||||
|
||||
Returns:
|
||||
dict: History response
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.get(
|
||||
f"{self.base_url}/api/sessions/{session_id}/history",
|
||||
params={"limit": limit},
|
||||
headers=self._get_headers(),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise APIError(f"Failed to get history: {e}")
|
||||
|
||||
def list_sessions(self) -> list[dict[str, Any]]:
|
||||
"""List all user sessions.
|
||||
|
||||
Returns:
|
||||
list: List of sessions
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.get(
|
||||
f"{self.base_url}/api/sessions",
|
||||
headers=self._get_headers(),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise APIError(f"Failed to list sessions: {e}")
|
||||
|
||||
def delete_session(self, session_id: str) -> dict[str, Any]:
|
||||
"""Delete a session.
|
||||
|
||||
Args:
|
||||
session_id: Session identifier
|
||||
|
||||
Returns:
|
||||
dict: Deletion response
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.delete(
|
||||
f"{self.base_url}/api/sessions/{session_id}",
|
||||
headers=self._get_headers(),
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise APIError(f"Failed to delete session: {e}")
|
||||
|
||||
def health_check(self) -> dict[str, Any]:
|
||||
"""Check API health.
|
||||
|
||||
Returns:
|
||||
dict: Health status
|
||||
|
||||
Raises:
|
||||
APIError: If request fails
|
||||
"""
|
||||
try:
|
||||
response = self.client.get(f"{self.base_url}/api/health")
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise APIError(f"Health check failed: {e}")
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the HTTP client."""
|
||||
self.client.close()
|
||||
|
||||
def __enter__(self):
|
||||
"""Context manager entry."""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Context manager exit."""
|
||||
self.close()
|
||||
Reference in New Issue
Block a user