From d7e2524073a08b6cd11578d9fe094bc6f45144a6 Mon Sep 17 00:00:00 2001 From: sambella Date: Fri, 16 Jan 2026 22:32:34 +0530 Subject: [PATCH 1/3] Add system diagnostics health endpoint and UI --- backend/app/controller/health_controller.py | 90 ++++++++++++++++++++- src/pages/Diagnostics.tsx | 57 +++++++++++++ src/routers/index.tsx | 28 +++++-- 3 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 src/pages/Diagnostics.tsx diff --git a/backend/app/controller/health_controller.py b/backend/app/controller/health_controller.py index 87ea5e2d0..40083e8b8 100644 --- a/backend/app/controller/health_controller.py +++ b/backend/app/controller/health_controller.py @@ -1,22 +1,104 @@ from fastapi import APIRouter from pydantic import BaseModel +from sqlalchemy import text from utils import traceroot_wrapper as traceroot +import os logger = traceroot.get_logger("health_controller") router = APIRouter(tags=["Health"]) +# ------------------------------- +# Response Models +# ------------------------------- + +class DatabaseStatus(BaseModel): + status: str + + +class ModelStatus(BaseModel): + configured: bool + + +class ToolStatus(BaseModel): + available: bool + + class HealthResponse(BaseModel): status: str service: str + database: DatabaseStatus + model: ModelStatus + tools: ToolStatus +# ------------------------------- +# Health Endpoint +# ------------------------------- + @router.get("/health", name="health check", response_model=HealthResponse) async def health_check(): - """Health check endpoint for verifying backend is ready to accept requests.""" + """ + Health & diagnostics endpoint. + + Verifies: + - Backend availability + - Database connectivity + - Model configuration + - Tool registry availability + """ + logger.debug("Health check requested") - response = HealthResponse(status="ok", service="eigent") - logger.debug("Health check completed", extra={"status": response.status, "service": response.service}) - return response + # ------------------------------- + # Database check + # ------------------------------- + db_status = "unknown" + try: + from app.database import engine # adjust path ONLY if needed + with engine.connect() as conn: + conn.execute(text("SELECT 1")) + db_status = "ok" + except Exception as e: + logger.warning("Database health check failed", extra={"error": str(e)}) + db_status = "error" + + # ------------------------------- + # Model configuration check + # ------------------------------- + model_api_key = os.getenv("MODEL_API_KEY") + model_name = os.getenv("MODEL_NAME") + + model_configured = bool(model_api_key and model_name) + + # ------------------------------- + # Tool availability check + # ------------------------------- + tools_available = False + try: + from app.tools.registry import TOOL_REGISTRY # adjust path if needed + tools_available = len(TOOL_REGISTRY) > 0 + except Exception as e: + logger.warning("Tool registry check failed", extra={"error": str(e)}) + + response = HealthResponse( + status="ok", + service="eigent", + database=DatabaseStatus(status=db_status), + model=ModelStatus(configured=model_configured), + tools=ToolStatus(available=tools_available), + ) + + logger.debug( + "Health check completed", + extra={ + "status": response.status, + "service": response.service, + "database": db_status, + "model_configured": model_configured, + "tools_available": tools_available, + }, + ) + + return response diff --git a/src/pages/Diagnostics.tsx b/src/pages/Diagnostics.tsx new file mode 100644 index 000000000..9d367da2b --- /dev/null +++ b/src/pages/Diagnostics.tsx @@ -0,0 +1,57 @@ +import { useEffect, useState } from "react"; + +type HealthResponse = { + status: string; + service: string; + database: { status: string }; + model: { configured: boolean }; + tools: { available: boolean }; +}; + +export default function Diagnostics() { + const [data, setData] = useState(null); + const [error, setError] = useState(""); + + useEffect(() => { + fetch("/health") + .then((res) => { + if (!res.ok) throw new Error("Backend unreachable"); + return res.json(); + }) + .then(setData) + .catch((err) => setError(err.message)); + }, []); + + if (error) { + return
❌ {error}
; + } + + if (!data) { + return
Loading system diagnostics...
; + } + + return ( +
+

System Diagnostics

+ +

Backend: ✅ Running

+ +

+ Database:{" "} + {data.database.status === "ok" ? "✅ Connected" : "❌ Error"} +

+ +

+ Model:{" "} + {data.model.configured + ? "✅ Configured" + : "⚠️ Not Configured"} +

+ +

+ Tools:{" "} + {data.tools.available ? "✅ Available" : "❌ Not Available"} +

+
+ ); +} diff --git a/src/routers/index.tsx b/src/routers/index.tsx index 223d0a52e..10bd4093a 100644 --- a/src/routers/index.tsx +++ b/src/routers/index.tsx @@ -3,11 +3,13 @@ import { Routes, Route, Navigate, Outlet } from "react-router-dom"; import { useAuthStore } from "@/store/authStore"; import Layout from "@/components/Layout"; + // Lazy load page components const Login = lazy(() => import("@/pages/Login")); const Signup = lazy(() => import("@/pages/SignUp")); const Home = lazy(() => import("@/pages/Home")); const History = lazy(() => import("@/pages/History")); +const Diagnostics = lazy(() => import("@/pages/Diagnostics")); const NotFound = lazy(() => import("@/pages/NotFound")); // Route guard: Check if user is logged in @@ -17,15 +19,16 @@ const ProtectedRoute = () => { const [initialized, setInitialized] = useState(false); const { token, localProxyValue, logout } = useAuthStore(); + useEffect(() => { // Check VITE_USE_LOCAL_PROXY value on app startup if (token) { const currentProxyValue = import.meta.env.VITE_USE_LOCAL_PROXY || null; const storedProxyValue = localProxyValue; - + // If stored value exists and differs from current, logout if (storedProxyValue !== null && storedProxyValue !== currentProxyValue) { - console.warn('VITE_USE_LOCAL_PROXY value changed, logging out user'); + console.warn("VITE_USE_LOCAL_PROXY value changed, logging out user"); logout(); setIsAuthenticated(false); setLoading(false); @@ -33,12 +36,12 @@ const ProtectedRoute = () => { return; } } - + setIsAuthenticated(!!token); setLoading(false); setInitialized(true); }, [token, localProxyValue, logout]); - + if (loading || !initialized) { return (
@@ -46,22 +49,35 @@ const ProtectedRoute = () => {
); } + return isAuthenticated ? : ; }; // Main route configuration const AppRoutes = () => ( + {/* Public routes */} } /> } /> + + {/* Protected routes */} }> }> } /> } /> - } /> - } /> + } /> + } + /> + } + /> + + {/* Fallback */} } /> ); From 89ed2a82bdf8e827ea5c911a8002c607ee1498c1 Mon Sep 17 00:00:00 2001 From: sambella Date: Sun, 18 Jan 2026 22:37:14 +0530 Subject: [PATCH 2/3] Fix diagnostics page to align with backend health response --- backend/app/controller/health_controller.py | 61 ++------------------- src/pages/Diagnostics.tsx | 20 ++----- 2 files changed, 8 insertions(+), 73 deletions(-) diff --git a/backend/app/controller/health_controller.py b/backend/app/controller/health_controller.py index 40083e8b8..9fbd5020e 100644 --- a/backend/app/controller/health_controller.py +++ b/backend/app/controller/health_controller.py @@ -2,61 +2,34 @@ from pydantic import BaseModel from sqlalchemy import text from utils import traceroot_wrapper as traceroot -import os logger = traceroot.get_logger("health_controller") router = APIRouter(tags=["Health"]) -# ------------------------------- -# Response Models -# ------------------------------- - class DatabaseStatus(BaseModel): status: str -class ModelStatus(BaseModel): - configured: bool - - -class ToolStatus(BaseModel): - available: bool - - class HealthResponse(BaseModel): status: str service: str database: DatabaseStatus - model: ModelStatus - tools: ToolStatus - -# ------------------------------- -# Health Endpoint -# ------------------------------- @router.get("/health", name="health check", response_model=HealthResponse) async def health_check(): """ - Health & diagnostics endpoint. - - Verifies: - - Backend availability - - Database connectivity - - Model configuration - - Tool registry availability + Health check endpoint for verifying backend and database readiness. """ logger.debug("Health check requested") - # ------------------------------- - # Database check - # ------------------------------- + # Database connectivity check db_status = "unknown" try: - from app.database import engine # adjust path ONLY if needed + from app.database import engine # existing project database engine with engine.connect() as conn: conn.execute(text("SELECT 1")) db_status = "ok" @@ -64,41 +37,15 @@ async def health_check(): logger.warning("Database health check failed", extra={"error": str(e)}) db_status = "error" - # ------------------------------- - # Model configuration check - # ------------------------------- - model_api_key = os.getenv("MODEL_API_KEY") - model_name = os.getenv("MODEL_NAME") - - model_configured = bool(model_api_key and model_name) - - # ------------------------------- - # Tool availability check - # ------------------------------- - tools_available = False - try: - from app.tools.registry import TOOL_REGISTRY # adjust path if needed - tools_available = len(TOOL_REGISTRY) > 0 - except Exception as e: - logger.warning("Tool registry check failed", extra={"error": str(e)}) - response = HealthResponse( status="ok", service="eigent", database=DatabaseStatus(status=db_status), - model=ModelStatus(configured=model_configured), - tools=ToolStatus(available=tools_available), ) logger.debug( "Health check completed", - extra={ - "status": response.status, - "service": response.service, - "database": db_status, - "model_configured": model_configured, - "tools_available": tools_available, - }, + extra={"status": response.status, "database": db_status}, ) return response diff --git a/src/pages/Diagnostics.tsx b/src/pages/Diagnostics.tsx index 9d367da2b..8a4e782c8 100644 --- a/src/pages/Diagnostics.tsx +++ b/src/pages/Diagnostics.tsx @@ -3,9 +3,9 @@ import { useEffect, useState } from "react"; type HealthResponse = { status: string; service: string; - database: { status: string }; - model: { configured: boolean }; - tools: { available: boolean }; + database: { + status: string; + }; }; export default function Diagnostics() { @@ -13,7 +13,7 @@ export default function Diagnostics() { const [error, setError] = useState(""); useEffect(() => { - fetch("/health") + fetch("/api/health") .then((res) => { if (!res.ok) throw new Error("Backend unreachable"); return res.json(); @@ -40,18 +40,6 @@ export default function Diagnostics() { Database:{" "} {data.database.status === "ok" ? "✅ Connected" : "❌ Error"}

