feat(platform): Display error message on save failure

This commit is contained in:
Zamil Majdy
2024-11-04 20:33:31 +07:00
parent 594aa996d7
commit eb1e53aba3
4 changed files with 50 additions and 20 deletions

View File

@@ -1,9 +1,10 @@
import contextlib
import logging
import typing
import fastapi
import fastapi.middleware.cors
import fastapi.responses
import starlette.middleware.cors
import uvicorn
import backend.data.block
@@ -14,6 +15,7 @@ import backend.util.service
import backend.util.settings
settings = backend.util.settings.Settings()
logger = logging.getLogger(__name__)
@contextlib.asynccontextmanager
@@ -25,6 +27,21 @@ async def lifespan_context(app: fastapi.FastAPI):
await backend.data.db.disconnect()
def handle_internal_http_error(status_code: int = 500, log_error: bool = True):
def handler(request: fastapi.Request, exc: Exception):
if log_error:
logger.exception(f"{request.method} {request.url.path} failed: {exc}")
return fastapi.responses.JSONResponse(
content={
"message": f"{request.method} {request.url.path} failed",
"detail": str(exc),
},
status_code=status_code,
)
return handler
docs_url = (
"/docs"
if settings.config.app_env == backend.util.settings.AppEnvironment.LOCAL
@@ -43,14 +60,9 @@ app = fastapi.FastAPI(
docs_url=docs_url,
)
app.add_exception_handler(ValueError, handle_internal_http_error(400))
app.add_exception_handler(500, handle_internal_http_error(500))
app.include_router(backend.server.routers.v1.v1_router, tags=["v1"])
app.add_middleware(
fastapi.middleware.cors.CORSMiddleware,
allow_origins=settings.config.backend_cors_allow_origins,
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
@app.get(path="/health", tags=["health"], dependencies=[])
@@ -58,15 +70,13 @@ async def health():
return {"status": "healthy"}
@app.exception_handler(Exception)
def handle_internal_http_error(request: fastapi.Request, exc: Exception):
return fastapi.responses.JSONResponse(
content={
"message": f"{request.method} {request.url.path} failed",
"error": str(exc),
},
status_code=500,
)
app = starlette.middleware.cors.CORSMiddleware(
app=app,
allow_origins=settings.config.backend_cors_allow_origins,
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
class AgentServer(backend.util.service.AppProcess):

View File

@@ -25,7 +25,7 @@ const ToastViewport = React.forwardRef<
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border border-neutral-200 p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full dark:border-neutral-800",
"whitespace-pre-line group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border border-neutral-200 p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full dark:border-neutral-800",
{
variants: {
variant: {

View File

@@ -17,6 +17,7 @@ import { Connection, MarkerType } from "@xyflow/react";
import Ajv from "ajv";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { useToast } from "@/components/ui/use-toast";
const ajv = new Ajv({ strict: false, allErrors: true });
@@ -25,6 +26,7 @@ export default function useAgentGraph(
template?: boolean,
passDataToBeads?: boolean,
) {
const { toast } = useToast();
const [router, searchParams, pathname] = [
useRouter(),
useSearchParams(),
@@ -588,7 +590,8 @@ export default function useAgentGraph(
[availableNodes],
);
const saveAgent = useCallback(
const _saveAgent = (
() =>
async (asTemplate: boolean = false) => {
//FIXME frontend ids should be resolved better (e.g. returned from the server)
// currently this relays on block_id and position
@@ -742,6 +745,23 @@ export default function useAgentGraph(
},
}));
});
}
)();
const saveAgent = useCallback(
async (asTemplate: boolean = false) => {
try {
await _saveAgent(asTemplate);
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error("Error saving agent", error);
toast({
variant: "destructive",
title: "Error saving agent",
description: errorMessage,
});
}
},
[
api,

View File

@@ -287,7 +287,7 @@ export default class BaseAutoGPTServerAPI {
errorDetail = response.statusText;
}
throw new Error(`HTTP error ${response.status}! ${errorDetail}`);
throw new Error(errorDetail);
}
// Handle responses with no content (like DELETE requests)