diff --git a/src/app/(dashboard)/dashboard/health/page.tsx b/src/app/(dashboard)/dashboard/health/page.tsx
index 58afb12afd..6871ed33a0 100644
--- a/src/app/(dashboard)/dashboard/health/page.tsx
+++ b/src/app/(dashboard)/dashboard/health/page.tsx
@@ -44,6 +44,7 @@ export default function HealthPage() {
const [telemetry, setTelemetry] = useState(null);
const [cache, setCache] = useState(null);
const [signatureCache, setSignatureCache] = useState(null);
+ const [resetting, setResetting] = useState(false);
const fetchHealth = useCallback(async () => {
try {
@@ -82,6 +83,27 @@ export default function HealthPage() {
return () => clearInterval(interval);
}, [fetchHealth, fetchExtras]);
+ const handleResetHealth = async () => {
+ if (
+ !confirm(
+ "Reset all circuit breakers to healthy state? This will clear all failure counts and restore all providers to operational status."
+ )
+ )
+ return;
+ setResetting(true);
+ try {
+ const res = await fetch("/api/monitoring/health", { method: "DELETE" });
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ // Refresh health data immediately
+ await fetchHealth();
+ await fetchExtras();
+ } catch (err) {
+ console.error("Failed to reset health:", err);
+ } finally {
+ setResetting(false);
+ }
+ };
+
const fmtMs = (ms) => (ms != null ? `${Math.round(ms)}ms` : "—");
if (!data && !error) {
@@ -332,19 +354,47 @@ export default function HealthPage() {
Provider Health
- {cbEntries.length > 0 && (
-
-
- Healthy
-
-
- Recovering
-
-
- Down
-
-
- )}
+
+ {cbEntries.some(([, cb]: [string, any]) => cb.state !== "CLOSED") && (
+
+ )}
+ {cbEntries.length > 0 && (
+
+
+ Healthy
+
+
+ Recovering
+
+
+ Down
+
+
+ )}
+
{cbEntries.length === 0 ? (
@@ -505,69 +555,75 @@ export default function HealthPage() {
- {entries.map(({ key, displayName, providerInfo, connectionId, model, status }: any) => {
- const isActive = (status.queued || 0) + (status.running || 0) > 0;
- const isQueued = (status.queued || 0) > 0;
- return (
-
-
-
- {providerInfo?.textIcon || displayName.slice(0, 2).toUpperCase()}
-
-
-
- {displayName}
-
- {connectionId && (
-
- {connectionId.length > 12
- ? connectionId.slice(0, 8) + "…"
- : connectionId}
- {model && · {model}}
+ {entries.map(
+ ({ key, displayName, providerInfo, connectionId, model, status }: any) => {
+ const isActive = (status.queued || 0) + (status.running || 0) > 0;
+ const isQueued = (status.queued || 0) > 0;
+ return (
+
+
+
+ {providerInfo?.textIcon || displayName.slice(0, 2).toUpperCase()}
+
+
+
+ {displayName}
- )}
+ {connectionId && (
+
+ {connectionId.length > 12
+ ? connectionId.slice(0, 8) + "…"
+ : connectionId}
+ {model && (
+ · {model}
+ )}
+
+ )}
+
+
+ {isQueued ? "Queued" : isActive ? "Active" : "OK"}
+
+
+
+
+ schedule
+ {status.queued || 0} queued
+
+
+
+ play_arrow
+
+ {status.running || 0} running
+
-
- {isQueued ? "Queued" : isActive ? "Active" : "OK"}
-
-
-
- schedule
- {status.queued || 0} queued
-
-
- play_arrow
- {status.running || 0} running
-
-
-
- );
- })}
+ );
+ }
+ )}
);
diff --git a/src/app/api/monitoring/health/route.ts b/src/app/api/monitoring/health/route.ts
index 99ac4b334a..cdf0b0d8f4 100644
--- a/src/app/api/monitoring/health/route.ts
+++ b/src/app/api/monitoring/health/route.ts
@@ -12,8 +12,7 @@ export async function GET() {
try {
const { getAllCircuitBreakerStatuses } =
await import("@/../../src/shared/utils/circuitBreaker");
- const { getAllRateLimitStatus } =
- await import("@omniroute/open-sse/services/rateLimitManager");
+ const { getAllRateLimitStatus } = await import("@omniroute/open-sse/services/rateLimitManager");
const { getAllModelLockouts } = await import("@omniroute/open-sse/services/accountFallback");
const settings = await getSettings();
@@ -57,3 +56,32 @@ export async function GET() {
return NextResponse.json({ status: "error", error: error.message }, { status: 500 });
}
}
+
+/**
+ * DELETE /api/monitoring/health — Reset all circuit breakers
+ *
+ * Resets all provider circuit breakers to CLOSED state,
+ * clearing failure counts and persisted state.
+ */
+export async function DELETE() {
+ try {
+ const { resetAllCircuitBreakers, getAllCircuitBreakerStatuses } =
+ await import("@/../../src/shared/utils/circuitBreaker");
+
+ const before = getAllCircuitBreakerStatuses();
+ const resetCount = before.length;
+
+ resetAllCircuitBreakers();
+
+ console.log(`[API] DELETE /api/monitoring/health — Reset ${resetCount} circuit breakers`);
+
+ return NextResponse.json({
+ success: true,
+ message: `Reset ${resetCount} circuit breaker(s) to healthy state`,
+ resetCount,
+ });
+ } catch (error) {
+ console.error("[API] DELETE /api/monitoring/health error:", error);
+ return NextResponse.json({ error: error.message }, { status: 500 });
+ }
+}