diff --git a/autogpt_platform/backend/backend/server/v2/library/db.py b/autogpt_platform/backend/backend/server/v2/library/db.py index c5b240d3b731..4dcb9f7190e9 100644 --- a/autogpt_platform/backend/backend/server/v2/library/db.py +++ b/autogpt_platform/backend/backend/server/v2/library/db.py @@ -1,3 +1,4 @@ +import datetime import logging from typing import Optional @@ -29,7 +30,7 @@ async def list_library_agents( user_id: str, search_term: Optional[str] = None, - sort_by: library_model.LibraryAgentSort = library_model.LibraryAgentSort.UPDATED_AT, + sort_by: library_model.LibraryAgentSort = library_model.LibraryAgentSort.LAST_EXECUTED_AT, page: int = 1, page_size: int = 50, ) -> library_model.LibraryAgentResponse: @@ -95,16 +96,23 @@ async def list_library_agents( order_by = {"updatedAt": "desc"} try: - library_agents = await prisma.models.LibraryAgent.prisma().find_many( - where=where_clause, - include=library_agent_include(user_id), - order=order_by, - skip=(page - 1) * page_size, - take=page_size, - ) - agent_count = await prisma.models.LibraryAgent.prisma().count( - where=where_clause - ) + if sort_by == library_model.LibraryAgentSort.LAST_EXECUTED_AT: + library_agents = await prisma.models.LibraryAgent.prisma().find_many( + where=where_clause, + include=library_agent_include(user_id), + ) + agent_count = len(library_agents) + else: + library_agents = await prisma.models.LibraryAgent.prisma().find_many( + where=where_clause, + include=library_agent_include(user_id), + order=order_by, + skip=(page - 1) * page_size, + take=page_size, + ) + agent_count = await prisma.models.LibraryAgent.prisma().count( + where=where_clause + ) logger.debug( f"Retrieved {len(library_agents)} library agents for user #{user_id}" @@ -124,7 +132,15 @@ async def list_library_agents( ) continue - # Return the response with only valid agents + if sort_by == library_model.LibraryAgentSort.LAST_EXECUTED_AT: + valid_library_agents.sort( + key=lambda a: a.last_executed_at + or datetime.datetime.min.replace(tzinfo=datetime.timezone.utc), + reverse=True, + ) + start = (page - 1) * page_size + valid_library_agents = valid_library_agents[start : start + page_size] + return library_model.LibraryAgentResponse( agents=valid_library_agents, pagination=backend.server.model.Pagination( diff --git a/autogpt_platform/backend/backend/server/v2/library/model.py b/autogpt_platform/backend/backend/server/v2/library/model.py index c38f8f7333b7..1672ae83e81b 100644 --- a/autogpt_platform/backend/backend/server/v2/library/model.py +++ b/autogpt_platform/backend/backend/server/v2/library/model.py @@ -36,6 +36,8 @@ class LibraryAgent(pydantic.BaseModel): status: LibraryAgentStatus updated_at: datetime.datetime + # Most recent time this agent was executed + last_executed_at: Optional[datetime.datetime] = None name: str description: str @@ -88,6 +90,10 @@ def from_db(agent: prisma.models.LibraryAgent) -> "LibraryAgent": status = status_result.status new_output = status_result.new_output + last_executed_at = None + if executions: + last_executed_at = max(exec.createdAt for exec in executions) + # Check if user can access the graph can_access_graph = agent.AgentGraph.userId == agent.userId @@ -103,6 +109,7 @@ def from_db(agent: prisma.models.LibraryAgent) -> "LibraryAgent": creator_image_url=creator_image_url, status=status, updated_at=updated_at, + last_executed_at=last_executed_at, name=graph.name, description=graph.description, input_schema=graph.input_schema, @@ -235,6 +242,7 @@ class LibraryAgentSort(str, Enum): CREATED_AT = "createdAt" UPDATED_AT = "updatedAt" + LAST_EXECUTED_AT = "lastExecutedAt" class LibraryAgentUpdateRequest(pydantic.BaseModel): diff --git a/autogpt_platform/backend/backend/server/v2/library/routes/agents.py b/autogpt_platform/backend/backend/server/v2/library/routes/agents.py index 141d6d2e5076..1ac60efa596f 100644 --- a/autogpt_platform/backend/backend/server/v2/library/routes/agents.py +++ b/autogpt_platform/backend/backend/server/v2/library/routes/agents.py @@ -30,7 +30,7 @@ async def list_library_agents( None, description="Search term to filter agents" ), sort_by: library_model.LibraryAgentSort = Query( - library_model.LibraryAgentSort.UPDATED_AT, + library_model.LibraryAgentSort.LAST_EXECUTED_AT, description="Criteria to sort results by", ), page: int = Query( diff --git a/autogpt_platform/backend/backend/server/v2/library/routes_test.py b/autogpt_platform/backend/backend/server/v2/library/routes_test.py index 962da72d86ad..ec2c5722d004 100644 --- a/autogpt_platform/backend/backend/server/v2/library/routes_test.py +++ b/autogpt_platform/backend/backend/server/v2/library/routes_test.py @@ -85,7 +85,7 @@ async def test_get_library_agents_success(mocker: pytest_mock.MockFixture): mock_db_call.assert_called_once_with( user_id="test-user-id", search_term="test", - sort_by=library_model.LibraryAgentSort.UPDATED_AT, + sort_by=library_model.LibraryAgentSort.LAST_EXECUTED_AT, page=1, page_size=15, ) @@ -100,7 +100,7 @@ def test_get_library_agents_error(mocker: pytest_mock.MockFixture): mock_db_call.assert_called_once_with( user_id="test-user-id", search_term="test", - sort_by=library_model.LibraryAgentSort.UPDATED_AT, + sort_by=library_model.LibraryAgentSort.LAST_EXECUTED_AT, page=1, page_size=15, ) diff --git a/autogpt_platform/frontend/src/app/(platform)/library/state-provider.tsx b/autogpt_platform/frontend/src/app/(platform)/library/state-provider.tsx index 70ac649a3f40..59048cc6f5f8 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/state-provider.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/state-provider.tsx @@ -37,7 +37,7 @@ export function LibraryPageStateProvider({ const [searchTerm, setSearchTerm] = useState(""); const [uploadedFile, setUploadedFile] = useState(null); const [librarySort, setLibrarySort] = useState( - LibraryAgentSortEnum.UPDATED_AT, + LibraryAgentSortEnum.LAST_EXECUTED_AT, ); return ( diff --git a/autogpt_platform/frontend/src/components/library/library-sort-menu.tsx b/autogpt_platform/frontend/src/components/library/library-sort-menu.tsx index 3e47aa114d52..bf1d59dd6027 100644 --- a/autogpt_platform/frontend/src/components/library/library-sort-menu.tsx +++ b/autogpt_platform/frontend/src/components/library/library-sort-menu.tsx @@ -34,7 +34,7 @@ export default function LibrarySortMenu(): React.ReactNode { diff --git a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts index 1aec142578a7..61ba5d6b7b6e 100644 --- a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts +++ b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts @@ -397,6 +397,7 @@ export type LibraryAgent = { creator_image_url: string; status: AgentStatus; updated_at: Date; + last_executed_at?: Date; name: string; description: string; input_schema: BlockIOObjectSubSchema; @@ -456,6 +457,7 @@ export interface CreateLibraryAgentPresetRequest { export enum LibraryAgentSortEnum { CREATED_AT = "createdAt", UPDATED_AT = "updatedAt", + LAST_EXECUTED_AT = "lastExecutedAt", } /* *** CREDENTIALS *** */