feat: add proper HTTP status codes to all API error responses

- 217 error returns across 18 route files + api.py now use JSONResponse
  with appropriate HTTP status codes instead of returning HTTP 200
- Status code distribution: 500 (121), 400 (39), 503 (28), 404 (24), 409 (3), 502 (2)
- Fixed language.py tuple-return bug (was serializing as JSON array)
- Fixed bare except clauses in bipolar_mode.py and voice.py
- Body-level error schemas preserved (status/error + success/error patterns)
  so web UI continues working without changes
- chat.py (SSE) unchanged: errors sent within stream protocol
- All 170 tests pass
This commit is contained in:
2026-04-15 15:43:18 +03:00
parent 33b2033cc3
commit edc9f27925
19 changed files with 243 additions and 227 deletions

View File

@@ -2,6 +2,7 @@
from typing import Optional
from fastapi import APIRouter, Form
from fastapi.responses import JSONResponse
import globals
from routes.models import MemoryDeleteRequest, MemoryEditRequest, MemoryCreateRequest
from utils.logger import get_logger
@@ -51,7 +52,7 @@ async def get_memory_stats():
from utils.cat_client import cat_adapter
stats = await cat_adapter.get_memory_stats()
if stats is None:
return {"success": False, "error": "Could not reach Cheshire Cat"}
return JSONResponse(status_code=502, content={"success": False, "error": "Could not reach Cheshire Cat"})
return {"success": True, "collections": stats.get("collections", [])}
@@ -69,7 +70,7 @@ async def get_episodic_memories():
from utils.cat_client import cat_adapter
result = await cat_adapter.get_memory_points(collection="episodic", limit=100)
if result is None:
return {"success": False, "error": "Could not reach Cheshire Cat"}
return JSONResponse(status_code=502, content={"success": False, "error": "Could not reach Cheshire Cat"})
memories = []
for point in result.get("points", []):
@@ -90,7 +91,7 @@ async def trigger_memory_consolidation():
logger.info("🌙 Manual memory consolidation triggered via API")
result = await cat_adapter.trigger_consolidation()
if result is None:
return {"success": False, "error": "Consolidation failed or timed out"}
return JSONResponse(status_code=500, content={"success": False, "error": "Consolidation failed or timed out"})
return {"success": True, "result": result}
@@ -108,11 +109,11 @@ async def delete_all_memories(request: MemoryDeleteRequest):
if request.confirmation != REQUIRED_CONFIRMATION:
logger.warning(f"Memory deletion rejected: wrong confirmation string")
return {
return JSONResponse(status_code=400, content={
"success": False,
"error": "Confirmation string does not match. "
f"Expected exactly: \"{REQUIRED_CONFIRMATION}\""
}
})
from utils.cat_client import cat_adapter
logger.warning("⚠️ MEMORY DELETION CONFIRMED — wiping all memories!")
@@ -132,10 +133,10 @@ async def delete_all_memories(request: MemoryDeleteRequest):
"conversation_history_cleared": history_success
}
else:
return {
return JSONResponse(status_code=500, content={
"success": False,
"error": "Failed to wipe memory collections. Check Cat connection."
}
})
@router.delete("/memory/point/{collection}/{point_id}")
@@ -146,7 +147,7 @@ async def delete_single_memory_point(collection: str, point_id: str):
if success:
return {"success": True, "deleted": point_id}
else:
return {"success": False, "error": f"Failed to delete point {point_id}"}
return JSONResponse(status_code=500, content={"success": False, "error": f"Failed to delete point {point_id}"})
@router.put("/memory/point/{collection}/{point_id}")
@@ -162,7 +163,7 @@ async def edit_memory_point(collection: str, point_id: str, request: MemoryEditR
if success:
return {"success": True, "updated": point_id}
else:
return {"success": False, "error": f"Failed to update point {point_id}"}
return JSONResponse(status_code=500, content={"success": False, "error": f"Failed to update point {point_id}"})
@router.post("/memory/create")
@@ -176,7 +177,7 @@ async def create_memory_point(request: MemoryCreateRequest):
from utils.cat_client import cat_adapter
if request.collection not in ['declarative', 'episodic']:
return {"success": False, "error": "Collection must be 'declarative' or 'episodic'"}
return JSONResponse(status_code=400, content={"success": False, "error": "Collection must be 'declarative' or 'episodic'"})
# Create the memory point
result = await cat_adapter.create_memory_point(
@@ -190,4 +191,4 @@ async def create_memory_point(request: MemoryCreateRequest):
if result:
return {"success": True, "point_id": result, "collection": request.collection}
else:
return {"success": False, "error": "Failed to create memory point"}
return JSONResponse(status_code=500, content={"success": False, "error": "Failed to create memory point"})