Phase 0 (housekeeping): - Add .gitignore to protect credentials and runtime files - Track all project source code, docs, and config Phase 1 (perception loop): - Implement pluggable parser architecture (BaseMudParser ABC + ParserFactory) - Add DeadSoulsParser with regex for HP/MP/SP prompt, room descriptions, exits (multiple formats), NPC/item detection, and combat events - Add OutputBuffer for accumulating text between prompts - Update GameState with SP support and update_from_prompt/room/combat methods - Rewire main loop to use parser + buffer for real-time game state updates - Add reconnection logic to TelnetClient (retry with backoff) - Remove old TextParser (replaced by pluggable system) - Add mud_type config field for selecting parser at runtime - Add comprehensive test suite (50 tests, all passing)
307 lines
8.6 KiB
Markdown
307 lines
8.6 KiB
Markdown
<img src="https://r2cdn.perplexity.ai/pplx-full-logo-primary-dark%402x.png" style="height:64px;margin-right:32px"/>
|
|
|
|
# puoi produrre un PR.MD per chiedere ad un agente tipo ralph di produrre un automapper con queste caratteristiche ?
|
|
|
|
```markdown
|
|
# PR: Implementazione Automapper MUD con Archivio Ibrido SQLite/Memvid
|
|
|
|
## Descrizione
|
|
Implementare un modulo automapper per un client MUD che costruisca automaticamente una mappa del mondo di gioco durante l'esplorazione, con persistenza ibrida: SQLite per la memoria attiva real-time e Memvid per l'archivio storico compresso.
|
|
|
|
## Obiettivi
|
|
|
|
- [ ] Parsing delle descrizioni stanze dal protocollo Telnet MUD
|
|
- [ ] Costruzione incrementale del grafo di navigazione (stanze = nodi, direzioni = archi)
|
|
- [ ] Identificazione univoca delle stanze (room fingerprinting)
|
|
- [ ] Auto-mapping durante l'esplorazione senza intervento umano
|
|
- [ ] Pathfinding A* tra stanze note
|
|
- [ ] Storage layer ibrido: SQLite (attivo) + Memvid (storico)
|
|
- [ ] Sistema di ricerca semantica sulle descrizioni stanze
|
|
|
|
## Architettura Proposta
|
|
|
|
### 1. Telnet Parser & Room Extractor
|
|
```python
|
|
class RoomExtractor:
|
|
"""Estrae informazioni stanza dal testo MUD grezzo"""
|
|
|
|
def parse(self, raw_output: str) -> RoomData:
|
|
# Estrae: nome stanza, descrizione, exits disponibili,
|
|
# oggetti presenti, mob/NPC visibili
|
|
pass
|
|
```
|
|
|
|
**Input**: Testo raw dal server MUD (con ANSI color codes)
|
|
**Output**: `RoomData` strutturato con:
|
|
|
|
- `room_id`: hash univoco (descrizione + exits + nome)
|
|
- `name`: nome breve stanza
|
|
- `description`: descrizione lunga
|
|
- `exits`: dict {direzione: room_id_target} o None se non esplorato
|
|
- `entities`: lista mob/NPC/oggetti presenti
|
|
- `metadata`: timestamp, coordinate approssimative (se disponibili)
|
|
|
|
|
|
### 2. Graph Manager (NetworkX)
|
|
|
|
```python
|
|
class MUDGraph:
|
|
"""Grafo delle stanze con metodi di navigazione"""
|
|
|
|
def add_room(self, room: RoomData) -> bool:
|
|
# Aggiunge nodo, aggiorna archi bidirezionali
|
|
pass
|
|
|
|
def find_path(self, from_id: str, to_id: str) -> List[str]:
|
|
# A* pathfinding, ritorna lista di direzioni [n, n, e, u, ...]
|
|
pass
|
|
|
|
def get_unexplored_exits(self, room_id: str) -> List[str]:
|
|
# Ritorna direzioni da esplorare (exit con target=None)
|
|
pass
|
|
```
|
|
|
|
|
|
### 3. Storage Layer Ibrido
|
|
|
|
#### Layer A - SQLite (Memoria Attiva)
|
|
|
|
Per operazioni real-time durante l'esplorazione:
|
|
|
|
```sql
|
|
-- rooms: cache attiva delle stanze esplorate
|
|
CREATE TABLE rooms (
|
|
room_id TEXT PRIMARY KEY,
|
|
name TEXT,
|
|
description TEXT,
|
|
embedding BLOB, -- vettore per ricerca semantica
|
|
discovered_at TIMESTAMP,
|
|
visit_count INTEGER DEFAULT 1,
|
|
last_visit TIMESTAMP
|
|
);
|
|
|
|
-- exits: grafo di navigazione
|
|
CREATE TABLE exits (
|
|
from_room TEXT,
|
|
direction TEXT,
|
|
to_room TEXT, -- NULL se non esplorato
|
|
FOREIGN KEY (from_room) REFERENCES rooms(room_id)
|
|
);
|
|
|
|
-- exploration_queue: stanze con exit non esplorati
|
|
CREATE TABLE exploration_queue (
|
|
room_id TEXT,
|
|
direction TEXT,
|
|
priority INTEGER,
|
|
added_at TIMESTAMP
|
|
);
|
|
```
|
|
|
|
|
|
#### Layer B - Memvid (Archivio Storico)
|
|
|
|
Per storage compresso e ricerca semantica a lungo termine:
|
|
|
|
```python
|
|
class MemvidArchive:
|
|
"""Archivio storico in MP4 con QR code frames"""
|
|
|
|
def snapshot(self, db_path: str) -> str:
|
|
# 1. Estrae tutte le stanze da SQLite
|
|
# 2. Chunking descrizioni + metadati
|
|
# 3. Embedding con sentence-transformers
|
|
# 4. Encoding in QR code frames
|
|
# 5. Genera MP4 H.264 + indice FAISS
|
|
pass
|
|
|
|
def semantic_search(self, query: str, top_k: int = 5) -> List[RoomData]:
|
|
# Ricerca vettoriale sul MP4 storico
|
|
pass
|
|
```
|
|
|
|
|
|
### 4. Auto-Explorer Controller
|
|
|
|
```python
|
|
class AutoExplorer:
|
|
"""Orchestra l'esplorazione automatica"""
|
|
|
|
def decide_next_move(self, current_room: RoomData) -> str:
|
|
# Logica:
|
|
# 1. Se ci sono exit non esplorati, scegli quella più vicina
|
|
# 2. Altrimenti, BFS verso la stanza con exit non esplorati
|
|
# 3. Evita loop (no back-and-forth)
|
|
pass
|
|
|
|
def update_graph(self, move: str, result: str) -> None:
|
|
# Aggiorna grafo dopo ogni movimento
|
|
# Se result è "You can't go that way", marca exit come blocked
|
|
pass
|
|
```
|
|
|
|
|
|
### 5. Sync Manager
|
|
|
|
```python
|
|
class SyncManager:
|
|
"""Gestisce la sincronizzazione tra SQLite e Memvid"""
|
|
|
|
def __init__(self, sync_interval: int = 100):
|
|
# Ogni N stanze nuove, triggera snapshot Memvid
|
|
pass
|
|
|
|
def should_sync(self) -> bool:
|
|
# Controlla se ci sono abbastanza nuove stanze
|
|
pass
|
|
|
|
def perform_sync(self):
|
|
# 1. Crea backup SQLite
|
|
# 2. Genera snapshot Memvid
|
|
# 3. Verifica integrità (sample random decode)
|
|
# 4. Opzionale: pulisce SQLite delle stanze meno recenti
|
|
pass
|
|
```
|
|
|
|
|
|
## Criteri di Accettazione
|
|
|
|
### Test 1: Parsing Base
|
|
|
|
```python
|
|
raw_mud_output = """
|
|
[Exits: n e w]
|
|
The Village Square
|
|
You are standing in the village square. A fountain bubbles here.
|
|
A guard is standing here.
|
|
A signpost points north to the Forest, east to the Shop.
|
|
"""
|
|
room = extractor.parse(raw_mud_output)
|
|
assert room.name == "The Village Square"
|
|
assert room.exits == {"n": None, "e": None, "w": None}
|
|
assert "guard" in room.entities
|
|
```
|
|
|
|
|
|
### Test 2: Costruzione Grafo
|
|
|
|
```python
|
|
# Simula esplorazione: Square → North → Forest
|
|
graph = MUDGraph()
|
|
# ... aggiungi stanze ...
|
|
path = graph.find_path("square_123", "forest_456")
|
|
assert path == ["n"] # diretta, una sola mossa
|
|
```
|
|
|
|
|
|
### Test 3: Persistenza SQLite
|
|
|
|
```python
|
|
# Dopo 10 stanze esplorate
|
|
assert db.count_rooms() == 10
|
|
assert db.get_room("square_123").visit_count >= 1
|
|
```
|
|
|
|
|
|
### Test 4: Memvid Snapshot
|
|
|
|
```python
|
|
# Dopo sync, verifica che MP4 sia leggibile
|
|
archive = MemvidArchive("world_map.mp4")
|
|
results = archive.semantic_search("forest with dark trees")
|
|
assert len(results) > 0
|
|
assert "forest" in results.description.lower()
|
|
```
|
|
|
|
|
|
### Test 5: Auto-Explorer (Integration)
|
|
|
|
```python
|
|
# Simula 20 movimenti in un mondo di test
|
|
explorer = AutoExplorer(graph)
|
|
for _ in range(20):
|
|
move = explorer.decide_next_move(current_room)
|
|
# Simula risposta server
|
|
new_room = simulate_mud_response(move)
|
|
explorer.update_graph(move, new_room)
|
|
|
|
# Dovrebbe aver esplorato almeno 5 stanze uniche
|
|
assert len(graph.rooms) >= 5
|
|
```
|
|
|
|
|
|
## Considerazioni Tecniche
|
|
|
|
### Room ID Generation
|
|
|
|
Usare hash consistente (SHA256 truncato) di:
|
|
|
|
- Nome stanza normalizzato (lowercase, no color codes)
|
|
- Descrizione normalizzata (prime 100 char)
|
|
- Lista di exits disponibili (ordinata)
|
|
|
|
|
|
### Gestione Stanze Dinamiche
|
|
|
|
Alcuni MUD hanno stanze che cambiano (portali random, maze). Implementare:
|
|
|
|
- `is_dynamic`: flag se la stanza cambia tra visite
|
|
- `confidence`: score 0-1 sulla stabilità dell'ID
|
|
|
|
|
|
### Performance Targets
|
|
|
|
- Parsing stanza: < 50ms
|
|
- Query pathfinding: < 100ms per 1000 stanze
|
|
- Sync SQLite→Memvid: background, non bloccare < 500ms UI
|
|
|
|
|
|
### Dipendenze
|
|
|
|
```
|
|
# requirements.txt
|
|
networkx
|
|
sqlite3
|
|
numpy
|
|
sentence-transformers
|
|
pillow # QR generation
|
|
opencv-python # QR decoding
|
|
faiss-cpu # o faiss-gpu
|
|
```
|
|
|
|
|
|
## Checklist Implementazione
|
|
|
|
- [ ] Implementare `RoomExtractor` con regex MUD
|
|
- [ ] Implementare `MUDGraph` con NetworkX
|
|
- [ ] Setup schema SQLite
|
|
- [ ] Implementare `AutoExplorer` con BFS per exit non esplorati
|
|
- [ ] Implementare `MemvidArchive` encoding/decoding
|
|
- [ ] Implementare `SyncManager` con trigger automatico
|
|
- [ ] Scrivere test unitari per ogni modulo
|
|
- [ ] Scrivere test di integrazione con server MUD mock
|
|
- [ ] Documentazione API (docstring)
|
|
- [ ] Esempio di usage in `examples/basic_explorer.py`
|
|
|
|
|
|
## Note per l'Agente
|
|
|
|
1. **Inizia dal SQLite**: implementa prima il grafo in-memory + SQLite, il Memvid è un "nice to have" iniziale
|
|
2. **Mock del server**: crea un `MockMUDServer` che risponde con testo predefinito per i test
|
|
3. **Logging**: usa `logging` per tracciare ogni decisione dell'explorer (utile per debug)
|
|
4. **Configurazione**: usa `pydantic.BaseSettings` per parametri (sync_interval, embedding model, ecc.)
|
|
|
|
## Definizione di Completato
|
|
|
|
L'automapper è considerato completato quando:
|
|
|
|
1. ✅ Può esplorare autonomamente un mondo MUD di test con 50+ stanze
|
|
2. ✅ Costruisce un grafo navigabile con pathfinding funzionante
|
|
3. ✅ Persiste i dati in SQLite senza perdita di informazioni
|
|
4. ✅ Genera correttamente un archivio Memvid ricercabile
|
|
5. ✅ Tutti i test passano (`pytest tests/ -v`)
|
|
|
|
---
|
|
|
|
**Priorità**: Alta
|
|
|