From 13abb03d87a943055911a6dade6e3f4bc66e9d8c Mon Sep 17 00:00:00 2001 From: Eternity <1533512157@qq.com> Date: Thu, 19 Mar 2026 17:44:40 +0800 Subject: [PATCH 1/3] feat(memory): add pagination support for conversation list in working memory --- .../controllers/memory_working_controller.py | 42 ++++++++++++------- .../repositories/conversation_repository.py | 35 +++++++++------- api/app/services/conversation_service.py | 22 +++++----- api/app/services/user_memory_service.py | 5 +-- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/api/app/controllers/memory_working_controller.py b/api/app/controllers/memory_working_controller.py index 8aab039a..473adedb 100644 --- a/api/app/controllers/memory_working_controller.py +++ b/api/app/controllers/memory_working_controller.py @@ -33,35 +33,47 @@ def get_memory_count( @router.get("/{end_user_id}/conversations", response_model=ApiResponse) def get_conversations( end_user_id: uuid.UUID, + page: int = 1, + page_size: int = 20, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """ - Retrieve all conversations for the current user in a specific group. + Retrieve conversations for the current user in a specific group with pagination. Args: end_user_id (UUID): The group identifier. + page (int): Page number (1-based). Defaults to 1. + page_size (int): Number of items per page. Defaults to 20. current_user (User, optional): The authenticated user. db (Session, optional): SQLAlchemy session. Returns: - ApiResponse: Contains a list of conversation IDs. - - Notes: - - Initializes the ConversationService with the current DB session. - - Returns only conversation IDs for lightweight response. - - Logs can be added to trace requests in production. + ApiResponse: Contains a paginated list of conversations. """ + page = max(1, page) + page_size = max(1, min(page_size, 100)) # Limit page size between 1 and 100 conversation_service = ConversationService(db) - conversations = conversation_service.get_user_conversations( - end_user_id + conversations, total = conversation_service.get_user_conversations( + end_user_id, + page=page, + page_size=page_size ) - return success(data=[ - { - "id": conversation.id, - "title": conversation.title - } for conversation in conversations - ], msg="get conversations success") + return success(data={ + "items": [ + { + "id": conversation.id, + "title": conversation.title + } for conversation in conversations + ], + "total": total, + "page": { + "page": page, + "pagesize": page_size, + "total": total, + "hasnext": (page * page_size) < total + }, + }, msg="get conversations success") @router.get("/{end_user_id}/messages", response_model=ApiResponse) diff --git a/api/app/repositories/conversation_repository.py b/api/app/repositories/conversation_repository.py index eb5d3c61..90f2d6ec 100644 --- a/api/app/repositories/conversation_repository.py +++ b/api/app/repositories/conversation_repository.py @@ -90,27 +90,27 @@ class ConversationRepository: self, user_id: uuid.UUID, workspace_id: uuid.UUID = None, - limit: int = 10, - is_activate: bool = True - ) -> list[Conversation]: + is_activate: bool = True, + page: int = 1, + page_size: int = 20 + ) -> tuple[list[Conversation], int]: """ - Retrieve recent conversations for a specific user. + Retrieve recent conversations for a specific user with pagination. This method queries conversations associated with the given user ID, optionally scoped to a specific workspace. Results are ordered by the - most recently updated conversations and limited to a fixed number. + most recently updated conversations. Args: user_id (uuid.UUID): Unique identifier of the user. workspace_id (uuid.UUID, optional): Workspace scope for the query. If provided, only conversations under this workspace will be returned. - limit (int): Maximum number of conversations to return. - Defaults to 10. - is_activate (bool): Convsersation State limit + is_activate (bool): Conversation State limit. + page (int): Page number (1-based). Defaults to 1. + page_size (int): Number of items per page. Defaults to 20. Returns: - list[Conversation]: A list of conversation entities ordered by - last updated time (descending). + tuple[list[Conversation], int]: A list of conversation entities and total count. """ logger.info(f"Fetching conversation by user_id: {user_id}") @@ -122,18 +122,25 @@ class ConversationRepository: if workspace_id: stmt = stmt.where(Conversation.workspace_id == workspace_id) - stmt = stmt.order_by(desc(Conversation.updated_at)) - stmt = stmt.limit(limit) + # Calculate total count + total = int(self.db.execute( + select(func.count()).select_from(stmt.subquery()) + ).scalar_one()) - convsersations = list(self.db.scalars(stmt).all()) + # Apply ordering and pagination + stmt = stmt.order_by(desc(Conversation.updated_at)) + stmt = stmt.offset((page - 1) * page_size).limit(page_size) + + conversations = list(self.db.scalars(stmt).all()) logger.info( "Conversation fetched successfully", extra={ "user_id": str(user_id), "workspace_id": str(workspace_id), + "total": total, } ) - return convsersations + return conversations, total def list_conversations( self, diff --git a/api/app/services/conversation_service.py b/api/app/services/conversation_service.py index aff5f533..87568b06 100644 --- a/api/app/services/conversation_service.py +++ b/api/app/services/conversation_service.py @@ -119,25 +119,27 @@ class ConversationService: def get_user_conversations( self, - user_id: uuid.UUID - ) -> list[Conversation]: + user_id: uuid.UUID, + page: int = 1, + page_size: int = 20 + ) -> tuple[list[Conversation], int]: """ - Retrieve recent conversations for a specific user - - This method delegates persistence logic to the repository layer and - applies service-level defaults (e.g. recent conversation limit). + Retrieve recent conversations for a specific user with pagination. Args: user_id (uuid.UUID): Unique identifier of the user. + page (int): Page number (1-based). Defaults to 1. + page_size (int): Number of items per page. Defaults to 20. Returns: - list[Conversation]: A list of recent conversation entities. + tuple[list[Conversation], int]: A list of recent conversation entities and total count. """ - conversations = self.conversation_repo.get_conversation_by_user_id( + conversations, total = self.conversation_repo.get_conversation_by_user_id( user_id, - limit=10 + page=page, + page_size=page_size ) - return conversations + return conversations, total def list_conversations( self, diff --git a/api/app/services/user_memory_service.py b/api/app/services/user_memory_service.py index d5d19e0d..12e0c324 100644 --- a/api/app/services/user_memory_service.py +++ b/api/app/services/user_memory_service.py @@ -1408,12 +1408,11 @@ async def analytics_memory_types( if end_user_id: try: conversation_repo = ConversationRepository(db) - conversations = conversation_repo.get_conversation_by_user_id( + conversations, total = conversation_repo.get_conversation_by_user_id( user_id=uuid.UUID(end_user_id), - limit=100, # 获取更多会话以准确统计 is_activate=True ) - work_count = len(conversations) + work_count = total logger.debug(f"工作记忆数量(会话数): {work_count} (end_user_id={end_user_id})") except Exception as e: logger.warning(f"获取会话数量失败,工作记忆数量设为0: {str(e)}") From 7aec15785967084d2bb7994d412324fc55d870bc Mon Sep 17 00:00:00 2001 From: lanceyq <1982376970@qq.com> Date: Thu, 19 Mar 2026 17:53:01 +0800 Subject: [PATCH 2/3] [changes] keep two decimals --- api/app/services/memory_forget_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/services/memory_forget_service.py b/api/app/services/memory_forget_service.py index 84c4aff6..a0bcc1a1 100644 --- a/api/app/services/memory_forget_service.py +++ b/api/app/services/memory_forget_service.py @@ -619,7 +619,7 @@ class MemoryForgetService: recent_trends.append({ 'date': date_str, 'merged_count': record.merged_count, - 'average_activation': record.average_activation_value, + 'average_activation': round(record.average_activation_value, 2) if record.average_activation_value is not None else None, 'total_nodes': record.total_nodes, 'execution_time': int(record.execution_time.timestamp() * 1000) }) From 37a22fbfa9fa09d9f450d04055212039ef8ba0dc Mon Sep 17 00:00:00 2001 From: Eternity <1533512157@qq.com> Date: Thu, 19 Mar 2026 18:23:09 +0800 Subject: [PATCH 3/3] feat(memory): add pagination support for conversation list in working memory --- api/app/controllers/memory_working_controller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/app/controllers/memory_working_controller.py b/api/app/controllers/memory_working_controller.py index 473adedb..c06fd432 100644 --- a/api/app/controllers/memory_working_controller.py +++ b/api/app/controllers/memory_working_controller.py @@ -34,7 +34,7 @@ def get_memory_count( def get_conversations( end_user_id: uuid.UUID, page: int = 1, - page_size: int = 20, + pagesize: int = 20, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): @@ -44,7 +44,7 @@ def get_conversations( Args: end_user_id (UUID): The group identifier. page (int): Page number (1-based). Defaults to 1. - page_size (int): Number of items per page. Defaults to 20. + pagesize (int): Number of items per page. Defaults to 20. current_user (User, optional): The authenticated user. db (Session, optional): SQLAlchemy session. @@ -52,7 +52,7 @@ def get_conversations( ApiResponse: Contains a paginated list of conversations. """ page = max(1, page) - page_size = max(1, min(page_size, 100)) # Limit page size between 1 and 100 + page_size = max(1, min(pagesize, 100)) # Limit page size between 1 and 100 conversation_service = ConversationService(db) conversations, total = conversation_service.get_user_conversations( end_user_id,