diff --git a/autogpt_platform/backend/backend/api/features/library/db.py b/autogpt_platform/backend/backend/api/features/library/db.py
index 6561c341bd..ea9b97bfd7 100644
--- a/autogpt_platform/backend/backend/api/features/library/db.py
+++ b/autogpt_platform/backend/backend/api/features/library/db.py
@@ -7,12 +7,12 @@ import prisma.errors
import prisma.models
import prisma.types
-from backend.api.features.library.exceptions import FolderValidationError
import backend.api.features.store.exceptions as store_exceptions
import backend.api.features.store.image_gen as store_image_gen
import backend.api.features.store.media as store_media
import backend.data.graph as graph_db
import backend.data.integrations as integrations_db
+from backend.api.features.library.exceptions import FolderValidationError
from backend.data.db import transaction
from backend.data.execution import get_graph_execution
from backend.data.graph import GraphSettings
@@ -1528,7 +1528,8 @@ async def delete_folder(
"isDeleted": False,
},
)
- for agent in affected_agents:
+
+ async def _cleanup_agent(agent: prisma.models.LibraryAgent) -> None:
try:
await _cleanup_schedules_for_graph(
graph_id=agent.agentGraphId, user_id=user_id
@@ -1542,6 +1543,8 @@ async def delete_folder(
f"(graph {agent.agentGraphId}): {e}"
)
+ await asyncio.gather(*[_cleanup_agent(a) for a in affected_agents])
+
async with transaction() as tx:
if soft_delete:
# Soft-delete all agents in these folders
diff --git a/autogpt_platform/backend/backend/api/features/library/exceptions.py b/autogpt_platform/backend/backend/api/features/library/exceptions.py
index 1288f0807c..bd9d307b80 100644
--- a/autogpt_platform/backend/backend/api/features/library/exceptions.py
+++ b/autogpt_platform/backend/backend/api/features/library/exceptions.py
@@ -1,4 +1,4 @@
class FolderValidationError(Exception):
"""Raised when folder operations fail validation."""
- pass
\ No newline at end of file
+ pass
diff --git a/autogpt_platform/backend/backend/api/features/library/routes/agents.py b/autogpt_platform/backend/backend/api/features/library/routes/agents.py
index 801a5a703b..eee7849451 100644
--- a/autogpt_platform/backend/backend/api/features/library/routes/agents.py
+++ b/autogpt_platform/backend/backend/api/features/library/routes/agents.py
@@ -1,3 +1,4 @@
+import logging
from typing import Literal, Optional
import autogpt_libs.auth as autogpt_auth_lib
@@ -6,10 +7,13 @@ from fastapi.responses import Response
from prisma.enums import OnboardingStep
from backend.data.onboarding import complete_onboarding_step
+from backend.util.exceptions import DatabaseError, NotFoundError
from .. import db as library_db
from .. import model as library_model
+logger = logging.getLogger(__name__)
+
router = APIRouter(
prefix="/agents",
tags=["library", "private"],
@@ -194,9 +198,7 @@ async def update_library_agent(
detail=str(e),
) from e
except DatabaseError as e:
- logger.error(
- f"Database error while updating library agent: {e}", exc_info=True
- )
+ logger.error(f"Database error while updating library agent: {e}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={"message": "Internal server error", "hint": "Contact support"},
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/FavoritesSection/FavoritesSection.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/FavoritesSection/FavoritesSection.tsx
index a9ed3bdc14..f81b34ee92 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/FavoritesSection/FavoritesSection.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/FavoritesSection/FavoritesSection.tsx
@@ -19,7 +19,13 @@ interface Props {
setLibrarySort: (value: LibraryAgentSort) => void;
}
-export function FavoritesSection({ searchTerm, tabs, activeTab, onTabChange, setLibrarySort }: Props) {
+export function FavoritesSection({
+ searchTerm,
+ tabs,
+ activeTab,
+ onTabChange,
+ setLibrarySort,
+}: Props) {
const {
allAgents: favoriteAgents,
agentLoading: isLoading,
@@ -31,8 +37,15 @@ export function FavoritesSection({ searchTerm, tabs, activeTab, onTabChange, set
return (
<>
-
-
+
+
{isLoading ? (
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/LibraryAgentCard.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/LibraryAgentCard.tsx
index 6db91fe4f9..b7d74e712d 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/LibraryAgentCard.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/LibraryAgentCard.tsx
@@ -22,10 +22,7 @@ interface Props {
draggable?: boolean;
}
-export function LibraryAgentCard({
- agent,
- draggable = true,
-}: Props) {
+export function LibraryAgentCard({ agent, draggable = true }: Props) {
const { id, name, graph_id, can_access_graph, image_url } = agent;
const { triggerFavoriteAnimation } = useFavoriteAnimation();
@@ -63,95 +60,95 @@ export function LibraryAgentCard({
}}
style={{ willChange: "transform" }}
>
-
-
-
-
- {name.charAt(0)}
-
-
- {isFromMarketplace ? "FROM MARKETPLACE" : "Built by you"}
-
-
-
-
-
+
+
+
+
+ {name.charAt(0)}
+
+
+ {isFromMarketplace ? "FROM MARKETPLACE" : "Built by you"}
+
+
+
+
+
-
-
-
- {name}
-
-
- {!image_url ? (
-
- ) : (
-
- )}
-
-
-
+
- See runs
+
+ {name}
+
+
+ {!image_url ? (
+
+ ) : (
+
+ )}
- {can_access_graph && (
+
- Open in builder
+ See runs
- )}
+
+ {can_access_graph && (
+
+ Open in builder
+
+ )}
+
-
);
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/components/FavoriteButton.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/components/FavoriteButton.tsx
index a003d64f59..2289ab918b 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/components/FavoriteButton.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/components/FavoriteButton.tsx
@@ -8,7 +8,10 @@ import { motion, AnimatePresence } from "framer-motion";
interface FavoriteButtonProps {
isFavorite: boolean;
- onClick: (e: MouseEvent
, position: { x: number; y: number }) => void;
+ onClick: (
+ e: MouseEvent,
+ position: { x: number; y: number },
+ ) => void;
className?: string;
}
@@ -22,7 +25,10 @@ export function FavoriteButton({
function handleClick(e: MouseEvent) {
const rect = buttonRef.current?.getBoundingClientRect();
const position = rect
- ? { x: rect.left + rect.width / 2 - 12, y: rect.top + rect.height / 2 - 12 }
+ ? {
+ x: rect.left + rect.width / 2 - 12,
+ y: rect.top + rect.height / 2 - 12,
+ }
: { x: 0, y: 0 };
onClick(e, position);
}
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/useLibraryAgentCard.ts b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/useLibraryAgentCard.ts
index 1b1feccdd4..4362da1ea8 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/useLibraryAgentCard.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/useLibraryAgentCard.ts
@@ -51,7 +51,7 @@ export function useLibraryAgentCard({ agent, onFavoriteAdd }: Props) {
async function handleToggleFavorite(
e: React.MouseEvent,
- position: { x: number; y: number }
+ position: { x: number; y: number },
) {
e.preventDefault();
e.stopPropagation();
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx
index e625fbaee2..532e0a02b1 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx
@@ -217,7 +217,9 @@ export function LibraryAgentList({
transition={{
...activeTransition,
delay:
- ((showFolders ? foldersData?.folders.length ?? 0 : 0) +
+ ((showFolders
+ ? (foldersData?.folders.length ?? 0)
+ : 0) +
i) *
0.04,
}}
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts
index 65f22eef5c..2304a13e3e 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts
@@ -19,7 +19,7 @@ import {
import { useToast } from "@/components/molecules/Toast/use-toast";
import { useFavoriteAgents } from "../../hooks/useFavoriteAgents";
import { getQueryClient } from "@/lib/react-query/queryClient";
-import { keepPreviousData, useQueryClient } from "@tanstack/react-query";
+import { useQueryClient } from "@tanstack/react-query";
import { useEffect, useRef, useState } from "react";
interface Props {
@@ -86,8 +86,6 @@ export function useLibraryAgentList({
: [];
const allAgentsCount = getPaginatedTotalCount(agentsQueryData);
- // --- Favorites ---
-
const favoriteAgentsData = useFavoriteAgents({ searchTerm });
const {
@@ -108,13 +106,10 @@ export function useLibraryAgentList({
fetchNextPage: fetchNextPage,
};
- // --- Folders ---
-
const { data: rawFoldersData } = useGetV2ListLibraryFolders(undefined, {
query: { select: okData },
});
- // When searching, suppress folder data so only agent results show
const foldersData = searchTerm ? undefined : rawFoldersData;
const { mutate: moveAgentToFolder } = usePostV2BulkMoveAgents({
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx
index a7be232caf..55aff18726 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx
@@ -1,4 +1,3 @@
-import { useState } from "react";
import { motion } from "framer-motion";
import { Text } from "@/components/atoms/Text/Text";
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolderCreationDialog/LibraryFolderCreationDialog.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolderCreationDialog/LibraryFolderCreationDialog.tsx
index 2fe0078896..4606a7baa9 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolderCreationDialog/LibraryFolderCreationDialog.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolderCreationDialog/LibraryFolderCreationDialog.tsx
@@ -46,7 +46,9 @@ export default function LibraryFolderCreationDialog() {
const { mutate: createFolder, isPending } = usePostV2CreateFolder({
mutation: {
onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: getGetV2ListLibraryFoldersQueryKey() });
+ queryClient.invalidateQueries({
+ queryKey: getGetV2ListLibraryFoldersQueryKey(),
+ });
setIsOpen(false);
form.reset();
toast({
@@ -110,7 +112,7 @@ export default function LibraryFolderCreationDialog() {
-
{
field.onChange(emoji);
@@ -198,7 +199,10 @@ export default function LibraryFolderCreationDialog() {
className="w-full rounded-2xl px-2"
>
-
+
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySubSection/LibrarySubSection.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySubSection/LibrarySubSection.tsx
index 1d0f1e6e5e..f69f9f57ac 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySubSection/LibrarySubSection.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibrarySubSection/LibrarySubSection.tsx
@@ -9,9 +9,13 @@ interface Props {
export function LibrarySubSection({ tabs, activeTab, onTabChange }: Props) {
return (
-
-
+
+
);
-}
\ No newline at end of file
+}
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/context/FavoriteAnimationContext.tsx b/autogpt_platform/frontend/src/app/(platform)/library/context/FavoriteAnimationContext.tsx
index 144e491d1c..f2d7fa2051 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/context/FavoriteAnimationContext.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/context/FavoriteAnimationContext.tsx
@@ -1,6 +1,12 @@
"use client";
-import { createContext, useContext, useState, useCallback, useRef } from "react";
+import {
+ createContext,
+ useContext,
+ useState,
+ useCallback,
+ useRef,
+} from "react";
import { FlyingHeart } from "../components/FlyingHeart/FlyingHeart";
interface FavoriteAnimationContextType {
@@ -8,7 +14,8 @@ interface FavoriteAnimationContextType {
registerFavoritesTabRef: (element: HTMLElement | null) => void;
}
-const FavoriteAnimationContext = createContext
(null);
+const FavoriteAnimationContext =
+ createContext(null);
interface FavoriteAnimationProviderProps {
children: React.ReactNode;
@@ -44,7 +51,7 @@ export function FavoriteAnimationProvider({
setAnimationState({ startPosition, targetPosition });
}
},
- []
+ [],
);
function handleAnimationComplete() {
@@ -70,7 +77,7 @@ export function useFavoriteAnimation() {
const context = useContext(FavoriteAnimationContext);
if (!context) {
throw new Error(
- "useFavoriteAnimation must be used within FavoriteAnimationProvider"
+ "useFavoriteAnimation must be used within FavoriteAnimationProvider",
);
}
return context;
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/page.tsx b/autogpt_platform/frontend/src/app/(platform)/library/page.tsx
index 128ba609dd..2510bd8f33 100644
--- a/autogpt_platform/frontend/src/app/(platform)/library/page.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/library/page.tsx
@@ -34,7 +34,9 @@ export default function LibraryPage() {
}, []);
return (
-
+