From bb1f1a56a5d94e561ae8fc5a7d98a8dd4ed23f69 Mon Sep 17 00:00:00 2001 From: Stream Date: Sun, 28 Sep 2025 22:36:10 +0800 Subject: [PATCH] feat: update MemoryListApi response format with ChatflowConversationMetadata --- .../service_api/app/chatflow_memory.py | 34 +++++---- api/controllers/web/chatflow_memory.py | 35 ++++++---- api/core/memory/entities.py | 27 ++++++++ api/services/chatflow_history_service.py | 16 ++++- api/services/chatflow_memory_service.py | 69 ++++++++++++++++--- 5 files changed, 142 insertions(+), 39 deletions(-) diff --git a/api/controllers/service_api/app/chatflow_memory.py b/api/controllers/service_api/app/chatflow_memory.py index e9bd55a4f3..1f56dfba43 100644 --- a/api/controllers/service_api/app/chatflow_memory.py +++ b/api/controllers/service_api/app/chatflow_memory.py @@ -21,21 +21,27 @@ class MemoryListApi(Resource): memory_id = args.get("memory_id") version = args.get("version") - result = ChatflowMemoryService.get_persistent_memories( - app_model, - MemoryCreatedBy(end_user_id=end_user.id), - version - ) if conversation_id: - result = [ - *result, - *ChatflowMemoryService.get_session_memories( - app_model, - MemoryCreatedBy(end_user_id=end_user.id), - conversation_id, - version - ) - ] + result = ChatflowMemoryService.get_persistent_memories_with_conversation( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + conversation_id, + version + ) + session_memories = ChatflowMemoryService.get_session_memories_with_conversation( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + conversation_id, + version + ) + result = [*result, *session_memories] + else: + result = ChatflowMemoryService.get_persistent_memories( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + version + ) + if memory_id: result = [it for it in result if it.spec.id == memory_id] return [it for it in result if it.spec.end_user_visible] diff --git a/api/controllers/web/chatflow_memory.py b/api/controllers/web/chatflow_memory.py index 1387807c6c..5969d66bcf 100644 --- a/api/controllers/web/chatflow_memory.py +++ b/api/controllers/web/chatflow_memory.py @@ -20,21 +20,28 @@ class MemoryListApi(WebApiResource): memory_id = args.get("memory_id") version = args.get("version") - result = ChatflowMemoryService.get_persistent_memories( - app_model, - MemoryCreatedBy(end_user_id=end_user.id), - version - ) + if conversation_id: - result = [ - *result, - *ChatflowMemoryService.get_session_memories( - app_model, - MemoryCreatedBy(end_user_id=end_user.id), - conversation_id, - version - ) - ] + result = ChatflowMemoryService.get_persistent_memories_with_conversation( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + conversation_id, + version + ) + session_memories = ChatflowMemoryService.get_session_memories_with_conversation( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + conversation_id, + version + ) + result = [*result, *session_memories] + else: + result = ChatflowMemoryService.get_persistent_memories( + app_model, + MemoryCreatedBy(end_user_id=end_user.id), + version + ) + if memory_id: result = [it for it in result if it.spec.id == memory_id] return [it for it in result if it.spec.end_user_visible] diff --git a/api/core/memory/entities.py b/api/core/memory/entities.py index 0cee9ad0e7..88602142b3 100644 --- a/api/core/memory/entities.py +++ b/api/core/memory/entities.py @@ -90,3 +90,30 @@ class ChatflowConversationMetadata(BaseModel): """Metadata for chatflow conversation with visible message count""" type: str = "mutable_visible_window" visible_count: int = Field(gt=0, description="Number of visible messages to keep") + + +class MemoryBlockWithConversation(MemoryBlock): + """MemoryBlock with optional conversation metadata for session memories""" + conversation_metadata: ChatflowConversationMetadata = Field( + description="Conversation metadata, only present for session memories" + ) + + @classmethod + def from_memory_block( + cls, + memory_block: MemoryBlock, + conversation_metadata: ChatflowConversationMetadata + ) -> "MemoryBlockWithConversation": + """Create MemoryBlockWithConversation from MemoryBlock""" + return cls( + spec=memory_block.spec, + tenant_id=memory_block.tenant_id, + value=memory_block.value, + app_id=memory_block.app_id, + conversation_id=memory_block.conversation_id, + node_id=memory_block.node_id, + edited_by_user=memory_block.edited_by_user, + created_by=memory_block.created_by, + version=memory_block.version, + conversation_metadata=conversation_metadata + ) diff --git a/api/services/chatflow_history_service.py b/api/services/chatflow_history_service.py index 521cf22218..8ea3240f4f 100644 --- a/api/services/chatflow_history_service.py +++ b/api/services/chatflow_history_service.py @@ -1,5 +1,4 @@ import json -import time from collections.abc import MutableMapping, Sequence from typing import Literal, Optional, overload @@ -134,6 +133,21 @@ class ChatflowHistoryService: session.commit() + @staticmethod + def get_conversation_metadata( + tenant_id: str, + app_id: str, + conversation_id: str, + node_id: Optional[str] + ) -> ChatflowConversationMetadata: + with Session(db.engine) as session: + chatflow_conv = ChatflowHistoryService._get_or_create_chatflow_conversation( + session, conversation_id, app_id, tenant_id, node_id, create_if_missing=False + ) + if not chatflow_conv: + raise ValueError(f"Conversation not found: {conversation_id}") + return ChatflowConversationMetadata.model_validate_json(chatflow_conv.conversation_metadata) + @staticmethod def _filter_latest_messages(raw_messages: Sequence[ChatflowMessage]) -> Sequence[ChatflowMessage]: index_to_message: MutableMapping[int, ChatflowMessage] = {} diff --git a/api/services/chatflow_memory_service.py b/api/services/chatflow_memory_service.py index 0e6e064b89..13b2662640 100644 --- a/api/services/chatflow_memory_service.py +++ b/api/services/chatflow_memory_service.py @@ -11,6 +11,7 @@ from core.llm_generator.llm_generator import LLMGenerator from core.memory.entities import ( MemoryBlock, MemoryBlockSpec, + MemoryBlockWithConversation, MemoryCreatedBy, MemoryScheduleMode, MemoryScope, @@ -280,7 +281,8 @@ class ChatflowMemoryService: block=memory_block, is_draft=is_draft, variable_pool=variable_pool, - visible_messages=visible_messages + visible_messages=visible_messages, + conversation_id=conversation_id, ) # sync mode: submit a batch update task @@ -332,7 +334,8 @@ class ChatflowMemoryService: visible_messages=visible_messages, memory_block=memory_block, variable_pool=variable_pool, - is_draft=is_draft + is_draft=is_draft, + conversation_id=conversation_id ) else: # Node-level async: execute asynchronously @@ -340,7 +343,8 @@ class ChatflowMemoryService: memory_block=memory_block, visible_messages=visible_messages, variable_pool=variable_pool, - is_draft=is_draft + is_draft=is_draft, + conversation_id=conversation_id ) return True @@ -422,6 +426,7 @@ class ChatflowMemoryService: block: MemoryBlock, visible_messages: Sequence[PromptMessage], variable_pool: VariablePool, + conversation_id: str, is_draft: bool ): thread = threading.Thread( @@ -430,7 +435,8 @@ class ChatflowMemoryService: 'memory_block': block, 'visible_messages': visible_messages, 'variable_pool': variable_pool, - 'is_draft': is_draft + 'is_draft': is_draft, + 'conversation_id': conversation_id }, ) thread.start() @@ -478,7 +484,8 @@ class ChatflowMemoryService: 'memory_block': block, 'visible_messages': visible_messages, 'variable_pool': variable_pool, - 'is_draft': is_draft + 'is_draft': is_draft, + 'conversation_id': conversation_id, }, ) threads.append(thread) @@ -494,13 +501,15 @@ class ChatflowMemoryService: memory_block: MemoryBlock, visible_messages: Sequence[PromptMessage], variable_pool: VariablePool, + conversation_id: str, is_draft: bool ): ChatflowMemoryService._perform_memory_update( memory_block=memory_block, visible_messages=visible_messages, variable_pool=variable_pool, - is_draft=is_draft + is_draft=is_draft, + conversation_id=conversation_id ) @staticmethod @@ -508,6 +517,7 @@ class ChatflowMemoryService: memory_block: MemoryBlock, visible_messages: Sequence[PromptMessage], variable_pool: VariablePool, + conversation_id: str, is_draft: bool = False ): thread = threading.Thread( @@ -516,7 +526,8 @@ class ChatflowMemoryService: 'memory_block': memory_block, 'visible_messages': visible_messages, 'variable_pool': variable_pool, - 'is_draft': is_draft + 'is_draft': is_draft, + 'conversation_id': conversation_id, }, daemon=True ) @@ -526,6 +537,7 @@ class ChatflowMemoryService: def _perform_memory_update( memory_block: MemoryBlock, variable_pool: VariablePool, + conversation_id: str, visible_messages: Sequence[PromptMessage], is_draft: bool ): @@ -541,7 +553,7 @@ class ChatflowMemoryService: value=updated_value, spec=memory_block.spec, app_id=memory_block.app_id, - conversation_id=memory_block.conversation_id, + conversation_id=conversation_id, node_id=memory_block.node_id, edited_by_user=False, created_by=memory_block.created_by, @@ -549,9 +561,8 @@ class ChatflowMemoryService: ) ChatflowMemoryService.save_memory(updated_memory, variable_pool, is_draft) - # 添加以下代码:重置 visible_count 为 preserved_turns ChatflowHistoryService.update_visible_count( - conversation_id=memory_block.conversation_id, + conversation_id=conversation_id, node_id=memory_block.node_id, new_visible_count=memory_block.spec.preserved_turns, app_id=memory_block.app_id, @@ -609,6 +620,44 @@ class ChatflowMemoryService: session.execute(stmt) session.commit() + @staticmethod + def get_persistent_memories_with_conversation( + app: App, + created_by: MemoryCreatedBy, + conversation_id: str, + version: int | None = None + ) -> Sequence[MemoryBlockWithConversation]: + """Get persistent memories with conversation metadata (always None for persistent)""" + memory_blocks = ChatflowMemoryService.get_persistent_memories(app, created_by, version) + return [ + MemoryBlockWithConversation.from_memory_block( + block, + ChatflowHistoryService.get_conversation_metadata( + app.tenant_id, app.id, conversation_id, block.node_id + ) + ) + for block in memory_blocks + ] + + @staticmethod + def get_session_memories_with_conversation( + app: App, + created_by: MemoryCreatedBy, + conversation_id: str, + version: int | None = None + ) -> Sequence[MemoryBlockWithConversation]: + """Get session memories with conversation metadata""" + memory_blocks = ChatflowMemoryService.get_session_memories(app, created_by, conversation_id, version) + return [ + MemoryBlockWithConversation.from_memory_block( + block, + ChatflowHistoryService.get_conversation_metadata( + app.tenant_id, app.id, conversation_id, block.node_id + ) + ) + for block in memory_blocks + ] + @staticmethod def _format_chat_history(messages: Sequence[PromptMessage]) -> Sequence[tuple[str, str]]: result = []