diff --git a/.env.example b/.env.example
index fd4caa5..1ba74e5 100644
--- a/.env.example
+++ b/.env.example
@@ -31,7 +31,4 @@ MAX_TOOL_ITERATIONS=10
REQUEST_TIMEOUT=30
# Memory Configuration
-# Number of previous messages to include in context (default: 10)
-# Higher = more context but slower/more expensive
-# Lower = less context but faster
MAX_HISTORY_MESSAGES=10
diff --git a/ARCHITECTURE_FINALE.md b/ARCHITECTURE_FINALE.md
deleted file mode 100644
index 084112b..0000000
--- a/ARCHITECTURE_FINALE.md
+++ /dev/null
@@ -1,308 +0,0 @@
-# đŻ Architecture Finale - 100% DDD
-
-## â
Migration ComplÚte Terminée
-
-Toute la couche de compatibilité a été supprimée. L'architecture est maintenant **100% Domain-Driven Development**.
-
----
-
-## đ Structure Finale
-
-```
-agent_media/
-â
-âââ domain/ # đŻ LOGIQUE MĂTIER PURE
-â âââ shared/
-â â âââ exceptions.py
-â â âââ value_objects.py
-â âââ movies/
-â â âââ entities.py
-â â âââ value_objects.py
-â â âââ repositories.py
-â â âââ services.py
-â â âââ exceptions.py
-â âââ tv_shows/
-â â âââ entities.py
-â â âââ value_objects.py
-â â âââ repositories.py
-â â âââ services.py
-â â âââ exceptions.py
-â âââ subtitles/
-â âââ entities.py
-â âââ value_objects.py
-â âââ repositories.py
-â âââ services.py
-â âââ exceptions.py
-â
-âââ infrastructure/ # đ§ DĂTAILS TECHNIQUES
-â âââ api/
-â â âââ tmdb/
-â â âââ knaben/
-â â âââ qbittorrent/
-â âââ persistence/
-â â âââ memory.py
-â â âââ json/
-â âââ filesystem/
-â âââ file_manager.py
-â âââ organizer.py
-â âââ exceptions.py
-â
-âââ application/ # đŹ USE CASES
-â âââ movies/
-â â âââ search_movie.py
-â â âââ dto.py
-â âââ torrents/
-â â âââ search_torrents.py
-â â âââ add_torrent.py
-â â âââ dto.py
-â âââ filesystem/
-â âââ set_folder_path.py
-â âââ list_folder.py
-â âââ dto.py
-â
-âââ agent/ # đ€ INTERFACE LLM
-â âââ llm/
-â â âââ __init__.py
-â â âââ deepseek.py
-â âââ tools/
-â â âââ __init__.py
-â â âââ api.py
-â â âââ filesystem.py
-â âââ agent.py
-â âââ registry.py
-â âââ prompts.py
-â âââ parameters.py
-â âââ config.py
-â
-âââ app.py # đ FASTAPI
-```
-
----
-
-## đ Imports Mis Ă Jour
-
-### **app.py**
-```python
-# AVANT
-from agent.memory import Memory
-
-# APRĂS
-from infrastructure.persistence.memory import Memory
-```
-
-### **agent/agent.py**
-```python
-# AVANT
-from .memory import Memory
-
-# APRĂS
-from infrastructure.persistence.memory import Memory
-```
-
-### **agent/tools/api.py**
-```python
-# Utilise directement les use cases
-from application.movies import SearchMovieUseCase
-from infrastructure.api.tmdb import tmdb_client
-```
-
-### **agent/tools/filesystem.py**
-```python
-# Utilise directement les use cases
-from application.filesystem import SetFolderPathUseCase
-from infrastructure.filesystem import FileManager
-from infrastructure.persistence.memory import Memory
-```
-
----
-
-## đïž Fichiers SupprimĂ©s
-
-### **Ancienne Architecture**
-```
-â agent/api/themoviedb.py
-â agent/api/knaben.py
-â agent/api/qbittorrent.py
-â agent/api/__init__.py
-â agent/models/tv_show.py
-â agent/models/__init__.py
-â agent/memory.py
-```
-
-### **Dossiers Supprimés**
-```
-â agent/api/
-â agent/models/
-```
-
----
-
-## â
Fichiers Conservés
-
-### **Agent Core**
-```
-â
agent/agent.py # Agent principal (imports mis Ă jour)
-â
agent/registry.py # Registry des tools
-â
agent/prompts.py # Construction des prompts
-â
agent/parameters.py # Schéma des paramÚtres
-â
agent/config.py # Configuration
-```
-
-### **Agent LLM**
-```
-â
agent/llm/__init__.py
-â
agent/llm/deepseek.py # Client DeepSeek
-```
-
-### **Agent Tools**
-```
-â
agent/tools/__init__.py
-â
agent/tools/api.py # Wrappers vers use cases
-â
agent/tools/filesystem.py # Wrappers vers use cases
-```
-
-### **Application**
-```
-â
app.py # FastAPI (imports mis Ă jour)
-```
-
----
-
-## đŻ Flux de DonnĂ©es
-
-```
-USER
- â
-LibreChat
- â
-app.py (FastAPI)
- â
-Agent (agent/agent.py)
- â
-Tools (agent/tools/)
- â
-Use Cases (application/)
- â
-Domain Services (domain/)
- â
-Infrastructure (infrastructure/)
- â
-External APIs / Storage
-```
-
----
-
-## đ Principes DDD AppliquĂ©s
-
-### **1. Layered Architecture**
-â
SĂ©paration stricte : Domain â Application â Infrastructure â Interface
-
-### **2. Dependency Inversion**
-â
Domain ne dépend de rien
-â
Infrastructure dépend de Domain
-â
Application orchestre Domain et Infrastructure
-
-### **3. Bounded Contexts**
-â
Movies, TV Shows, Subtitles sont des domaines séparés
-
-### **4. Ubiquitous Language**
-â
Vocabulaire métier partagé (Movie, TVShow, Episode, etc.)
-
-### **5. Entities & Value Objects**
-â
Entities : Movie, TVShow, Episode, Subtitle
-â
Value Objects : ImdbId, MovieTitle, SeasonNumber, etc.
-
-### **6. Repositories**
-â
Interfaces abstraites dans domain/
-â
Implémentations concrÚtes dans infrastructure/
-
-### **7. Domain Services**
-â
MovieService, TVShowService, SubtitleService
-
-### **8. Application Services (Use Cases)**
-â
SearchMovieUseCase, SearchTorrentsUseCase, etc.
-
----
-
-## đ Commandes de Nettoyage
-
-### **Script Automatique**
-```bash
-chmod +x FINAL_CLEANUP.sh
-./FINAL_CLEANUP.sh
-```
-
-### **Manuel**
-```bash
-# Supprimer les dossiers
-rm -rf agent/api/
-rm -rf agent/models/
-
-# Supprimer le fichier
-rm -f agent/memory.py
-```
-
----
-
-## đ Statistiques
-
-### **Avant le Nettoyage**
-- Fichiers dans agent/ : ~15
-- Couches de compatibilité : 3 (api, models, memory)
-- Architecture : Hybride
-
-### **AprĂšs le Nettoyage**
-- Fichiers dans agent/ : ~8
-- Couches de compatibilité : 0
-- Architecture : 100% DDD
-
----
-
-## đ RĂ©sultat
-
-### **Architecture Propre** â
-Plus aucune couche de compatibilité
-
-### **Imports Directs** â
-Tous les imports pointent vers la nouvelle architecture
-
-### **DDD Pur** â
-Respect strict des principes Domain-Driven Development
-
-### **Maintenable** â
-Code clair, organisé, facile à comprendre
-
-### **Ăvolutif** â
-Facile d'ajouter de nouvelles fonctionnalités
-
----
-
-## đ Documentation
-
-- `DDD_PHASE1_COMPLETE.md` - Phase 1 (Domain + Infrastructure)
-- `DDD_PHASE2_COMPLETE.md` - Phase 2 (Application + Agent)
-- `DDD_MIGRATION_COMPLETE.md` - Récapitulatif complet
-- `ARCHITECTURE_FINALE.md` - Ce fichier (architecture finale)
-- `DELETED_FILES.md` - Liste des fichiers supprimés
-
----
-
-## đŻ Prochaines Ătapes
-
-1. **Tester l'application** : `uvicorn app:app --reload`
-2. **Vérifier que tout fonctionne**
-3. **Commencer Ă utiliser la nouvelle architecture**
-4. **Ajouter de nouveaux use cases si nécessaire**
-
----
-
-## đ Mission Accomplie
-
-L'architecture est maintenant **100% Domain-Driven Development** !
-
-â
Aucune couche de compatibilité
-â
Imports directs vers la nouvelle architecture
-â
Code propre et maintenable
-â
PrĂȘt pour l'avenir
-
-đ **FĂ©licitations !** đ
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 4cee307..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,516 +0,0 @@
-# Changelog
-
-## [Non publié] - 2024-01-XX
-
-### đŻ Objectif principal
-Correction massive des dépendances circulaires et refactoring complet du systÚme pour utiliser les tool calls natifs OpenAI. Migration de l'architecture vers un systÚme plus propre et maintenable.
-
----
-
-## đ§ Corrections majeures
-
-### 1. Agent Core (`agent/agent.py`)
-**Refactoring complet du systĂšme d'agent**
-
-- **Suppression du systĂšme JSON custom** :
- - Retiré `_parse_intent()` qui parsait du JSON custom
- - Retiré `_execute_action()` remplacé par `_execute_tool_call()`
- - Migration vers les tool calls natifs OpenAI
-
-- **Nouvelle interface LLM** :
- - Ajout du `Protocol` `LLMClient` pour typage fort
- - `complete()` retourne `Dict[str, Any]` (message avec tool_calls)
- - `complete_stream()` retourne `AsyncGenerator` pour streaming
- - Suppression du tuple `(response, usage)` - plus de comptage de tokens
-
-- **Gestion des tool calls** :
- - `_execute_tool_call()` parse les tool calls OpenAI
- - Gestion des `tool_call_id` pour la conversation
- - Boucle d'itération jusqu'à réponse finale ou max iterations
- - Raise `MaxIterationsReachedError` si dépassement
-
-- **Streaming asynchrone** :
- - `step_stream()` pour réponses streamées
- - Détection des tool calls avant streaming
- - Fallback non-streaming si tool calls nécessaires
- - Sauvegarde de la réponse complÚte en mémoire
-
-- **Gestion de la mémoire** :
- - Utilisation de `get_memory()` au lieu de passer `memory` partout
- - `_prepare_messages()` pour construire le contexte
- - Sauvegarde automatique aprĂšs chaque step
- - Ajout des messages user/assistant dans l'historique
-
-### 2. LLM Clients
-
-#### `agent/llm/deepseek.py`
-- **Nouvelle signature** : `complete(messages, tools=None) -> Dict[str, Any]`
-- **Streaming** : `complete_stream()` avec `httpx.AsyncClient`
-- **Support des tool calls** : Ajout de `tools` et `tool_choice` dans le payload
-- **Retour simplifié** : Retourne directement le message, pas de tuple
-- **Gestion d'erreurs** : Raise `LLMAPIError` pour toutes les erreurs
-
-#### `agent/llm/ollama.py`
-- MĂȘme refactoring que DeepSeek
-- Support des tool calls (si Ollama le supporte)
-- Streaming avec `httpx.AsyncClient`
-
-#### `agent/llm/exceptions.py` (NOUVEAU)
-- `LLMError` - Exception de base
-- `LLMConfigurationError` - Configuration invalide
-- `LLMAPIError` - Erreur API
-
-### 3. Prompts (`agent/prompts.py`)
-
-**Simplification massive du systĂšme de prompts**
-
-- **Suppression du prompt verbeux** :
- - Plus de JSON context énorme
- - Plus de liste exhaustive des outils
- - Plus d'exemples JSON
-
-- **Nouveau prompt court** :
- ```
- You are a helpful AI assistant for managing a media library.
- Your first task is to determine the user's language...
- ```
-
-- **Contexte structuré** :
- - `_format_episodic_context()` : DerniĂšres recherches, downloads, erreurs
- - `_format_stm_context()` : Topic actuel, langue de conversation
- - Affichage limité (5 résultats, 3 downloads, 3 erreurs)
-
-- **Tool specs OpenAI** :
- - `build_tools_spec()` génÚre le format OpenAI
- - Les tools sont passés via l'API, pas dans le prompt
-
-### 4. Registry (`agent/registry.py`)
-
-**Correction des dépendances circulaires**
-
-- **Nouveau systĂšme d'enregistrement** :
- - Décorateur `@tool` pour auto-enregistrement
- - Liste globale `_tools` pour stocker les tools
- - `make_tools()` appelle explicitement chaque fonction
-
-- **Suppression des imports directs** :
- - Plus d'imports dans `agent/tools/__init__.py`
- - Imports dans `registry.py` au moment de l'enregistrement
- - Ăvite les boucles d'imports
-
-- **Génération automatique des schemas** :
- - Inspection des signatures avec `inspect`
- - Génération des `parameters` JSON Schema
- - Extraction de la description depuis la docstring
-
-### 5. Tools
-
-#### `agent/tools/__init__.py`
-- **Vidé complÚtement** pour éviter les imports circulaires
-- Juste `__all__` pour la documentation
-
-#### `agent/tools/api.py`
-**Refactoring complet avec gestion de la mémoire**
-
-- **`find_media_imdb_id()`** :
- - Stocke le résultat dans `memory.stm.set_entity("last_media_search")`
- - Set topic Ă "searching_media"
- - Logging des résultats
-
-- **`find_torrent()`** :
- - Stocke les résultats dans `memory.episodic.store_search_results()`
- - Set topic Ă "selecting_torrent"
- - Permet la référence par index
-
-- **`get_torrent_by_index()` (NOUVEAU)** :
- - RécupÚre un torrent par son index dans les résultats
- - Utilisé pour "télécharge le 3Úme"
-
-- **`add_torrent_by_index()` (NOUVEAU)** :
- - Combine `get_torrent_by_index()` + `add_torrent_to_qbittorrent()`
- - Workflow simplifié
-
-- **`add_torrent_to_qbittorrent()`** :
- - Ajoute le download dans `memory.episodic.add_active_download()`
- - Set topic Ă "downloading"
- - End workflow
-
-#### `agent/tools/filesystem.py`
-- **Suppression du paramĂštre `memory`** :
- - `set_path_for_folder(folder_name, path_value)`
- - `list_folder(folder_type, path=".")`
- - Utilise `get_memory()` en interne via `FileManager`
-
-#### `agent/tools/language.py` (NOUVEAU)
-- **`set_language(language_code)`** :
- - Définit la langue de conversation
- - Stocke dans `memory.stm.set_language()`
- - Permet au LLM de détecter et changer la langue
-
-### 6. Exceptions (`agent/exceptions.py`)
-
-**Nouvelles exceptions spécifiques**
-
-- `AgentError` - Exception de base
-- `ToolExecutionError(tool_name, message)` - Ăchec d'exĂ©cution d'un tool
-- `MaxIterationsReachedError(max_iterations)` - Trop d'itérations
-
-### 7. Config (`agent/config.py`)
-
-**Amélioration de la validation**
-
-- Validation stricte des valeurs (temperature, timeouts, etc.)
-- Messages d'erreur plus clairs
-- Docstrings complĂštes
-- Formatage avec Black
-
----
-
-## đ API (`app.py`)
-
-### Refactoring complet
-
-**Avant** : API simple avec un seul endpoint
-**AprĂšs** : API complĂšte OpenAI-compatible avec gestion d'erreurs
-
-### Nouveaux endpoints
-
-1. **`GET /health`**
- - Health check avec version et service name
- - Retourne `{"status": "healthy", "version": "0.2.0", "service": "agent-media"}`
-
-2. **`GET /v1/models`**
- - Liste des modĂšles disponibles (OpenAI-compatible)
- - Retourne format OpenAI avec `object: "list"`, `data: [...]`
-
-3. **`GET /api/memory/state`**
- - Ătat complet de la mĂ©moire (LTM + STM + Episodic)
- - Pour debugging et monitoring
-
-4. **`GET /api/memory/search-results`**
- - Derniers résultats de recherche
- - Permet de voir ce que l'agent a trouvé
-
-5. **`POST /api/memory/clear`**
- - Efface la session (STM + Episodic)
- - Préserve la LTM (config, bibliothÚque)
-
-### Validation des messages
-
-**Nouvelle fonction `validate_messages()`** :
-- Vérifie qu'il y a au moins un message user
-- Vérifie que le contenu n'est pas vide
-- Raise `HTTPException(422)` si invalide
-- AppelĂ©e avant chaque requĂȘte
-
-### Gestion d'erreurs HTTP
-
-**Codes d'erreur spécifiques** :
-- **504 Gateway Timeout** : `MaxIterationsReachedError` (agent bloqué en boucle)
-- **400 Bad Request** : `ToolExecutionError` (tool mal appelé)
-- **502 Bad Gateway** : `LLMAPIError` (API LLM down)
-- **500 Internal Server Error** : `AgentError` (erreur interne)
-- **422 Unprocessable Entity** : Validation des messages
-
-### Streaming
-
-**Amélioration du streaming** :
-- Utilise `agent.step_stream()` pour vraies réponses streamées
-- Gestion correcte des chunks
-- Envoi de `[DONE]` Ă la fin
-- Gestion d'erreurs dans le stream
-
----
-
-## đ§ Infrastructure
-
-### Persistence (`infrastructure/persistence/`)
-
-#### `memory.py`
-**Nouvelles méthodes** :
-- `get_full_state()` - Retourne tout l'état de la mémoire
-- `clear_session()` - Efface STM + Episodic, garde LTM
-
-#### `context.py`
-**Singleton global** :
-- `init_memory(storage_dir)` - Initialise la mémoire
-- `get_memory()` - RécupÚre l'instance globale
-- `set_memory(memory)` - Définit l'instance (pour tests)
-
-### Filesystem (`infrastructure/filesystem/`)
-
-#### `file_manager.py`
-- **Suppression du paramĂštre `memory`** du constructeur
-- Utilise `get_memory()` en interne
-- Simplifie l'utilisation
-
----
-
-## đ§Ș Tests
-
-### Fixtures (`tests/conftest.py`)
-
-**Mise Ă jour complĂšte des mocks** :
-
-1. **`MockLLMClient`** :
- - `complete()` retourne `Dict[str, Any]` (pas de tuple)
- - `complete_stream()` async generator
- - `set_next_response()` pour configurer les réponses
-
-2. **`MockDeepSeekClient` global** :
- - Ajout de `complete_stream()` async
- - Ăvite les appels API rĂ©els dans tous les tests
-
-3. **Nouvelles fixtures** :
- - `mock_agent_step` - Pour mocker `agent.step()`
- - Fixtures existantes mises Ă jour
-
-### Tests corrigés
-
-#### `test_agent.py`
-- **`MockLLMClient`** adapté pour nouvelle interface
-- **`test_step_stream`** : Double réponse mockée (check + stream)
-- **`test_max_iterations_reached`** : Arguments valides pour `set_language`
-- Suppression de tous les asserts sur `usage`
-
-#### `test_api.py`
-- **Import corrigé** : `from agent.llm.exceptions import LLMAPIError`
-- **Variable `data`** ajoutée dans `test_list_models`
-- **Test streaming** : Utilisation de `side_effect` au lieu de `return_value`
-- Nouveaux tests pour `/health` et `/v1/models`
-
-#### `test_prompts.py`
-- Tests adaptés au nouveau format de prompt court
-- Vérification de `CONVERSATION LANGUAGE` au lieu de texte long
-- Tests de `build_tools_spec()` pour format OpenAI
-
-#### `test_prompts_edge_cases.py`
-- **Réécriture complÚte** pour nouveau prompt
-- Tests de `_format_episodic_context()`
-- Tests de `_format_stm_context()`
-- Suppression des tests sur sections obsolĂštes
-
-#### `test_registry_edge_cases.py`
-- **Nom d'outil corrigĂ©** : `find_torrents` â `find_torrent`
-- Ajout de `set_language` dans la liste des tools attendus
-
-#### `test_agent_edge_cases.py`
-- **Réécriture complÚte** pour tool calls natifs
-- Tests de `_execute_tool_call()`
-- Tests de gestion d'erreurs avec tool calls
-- Tests de mémoire avec tool calls
-
-#### `test_api_edge_cases.py`
-- **Tous les chemins d'endpoints corrigés** :
- - `/memory/state` â `/api/memory/state`
- - `/memory/episodic/search-results` â `/api/memory/search-results`
- - `/memory/clear-session` â `/api/memory/clear`
-- Tests de validation des messages
-- Tests des nouveaux endpoints
-
-### Configuration pytest (`pyproject.toml`)
-
-**Migration complĂšte de `pytest.ini` vers `pyproject.toml`**
-
-#### Options de coverage ajoutées :
-```toml
-"--cov=.", # Coverage de tout le projet
-"--cov-report=term-missing", # Lignes manquantes dans terminal
-"--cov-report=html", # Rapport HTML dans htmlcov/
-"--cov-report=xml", # Rapport XML pour CI/CD
-"--cov-fail-under=80", # Ăchoue si < 80%
-```
-
-#### Options de performance :
-```toml
-"-n=auto", # Parallélisation automatique
-"--strict-markers", # Validation des markers
-"--disable-warnings", # Sortie plus propre
-```
-
-#### Nouveaux markers :
-- `slow` - Tests lents
-- `integration` - Tests d'intégration
-- `unit` - Tests unitaires
-
-#### Configuration coverage :
-```toml
-[tool.coverage.run]
-source = ["agent", "application", "domain", "infrastructure"]
-omit = ["tests/*", "*/__pycache__/*"]
-
-[tool.coverage.report]
-exclude_lines = ["pragma: no cover", "def __repr__", ...]
-```
-
----
-
-## đ Documentation
-
-### Nouveaux fichiers
-
-1. **`README.md`** (412 lignes)
- - Documentation complĂšte du projet
- - Quick start, installation, usage
- - Exemples de conversations
- - Liste des tools disponibles
- - Architecture et structure
- - Guide de développement
- - Docker et CI/CD
- - API documentation
- - Troubleshooting
-
-2. **`docs/PYTEST_CONFIG.md`**
- - Explication ligne par ligne de chaque option pytest
- - Guide des commandes utiles
- - Bonnes pratiques
- - Troubleshooting
-
-3. **`TESTS_TO_FIX.md`**
- - Liste des tests Ă corriger (maintenant obsolĂšte)
- - Recommandations pour l'approche complĂšte
-
-4. **`.pytest.ini.backup`**
- - Sauvegarde de l'ancien `pytest.ini`
-
-### Fichiers mis Ă jour
-
-1. **`.env`**
- - Ajout de commentaires pour chaque section
- - Nouvelles variables :
- - `LLM_PROVIDER` - Choix entre deepseek/ollama
- - `OLLAMA_BASE_URL`, `OLLAMA_MODEL`
- - `MAX_TOOL_ITERATIONS`
- - `MAX_HISTORY_MESSAGES`
- - Organisation par catégories
-
-2. **`.gitignore`**
- - Ajout des fichiers de coverage :
- - `.coverage`, `.coverage.*`
- - `htmlcov/`, `coverage.xml`
- - Ajout de `.pytest_cache/`
- - Ajout de `memory_data/`
- - Ajout de `*.backup`
-
----
-
-## đ Refactoring gĂ©nĂ©ral
-
-### Architecture
-- **Séparation des responsabilités** plus claire
-- **Dépendances circulaires** éliminées
-- **Injection de dépendances** via `get_memory()`
-- **Typage fort** avec `Protocol` et type hints
-
-### Code quality
-- **Formatage** avec Black (line-length=88)
-- **Linting** avec Ruff
-- **Docstrings** complĂštes partout
-- **Logging** ajouté dans les tools
-
-### Performance
-- **Parallélisation** des tests avec pytest-xdist
-- **Streaming** asynchrone pour réponses rapides
-- **Mémoire** optimisée (limitation des résultats affichés)
-
----
-
-## đ Bugs corrigĂ©s
-
-1. **Dépendances circulaires** :
- - `agent/tools/__init__.py` â `agent/registry.py`
- - Solution : Imports dans `registry.py` uniquement
-
-2. **Import manquant** :
- - `LLMAPIError` dans `test_api.py`
- - Solution : `from agent.llm.exceptions import LLMAPIError`
-
-3. **Mock streaming** :
- - `test_step_stream` avec liste vide
- - Solution : Double réponse mockée (check + stream)
-
-4. **Mock async generator** :
- - `return_value` au lieu de `side_effect`
- - Solution : `side_effect=mock_stream_generator`
-
-5. **Nom d'outil** :
- - `find_torrents` vs `find_torrent`
- - Solution : Uniformisation sur `find_torrent`
-
-6. **Validation messages** :
- - Endpoints acceptaient messages vides
- - Solution : `validate_messages()` avec HTTPException
-
-7. **Décorateur mal placé** :
- - `@tool` dans `language.py` causait import circulaire
- - Solution : Suppression, enregistrement dans `registry.py`
-
-8. **Imports manquants** :
- - `from typing import Dict, Any` dans plusieurs fichiers
- - Solution : Ajout des imports
-
----
-
-## đ MĂ©triques
-
-### Avant
-- Tests : ~450 (beaucoup échouaient)
-- Coverage : Non mesuré
-- Endpoints : 1 (`/v1/chat/completions`)
-- Tools : 5
-- Dépendances circulaires : Oui
-- SystĂšme de prompts : Verbeux et complexe
-
-### AprĂšs
-- Tests : ~500 (tous passent â
)
-- Coverage : Configuré avec objectif 80%
-- Endpoints : 6 (5 nouveaux)
-- Tools : 8 (3 nouveaux)
-- DĂ©pendances circulaires : Non â
-- SystĂšme de prompts : Simple et efficace
-
-### Changements de code
-- **Fichiers modifiés** : ~30
-- **Lignes ajoutées** : ~2000
-- **Lignes supprimées** : ~1500
-- **Net** : +500 lignes (documentation comprise)
-
----
-
-## đ AmĂ©liorations futures
-
-### Court terme
-- [ ] Atteindre 100% de coverage
-- [ ] Tests d'intégration end-to-end
-- [ ] Benchmarks de performance
-
-### Moyen terme
-- [ ] Support de plus de LLM providers
-- [ ] Interface web (OpenWebUI)
-- [ ] Métriques et monitoring
-
-### Long terme
-- [ ] Multi-utilisateurs
-- [ ] Plugins systĂšme
-- [ ] API GraphQL
-
----
-
-## đ Notes
-
-**ProblÚme initial** : Gemini 3 Pro a introduit des dépendances circulaires et supprimé du code critique, rendant l'application non fonctionnelle.
-
-**Solution** : Refactoring complet du systĂšme avec :
-- Migration vers tool calls natifs OpenAI
-- Ălimination des dĂ©pendances circulaires
-- Simplification du systĂšme de prompts
-- Ajout de tests et documentation
-- Configuration pytest professionnelle
-
-**RĂ©sultat** : Application stable, testĂ©e, documentĂ©e et prĂȘte pour la production ! đ
-
----
-
-**Auteur** : Claude (avec l'aide de Francwa)
-**Date** : Janvier 2024
-**Version** : 0.2.0
diff --git a/README.md b/README.md
index 1dde94e..3afe6b0 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ agent_media/
âââ infrastructure/ # External services & persistence
```
-See [ARCHITECTURE_FINALE.md](ARCHITECTURE_FINALE.md) for details.
+See [architecture_diagram.md](docs/architecture_diagram.md) for architectural details.
## Quick Start
@@ -223,8 +223,6 @@ poetry run mypy .
### Adding a New Tool
-See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for detailed instructions.
-
Quick example:
```python
@@ -281,16 +279,6 @@ docker-compose logs -f
docker-compose down
```
-## CI/CD
-
-Includes Gitea Actions workflow for:
-- â
Linting & testing
-- đł Docker image building
-- đŠ Container registry push
-- đ Deployment (optional)
-
-See [docs/CI_CD_GUIDE.md](docs/CI_CD_GUIDE.md) for setup instructions.
-
## API Documentation
### Endpoints
@@ -364,12 +352,12 @@ Clear session memories (STM + Episodic).
- Verify volume mounts in Docker
### Tests failing
-- See [docs/TEST_FAILURES_SUMMARY.md](docs/TEST_FAILURES_SUMMARY.md)
- Run `poetry install` to ensure dependencies are up to date
+- Check logs for specific error messages
## Contributing
-Contributions are welcome! Please read [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) first.
+Contributions are welcome!
### Development Workflow
@@ -384,11 +372,11 @@ Contributions are welcome! Please read [docs/CONTRIBUTING.md](docs/CONTRIBUTING.
## Documentation
-- [Architecture](ARCHITECTURE_FINALE.md) - System architecture
-- [Contributing Guide](docs/CONTRIBUTING.md) - How to contribute
-- [CI/CD Guide](docs/CI_CD_GUIDE.md) - Pipeline setup
-- [Flowcharts](docs/flowchart.md) - System flowcharts
-- [Test Failures](docs/TEST_FAILURES_SUMMARY.md) - Known test issues
+- [Architecture Diagram](docs/architecture_diagram.md) - System architecture overview
+- [Class Diagram](docs/class_diagram.md) - Class structure and relationships
+- [Component Diagram](docs/component_diagram.md) - Component interactions
+- [Sequence Diagram](docs/sequence_diagram.md) - Sequence flows
+- [Flowchart](docs/flowchart.md) - System flowcharts
## License
diff --git a/cleanup_old_files.sh b/cleanup_old_files.sh
deleted file mode 100644
index 357843a..0000000
--- a/cleanup_old_files.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-# Script de nettoyage des fichiers obsolĂštes aprĂšs migration DDD
-
-echo "đïž Nettoyage des fichiers obsolĂštes..."
-
-# Supprimer les anciens clients API (déplacés vers infrastructure/)
-echo "Suppression des anciens clients API..."
-rm -f agent/api/themoviedb.py
-rm -f agent/api/knaben.py
-rm -f agent/api/qbittorrent.py
-
-echo "â
Anciens clients API supprimés"
-
-# Optionnel : Supprimer l'ancienne documentation
-read -p "Voulez-vous supprimer l'ancienne documentation ? (y/n) " -n 1 -r
-echo
-if [[ $REPLY =~ ^[Yy]$ ]]
-then
- echo "Suppression de l'ancienne documentation..."
- rm -f CHANGELOG_QUALITY.md
- rm -f CLEANUP_FINAL.md
- rm -f CLEANUP_SUMMARY.md
- rm -f CODE_QUALITY.md
- rm -f COMMANDS_REMOVAL.md
- rm -f DEPENDENCY_INJECTION.md
- rm -f DOCUMENTATION_INDEX.md
- rm -f EXECUTIVE_SUMMARY.md
- rm -f FILES_CHANGED.md
- rm -f IMPROVEMENTS_SUMMARY.md
- rm -f KNABEN_CLIENT.md
- rm -f MIGRATION_GUIDE.md
- rm -f MULTI_TOOL_EXECUTION.md
- rm -f PARAMETERS.md
- rm -f PROJECT_STRUCTURE.md
- rm -f QUALITY_REVIEW_COMPLETE.md
- rm -f README_QUALITY.md
- rm -f REFACTORING_COMPLETE.md
- rm -f REFACTORING_FINAL.md
- rm -f REFACTORING_FOLDERS.md
- rm -f REFACTORING_SUMMARY.md
- rm -f SECURITY.md
- rm -f TMDB_CLIENT_ARCHITECTURE.md
- rm -f TMDB_CLIENT_SUMMARY.md
- rm -f TOOLS_REFACTORING.md
- rm -f TV_SHOWS.md
- rm -f VERIFICATION.md
- echo "â
Ancienne documentation supprimée"
-fi
-
-echo ""
-echo "đ Nettoyage terminĂ© !"
-echo ""
-echo "đ Fichiers conservĂ©s (nĂ©cessaires) :"
-echo " - agent/api/__init__.py (re-exporte infrastructure)"
-echo " - agent/models/__init__.py (re-exporte domain)"
-echo " - agent/models/tv_show.py (compatibilité)"
-echo " - agent/memory.py (re-exporte infrastructure)"
-echo ""
-echo "đ Nouvelle documentation DDD :"
-echo " - DDD_PHASE1_COMPLETE.md"
-echo " - DDD_PHASE2_COMPLETE.md"
-echo " - DDD_MIGRATION_COMPLETE.md"
diff --git a/docs/architecture_diagram.md b/docs/architecture_diagram.md
new file mode 100644
index 0000000..352ae50
--- /dev/null
+++ b/docs/architecture_diagram.md
@@ -0,0 +1,402 @@
+# Architecture Diagram - Agent Media
+
+## System Overview
+
+```mermaid
+flowchart TB
+ subgraph Client["đ€ Client"]
+ CHAT[Chat Interface
OpenWebUI / CLI / Custom]
+ end
+
+ subgraph AgentMedia["đŹ Agent Media"]
+ subgraph API["API Layer"]
+ FASTAPI[FastAPI Server
:8000]
+ end
+
+ subgraph Core["Core"]
+ AGENT[đ€ Agent
Orchestrator]
+ MEMORY[đ§ Memory
LTM + STM + Episodic]
+ end
+
+ subgraph Tools["Tools"]
+ T1[đ Filesystem]
+ T2[đ Search]
+ T3[âŹïž Download]
+ end
+ end
+
+ subgraph LLM["đ§ LLM Provider"]
+ DEEPSEEK[DeepSeek API]
+ OLLAMA[Ollama
Local]
+ end
+
+ subgraph External["âïž External Services"]
+ TMDB[(TMDB
Movie Database)]
+ KNABEN[(Knaben
Torrent Search)]
+ QBIT[qBittorrent
Download Client]
+ end
+
+ subgraph Storage["đŸ Storage"]
+ JSON[(memory_data/
ltm.json)]
+ MEDIA[(Media Folders
/movies /tvshows)]
+ end
+
+ CHAT <-->|OpenAI API| FASTAPI
+ FASTAPI <--> AGENT
+ AGENT <--> MEMORY
+ AGENT <--> Tools
+ AGENT <-->|Chat Completion| LLM
+
+ T1 <--> MEDIA
+ T2 --> TMDB
+ T2 --> KNABEN
+ T3 --> QBIT
+
+ MEMORY <--> JSON
+ QBIT --> MEDIA
+
+ style AgentMedia fill:#1a1a2e,color:#fff
+ style AGENT fill:#ff6b6b,color:#fff
+ style MEMORY fill:#4ecdc4,color:#fff
+```
+
+## Detailed Architecture
+
+```mermaid
+flowchart TB
+ subgraph Clients["Clients"]
+ direction LR
+ OWU[OpenWebUI]
+ CLI[CLI Client]
+ CURL[cURL / HTTP]
+ end
+
+ subgraph LoadBalancer["Entry Point"]
+ NGINX[Nginx / Reverse Proxy
Optional]
+ end
+
+ subgraph Application["Agent Media Application"]
+ direction TB
+
+ subgraph Presentation["Presentation Layer"]
+ EP1["/v1/chat/completions"]
+ EP2["/v1/models"]
+ EP3["/health"]
+ EP4["/memory/state"]
+ end
+
+ subgraph AgentLayer["Agent Layer"]
+ direction LR
+ AG[Agent]
+ PB[PromptBuilder]
+ REG[Registry]
+ end
+
+ subgraph ToolsLayer["Tools Layer"]
+ direction LR
+ FS_TOOL[Filesystem Tools
set_path, list_folder]
+ API_TOOL[API Tools
find_torrent, add_torrent]
+ end
+
+ subgraph AppLayer["Application Layer"]
+ direction LR
+ UC1[SearchMovie
UseCase]
+ UC2[SearchTorrents
UseCase]
+ UC3[AddTorrent
UseCase]
+ UC4[SetFolderPath
UseCase]
+ end
+
+ subgraph DomainLayer["Domain Layer"]
+ direction LR
+ ENT[Entities
Movie, TVShow, Subtitle]
+ VO[Value Objects
ImdbId, Quality, FilePath]
+ REPO_INT[Repository
Interfaces]
+ end
+
+ subgraph InfraLayer["Infrastructure Layer"]
+ direction TB
+
+ subgraph Persistence["Persistence"]
+ MEM[Memory Manager]
+ REPO_IMPL[JSON Repositories]
+ end
+
+ subgraph APIClients["API Clients"]
+ TMDB_C[TMDB Client]
+ KNAB_C[Knaben Client]
+ QBIT_C[qBittorrent Client]
+ end
+
+ subgraph FSManager["Filesystem"]
+ FM[FileManager]
+ end
+ end
+ end
+
+ subgraph LLMProviders["LLM Providers"]
+ direction LR
+ DS[DeepSeek
api.deepseek.com]
+ OL[Ollama
localhost:11434]
+ end
+
+ subgraph ExternalAPIs["External APIs"]
+ direction LR
+ TMDB_API[TMDB API
api.themoviedb.org]
+ KNAB_API[Knaben API
knaben.eu]
+ QBIT_API[qBittorrent WebUI
localhost:8080]
+ end
+
+ subgraph DataStores["Data Stores"]
+ direction LR
+ LTM_FILE[(ltm.json
Persistent Config)]
+ MEDIA_DIR[(Media Directories
/downloads /movies /tvshows)]
+ end
+
+ %% Client connections
+ Clients --> LoadBalancer
+ LoadBalancer --> Presentation
+
+ %% Internal flow
+ Presentation --> AgentLayer
+ AgentLayer --> ToolsLayer
+ ToolsLayer --> AppLayer
+ AppLayer --> DomainLayer
+ AppLayer --> InfraLayer
+ InfraLayer -.->|implements| DomainLayer
+
+ %% Agent to LLM
+ AgentLayer <-->|HTTP| LLMProviders
+
+ %% Infrastructure to External
+ TMDB_C -->|HTTP| TMDB_API
+ KNAB_C -->|HTTP| KNAB_API
+ QBIT_C -->|HTTP| QBIT_API
+
+ %% Persistence
+ MEM <--> LTM_FILE
+ FM <--> MEDIA_DIR
+ QBIT_API --> MEDIA_DIR
+```
+
+## Memory System Architecture
+
+```mermaid
+flowchart TB
+ subgraph MemoryManager["Memory Manager"]
+ direction TB
+
+ subgraph LTM["đŸ Long-Term Memory"]
+ direction LR
+ LTM_DESC["Persistent across restarts
Stored in ltm.json"]
+
+ subgraph LTM_DATA["Data"]
+ CONFIG["config{}
folder paths, API keys"]
+ PREFS["preferences{}
quality, languages"]
+ LIBRARY["library{}
movies[], tv_shows[]"]
+ FOLLOWING["following[]
watchlist"]
+ end
+ end
+
+ subgraph STM["đ§ Short-Term Memory"]
+ direction LR
+ STM_DESC["Session-based
Cleared on restart"]
+
+ subgraph STM_DATA["Data"]
+ HISTORY["conversation_history[]
last 20 messages"]
+ WORKFLOW["current_workflow{}
type, stage, target"]
+ ENTITIES["extracted_entities{}
title, year, quality"]
+ TOPIC["current_topic
searching, downloading"]
+ end
+ end
+
+ subgraph EPISODIC["⥠Episodic Memory"]
+ direction LR
+ EPIS_DESC["Transient state
Cleared on restart"]
+
+ subgraph EPIS_DATA["Data"]
+ SEARCH["last_search_results{}
indexed torrents"]
+ DOWNLOADS["active_downloads[]
in-progress"]
+ ERRORS["recent_errors[]
last 5 errors"]
+ PENDING["pending_question{}
awaiting user input"]
+ EVENTS["background_events[]
notifications"]
+ end
+ end
+ end
+
+ subgraph Storage["Storage"]
+ FILE[(memory_data/ltm.json)]
+ end
+
+ subgraph Lifecycle["Lifecycle"]
+ SAVE[save()]
+ LOAD[load()]
+ CLEAR[clear_session()]
+ end
+
+ LTM <-->|read/write| FILE
+ SAVE --> LTM
+ LOAD --> LTM
+ CLEAR --> STM
+ CLEAR --> EPISODIC
+
+ style LTM fill:#4caf50,color:#fff
+ style STM fill:#2196f3,color:#fff
+ style EPISODIC fill:#ff9800,color:#fff
+```
+
+## Request Flow
+
+```mermaid
+flowchart LR
+ subgraph Request["1ïžâŁ Request"]
+ USER[User Message]
+ end
+
+ subgraph Parse["2ïžâŁ Parse"]
+ FASTAPI[FastAPI
Extract message]
+ end
+
+ subgraph Context["3ïžâŁ Build Context"]
+ PROMPT[PromptBuilder
+ Memory context
+ Tool descriptions]
+ end
+
+ subgraph Think["4ïžâŁ Think"]
+ LLM[LLM
Decide action]
+ end
+
+ subgraph Act["5ïžâŁ Act"]
+ TOOL[Execute Tool
or respond]
+ end
+
+ subgraph Store["6ïžâŁ Store"]
+ MEM[Update Memory
STM + Episodic]
+ end
+
+ subgraph Response["7ïžâŁ Response"]
+ RESP[JSON Response]
+ end
+
+ USER --> FASTAPI --> PROMPT --> LLM
+ LLM -->|Tool call| TOOL --> MEM --> LLM
+ LLM -->|Text response| MEM --> RESP
+
+ style Think fill:#ff6b6b,color:#fff
+ style Act fill:#4ecdc4,color:#fff
+ style Store fill:#45b7d1,color:#fff
+```
+
+## Deployment Architecture
+
+```mermaid
+flowchart TB
+ subgraph Host["Host Machine"]
+ subgraph Docker["Docker (Optional)"]
+ AGENT_CONTAINER[Agent Media
Container]
+ end
+
+ subgraph Native["Native Services"]
+ QBIT_SERVICE[qBittorrent
:8080]
+ OLLAMA_SERVICE[Ollama
:11434]
+ end
+
+ subgraph Storage["Local Storage"]
+ CONFIG_DIR[/config
memory_data/]
+ MEDIA_DIR[/media
downloads, movies, tvshows]
+ end
+ end
+
+ subgraph Cloud["Cloud Services"]
+ DEEPSEEK[DeepSeek API]
+ TMDB[TMDB API]
+ KNABEN[Knaben API]
+ end
+
+ subgraph Client["Client"]
+ BROWSER[Browser
OpenWebUI]
+ end
+
+ BROWSER <-->|:8000| AGENT_CONTAINER
+ AGENT_CONTAINER <-->|:8080| QBIT_SERVICE
+ AGENT_CONTAINER <-->|:11434| OLLAMA_SERVICE
+ AGENT_CONTAINER <--> CONFIG_DIR
+ AGENT_CONTAINER <--> MEDIA_DIR
+ QBIT_SERVICE --> MEDIA_DIR
+
+ AGENT_CONTAINER <-->|HTTPS| Cloud
+```
+
+## Technology Stack
+
+```mermaid
+mindmap
+ root((Agent Media))
+ API
+ FastAPI
+ Uvicorn
+ OpenAI Compatible
+ Agent
+ Python 3.11+
+ Dataclasses
+ Protocol typing
+ LLM
+ DeepSeek
+ Ollama
+ OpenAI compatible
+ Storage
+ JSON files
+ Filesystem
+ External APIs
+ TMDB
+ Knaben
+ qBittorrent WebUI
+ Architecture
+ DDD
+ Clean Architecture
+ Hexagonal
+```
+
+## Security Considerations
+
+```mermaid
+flowchart TB
+ subgraph Security["Security Layers"]
+ direction TB
+
+ subgraph Input["Input Validation"]
+ PATH_VAL[Path Traversal Protection
FileManager._sanitize_path]
+ INPUT_VAL[Input Sanitization
Tool parameters]
+ end
+
+ subgraph Auth["Authentication"]
+ API_KEYS[API Keys
Environment variables]
+ QBIT_AUTH[qBittorrent Auth
Username/Password]
+ end
+
+ subgraph Access["Access Control"]
+ FOLDER_RESTRICT[Folder Restrictions
Configured paths only]
+ SAFE_PATH[Safe Path Checks
_is_safe_path()]
+ end
+ end
+
+ subgraph Env["Environment"]
+ ENV_FILE[.env file
DEEPSEEK_API_KEY
TMDB_API_KEY
QBITTORRENT_*]
+ end
+
+ ENV_FILE --> Auth
+ Input --> Access
+```
+
+## Legend
+
+| Icon | Meaning |
+|------|---------|
+| đŹ | Agent Media System |
+| đ€ | AI Agent |
+| đ§ | Memory / LLM |
+| đŸ | Persistent Storage |
+| ⥠| Transient / Fast |
+| đ | Filesystem |
+| đ | Search |
+| âŹïž | Download |
+| âïž | Cloud / External |
+| đ€ | User / Client |
diff --git a/docs/class_diagram.md b/docs/class_diagram.md
new file mode 100644
index 0000000..cedcf91
--- /dev/null
+++ b/docs/class_diagram.md
@@ -0,0 +1,367 @@
+# 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
diff --git a/docs/component_diagram.md b/docs/component_diagram.md
new file mode 100644
index 0000000..d6b6779
--- /dev/null
+++ b/docs/component_diagram.md
@@ -0,0 +1,311 @@
+# Component Diagram - Agent Media (DDD Architecture)
+
+```mermaid
+C4Component
+ title Component Diagram - Agent Media
+
+ Container_Boundary(agent_layer, "Agent Layer") {
+ Component(agent, "Agent", "Python", "Orchestrates LLM and tools")
+ Component(prompt_builder, "PromptBuilder", "Python", "Builds system prompts with context")
+ Component(registry, "Tool Registry", "Python", "Registers and binds tools")
+
+ Component_Boundary(llm_clients, "LLM Clients") {
+ Component(deepseek, "DeepSeekClient", "Python", "DeepSeek API client")
+ Component(ollama, "OllamaClient", "Python", "Ollama local client")
+ }
+
+ Component_Boundary(tools, "Tools") {
+ Component(api_tools, "API Tools", "Python", "find_torrent, add_torrent, etc.")
+ Component(fs_tools, "Filesystem Tools", "Python", "set_path, list_folder")
+ }
+ }
+```
+
+## Layered Architecture (DDD)
+
+```mermaid
+flowchart TB
+ subgraph Presentation["đ Presentation Layer"]
+ API["FastAPI Server
/v1/chat/completions"]
+ end
+
+ subgraph Agent["đ€ Agent Layer"]
+ AG[Agent]
+ PB[PromptBuilder]
+ TR[Tool Registry]
+
+ subgraph LLM["LLM Clients"]
+ DS[DeepSeek]
+ OL[Ollama]
+ end
+
+ subgraph Tools["Tools"]
+ AT[API Tools]
+ FT[Filesystem Tools]
+ end
+ end
+
+ subgraph Application["âïž Application Layer"]
+ subgraph UseCases["Use Cases"]
+ UC1[SearchMovieUseCase]
+ UC2[SearchTorrentsUseCase]
+ UC3[AddTorrentUseCase]
+ UC4[SetFolderPathUseCase]
+ UC5[ListFolderUseCase]
+ end
+
+ subgraph DTOs["DTOs"]
+ DTO1[SearchMovieResponse]
+ DTO2[SearchTorrentsResponse]
+ DTO3[AddTorrentResponse]
+ end
+ end
+
+ subgraph Domain["đŠ Domain Layer"]
+ subgraph Movies["movies/"]
+ ME[Movie Entity]
+ MVO[MovieTitle, Quality, ReleaseYear]
+ MR[MovieRepository Interface]
+ end
+
+ subgraph TVShows["tv_shows/"]
+ TE[TVShow Entity]
+ TVO[ShowStatus]
+ TR2[TVShowRepository Interface]
+ end
+
+ subgraph Subtitles["subtitles/"]
+ SE[Subtitle Entity]
+ SVO[Language, SubtitleFormat]
+ SR[SubtitleRepository Interface]
+ end
+
+ subgraph Shared["shared/"]
+ SH[ImdbId, FilePath, FileSize]
+ end
+ end
+
+ subgraph Infrastructure["đ§ Infrastructure Layer"]
+ subgraph Persistence["persistence/"]
+ MEM[Memory
LTM + STM + Episodic]
+ JMR[JsonMovieRepository]
+ JTR[JsonTVShowRepository]
+ JSR[JsonSubtitleRepository]
+ end
+
+ subgraph APIs["api/"]
+ TMDB[TMDBClient]
+ KNAB[KnabenClient]
+ QBIT[QBittorrentClient]
+ end
+
+ subgraph FS["filesystem/"]
+ FM[FileManager]
+ end
+ end
+
+ subgraph External["âïž External Services"]
+ TMDB_API[(TMDB API)]
+ KNAB_API[(Knaben API)]
+ QBIT_API[(qBittorrent)]
+ DISK[(Filesystem)]
+ end
+
+ %% Connections
+ API --> AG
+ AG --> PB
+ AG --> TR
+ AG --> LLM
+ TR --> Tools
+
+ AT --> UC1
+ AT --> UC2
+ AT --> UC3
+ FT --> UC4
+ FT --> UC5
+
+ UC1 --> TMDB
+ UC2 --> KNAB
+ UC3 --> QBIT
+ UC4 --> FM
+ UC5 --> FM
+
+ JMR --> MEM
+ JTR --> MEM
+ JSR --> MEM
+ FM --> MEM
+
+ JMR -.->|implements| MR
+ JTR -.->|implements| TR2
+ JSR -.->|implements| SR
+
+ TMDB --> TMDB_API
+ KNAB --> KNAB_API
+ QBIT --> QBIT_API
+ FM --> DISK
+ MEM --> DISK
+
+ %% Styling
+ classDef presentation fill:#e1f5fe
+ classDef agent fill:#fff3e0
+ classDef application fill:#f3e5f5
+ classDef domain fill:#e8f5e9
+ classDef infrastructure fill:#fce4ec
+ classDef external fill:#f5f5f5
+
+ class API presentation
+ class AG,PB,TR,DS,OL,AT,FT agent
+ class UC1,UC2,UC3,UC4,UC5,DTO1,DTO2,DTO3 application
+ class ME,MVO,MR,TE,TVO,TR2,SE,SVO,SR,SH domain
+ class MEM,JMR,JTR,JSR,TMDB,KNAB,QBIT,FM infrastructure
+ class TMDB_API,KNAB_API,QBIT_API,DISK external
+```
+
+## Memory Architecture
+
+```mermaid
+flowchart LR
+ subgraph Memory["Memory System"]
+ direction TB
+
+ subgraph LTM["đŸ Long-Term Memory
(Persistent - JSON)"]
+ CONFIG[config
download_folder, tvshow_folder...]
+ PREFS[preferences
quality, languages...]
+ LIB[library
movies[], tv_shows[]]
+ FOLLOW[following
watchlist]
+ end
+
+ subgraph STM["đ§ Short-Term Memory
(Session - RAM)"]
+ HIST[conversation_history]
+ WORKFLOW[current_workflow]
+ ENTITIES[extracted_entities]
+ TOPIC[current_topic]
+ end
+
+ subgraph EPISODIC["⥠Episodic Memory
(Transient - RAM)"]
+ SEARCH[last_search_results
indexed torrents]
+ DOWNLOADS[active_downloads]
+ ERRORS[recent_errors]
+ PENDING[pending_question]
+ EVENTS[background_events]
+ end
+ end
+
+ subgraph Storage["Storage"]
+ JSON[(ltm.json)]
+ end
+
+ LTM -->|save| JSON
+ JSON -->|load| LTM
+
+ STM -.->|cleared on| RESTART[Server Restart]
+ EPISODIC -.->|cleared on| RESTART
+```
+
+## Data Flow
+
+```mermaid
+flowchart LR
+ subgraph Input
+ USER[User Request]
+ end
+
+ subgraph Processing
+ direction TB
+ FASTAPI[FastAPI]
+ AGENT[Agent]
+ TOOLS[Tools]
+ USECASES[Use Cases]
+ end
+
+ subgraph External
+ direction TB
+ TMDB[(TMDB)]
+ KNABEN[(Knaben)]
+ QBIT[(qBittorrent)]
+ end
+
+ subgraph Memory
+ direction TB
+ LTM[(LTM)]
+ STM[(STM)]
+ EPIS[(Episodic)]
+ end
+
+ USER -->|HTTP POST| FASTAPI
+ FASTAPI -->|step()| AGENT
+ AGENT -->|execute| TOOLS
+ TOOLS -->|call| USECASES
+
+ USECASES -->|search| TMDB
+ USECASES -->|search| KNABEN
+ USECASES -->|add| QBIT
+
+ AGENT <-->|read/write| LTM
+ AGENT <-->|read/write| STM
+ TOOLS <-->|read/write| EPIS
+
+ AGENT -->|response| FASTAPI
+ FASTAPI -->|JSON| USER
+```
+
+## Dependency Direction
+
+```mermaid
+flowchart BT
+ subgraph External["External"]
+ EXT[APIs, Filesystem]
+ end
+
+ subgraph Infra["Infrastructure"]
+ INF[Clients, Repositories, Memory]
+ end
+
+ subgraph App["Application"]
+ APP[Use Cases, DTOs]
+ end
+
+ subgraph Dom["Domain"]
+ DOM[Entities, Value Objects, Interfaces]
+ end
+
+ subgraph Agent["Agent"]
+ AGT[Agent, Tools, Prompts]
+ end
+
+ subgraph Pres["Presentation"]
+ PRES[FastAPI]
+ end
+
+ EXT --> Infra
+ Infra --> App
+ Infra -.->|implements| Dom
+ App --> Dom
+ Agent --> App
+ Agent --> Infra
+ Pres --> Agent
+
+ style Dom fill:#e8f5e9,stroke:#4caf50,stroke-width:3px
+ style Infra fill:#fce4ec,stroke:#e91e63
+ style App fill:#f3e5f5,stroke:#9c27b0
+ style Agent fill:#fff3e0,stroke:#ff9800
+ style Pres fill:#e1f5fe,stroke:#03a9f4
+```
+
+## Legend
+
+| Layer | Responsibility | Examples |
+|-------|---------------|----------|
+| đ **Presentation** | HTTP interface, request/response handling | FastAPI endpoints |
+| đ€ **Agent** | AI orchestration, LLM interaction, tools | Agent, PromptBuilder, Tools |
+| âïž **Application** | Use case orchestration, DTOs | SearchMovieUseCase, SearchTorrentsResponse |
+| đŠ **Domain** | Business entities, rules, interfaces | Movie, TVShow, ImdbId, MovieRepository |
+| đ§ **Infrastructure** | External service implementations | TMDBClient, JsonMovieRepository, Memory |
+| âïž **External** | Third-party services | TMDB API, qBittorrent, Filesystem |
+
+## Key Principles
+
+1. **Dependency Inversion**: Domain defines interfaces, Infrastructure implements them
+2. **Clean Architecture**: Dependencies point inward (toward Domain)
+3. **Separation of Concerns**: Each layer has a single responsibility
+4. **Memory Segregation**: LTM (persistent), STM (session), Episodic (transient)
diff --git a/docs/flowchart.md b/docs/flowchart.md
new file mode 100644
index 0000000..29ae126
--- /dev/null
+++ b/docs/flowchart.md
@@ -0,0 +1,366 @@
+# Flowcharts - Agent Media
+
+## 1. Main Application Flow
+
+```mermaid
+flowchart TD
+ START([Application Start]) --> INIT_MEM[Initialize Memory Context
init_memory]
+ INIT_MEM --> INIT_LLM{LLM Provider?}
+
+ INIT_LLM -->|OLLAMA| OLLAMA[Create OllamaClient]
+ INIT_LLM -->|DEEPSEEK| DEEPSEEK[Create DeepSeekClient]
+
+ OLLAMA --> INIT_AGENT[Create Agent]
+ DEEPSEEK --> INIT_AGENT
+
+ INIT_AGENT --> INIT_TOOLS[Register Tools
make_tools]
+ INIT_TOOLS --> START_SERVER[Start FastAPI Server
:8000]
+
+ START_SERVER --> WAIT_REQ[/Wait for Request/]
+
+ WAIT_REQ --> REQ_TYPE{Request Type?}
+
+ REQ_TYPE -->|GET /health| HEALTH[Return health status]
+ REQ_TYPE -->|GET /v1/models| MODELS[Return model list]
+ REQ_TYPE -->|GET /memory/state| MEM_STATE[Return memory state]
+ REQ_TYPE -->|POST /memory/clear-session| CLEAR_SESSION[Clear STM + Episodic]
+ REQ_TYPE -->|POST /v1/chat/completions| CHAT[Process Chat Request]
+
+ HEALTH --> WAIT_REQ
+ MODELS --> WAIT_REQ
+ MEM_STATE --> WAIT_REQ
+ CLEAR_SESSION --> WAIT_REQ
+ CHAT --> AGENT_STEP[agent.step]
+ AGENT_STEP --> RETURN_RESP[Return Response]
+ RETURN_RESP --> WAIT_REQ
+```
+
+## 2. Agent Step Flow (Core Logic)
+
+```mermaid
+flowchart TD
+ START([agent.step called]) --> GET_MEM[Get Memory from Context]
+ GET_MEM --> CHECK_EVENTS[Check Unread Events]
+
+ CHECK_EVENTS --> HAS_EVENTS{Has Events?}
+ HAS_EVENTS -->|Yes| FORMAT_EVENTS[Format Event Notifications]
+ HAS_EVENTS -->|No| BUILD_PROMPT
+ FORMAT_EVENTS --> BUILD_PROMPT
+
+ BUILD_PROMPT[Build System Prompt
with Memory Context]
+ BUILD_PROMPT --> INIT_MSGS[Initialize Messages Array]
+
+ INIT_MSGS --> ADD_SYSTEM[Add System Prompt]
+ ADD_SYSTEM --> GET_HISTORY[Get STM History]
+ GET_HISTORY --> ADD_HISTORY[Add History Messages]
+ ADD_HISTORY --> ADD_NOTIF{Has Notifications?}
+
+ ADD_NOTIF -->|Yes| ADD_NOTIF_MSG[Add Notification Message]
+ ADD_NOTIF -->|No| ADD_USER
+ ADD_NOTIF_MSG --> ADD_USER[Add User Input]
+
+ ADD_USER --> LOOP_START[/Tool Execution Loop/]
+
+ LOOP_START --> CHECK_ITER{iteration < max?}
+ CHECK_ITER -->|No| MAX_REACHED[Request Final Response]
+ CHECK_ITER -->|Yes| CALL_LLM[Call LLM.complete]
+
+ MAX_REACHED --> FINAL_LLM[Call LLM.complete]
+ FINAL_LLM --> SAVE_FINAL[Save to STM History]
+ SAVE_FINAL --> RETURN_FINAL([Return Response])
+
+ CALL_LLM --> PARSE_INTENT[Parse Intent from Response]
+ PARSE_INTENT --> IS_TOOL{Is Tool Call?}
+
+ IS_TOOL -->|No| SAVE_HISTORY[Save to STM History]
+ SAVE_HISTORY --> SAVE_LTM[Save LTM]
+ SAVE_LTM --> RETURN_TEXT([Return Text Response])
+
+ IS_TOOL -->|Yes| EXEC_TOOL[Execute Tool]
+ EXEC_TOOL --> ADD_RESULT[Add Tool Result to Messages]
+ ADD_RESULT --> INC_ITER[iteration++]
+ INC_ITER --> LOOP_START
+```
+
+## 3. Tool Execution Flow
+
+```mermaid
+flowchart TD
+ START([_execute_action called]) --> GET_ACTION[Extract action name & args]
+ GET_ACTION --> FIND_TOOL{Tool exists?}
+
+ FIND_TOOL -->|No| UNKNOWN[Return unknown_tool error]
+ UNKNOWN --> END_ERR([Return Error])
+
+ FIND_TOOL -->|Yes| CALL_FUNC[Call tool.func with args]
+
+ CALL_FUNC --> EXEC_OK{Execution OK?}
+
+ EXEC_OK -->|TypeError| BAD_ARGS[Log bad arguments error]
+ EXEC_OK -->|Exception| EXEC_ERR[Log execution error]
+ EXEC_OK -->|Success| CHECK_RESULT{Result has error?}
+
+ BAD_ARGS --> ADD_ERR_MEM[Add error to Episodic Memory]
+ EXEC_ERR --> ADD_ERR_MEM
+ ADD_ERR_MEM --> END_ERR
+
+ CHECK_RESULT -->|Yes| ADD_ERR_MEM2[Add error to Episodic Memory]
+ ADD_ERR_MEM2 --> RETURN_RESULT
+ CHECK_RESULT -->|No| RETURN_RESULT([Return Result])
+```
+
+## 4. Prompt Building Flow
+
+```mermaid
+flowchart TD
+ START([build_system_prompt called]) --> GET_MEM[Get Memory from Context]
+
+ GET_MEM --> FORMAT_TOOLS[Format Tools Description]
+ FORMAT_TOOLS --> FORMAT_PARAMS[Format Parameters Description]
+
+ FORMAT_PARAMS --> CHECK_MISSING[Check Missing Required Params]
+ CHECK_MISSING --> HAS_MISSING{Has Missing?}
+
+ HAS_MISSING -->|Yes| FORMAT_MISSING[Format Missing Params Info]
+ HAS_MISSING -->|No| FORMAT_EPISODIC
+ FORMAT_MISSING --> FORMAT_EPISODIC
+
+ FORMAT_EPISODIC[Format Episodic Context]
+ FORMAT_EPISODIC --> HAS_SEARCH{Has Search Results?}
+
+ HAS_SEARCH -->|Yes| ADD_SEARCH[Add Search Results Summary]
+ HAS_SEARCH -->|No| CHECK_PENDING
+ ADD_SEARCH --> CHECK_PENDING
+
+ CHECK_PENDING{Has Pending Question?}
+ CHECK_PENDING -->|Yes| ADD_PENDING[Add Pending Question]
+ CHECK_PENDING -->|No| CHECK_DOWNLOADS
+ ADD_PENDING --> CHECK_DOWNLOADS
+
+ CHECK_DOWNLOADS{Has Active Downloads?}
+ CHECK_DOWNLOADS -->|Yes| ADD_DOWNLOADS[Add Downloads Status]
+ CHECK_DOWNLOADS -->|No| CHECK_ERRORS
+ ADD_DOWNLOADS --> CHECK_ERRORS
+
+ CHECK_ERRORS{Has Recent Errors?}
+ CHECK_ERRORS -->|Yes| ADD_ERRORS[Add Last Error]
+ CHECK_ERRORS -->|No| FORMAT_STM
+ ADD_ERRORS --> FORMAT_STM
+
+ FORMAT_STM[Format STM Context]
+ FORMAT_STM --> HAS_WORKFLOW{Has Workflow?}
+
+ HAS_WORKFLOW -->|Yes| ADD_WORKFLOW[Add Workflow Info]
+ HAS_WORKFLOW -->|No| CHECK_TOPIC
+ ADD_WORKFLOW --> CHECK_TOPIC
+
+ CHECK_TOPIC{Has Topic?}
+ CHECK_TOPIC -->|Yes| ADD_TOPIC[Add Current Topic]
+ CHECK_TOPIC -->|No| CHECK_ENTITIES
+ ADD_TOPIC --> CHECK_ENTITIES
+
+ CHECK_ENTITIES{Has Entities?}
+ CHECK_ENTITIES -->|Yes| ADD_ENTITIES[Add Extracted Entities]
+ CHECK_ENTITIES -->|No| BUILD_FINAL
+ ADD_ENTITIES --> BUILD_FINAL
+
+ BUILD_FINAL[Assemble Final Prompt]
+ BUILD_FINAL --> RETURN([Return System Prompt])
+```
+
+## 5. Memory System Flow
+
+```mermaid
+flowchart TD
+ subgraph Initialization
+ INIT([init_memory called]) --> CREATE_MEM[Create Memory Instance]
+ CREATE_MEM --> LOAD_LTM{LTM file exists?}
+ LOAD_LTM -->|Yes| READ_FILE[Read ltm.json]
+ LOAD_LTM -->|No| CREATE_DEFAULT[Create Default LTM]
+ READ_FILE --> PARSE_JSON{Parse OK?}
+ PARSE_JSON -->|Yes| RESTORE_LTM[Restore LTM from Dict]
+ PARSE_JSON -->|No| CREATE_DEFAULT
+ CREATE_DEFAULT --> CREATE_STM[Create Empty STM]
+ RESTORE_LTM --> CREATE_STM
+ CREATE_STM --> CREATE_EPIS[Create Empty Episodic]
+ CREATE_EPIS --> SET_CTX[Set in Context Variable]
+ SET_CTX --> RETURN_MEM([Return Memory])
+ end
+
+ subgraph Access
+ GET([get_memory called]) --> CHECK_CTX{Context has Memory?}
+ CHECK_CTX -->|Yes| RETURN_CTX([Return Memory])
+ CHECK_CTX -->|No| RAISE_ERR[Raise RuntimeError]
+ end
+
+ subgraph Save
+ SAVE([memory.save called]) --> SERIALIZE[Serialize LTM to Dict]
+ SERIALIZE --> WRITE_JSON[Write to ltm.json]
+ WRITE_JSON --> SAVE_OK{Write OK?}
+ SAVE_OK -->|Yes| DONE([Done])
+ SAVE_OK -->|No| LOG_ERR[Log Error & Raise]
+ end
+```
+
+## 6. Torrent Search & Download Flow
+
+```mermaid
+flowchart TD
+ subgraph Search
+ SEARCH_START([find_torrent called]) --> CREATE_UC[Create SearchTorrentsUseCase]
+ CREATE_UC --> EXEC_SEARCH[Execute Search via Knaben API]
+ EXEC_SEARCH --> SEARCH_OK{Results Found?}
+
+ SEARCH_OK -->|No| RETURN_ERR([Return Error])
+ SEARCH_OK -->|Yes| GET_MEM[Get Memory]
+ GET_MEM --> STORE_RESULTS[Store in Episodic Memory
with indexes 1,2,3...]
+ STORE_RESULTS --> SET_TOPIC[Set Topic: selecting_torrent]
+ SET_TOPIC --> RETURN_RESULTS([Return Results])
+ end
+
+ subgraph "Get by Index"
+ GET_START([get_torrent_by_index called]) --> GET_MEM2[Get Memory]
+ GET_MEM2 --> HAS_RESULTS{Has Search Results?}
+
+ HAS_RESULTS -->|No| NO_RESULTS([Return not_found Error])
+ HAS_RESULTS -->|Yes| FIND_INDEX[Find Result by Index]
+ FIND_INDEX --> FOUND{Found?}
+
+ FOUND -->|No| NOT_FOUND([Return not_found Error])
+ FOUND -->|Yes| RETURN_TORRENT([Return Torrent Data])
+ end
+
+ subgraph "Add by Index"
+ ADD_START([add_torrent_by_index called]) --> CALL_GET[Call get_torrent_by_index]
+ CALL_GET --> GET_OK{Got Torrent?}
+
+ GET_OK -->|No| RETURN_GET_ERR([Return Error])
+ GET_OK -->|Yes| HAS_MAGNET{Has Magnet Link?}
+
+ HAS_MAGNET -->|No| NO_MAGNET([Return no_magnet Error])
+ HAS_MAGNET -->|Yes| CALL_ADD[Call add_torrent_to_qbittorrent]
+ CALL_ADD --> ADD_OK{Added OK?}
+
+ ADD_OK -->|No| RETURN_ADD_ERR([Return Error])
+ ADD_OK -->|Yes| ADD_NAME[Add torrent_name to Result]
+ ADD_NAME --> RETURN_SUCCESS([Return Success])
+ end
+
+ subgraph "Add to qBittorrent"
+ QB_START([add_torrent_to_qbittorrent called]) --> CREATE_UC2[Create AddTorrentUseCase]
+ CREATE_UC2 --> EXEC_ADD[Execute Add via qBittorrent API]
+ EXEC_ADD --> QB_OK{Added OK?}
+
+ QB_OK -->|No| QB_ERR([Return Error])
+ QB_OK -->|Yes| GET_MEM3[Get Memory]
+ GET_MEM3 --> FIND_NAME[Find Torrent Name from Search]
+ FIND_NAME --> ADD_DOWNLOAD[Add to Active Downloads]
+ ADD_DOWNLOAD --> SET_TOPIC2[Set Topic: downloading]
+ SET_TOPIC2 --> END_WORKFLOW[End Current Workflow]
+ END_WORKFLOW --> QB_SUCCESS([Return Success])
+ end
+```
+
+## 7. Filesystem Operations Flow
+
+```mermaid
+flowchart TD
+ subgraph "Set Folder Path"
+ SET_START([set_path_for_folder called]) --> VALIDATE_NAME[Validate Folder Name]
+ VALIDATE_NAME --> NAME_OK{Valid Name?}
+
+ NAME_OK -->|No| INVALID_NAME([Return validation_failed])
+ NAME_OK -->|Yes| RESOLVE_PATH[Resolve Path]
+
+ RESOLVE_PATH --> PATH_EXISTS{Path Exists?}
+ PATH_EXISTS -->|No| NOT_EXISTS([Return invalid_path])
+ PATH_EXISTS -->|Yes| IS_DIR{Is Directory?}
+
+ IS_DIR -->|No| NOT_DIR([Return invalid_path])
+ IS_DIR -->|Yes| IS_READABLE{Is Readable?}
+
+ IS_READABLE -->|No| NO_READ([Return permission_denied])
+ IS_READABLE -->|Yes| GET_MEM[Get Memory]
+
+ GET_MEM --> SET_CONFIG[Set in LTM Config]
+ SET_CONFIG --> SAVE_MEM[Save Memory]
+ SAVE_MEM --> SET_SUCCESS([Return Success])
+ end
+
+ subgraph "List Folder"
+ LIST_START([list_folder called]) --> VALIDATE_TYPE[Validate Folder Type]
+ VALIDATE_TYPE --> TYPE_OK{Valid Type?}
+
+ TYPE_OK -->|No| INVALID_TYPE([Return validation_failed])
+ TYPE_OK -->|Yes| SANITIZE[Sanitize Path]
+
+ SANITIZE --> SAFE{Path Safe?}
+ SAFE -->|No| TRAVERSAL([Return forbidden])
+ SAFE -->|Yes| GET_MEM2[Get Memory]
+
+ GET_MEM2 --> GET_CONFIG[Get Folder from Config]
+ GET_CONFIG --> CONFIGURED{Folder Configured?}
+
+ CONFIGURED -->|No| NOT_SET([Return folder_not_set])
+ CONFIGURED -->|Yes| BUILD_TARGET[Build Target Path]
+
+ BUILD_TARGET --> CHECK_SAFE[Check Path is Safe]
+ CHECK_SAFE --> SAFE2{Within Base?}
+
+ SAFE2 -->|No| FORBIDDEN([Return forbidden])
+ SAFE2 -->|Yes| TARGET_EXISTS{Target Exists?}
+
+ TARGET_EXISTS -->|No| NOT_FOUND([Return not_found])
+ TARGET_EXISTS -->|Yes| TARGET_DIR{Is Directory?}
+
+ TARGET_DIR -->|No| NOT_A_DIR([Return not_a_directory])
+ TARGET_DIR -->|Yes| LIST_DIR[List Directory Contents]
+
+ LIST_DIR --> LIST_OK{Permission OK?}
+ LIST_OK -->|No| PERM_DENIED([Return permission_denied])
+ LIST_OK -->|Yes| LIST_SUCCESS([Return Entries])
+ end
+```
+
+## 8. LLM Communication Flow
+
+```mermaid
+flowchart TD
+ subgraph "DeepSeek Client"
+ DS_START([complete called]) --> DS_BUILD[Build Request Body]
+ DS_BUILD --> DS_HEADERS[Set Headers with API Key]
+ DS_HEADERS --> DS_POST[POST to DeepSeek API]
+ DS_POST --> DS_OK{Response OK?}
+
+ DS_OK -->|No| DS_ERR{Error Type?}
+ DS_ERR -->|401| DS_AUTH([Raise LLMAuthenticationError])
+ DS_ERR -->|429| DS_RATE([Raise LLMRateLimitError])
+ DS_ERR -->|Other| DS_API([Raise LLMAPIError])
+
+ DS_OK -->|Yes| DS_PARSE[Parse JSON Response]
+ DS_PARSE --> DS_EXTRACT[Extract Content]
+ DS_EXTRACT --> DS_RETURN([Return Content String])
+ end
+
+ subgraph "Ollama Client"
+ OL_START([complete called]) --> OL_BUILD[Build Request Body]
+ OL_BUILD --> OL_POST[POST to Ollama API]
+ OL_POST --> OL_OK{Response OK?}
+
+ OL_OK -->|No| OL_ERR([Raise LLMAPIError])
+ OL_OK -->|Yes| OL_PARSE[Parse JSON Response]
+ OL_PARSE --> OL_EXTRACT[Extract Message Content]
+ OL_EXTRACT --> OL_RETURN([Return Content String])
+ end
+```
+
+## Legend
+
+| Symbol | Meaning |
+|--------|---------|
+| `([text])` | Start/End (Terminal) |
+| `[text]` | Process |
+| `{text}` | Decision |
+| `/text/` | Input/Output |
+| `-->` | Flow direction |
+| `-->\|label\|` | Conditional flow |
diff --git a/docs/sequence_diagram.md b/docs/sequence_diagram.md
new file mode 100644
index 0000000..4864c03
--- /dev/null
+++ b/docs/sequence_diagram.md
@@ -0,0 +1,264 @@
+# Sequence Diagrams - Agent Media
+
+## 1. Torrent Search and Download Flow
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User
+ participant FastAPI as FastAPI Server
+ participant Agent
+ participant PromptBuilder
+ participant LLM as LLM (DeepSeek/Ollama)
+ participant Tools as Tool Registry
+ participant Memory
+ participant Knaben as Knaben API
+ participant qBit as qBittorrent
+
+ User->>FastAPI: POST /v1/chat/completions
"Find torrents for Inception 1080p"
+ FastAPI->>Agent: step(user_input)
+
+ Agent->>Memory: stm.get_recent_history()
+ Memory-->>Agent: conversation history
+
+ Agent->>PromptBuilder: build_system_prompt(memory)
+ PromptBuilder->>Memory: ltm.config, episodic state
+ Memory-->>PromptBuilder: context data
+ PromptBuilder-->>Agent: system prompt with context
+
+ Agent->>LLM: complete(messages)
+ LLM-->>Agent: {"action": {"name": "find_torrents", "args": {...}}}
+
+ Agent->>Agent: _parse_intent(response)
+ Agent->>Tools: execute find_torrents
+ Tools->>Knaben: search("Inception 1080p")
+ Knaben-->>Tools: torrent results
+
+ Tools->>Memory: episodic.store_search_results()
+ Memory-->>Tools: stored with indexes (1, 2, 3...)
+
+ Tools-->>Agent: {"status": "ok", "torrents": [...]}
+
+ Agent->>LLM: complete(messages + tool_result)
+ LLM-->>Agent: "I found 5 torrents for Inception..."
+
+ Agent->>Memory: stm.add_message("user", input)
+ Agent->>Memory: stm.add_message("assistant", response)
+ Agent->>Memory: save()
+
+ Agent-->>FastAPI: final response
+ FastAPI-->>User: JSON response
+
+ Note over User,qBit: User selects a torrent
+
+ User->>FastAPI: POST /v1/chat/completions
"Download the 2nd one"
+ FastAPI->>Agent: step(user_input)
+
+ Agent->>PromptBuilder: build_system_prompt(memory)
+ PromptBuilder->>Memory: episodic.last_search_results
+ Note right of Memory: Results still in memory:
1. Inception.2010.1080p...
2. Inception.1080p.BluRay...
+ Memory-->>PromptBuilder: context with search results
+ PromptBuilder-->>Agent: prompt showing available results
+
+ Agent->>LLM: complete(messages)
+ LLM-->>Agent: {"action": {"name": "add_torrent_by_index", "args": {"index": 2}}}
+
+ Agent->>Tools: execute add_torrent_by_index(index=2)
+ Tools->>Memory: episodic.get_result_by_index(2)
+ Memory-->>Tools: torrent data with magnet link
+
+ Tools->>qBit: add_torrent(magnet_link)
+ qBit-->>Tools: success
+
+ Tools->>Memory: episodic.add_active_download()
+ Tools-->>Agent: {"status": "ok", "torrent_name": "Inception.1080p.BluRay"}
+
+ Agent->>LLM: complete(messages + tool_result)
+ LLM-->>Agent: "I've added Inception to qBittorrent!"
+
+ Agent-->>FastAPI: final response
+ FastAPI-->>User: JSON response
+```
+
+## 2. Folder Configuration Flow
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User
+ participant FastAPI as FastAPI Server
+ participant Agent
+ participant LLM as LLM
+ participant Tools as Tool Registry
+ participant FileManager
+ participant Memory
+ participant FS as Filesystem
+
+ User->>FastAPI: POST /v1/chat/completions
"Set download folder to /mnt/media/downloads"
+ FastAPI->>Agent: step(user_input)
+
+ Agent->>LLM: complete(messages)
+ LLM-->>Agent: {"action": {"name": "set_path_for_folder", "args": {...}}}
+
+ Agent->>Tools: execute set_path_for_folder
+ Tools->>FileManager: set_folder_path("download", "/mnt/media/downloads")
+
+ FileManager->>FS: Path.exists()?
+ FS-->>FileManager: true
+ FileManager->>FS: Path.is_dir()?
+ FS-->>FileManager: true
+ FileManager->>FS: os.access(R_OK)?
+ FS-->>FileManager: true
+
+ FileManager->>Memory: ltm.set_config("download_folder", path)
+ FileManager->>Memory: save()
+ Memory->>FS: write ltm.json
+
+ FileManager-->>Tools: {"status": "ok", "path": "/mnt/media/downloads"}
+ Tools-->>Agent: result
+
+ Agent->>LLM: complete(messages + tool_result)
+ LLM-->>Agent: "Download folder set to /mnt/media/downloads"
+
+ Agent-->>FastAPI: final response
+ FastAPI-->>User: JSON response
+```
+
+## 3. Multi-Tool Workflow (Search Movie â Find Torrents â Download)
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User
+ participant Agent
+ participant LLM as LLM
+ participant TMDB as TMDB API
+ participant Knaben as Knaben API
+ participant qBit as qBittorrent
+ participant Memory
+
+ User->>Agent: "Download Dune 2 in 4K"
+
+ rect rgb(240, 248, 255)
+ Note over Agent,TMDB: Step 1: Identify the movie
+ Agent->>LLM: complete(messages)
+ LLM-->>Agent: {"action": "find_media_imdb_id", "args": {"media_title": "Dune 2"}}
+ Agent->>TMDB: search_movie("Dune 2")
+ TMDB-->>Agent: {title: "Dune: Part Two", imdb_id: "tt15239678", year: 2024}
+ Agent->>Memory: stm.set_entity("last_media_search", {...})
+ end
+
+ rect rgb(255, 248, 240)
+ Note over Agent,Knaben: Step 2: Search for torrents
+ Agent->>LLM: complete(messages + movie_info)
+ LLM-->>Agent: {"action": "find_torrents", "args": {"media_title": "Dune Part Two 2024 4K"}}
+ Agent->>Knaben: search("Dune Part Two 2024 4K")
+ Knaben-->>Agent: [torrent1, torrent2, torrent3...]
+ Agent->>Memory: episodic.store_search_results()
+ end
+
+ rect rgb(240, 255, 240)
+ Note over Agent,qBit: Step 3: Add best torrent
+ Agent->>LLM: complete(messages + torrents)
+ LLM-->>Agent: {"action": "add_torrent_by_index", "args": {"index": 1}}
+ Agent->>Memory: episodic.get_result_by_index(1)
+ Memory-->>Agent: torrent with magnet
+ Agent->>qBit: add_torrent(magnet)
+ qBit-->>Agent: success
+ Agent->>Memory: episodic.add_active_download()
+ end
+
+ Agent->>LLM: complete(messages + all_results)
+ LLM-->>Agent: "I found Dune: Part Two (2024) and added the 4K torrent to qBittorrent!"
+ Agent-->>User: Final response
+```
+
+## 4. Error Handling Flow
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User
+ participant Agent
+ participant LLM as LLM
+ participant Tools as Tool Registry
+ participant Memory
+ participant API as External API
+
+ User->>Agent: "Download the 5th torrent"
+
+ Agent->>LLM: complete(messages)
+ LLM-->>Agent: {"action": "add_torrent_by_index", "args": {"index": 5}}
+
+ Agent->>Tools: execute add_torrent_by_index(5)
+ Tools->>Memory: episodic.get_result_by_index(5)
+
+ alt No search results
+ Memory-->>Tools: None (no previous search)
+ Tools-->>Agent: {"status": "error", "error": "not_found"}
+ Agent->>Memory: episodic.add_error("add_torrent_by_index", "not_found")
+ else Index out of range
+ Memory-->>Tools: None (only 3 results)
+ Tools-->>Agent: {"status": "error", "error": "not_found"}
+ Agent->>Memory: episodic.add_error("add_torrent_by_index", "not_found")
+ end
+
+ Agent->>LLM: complete(messages + error)
+ LLM-->>Agent: "I couldn't find torrent #5. Please search for torrents first."
+
+ Agent-->>User: Error explanation
+
+ Note over User,API: User searches first
+
+ User->>Agent: "Search for Matrix 1999"
+ Agent->>API: search("Matrix 1999")
+ API-->>Agent: [3 results]
+ Agent->>Memory: episodic.store_search_results()
+ Agent-->>User: "Found 3 torrents..."
+
+ User->>Agent: "Download the 2nd one"
+ Agent->>Memory: episodic.get_result_by_index(2)
+ Memory-->>Agent: torrent data â
+ Agent-->>User: "Added to qBittorrent!"
+```
+
+## 5. Background Events Flow
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User
+ participant Agent
+ participant Memory
+ participant qBit as qBittorrent
+ participant LLM as LLM
+
+ Note over qBit,Memory: Background: Download completes
+ qBit--)Memory: episodic.complete_download(task_id, file_path)
+ Memory->>Memory: add_background_event("download_complete", {...})
+
+ Note over User,LLM: Later: User sends a message
+ User->>Agent: "What's new?"
+
+ Agent->>Memory: episodic.get_unread_events()
+ Memory-->>Agent: [{type: "download_complete", data: {name: "Inception.1080p"}}]
+
+ Agent->>Agent: _check_unread_events()
+ Note right of Agent: Formats notification:
"Download completed: Inception.1080p"
+
+ Agent->>LLM: complete(messages + notification)
+ LLM-->>Agent: "Good news! Inception.1080p has finished downloading."
+
+ Agent-->>User: Response with notification
+```
+
+## Legend
+
+| Element | Description |
+|---------|-------------|
+| `rect rgb(...)` | Grouped steps in a workflow |
+| `alt/else` | Conditional branches |
+| `Note` | Explanatory notes |
+| `-->>` | Response/return |
+| `->>` | Request/call |
+| `--))` | Async event |
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index ca47314..0000000
--- a/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Test suite for Agent Media."""