- -

- Model:{" "} - {data.model.configured - ? "✅ Configured" - : "⚠️ Not Configured"} -

- -

- Tools:{" "} - {data.tools.available ? "✅ Available" : "❌ Not Available"} -

); } From 4bea985e0cd701e92d35d43d5792befd769020d3 Mon Sep 17 00:00:00 2001 From: sambella Date: Sun, 22 Mar 2026 15:50:08 +0530 Subject: [PATCH 3/3] Address review feedback: align health endpoint and diagnostics page --- backend/app/controller/health_controller.py | 24 +++----------------- src/pages/Diagnostics.tsx | 25 +++++++++------------ 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/backend/app/controller/health_controller.py b/backend/app/controller/health_controller.py index 9fbd5020e..793cd110f 100644 --- a/backend/app/controller/health_controller.py +++ b/backend/app/controller/health_controller.py @@ -1,6 +1,5 @@ from fastapi import APIRouter from pydantic import BaseModel -from sqlalchemy import text from utils import traceroot_wrapper as traceroot logger = traceroot.get_logger("health_controller") @@ -8,44 +7,27 @@ router = APIRouter(tags=["Health"]) -class DatabaseStatus(BaseModel): - status: str - - class HealthResponse(BaseModel): status: str service: str - database: DatabaseStatus @router.get("/health", name="health check", response_model=HealthResponse) async def health_check(): """ - Health check endpoint for verifying backend and database readiness. + Health check endpoint for verifying backend readiness. """ logger.debug("Health check requested") - # Database connectivity check - db_status = "unknown" - try: - from app.database import engine # existing project database engine - with engine.connect() as conn: - conn.execute(text("SELECT 1")) - db_status = "ok" - except Exception as e: - logger.warning("Database health check failed", extra={"error": str(e)}) - db_status = "error" - response = HealthResponse( status="ok", service="eigent", - database=DatabaseStatus(status=db_status), ) logger.debug( "Health check completed", - extra={"status": response.status, "database": db_status}, + extra={"status": response.status, "service": response.service}, ) - return response + return response \ No newline at end of file diff --git a/src/pages/Diagnostics.tsx b/src/pages/Diagnostics.tsx index 8a4e782c8..bf112cc84 100644 --- a/src/pages/Diagnostics.tsx +++ b/src/pages/Diagnostics.tsx @@ -1,11 +1,16 @@ +/* + * Copyright 2024 Eigent + * + * Licensed under the Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + */ + import { useEffect, useState } from "react"; +import { fetchGet } from "@/api/http"; type HealthResponse = { status: string; service: string; - database: { - status: string; - }; }; export default function Diagnostics() { @@ -13,11 +18,7 @@ export default function Diagnostics() { const [error, setError] = useState(""); useEffect(() => { - fetch("/api/health") - .then((res) => { - if (!res.ok) throw new Error("Backend unreachable"); - return res.json(); - }) + fetchGet("/health") .then(setData) .catch((err) => setError(err.message)); }, []); @@ -35,11 +36,7 @@ export default function Diagnostics() {

System Diagnostics

Backend: ✅ Running

- -

- Database:{" "} - {data.database.status === "ok" ? "✅ Connected" : "❌ Error"} -

+

Service: {data.service}

); -} +} \ No newline at end of file