# Class Diagram - Agent Media ```mermaid classDiagram direction TB %% =========================================== %% MEMORY SYSTEM %% =========================================== class Memory { +Path storage_dir +Path ltm_file +LongTermMemory ltm +ShortTermMemory stm +EpisodicMemory episodic +__init__(storage_dir: str) +save() void +get_context_for_prompt() Dict +get_full_state() Dict +clear_session() void } class LongTermMemory { +Dict config +Dict preferences +Dict~str, List~ library +List~Dict~ following +get_config(key: str) Any +set_config(key: str, value: Any) void +has_config(key: str) bool +add_to_library(media_type: str, media: Dict) void +get_library(media_type: str) List +follow_show(show: Dict) void +to_dict() Dict +from_dict(data: Dict)$ LongTermMemory } class ShortTermMemory { +List~Dict~ conversation_history +Dict current_workflow +Dict extracted_entities +str current_topic +int max_history +add_message(role: str, content: str) void +get_recent_history(n: int) List +start_workflow(type: str, target: Dict) void +update_workflow_stage(stage: str) void +end_workflow() void +set_entity(key: str, value: Any) void +get_entity(key: str) Any +clear() void +to_dict() Dict } class EpisodicMemory { +Dict last_search_results +List~Dict~ active_downloads +List~Dict~ recent_errors +Dict pending_question +List~Dict~ background_events +store_search_results(query: str, results: List) void +get_result_by_index(index: int) Dict +get_search_results() Dict +add_active_download(download: Dict) void +complete_download(task_id: str, path: str) Dict +add_error(action: str, error: str) void +set_pending_question(question: str, options: List) void +resolve_pending_question(index: int) Dict +add_background_event(type: str, data: Dict) void +get_unread_events() List +clear() void +to_dict() Dict } Memory *-- LongTermMemory : ltm Memory *-- ShortTermMemory : stm Memory *-- EpisodicMemory : episodic %% =========================================== %% AGENT SYSTEM %% =========================================== class Agent { +LLMClient llm +Memory memory +Dict~str, Tool~ tools +PromptBuilder prompt_builder +int max_tool_iterations +__init__(llm: LLMClient, memory: Memory) +step(user_input: str) str -_parse_intent(text: str) Dict -_execute_action(intent: Dict) Dict -_check_unread_events() str } class LLMClient { <> +complete(messages: List) str } class DeepSeekClient { +str api_key +str model +str base_url +complete(messages: List) str } class OllamaClient { +str base_url +str model +complete(messages: List) str } class PromptBuilder { +Dict~str, Tool~ tools +__init__(tools: Dict) +build_system_prompt(memory: Memory) str -_format_tools_description() str -_format_episodic_context(memory: Memory) str -_format_stm_context(memory: Memory) str } class Tool { <> +str name +str description +Callable func +Dict parameters } Agent --> LLMClient : uses Agent --> Memory : uses Agent --> PromptBuilder : uses Agent --> Tool : executes DeepSeekClient ..|> LLMClient OllamaClient ..|> LLMClient PromptBuilder --> Tool : formats %% =========================================== %% DOMAIN - MOVIES %% =========================================== class Movie { <> +ImdbId imdb_id +MovieTitle title +ReleaseYear release_year +Quality quality +FilePath file_path +FileSize file_size +int tmdb_id +datetime added_at } class MovieTitle { <> +str value +__init__(value: str) } class ReleaseYear { <> +int value +__init__(value: int) } class Quality { <> +str value +__init__(value: str) } class MovieRepository { <> +save(movie: Movie) void +find_by_imdb_id(imdb_id: ImdbId) Movie +find_all() List~Movie~ +delete(imdb_id: ImdbId) bool +exists(imdb_id: ImdbId) bool } Movie --> MovieTitle Movie --> ReleaseYear Movie --> Quality Movie --> ImdbId %% =========================================== %% DOMAIN - TV SHOWS %% =========================================== class TVShow { <> +ImdbId imdb_id +str title +int seasons_count +ShowStatus status +int tmdb_id +str first_air_date +datetime added_at } class ShowStatus { <> CONTINUING ENDED UNKNOWN +from_string(value: str)$ ShowStatus } class TVShowRepository { <> +save(show: TVShow) void +find_by_imdb_id(imdb_id: ImdbId) TVShow +find_all() List~TVShow~ +delete(imdb_id: ImdbId) bool } TVShow --> ShowStatus TVShow --> ImdbId %% =========================================== %% DOMAIN - SHARED %% =========================================== class ImdbId { <> +str value +__init__(value: str) +__str__() str } class FilePath { <> +str value +__init__(value: str) } class FileSize { <> +int bytes +__init__(bytes: int) +to_human_readable() str } %% =========================================== %% INFRASTRUCTURE - PERSISTENCE %% =========================================== class JsonMovieRepository { +Memory memory +__init__(memory: Memory) +save(movie: Movie) void +find_by_imdb_id(imdb_id: ImdbId) Movie +find_all() List~Movie~ +delete(imdb_id: ImdbId) bool } class JsonTVShowRepository { +Memory memory +__init__(memory: Memory) +save(show: TVShow) void +find_by_imdb_id(imdb_id: ImdbId) TVShow +find_all() List~TVShow~ +delete(imdb_id: ImdbId) bool } JsonMovieRepository ..|> MovieRepository JsonTVShowRepository ..|> TVShowRepository JsonMovieRepository --> Memory JsonTVShowRepository --> Memory %% =========================================== %% INFRASTRUCTURE - API CLIENTS %% =========================================== class TMDBClient { +str api_key +str base_url +search_movie(title: str) TMDBSearchResult +search_tv(title: str) TMDBSearchResult +get_external_ids(tmdb_id: int) Dict } class KnabenClient { +str base_url +search(query: str, limit: int) List~TorrentResult~ } class QBittorrentClient { +str host +str username +str password +add_torrent(magnet: str) bool +get_torrents() List } %% =========================================== %% INFRASTRUCTURE - FILESYSTEM %% =========================================== class FileManager { +Memory memory +__init__(memory: Memory) +set_folder_path(name: str, path: str) Dict +list_folder(type: str, path: str) Dict +move_file(source: str, dest: str) Dict } FileManager --> Memory %% =========================================== %% APPLICATION - USE CASES %% =========================================== class SearchMovieUseCase { +TMDBClient tmdb_client +execute(title: str) SearchMovieResponse } class SearchTorrentsUseCase { +KnabenClient knaben_client +execute(title: str, limit: int) SearchTorrentsResponse } class AddTorrentUseCase { +QBittorrentClient qbittorrent_client +execute(magnet: str) AddTorrentResponse } class SetFolderPathUseCase { +FileManager file_manager +execute(folder_name: str, path: str) SetFolderPathResponse } class ListFolderUseCase { +FileManager file_manager +execute(folder_type: str, path: str) ListFolderResponse } SearchMovieUseCase --> TMDBClient SearchTorrentsUseCase --> KnabenClient AddTorrentUseCase --> QBittorrentClient SetFolderPathUseCase --> FileManager ListFolderUseCase --> FileManager ``` ## Legend | Symbol | Meaning | |--------|---------| | `<>` | Domain entity with identity | | `<>` | Immutable value object | | `<>` | Abstract interface/protocol | | `<>` | Enumeration | | `<>` | Python dataclass | | `<>` | Python Protocol (structural typing) | | `*--` | Composition (owns) | | `-->` | Association (uses) | | `..\|>` | Implementation | ## Architecture Layers 1. **Domain Layer** - Business entities and rules (Movie, TVShow, ValueObjects) 2. **Application Layer** - Use cases orchestrating business logic 3. **Infrastructure Layer** - External services (APIs, filesystem, persistence) 4. **Agent Layer** - AI agent, LLM clients, tools, prompts