from enum import Enum from typing import Optional from uuid import uuid4 from pydantic import BaseModel, Field from core.app.app_config.entities import ModelConfig class MemoryScope(str, Enum): """Memory scope determined by node_id field""" APP = "app" # node_id is None NODE = "node" # node_id is not None class MemoryTerm(str, Enum): """Memory term determined by conversation_id field""" SESSION = "session" # conversation_id is not None PERSISTENT = "persistent" # conversation_id is None class MemoryStrategy(str, Enum): ON_TURNS = "on_turns" class MemoryScheduleMode(str, Enum): SYNC = "sync" ASYNC = "async" class MemoryBlockSpec(BaseModel): """Memory block specification for workflow configuration""" id: str = Field( default_factory=lambda: str(uuid4()), description="Unique identifier for the memory block", ) name: str = Field(description="Display name of the memory block") description: str = Field(default="", description="Description of the memory block") template: str = Field(description="Initial template content for the memory") instruction: str = Field(description="Instructions for updating the memory") scope: MemoryScope = Field(description="Scope of the memory (app or node level)") term: MemoryTerm = Field(description="Term of the memory (session or persistent)") strategy: MemoryStrategy = Field(description="Update strategy for the memory") update_turns: int = Field(gt=0, description="Number of turns between updates") preserved_turns: int = Field(gt=0, description="Number of conversation turns to preserve") schedule_mode: MemoryScheduleMode = Field(description="Synchronous or asynchronous update mode") model: ModelConfig = Field(description="Model configuration for memory updates") end_user_visible: bool = Field(default=False, description="Whether memory is visible to end users") end_user_editable: bool = Field(default=False, description="Whether memory is editable by end users") class MemoryBlock(BaseModel): """Runtime memory block instance Design Rules: - app_id = None: Global memory (future feature, not implemented yet) - app_id = str: App-specific memory - conversation_id = None: Persistent memory (cross-conversation) - conversation_id = str: Session memory (conversation-specific) - node_id = None: App-level scope - node_id = str: Node-level scope These rules implicitly determine scope and term without redundant storage. """ spec: MemoryBlockSpec tenant_id: str value: str app_id: str conversation_id: Optional[str] = None node_id: Optional[str] = None class MemoryBlockWithVisibility(BaseModel): id: str name: str value: str end_user_visible: bool end_user_editable: bool 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")