"""Couche outils IA (voir plan Phase 1, §4 — ai/tools.py) : chaque dispatch doit appeler DIRECTEMENT la fonction screens.*/db.* existante (jamais une structure parallèle), et les schémas doivent suivre les constantes SOURCE plutôt qu'une copie littérale (principe validé avec l'utilisateur : une nouvelle valeur d'énum doit suivre automatiquement).""" import ai import auth import db import screens from ai.tools import TOOLS, dispatch_tool def _tool(name): return next(t for t in TOOLS if t["name"] == name) def _create_jeu2d_game(client, tmp_game_slug_cleanup, name="pytest_ai_tools"): resp = client.post("/games/new", data={"name": name}, follow_redirects=False) slug = tmp_game_slug_cleanup(resp.headers["Location"].rstrip("/").split("/")[-1]) screen_id = screens.create_screen(slug, "Scène 1", kind="jeu_2d") return slug, screen_id def test_dispatch_add_scene_object_calls_the_real_function(client, tmp_game_slug_cleanup): slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup) result = dispatch_tool(slug, screen_id, 1, "add_scene_object", {"kind": "decor", "image_url": "/assets/1/x.png"}) obj = screens.get_scene_object(slug, result["object_id"]) assert obj["kind"] == "decor" assert obj["attributes"]["src"] == "/assets/1/x.png" def test_dispatch_add_scene_object_with_background_slug_uses_the_library_image(client, tmp_game_slug_cleanup): slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup) with client.session_transaction() as sess: admin_id = sess["user_id"] bg_slug = next(iter(screens.BACKGROUND_LIBRARY)) result = dispatch_tool(slug, screen_id, admin_id, "add_scene_object", {"kind": "fond", "background_slug": bg_slug}) obj = screens.get_scene_object(slug, result["object_id"]) assert obj["attributes"]["src"] == screens.BACKGROUND_LIBRARY[bg_slug]["url"] def test_dispatch_add_scene_object_raises_for_an_unknown_background_slug(client, tmp_game_slug_cleanup): """Bug corrigé : un slug inventé/mal orthographié par Claude était ignoré en silence (screens.add_scene_object, pensé pour un