diff --git a/autogpt_platform/backend/backend/blocks/llm.py b/autogpt_platform/backend/backend/blocks/llm.py index 66b1a04f55..fbd753ef98 100644 --- a/autogpt_platform/backend/backend/blocks/llm.py +++ b/autogpt_platform/backend/backend/blocks/llm.py @@ -187,6 +187,9 @@ class LlmModel(str, metaclass=LlmModelMeta): llm_model_metadata = {} for model in cls: model_name = model.value + # Skip disabled models - only show enabled models in the picker + if not llm_registry.is_model_enabled(model_name): + continue # Use registry directly with None check to gracefully handle # missing metadata during startup/import before registry is populated metadata = llm_registry.get_llm_model_metadata(model_name) diff --git a/autogpt_platform/frontend/src/app/(platform)/admin/llms/components/ModelsTable.tsx b/autogpt_platform/frontend/src/app/(platform)/admin/llms/components/ModelsTable.tsx index 665dd6654c..a3a71f1224 100644 --- a/autogpt_platform/frontend/src/app/(platform)/admin/llms/components/ModelsTable.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/admin/llms/components/ModelsTable.tsx @@ -1,5 +1,6 @@ "use client"; +import { useState, useEffect, useRef } from "react"; import type { LlmModel } from "@/app/api/__generated__/models/llmModel"; import type { LlmModelCreator } from "@/app/api/__generated__/models/llmModelCreator"; import type { LlmProvider } from "@/app/api/__generated__/models/llmProvider"; @@ -16,10 +17,13 @@ import { toggleLlmModelAction } from "../actions"; import { DeleteModelModal } from "./DeleteModelModal"; import { DisableModelModal } from "./DisableModelModal"; import { EditModelModal } from "./EditModelModal"; -import { Star } from "@phosphor-icons/react"; +import { Star, Spinner } from "@phosphor-icons/react"; +import { getV2ListLlmModels } from "@/app/api/__generated__/endpoints/admin/admin"; + +const PAGE_SIZE = 50; export function ModelsTable({ - models, + models: initialModels, providers, creators, }: { @@ -27,6 +31,75 @@ export function ModelsTable({ providers: LlmProvider[]; creators: LlmModelCreator[]; }) { + const [models, setModels] = useState(initialModels); + const [currentPage, setCurrentPage] = useState(1); + const [hasMore, setHasMore] = useState(initialModels.length === PAGE_SIZE); + const [isLoading, setIsLoading] = useState(false); + const loadedPagesRef = useRef(1); + + // Sync with parent when initialModels changes (e.g., after enable/disable) + // Re-fetch all loaded pages to preserve expanded state + useEffect(() => { + async function refetchAllPages() { + const pagesToLoad = loadedPagesRef.current; + + if (pagesToLoad === 1) { + // Only first page loaded, just use initialModels + setModels(initialModels); + setHasMore(initialModels.length === PAGE_SIZE); + return; + } + + // Re-fetch all pages we had loaded + const allModels: LlmModel[] = [...initialModels]; + let lastPageHadFullResults = initialModels.length === PAGE_SIZE; + + for (let page = 2; page <= pagesToLoad; page++) { + try { + const response = await getV2ListLlmModels({ + page, + page_size: PAGE_SIZE, + }); + if (response.status === 200) { + allModels.push(...response.data.models); + lastPageHadFullResults = response.data.models.length === PAGE_SIZE; + } + } catch (err) { + console.error(`Error refetching page ${page}:`, err); + break; + } + } + + setModels(allModels); + setHasMore(lastPageHadFullResults); + } + + refetchAllPages(); + }, [initialModels]); + + async function loadMore() { + if (isLoading) return; + setIsLoading(true); + + try { + const nextPage = currentPage + 1; + const response = await getV2ListLlmModels({ + page: nextPage, + page_size: PAGE_SIZE, + }); + + if (response.status === 200) { + setModels((prev) => [...prev, ...response.data.models]); + setCurrentPage(nextPage); + loadedPagesRef.current = nextPage; + setHasMore(response.data.models.length === PAGE_SIZE); + } + } catch (err) { + console.error("Error loading more models:", err); + } finally { + setIsLoading(false); + } + } if (!models.length) { return (
@@ -40,8 +113,9 @@ export function ModelsTable({ ); return ( -
- +
+
+
Model @@ -154,7 +228,23 @@ export function ModelsTable({ ); })} -
+ +
+ + {hasMore && ( +
+ +
+ )}
); }