132 lines
9.8 KiB
Markdown
132 lines
9.8 KiB
Markdown
# MiroFish — Fork Context (Private Impact Feature)
|
|
|
|
## Branche de travail
|
|
`feature/private-impact`
|
|
|
|
## Remotes
|
|
- `origin` → https://github.com/CyrilDEVIA/MiroResult.git (fork perso)
|
|
- `upstream` → https://github.com/666ghj/MiroFish.git (repo original)
|
|
|
|
---
|
|
|
|
## Historique des sessions
|
|
|
|
### 2026-04-16 — Session 1
|
|
|
|
#### Étapes terminées
|
|
- [x] **Prompt N°01** — Lecture complète du code source (audit, zéro modification)
|
|
- [x] **Prompt N°02** — Setup Git : fork + remote + branche `feature/private-impact`
|
|
- [x] **Prompt N°03** — Création `backend/scripts/run_private_simulation.py`
|
|
- [x] **Prompt N°04** — Création `backend/app/services/private_impact_profile_generator.py`
|
|
- [x] **Prompt N°05** — Création `backend/app/services/private_impact_config_generator.py`
|
|
- [x] **Prompt N°06** — Création `backend/app/services/private_impact_runner.py`
|
|
- [x] **Prompt N°07** — Blueprint `backend/app/api/private.py` + enregistrement (`api/__init__.py`, `app/__init__.py`)
|
|
- [x] **Prompt N°08** — Modification `backend/app/services/simulation_runner.py` (7 zones : champs private_*, start, monitor, read_log, check_completed, get_actions, cleanup)
|
|
- [x] **Prompt N°09** — Frontend : `api/private.js` + `ModeSelector.vue` + `PrivateImpactView.vue` + route `/private/:projectId`
|
|
- [x] **Prompt N°10** — `action_logger.py` : ajout `get_private_logger()` + suppression fallback `run_private_simulation.py` + intégration `ModeSelector` dans `Home.vue`
|
|
|
|
#### Fichiers créés / modifiés
|
|
| Fichier | Action |
|
|
|---|---|
|
|
| `backend/scripts/run_private_simulation.py` | Créé — moteur de simulation privé |
|
|
| `backend/scripts/private/` | Créé — répertoire de sortie actions.jsonl |
|
|
| `backend/app/services/private_impact_profile_generator.py` | Créé — générateur de profils relationnels |
|
|
| `backend/app/services/private_impact_config_generator.py` | Créé — générateur de paramètres comportementaux |
|
|
| `backend/app/services/private_impact_runner.py` | Créé — orchestrateur subprocess + monitoring |
|
|
| `CONTEXT.md` | Créé — ce fichier |
|
|
| `backend/app/api/private.py` | Créé — blueprint Flask /api/private-impact (7 routes) |
|
|
| `backend/app/api/__init__.py` | Modifié — ajout private_bp + import private |
|
|
| `backend/app/__init__.py` | Modifié — enregistrement private_bp |
|
|
| `backend/app/services/simulation_runner.py` | Modifié — 7 zones private (champs, start, monitor, read_log, check, get_actions, cleanup) |
|
|
| `frontend/src/api/private.js` | Créé — client API private impact (7 fonctions) |
|
|
| `frontend/src/components/ModeSelector.vue` | Créé — sélecteur Public / Private Impact (2 cartes) |
|
|
| `frontend/src/views/PrivateImpactView.vue` | Créé — wizard 5 étapes (form → prepare → run → report → chat) |
|
|
| `frontend/src/router/index.js` | Modifié — route `/private/:projectId` ajoutée |
|
|
| `backend/scripts/action_logger.py` | Modifié — ajout `get_private_logger()` à `SimulationLogManager` |
|
|
| `backend/scripts/run_private_simulation.py` | Modifié — suppression fallback `hasattr`, appel direct `log_manager.get_private_logger()` |
|
|
| `frontend/src/views/Home.vue` | Modifié — intégration `ModeSelector` (right panel) + `handleModeSelected` + sessionStorage `pendingSimMode` |
|
|
|
|
#### Décisions d'architecture prises
|
|
- Pas d'env OASIS (pas de Twitter/Reddit/PlatformConfig)
|
|
- Appels LLM directs via `camel-ai ChatAgent` + `asyncio.to_thread()`
|
|
- Graphe relationnel construit depuis `cascade_influence` dans agent_configs
|
|
- `REACT_PRIVATELY` = invisible → ne propage pas l'exposition
|
|
- Tous les autres actions (sauf `DO_NOTHING`) cascade vers `cascade_influence` targets
|
|
- `zep_graph_memory_updater.py` réutilisé sans modification (platform="private")
|
|
- IPC `PrivateIPCHandler` : interviews via LLM direct (pas de SQLite)
|
|
- Output : `private/actions.jsonl` (même format JSONL que twitter/reddit)
|
|
- `RelationalAgentProfile` hérite de `OasisAgentProfile` — 8 champs relationnels ajoutés
|
|
- Encodage des dimensions relationnelles dans le champ `persona` (texte naturel)
|
|
- Fallback rule-based par type : Employee, Manager, Client, Competitor, Partner, FamilyMember
|
|
- `to_private_format()` retourne le dict lu par `run_private_simulation.py`
|
|
- `PrivateImpactConfigGenerator.generate_config()` : entrée = liste de dicts agents (issue de profile_generator), pas d'EntityNode direct
|
|
- `PrivateTimeConfig` : jours + rounds/jour (matin/midi/soir) — pas d'heures ni timezone
|
|
- `PrivateEventConfig` : injection par `decision_statement` — pas de posts sociaux
|
|
- `RelationalActivityConfig.exposure_round` : round 0 = exposition directe (distance 1)
|
|
- Fallback rule-based : table `RELATIONAL_FALLBACKS` dans le générateur (6 types)
|
|
- `PrivateImpactRunner` : même pattern classmethods que `SimulationRunner` (états en mémoire de classe)
|
|
- Config lue depuis `private_simulation_config.json` (≠ `simulation_config.json` OASIS)
|
|
- Log unique : `{sim_dir}/private/actions.jsonl` (une seule plateforme)
|
|
- `PrivateRunnerStatus` : enum séparé — pas de réutilisation de `RunnerStatus`
|
|
- `private_simulated_days` lu depuis le champ `simulated_day` du `round_end` event
|
|
- Frontend : CSS plain (pas Tailwind — non présent dans package.json) — même style que les vues existantes
|
|
- `ModeSelector.vue` : composant standalone, émet `@mode-selected` avec `"public"` ou `"private"`, à intégrer manuellement dans `Home.vue` ou `Process.vue`
|
|
- `PrivateImpactView.vue` : route `/private/:projectId` — charge le projet via `getProject()` pour récupérer `graph_id`
|
|
- Step 3 : polling `/api/private-impact/status/{simId}` toutes les 3s + affichage `recent_actions` depuis `to_detail_dict()`
|
|
- Step 4 : report via `generatePrivateReport()` → task_id → polling `getReportStatus(reportId)` → `getReport(reportId)` (réutilise le ReportManager existant)
|
|
- Step 5 : `chatAgents` reconstruit depuis la liste d'actions (agent_id + agent_name) ; chat via `interviewAgents()` (réutilise simulation.js)
|
|
- `SimulationRunState` : 5 champs `private_*` ajoutés (current_round, simulated_days, running, actions_count, completed)
|
|
- `add_action()` : elif platform=="private" → private_actions_count (évite comptage dans reddit)
|
|
- `to_dict()` : private_* inclus dans total_actions_count
|
|
- `start_simulation()` : elif platform=="private" → run_private_simulation.py + private_running=True
|
|
- `_monitor_simulation()` : lecture `private/actions.jsonl` dans la boucle ET en final ; private_running=False à la fin
|
|
- `_read_action_log()` : simulation_end → private_completed=True ; round_end → private_current_round + private_simulated_days (depuis simulated_day)
|
|
- `_check_all_platforms_completed()` : private_log + private_enabled + check private_completed
|
|
- `get_all_actions()` : bloc private après reddit (même pattern)
|
|
- `cleanup_simulation_logs()` : private_simulation.db + dirs_to_clean inclut "private"
|
|
- Blueprint `private_bp` enregistré sans url_prefix (les routes déclarent `/api/private-impact/...` en entier)
|
|
- `/prepare` stocke les métadonnées (graph_id, sim_requirement, agent_count…) dans `private_meta.json` dans le sim_dir
|
|
- `/prepare` appelle `ZepEntityReader.get_entities_by_type()` en boucle sur les types relationnels puis `PrivateImpactProfileGenerator.generate_profiles_from_entities()`
|
|
- `/start` lit `private_simulation_config.json` via `PrivateImpactRunner.start_simulation()`
|
|
- `/status` retourne `to_detail_dict()` (inclut `recent_actions`)
|
|
- `/report` réutilise `ReportAgent` avec `simulation_id=sim_id` et `graph_id` lu depuis `private_meta.json`
|
|
- `/cleanup` délègue entièrement à `PrivateImpactRunner.cleanup()`
|
|
- `get_private_logger()` ajouté à `SimulationLogManager` — même pattern que `get_twitter_logger()` / `get_reddit_logger()` ; fallback supprimé dans `run_private_simulation.py`
|
|
- `ModeSelector` intégré dans `Home.vue` (right panel, au-dessus de `.console-box`) ; mode stocké dans `sessionStorage` (`pendingSimMode`) — `MainView.vue` (N°11) doit lire ce flag et rediriger vers `/private/:projectId` après création du projet
|
|
|
|
---
|
|
|
|
## Prochaines étapes
|
|
|
|
| Prompt | Fichier cible | Action |
|
|
|---|---|---|
|
|
| N°04 | `backend/app/services/private_impact_profile_generator.py` | ✅ Terminé |
|
|
| N°05 | `backend/app/services/private_impact_config_generator.py` | ✅ Terminé |
|
|
| N°06 | `backend/app/services/private_impact_runner.py` | ✅ Terminé |
|
|
| N°07 | `backend/app/api/private.py` | ✅ Terminé |
|
|
| N°07 | `backend/app/api/__init__.py` | ✅ Terminé |
|
|
| N°07 | `backend/app/__init__.py` | ✅ Terminé |
|
|
| N°08 | `backend/app/services/simulation_runner.py` | ✅ Terminé |
|
|
| N°09 | `frontend/src/views/PrivateImpactView.vue` | ✅ Terminé |
|
|
| N°09 | `frontend/src/components/ModeSelector.vue` | ✅ Terminé |
|
|
| N°10 | `backend/scripts/action_logger.py` | ✅ Terminé — `get_private_logger()` ajouté |
|
|
| N°10 | `backend/scripts/run_private_simulation.py` | ✅ Terminé — fallback supprimé |
|
|
| N°10 | `frontend/src/views/Home.vue` | ✅ Terminé — ModeSelector intégré |
|
|
| N°11 | `frontend/src/views/MainView.vue` | Lire `sessionStorage.pendingSimMode` après création du projet → rediriger vers `/private/:projectId` si 'private' |
|
|
| N°11 | Test end-to-end | Préparer → Lancer → Observer actions.jsonl |
|
|
|
|
## Point d'attention — `MainView.vue` (N°11)
|
|
**Status : ⏳ PENDING**
|
|
|
|
`Home.vue` stocke `sessionStorage.pendingSimMode = 'private'` quand l'utilisateur sélectionne Private Impact.
|
|
`MainView.vue` doit être modifié pour lire ce flag après la création du projet + le build du graphe Zep, et rediriger vers `/private/:projectId` au lieu de rester sur la vue OASIS standard.
|
|
|
|
**Action requise** dans `MainView.vue` — après la séquence upload → create_project → build_graph :
|
|
```javascript
|
|
const pendingMode = sessionStorage.getItem('pendingSimMode')
|
|
if (pendingMode === 'private') {
|
|
sessionStorage.removeItem('pendingSimMode')
|
|
router.push(`/private/${projectId}`)
|
|
}
|
|
```
|