"""The prompt editor: what it saves, what it refuses to save, and the preview.""" from __future__ import annotations import pytest from fastapi.testclient import TestClient from sqlalchemy import select from lembas.db.models import User from lembas.services import harness, prompts, settings_store from lembas.services.library import memories as memories_service @pytest.fixture def plain_user(client: TestClient, db, registered) -> User: """A second, non-admin account. Leaves the client signed in as them.""" client.post("/auth/logout", follow_redirects=False) client.post( "/auth/register", data={"name": "Sam", "email": "sam@shire.test", "password": "potatoes-po-ta-toes"}, follow_redirects=False, ) return db.scalar(select(User).where(User.email == "sam@shire.test")) def _owner(db) -> User: return db.scalar(select(User).where(User.email == "frodo@shire.test")) # --- Access ------------------------------------------------------------------ def test_the_page_lists_every_fragment(client: TestClient, registered): page = client.get("/admin/prompts").text for fragment in prompts.BUILTIN: assert f'name="prompt.{fragment.key}"' in page, fragment.key def test_the_page_is_refused_to_a_plain_user(client: TestClient, plain_user): assert client.get("/admin/prompts").status_code == 403 assert client.post("/admin/prompts", data={}).status_code == 403 # --- Saving ------------------------------------------------------------------ def test_saving_changes_what_a_model_is_told(client: TestClient, db, registered): client.post( "/admin/prompts", data={"prompt.tool.web_search": "- Always search twice.", "max_harness_chars": "0"}, follow_redirects=False, ) text = harness.compose(db, _owner(db), _tools("web_search")) assert "- Always search twice." in text assert "Look things up" not in text def test_a_cleared_box_turns_the_fragment_off(client: TestClient, db, registered): """The trap this page was written around: FastAPI cannot tell an empty form field from an absent one, so the handler reads the raw form.""" client.post( "/admin/prompts", data={"prompt.core.style": "", "max_harness_chars": "0"}, follow_redirects=False, ) assert prompts.stored(db) == {"core.style": ""} assert "Answer in the language" not in harness.compose(db, _owner(db), []) def test_a_fragment_not_submitted_at_all_is_left_alone(client: TestClient, db, registered): prompts.save(db, {"core.heading": "## Rules"}) client.post("/admin/prompts", data={"max_harness_chars": "0"}, follow_redirects=False) assert prompts.resolve(db, "core.heading") == "## Rules" def test_saving_the_built_in_wording_stores_nothing(client: TestClient, db, registered): """Opening the page and pressing Save must not freeze today's defaults, or a later release could never improve them.""" page_fields = {f"prompt.{f.key}": f.default for f in prompts.BUILTIN} client.post( "/admin/prompts", data={**page_fields, "max_harness_chars": "0"}, follow_redirects=False ) assert prompts.stored(db) == {} def test_the_character_cap_is_clamped_and_kept(client: TestClient, db, registered): client.post("/admin/prompts", data={"max_harness_chars": "-5"}, follow_redirects=False) assert settings_store.get(db, "max_harness_chars", key=settings_store.PROMPTS) == 0 client.post("/admin/prompts", data={"max_harness_chars": "600"}, follow_redirects=False) assert harness.limit_for(db) == 600 # --- Resetting --------------------------------------------------------------- def test_use_default_fills_the_box_without_saving(client: TestClient, db, registered): prompts.save(db, {"core.heading": "## Rules"}) response = client.post("/admin/prompts/default", data={"key": "core.heading"}) assert "## How to work" in response.text assert "edited" not in response.text # Nothing was written: it takes a Save to make it stick. assert prompts.resolve(db, "core.heading") == "## Rules" def test_use_default_on_an_unknown_key_is_a_404(client: TestClient, registered): assert client.post("/admin/prompts/default", data={"key": "nope.nope"}).status_code == 404 def test_restore_all_defaults_empties_the_overrides(client: TestClient, db, registered): prompts.save(db, {"core.heading": "## Rules", "core.style": ""}) client.post("/admin/prompts/reset", follow_redirects=False) assert prompts.stored(db) == {} # --- Preview ----------------------------------------------------------------- def test_the_preview_shows_text_that_has_not_been_saved(client: TestClient, db, registered): body = client.post( "/admin/prompts/preview", data={"prompt.core.heading": "## Draft heading", "preview_family": ["web_search"]}, ).text assert "## Draft heading" in body assert prompts.stored(db) == {} def test_the_preview_only_shows_guidance_for_the_families_ticked(client: TestClient, registered): body = client.post("/admin/prompts/preview", data={"preview_family": ["notes"]}).text assert "You keep notes" in body assert "Look things up" not in body def test_the_preview_escapes_what_a_model_wrote(client: TestClient, db, registered): """A memory is model-written text on an admin page. Hard rule 6 applies to the preview exactly as it does to a chat bubble.""" memories_service.add(db, owner=_owner(db), content="") body = client.post("/admin/prompts/preview", data={"preview_family": ["memory"]}).text assert "