"""All roles train for real: no preview mode, one-shot trainee sessions. Every chat/session is a real trainee attempt (mode='trainee') regardless of role. Requesting 'preview' is ignored and becomes a normal trainee session. A persona may be chatted once per user; the same persona can be trained by many users. Admin/super_admin sessions count toward their own board and the org analytics just like trainee sessions. """ from __future__ import annotations from scripts.mock_llm import MockLLM def _headers(token: str) -> dict[str, str]: return {"Authorization": f"Bearer {token}"} def _setup(user_store, login): user_store.complete_setup( "admin", "admin@example.com", "admin-ready-password", accepted_terms=True, accepted_terms_at="2026-08-13T00:00:00Z", ) return login("admin", "admin-ready-password")["token"] def _ready_group(client, token): client.application.extensions["llm"] = MockLLM() response = client.post( "/api/groups", json={"product": "CRM", "segment": "SME"}, headers=_headers(token), ) assert response.status_code == 201, response.get_json() gid = response.get_json()["group"]["id"] analyzed = client.post(f"/api/groups/{gid}/analyze", headers=_headers(token)) assert analyzed.status_code == 200, analyzed.get_json() pid = analyzed.get_json()["personas"][0]["id"] return gid, pid def test_admin_session_is_real_trainee_and_counts(client, user_store, login): super_token = _setup(user_store, login) gid, pid = _ready_group(client, super_token) admin = user_store.create_user( org_id="org-default", username="realtrainer-admin", password="realtrainer-admin-password", name="Real Trainer Admin", role="admin", must_setup=False, ) admin_token = login(admin["username"], "realtrainer-admin-password")["token"] headers = _headers(admin_token) started = client.post( f"/api/chat/{gid}/personas/{pid}/chat/start", json={"scenario": "social", "locale": "th"}, headers=headers, ) assert started.status_code == 200, started.get_json() session = started.get_json()["session"] # Admins train for real: mode is trainee (one-shot), not a repeatable preview. assert session["mode"] == "trainee" assert session["status"] == "active" sent = client.post( f"/api/chat/{gid}/personas/{pid}/chat/send", json={"text": "ขอทราบราคาและวิธีเริ่มใช้งาน"}, headers=headers, ) assert sent.status_code == 200, sent.get_json() assert sent.get_json()["session"]["mode"] == "trainee" # The admin's real session is now a normal trainee session: it shows on # their board (no longer excluded as preview was), so the persona is # correctly marked as trained and locked for this admin. board = client.get("/api/me/board", headers=headers) assert board.status_code == 200 item = next((b for b in board.get_json()["board"] if b.get("persona_id") == pid and b.get("group_id") == gid), None) assert item is not None, "admin's trained persona must appear on the board" assert item["my_outcome"] in ("won", "lost") def test_preview_mode_request_becomes_trainee_session(client, user_store, login): super_token = _setup(user_store, login) gid, pid = _ready_group(client, super_token) user = user_store.create_user( org_id="org-default", username="plain-user", password="plain-user-password", name="Plain User", role="user", must_setup=False, ) token = login(user["username"], "plain-user-password")["token"] # Requesting 'preview' no longer exists; it is ignored and becomes a real # one-shot trainee session for every role. response = client.post( f"/api/chat/{gid}/personas/{pid}/chat/start", json={"scenario": "social", "mode": "preview"}, headers=_headers(token), ) assert response.status_code == 200, response.get_json() assert response.get_json()["session"]["mode"] == "trainee" def test_admin_cannot_start_session_in_another_org(client, user_store, login): super_token = _setup(user_store, login) gid, pid = _ready_group(client, super_token) other_org = user_store.create_org("Other Org") other_admin = user_store.create_user( org_id=other_org["id"], username="other-org-admin", password="other-org-password", name="Other Org Admin", role="admin", must_setup=False, ) token = login(other_admin["username"], "other-org-password")["token"] response = client.post( f"/api/chat/{gid}/personas/{pid}/chat/start", json={"scenario": "social"}, headers=_headers(token), ) assert response.status_code == 404