"""What a folder carries, and what the chats inside it inherit from it.""" from __future__ import annotations from fastapi.testclient import TestClient from sqlalchemy import select from lembas.db.models import Chat, Connection, Folder, Model, SshProfile, User from lembas.services import chat as chat_service from lembas.services import settings_store from lembas.services.crypto import encrypt def _add_connection(db) -> Connection: connection = Connection( name="Test", base_url="http://127.0.0.1:1", api_key_encrypted=encrypt("") ) db.add(connection) db.commit() db.add(Model(connection_id=connection.id, model_id="test-model")) db.commit() return connection def _folder(db, name: str, parent: Folder | None = None, **fields) -> Folder: user = db.scalars(select(User).order_by(User.created_at)).first() folder = Folder( user_id=user.id, name=name, parent_id=parent.id if parent else None, **fields ) db.add(folder) db.commit() return folder # --- Naming and renaming ------------------------------------------------------- def test_a_folder_is_created_with_the_name_that_was_asked_for( client: TestClient, db, registered ): client.post("/api/folders", data={"name": "Isengard"}) assert db.scalar(select(Folder)).name == "Isengard" def test_a_folder_with_no_name_still_gets_one(client: TestClient, db, registered): """The button asks first, but a request that arrives without one must not produce a folder with a blank label nobody can click.""" client.post("/api/folders", data={}) assert db.scalar(select(Folder)).name == "New folder" def test_renaming_a_folder(client: TestClient, db, registered): """PATCH has been able to do this since folders existed and nothing in the interface called it, so a folder could not be renamed at all.""" folder = _folder(db, "Isengard") assert client.patch(f"/api/folders/{folder.id}", data={"name": "Orthanc"}).status_code == 204 db.refresh(folder) assert folder.name == "Orthanc" def test_a_blank_rename_is_ignored(client: TestClient, db, registered): """A folder nobody can see the name of is one nobody can find.""" folder = _folder(db, "Isengard") client.patch(f"/api/folders/{folder.id}", data={"name": " "}) db.refresh(folder) assert folder.name == "Isengard" # --- The system prompt ladder --------------------------------------------------- def test_a_folder_prompt_reaches_a_chat_inside_it(client: TestClient, db, registered, make_chat): _add_connection(db) folder = _folder(db, "Errands", system_prompt="Answer in the fewest words.") chat = db.get(Chat, make_chat()) chat.folder_id = folder.id db.commit() assert chat_service.effective_system_prompt(db, chat) == "Answer in the fewest words." def test_a_nested_folder_inherits_its_parents_prompt( client: TestClient, db, registered, make_chat ): """A project's prompt belongs on the project, not on each sub-folder of it.""" _add_connection(db) top = _folder(db, "Project", system_prompt="Answer in the fewest words.") inner = _folder(db, "Notes", parent=top) chat = db.get(Chat, make_chat()) chat.folder_id = inner.id db.commit() assert chat_service.effective_system_prompt(db, chat) == "Answer in the fewest words." def test_the_nearest_folder_prompt_wins(client: TestClient, db, registered, make_chat): _add_connection(db) top = _folder(db, "Project", system_prompt="From the top.") inner = _folder(db, "Notes", parent=top, system_prompt="From the sub-folder.") chat = db.get(Chat, make_chat()) chat.folder_id = inner.id db.commit() assert chat_service.effective_system_prompt(db, chat) == "From the sub-folder." def test_the_chats_own_prompt_still_wins(client: TestClient, db, registered, make_chat): _add_connection(db) folder = _folder(db, "Errands", system_prompt="From the folder.") chat = db.get(Chat, make_chat()) chat.folder_id = folder.id chat.system_prompt = "From the chat." db.commit() assert chat_service.effective_system_prompt(db, chat) == "From the chat." def test_a_folder_prompt_beats_the_models(client: TestClient, db, registered, make_chat): """The folder is the more specific statement: a model's prompt describes the model wherever it is used, a folder's describes this piece of work.""" _add_connection(db) model = db.scalar(select(Model)) model.system_prompt = "From the model." folder = _folder(db, "Errands", system_prompt="From the folder.") chat = db.get(Chat, make_chat()) chat.folder_id = folder.id db.commit() assert chat_service.effective_system_prompt(db, chat) == "From the folder." def test_an_empty_folder_prompt_falls_through(client: TestClient, db, registered, make_chat): _add_connection(db) model = db.scalar(select(Model)) model.system_prompt = "From the model." folder = _folder(db, "Errands") chat = db.get(Chat, make_chat()) chat.folder_id = folder.id db.commit() assert chat_service.effective_system_prompt(db, chat) == "From the model." def test_the_panel_names_the_folder_as_the_source(client: TestClient, db, registered, make_chat): """The settings panel mirrors the ladder and has to keep mirroring it. One naming the wrong source is worse than one naming none, because it is believed.""" _add_connection(db) folder = _folder(db, "Errands", system_prompt="Answer in the fewest words.") chat_id = make_chat() chat = db.get(Chat, chat_id) chat.folder_id = folder.id db.commit() page = client.get(f"/chat/{chat_id}").text assert "folder prompt" in page or "the folder" in page # --- Seeds ---------------------------------------------------------------------- def test_a_folder_seeds_a_new_chats_model(client: TestClient, db, registered): _add_connection(db) db.add(Model(connection_id=db.scalar(select(Connection)).id, model_id="other-model")) db.commit() folder = _folder(db, "Errands", model_id="other-model") client.post("/api/chats/start", data={"content": "Hello", "folder_id": folder.id}) chat = db.scalar(select(Chat)) assert chat.model_id == "other-model" def test_an_explicit_choice_beats_the_folders_seed(client: TestClient, db, registered): """The folder says what this work usually needs; the screen in front of somebody says what they want this time.""" _add_connection(db) db.add(Model(connection_id=db.scalar(select(Connection)).id, model_id="other-model")) db.commit() folder = _folder(db, "Errands", model_id="other-model") client.post( "/api/chats/start", data={"content": "Hello", "folder_id": folder.id, "model_id": "test-model"}, ) assert db.scalar(select(Chat)).model_id == "test-model" def test_a_folder_belonging_to_someone_else_seeds_nothing(client: TestClient, db, registered): _add_connection(db) other = User(name="Sam", email="sam@shire.test", password_hash="x") db.add(other) db.commit() folder = Folder(user_id=other.id, name="Theirs", model_id="other-model") db.add(folder) db.commit() client.post("/api/chats/start", data={"content": "Hello", "folder_id": folder.id}) chat = db.scalar(select(Chat)) assert chat.model_id == "test-model" def test_a_deleted_connection_on_a_folder_does_not_raise(client: TestClient, db, registered): """`ssh_profile_id` is a plain string, not a foreign key, so it can outlive the profile it names. It is validated on read instead.""" _add_connection(db) settings_store.update(db, {"enabled": True}, key=settings_store.AGENTS) folder = _folder(db, "Errands", kind="agent", ssh_profile_id="gone") response = client.post( "/api/chats/start", data={"content": "Hello", "folder_id": folder.id} ) assert response.status_code == 204 # No profile means no agent chat: `_agent_target` refuses rather than # creating one pointed at nothing. assert db.scalar(select(Chat)).kind == "chat" def test_the_seeds_are_saved_and_cleared_through_one_route(client: TestClient, db, registered): """Every field clearable, which is what reading the raw form buys: with `Form(None)` an empty box and an absent one are the same request.""" folder = _folder(db, "Errands") client.patch( f"/api/folders/{folder.id}", data={ "description": "Work on the tower.", "system_prompt": "Answer in the fewest words.", "model_id": "test-model", "kind": "agent", }, ) db.refresh(folder) assert folder.description == "Work on the tower." assert folder.system_prompt == "Answer in the fewest words." assert folder.kind == "agent" client.patch(f"/api/folders/{folder.id}", data={"system_prompt": "", "kind": ""}) db.refresh(folder) assert folder.system_prompt == "" assert folder.kind == "" # Untouched keys are left alone rather than blanked. assert folder.description == "Work on the tower." def test_a_kind_that_is_not_a_kind_is_dropped(client: TestClient, db, registered): """A folder seeding a kind that is not a kind hands every chat a value `_new_chat` then has to ignore anyway.""" folder = _folder(db, "Errands") client.patch(f"/api/folders/{folder.id}", data={"kind": "wizard", "agent_mode": "reckless"}) db.refresh(folder) assert folder.kind == "" assert folder.agent_mode == "" # --- Getting into a folder at all ----------------------------------------------- def test_new_chat_here_files_the_chat(client: TestClient, db, registered): """`/api/chats/start` has accepted a folder_id since folders existed and nothing ever sent one.""" _add_connection(db) folder = _folder(db, "Errands") page = client.get(f"/chat?folder={folder.id}").text assert f'name="folder_id" value="{folder.id}"' in page client.post("/api/chats/start", data={"content": "Hello", "folder_id": folder.id}) assert db.scalar(select(Chat)).folder_id == folder.id def test_a_folder_fixed_to_agent_opens_the_new_chat_screen_on_that_fork( client: TestClient, db, registered ): _add_connection(db) settings_store.update(db, {"enabled": True}, key=settings_store.AGENTS) db.add( SshProfile( owner_id=db.scalars(select(User).order_by(User.created_at)).first().id, name="Box", host="example.test", username="root", host_key="ssh-ed25519 AAAA", ) ) db.commit() folder = _folder(db, "Errands", kind="agent") page = client.get(f"/chat?folder={folder.id}").text assert 'name="kind" value="agent"' in page # --- The settings page ---------------------------------------------------------- def test_the_settings_page_renders_what_is_stored(client: TestClient, db, registered): _add_connection(db) folder = _folder(db, "Errands", system_prompt="Answer in the fewest words.") page = client.get(f"/folders/{folder.id}").text assert "Answer in the fewest words." in page assert f'hx-patch="/api/folders/{folder.id}"' in page def test_the_settings_page_refuses_someone_elses_folder(client: TestClient, db, registered): other = User(name="Sam", email="sam@shire.test", password_hash="x") db.add(other) db.commit() folder = Folder(user_id=other.id, name="Theirs") db.add(folder) db.commit() assert client.get(f"/folders/{folder.id}").status_code == 404 def test_the_settings_form_posts_at_a_route_that_serves_patch( client: TestClient, db, registered ): """A control wired to a method its route does not serve fails silently -- htmx surfaces nothing, so it looks exactly like a control that works.""" folder = _folder(db, "Errands") assert client.post(f"/api/folders/{folder.id}", data={"name": "x"}).status_code == 405 assert client.patch(f"/api/folders/{folder.id}", data={"name": "x"}).status_code == 204