| from __future__ import annotations |
|
|
| from sqlalchemy import select |
|
|
| from app.models import ChatSession, Event, Tenant |
| from app.tenancy import generate_dashboard_token |
| from app.tools import knowledge_tool |
| from app.tools.registry import ToolContext |
|
|
|
|
| async def _ctx(db, tenant_id): |
| s = ChatSession(shop="x", tenant_id=tenant_id) |
| db.add(s) |
| await db.flush() |
| return ToolContext(db=db, session=s, tenant_id=tenant_id) |
|
|
|
|
| async def test_unanswered_question_is_logged(db_session): |
| t = Tenant(slug="kx") |
| db_session.add(t) |
| await db_session.flush() |
| ctx = await _ctx(db_session, t.id) |
|
|
| out = await knowledge_tool.run({"query": "¿cuánto pesa el modelo XZ?"}, ctx) |
| assert out["note"] == "no relevant information found" |
| assert "NO la inventes" in out["hint"] |
|
|
| rows = (await db_session.execute( |
| select(Event).where(Event.type == "unresolved") |
| )).scalars().all() |
| assert len(rows) == 1 |
| assert rows[0].tenant_id == t.id |
| assert "XZ" in rows[0].meta["q"] |
|
|
|
|
| async def test_portal_lists_unresolved_scoped(app_client, db_session): |
| _app, client = app_client |
| a = Tenant(slug="ua") |
| b = Tenant(slug="ub") |
| db_session.add_all([a, b]) |
| await db_session.flush() |
| a_tok = await generate_dashboard_token(db_session, a) |
| |
| await knowledge_tool.run({"query": "pregunta de A"}, await _ctx(db_session, a.id)) |
| await knowledge_tool.run({"query": "pregunta de B"}, await _ctx(db_session, b.id)) |
| await db_session.commit() |
|
|
| rows = (await client.get( |
| "/portal/api/unresolved", headers={"Authorization": "Bearer " + a_tok} |
| )).json() |
| assert len(rows) == 1 |
| assert "A" in rows[0]["q"] |
|
|
|
|
| def test_portal_ui_has_unresolved_section(): |
| from pathlib import Path |
|
|
| html = ( |
| Path(__file__).resolve().parent.parent / "app" / "portal_ui" / "index.html" |
| ).read_text() |
| assert "loadUnresolved" in html |
| assert "/portal/api/unresolved" in html |
|
|