refactor: remediation plan Fase 0-4 completata
- Fase 0: env var allineate, SYSTEM_PROMPT deduplicato, .gitignore pulito - Fase 1: GameContext isolato, ciclo DM unificato, provider thread-safe (contextvars) - Fase 2: DB schema esteso (current_area_id, combat_state, character_items) - Fase 3: thread-local connection pool + WAL + busy_timeout - Fase 4: test suite (32 test, 100% pass) - heuristic_fallback come parser di riserva (non secondo pilota)
This commit is contained in:
1 parent
90f823fdb9
commit
cb45172717
16 files changed
+906
-221
No files matched your search
+12
-44
@@ -1,62 +1,29 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import contextvars
|
||||
import json
|
||||
import re
|
||||
|
||||
from src.engine.config import load_from_env
|
||||
from src.engine.providers import LLMProvider, create_provider
|
||||
|
||||
DEFAULT_MODEL = "gemma2:9b"
|
||||
|
||||
_KNOWN_TOOLS = {
|
||||
"roll_dice": {"die": "str", "count": "int (default 1)", "modifier": "int (default 0)"},
|
||||
"dice_chain": {"die": "str", "steps": "int"},
|
||||
"combat": {"character_id": "int", "target_ac": "int", "attack_bonus": "int (default 0)",
|
||||
"damage_die": "str (default d8)", "damage_bonus": "int (default 0)",
|
||||
"mighty_deed_die": "str (default '')", "luck_mod": "int (default 0)",
|
||||
"armor_type": "str (none/light/medium/heavy)"},
|
||||
"ability_check": {"character_id": "int", "dc": "int", "modifier": "int (default 0)"},
|
||||
"saving_throw": {"character_id": "int", "save_type": "str (Tempra/Riflessi/Volontà)", "dc": "int", "modifier": "int (default 0)"},
|
||||
"movement": {"distance_m": "int", "terrain": "str (normale/difficile/molto difficile)", "stealth": "bool (default false)"},
|
||||
"spellcasting": {"character_id": "int", "spell_name": "str", "spell_check": "int", "dc": "int (default 12)"},
|
||||
"update_inventory": {"character_id": "int", "item": "str", "action": "str (add/remove)"},
|
||||
"award_xp": {"character_id": "int", "xp": "int"},
|
||||
"dm_override": {"command": "str", "params": "dict (opzionale)"},
|
||||
}
|
||||
|
||||
SYSTEM_PROMPT = f"""Sei il Dungeon Master di una partita di DCC RPG (Dungeon Crawl Classics).
|
||||
Il giocatore scrive un'azione e TU decidi quale strumento chiamare.
|
||||
|
||||
Strumenti disponibili:
|
||||
{json.dumps(_KNOWN_TOOLS, indent=2)}
|
||||
|
||||
Regole:
|
||||
1. Scegli SEMPRE UNO strumento per rispondere all'azione del giocatore.
|
||||
2. I parametri DEVONO essere realistici per il contesto.
|
||||
3. Se il giocatore fa qualcosa di narrativo, usa dm_override con command="narrate".
|
||||
4. Tira sempre i dadi quando il giocatore tenta un'azione rischiosa.
|
||||
5. Rispondi SOLO con JSON in questo formato:
|
||||
{{"tool": "nome_tool", "params": {{...}}, "narration": "breve descrizione di cosa succede"}}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
_provider: LLMProvider | None = None
|
||||
_provider_var: contextvars.ContextVar[LLMProvider | None] = contextvars.ContextVar("provider", default=None)
|
||||
|
||||
|
||||
def get_provider() -> LLMProvider:
|
||||
global _provider
|
||||
if _provider is None:
|
||||
_provider = create_provider(load_from_env())
|
||||
return _provider
|
||||
provider = _provider_var.get()
|
||||
if provider is None:
|
||||
from src.engine.config import load_from_env
|
||||
provider = create_provider(load_from_env())
|
||||
_provider_var.set(provider)
|
||||
return provider
|
||||
|
||||
|
||||
def set_provider(provider: LLMProvider) -> None:
|
||||
global _provider
|
||||
_provider = provider
|
||||
_provider_var.set(provider)
|
||||
|
||||
|
||||
def ask(prompt: str, system: str = SYSTEM_PROMPT) -> str:
|
||||
def ask(prompt: str, system: str = "") -> str:
|
||||
return get_provider().ask(prompt, system=system)
|
||||
|
||||
|
||||
@@ -100,10 +67,11 @@ if __name__ == "__main__":
|
||||
"Attacco l'orco con la mia ascia!",
|
||||
"Esploro il corridoio buio",
|
||||
]
|
||||
from src.engine.prompts import SYSTEM_PROMPT as _DM_PROMPT
|
||||
for a in test_actions:
|
||||
print(f"\n>>> Giocatore: {a}")
|
||||
try:
|
||||
resp = ask(a)
|
||||
resp = ask(a, system=_DM_PROMPT)
|
||||
print(f"LLM: {resp[:300]}")
|
||||
parsed = parse_tool_call(resp)
|
||||
print(f"Parser: {json.dumps(parsed, indent=2)}")
|
||||
|
||||
Reference in new issue
Block a user