368 lines
9.5 KiB
Markdown
368 lines
9.5 KiB
Markdown
# 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 {
|
|
<<Protocol>>
|
|
+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 {
|
|
<<dataclass>>
|
|
+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 {
|
|
<<Entity>>
|
|
+ImdbId imdb_id
|
|
+MovieTitle title
|
|
+ReleaseYear release_year
|
|
+Quality quality
|
|
+FilePath file_path
|
|
+FileSize file_size
|
|
+int tmdb_id
|
|
+datetime added_at
|
|
}
|
|
|
|
class MovieTitle {
|
|
<<ValueObject>>
|
|
+str value
|
|
+__init__(value: str)
|
|
}
|
|
|
|
class ReleaseYear {
|
|
<<ValueObject>>
|
|
+int value
|
|
+__init__(value: int)
|
|
}
|
|
|
|
class Quality {
|
|
<<ValueObject>>
|
|
+str value
|
|
+__init__(value: str)
|
|
}
|
|
|
|
class MovieRepository {
|
|
<<Interface>>
|
|
+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 {
|
|
<<Entity>>
|
|
+ImdbId imdb_id
|
|
+str title
|
|
+int seasons_count
|
|
+ShowStatus status
|
|
+int tmdb_id
|
|
+str first_air_date
|
|
+datetime added_at
|
|
}
|
|
|
|
class ShowStatus {
|
|
<<Enum>>
|
|
CONTINUING
|
|
ENDED
|
|
UNKNOWN
|
|
+from_string(value: str)$ ShowStatus
|
|
}
|
|
|
|
class TVShowRepository {
|
|
<<Interface>>
|
|
+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 {
|
|
<<ValueObject>>
|
|
+str value
|
|
+__init__(value: str)
|
|
+__str__() str
|
|
}
|
|
|
|
class FilePath {
|
|
<<ValueObject>>
|
|
+str value
|
|
+__init__(value: str)
|
|
}
|
|
|
|
class FileSize {
|
|
<<ValueObject>>
|
|
+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 |
|
|
|--------|---------|
|
|
| `<<Entity>>` | Domain entity with identity |
|
|
| `<<ValueObject>>` | Immutable value object |
|
|
| `<<Interface>>` | Abstract interface/protocol |
|
|
| `<<Enum>>` | Enumeration |
|
|
| `<<dataclass>>` | Python dataclass |
|
|
| `<<Protocol>>` | 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
|