CI / ruff · pytest (pull_request) Successful in 2m22s
- An acked crisis is not raised again for the same signal: re-raised only if a newer triggering scale exists (seen live: AUDIT-C 0/0/0 re-fired the acked PHQ-9 item 9 crisis). - In an open crisis every non-acute message gets a reply (agent for questions, support otherwise) plus emergency contacts; acute messages still get the fixed script. - Questions and medicine mentions without «?» are answered mid-questionnaire; free-text steps (check-in, side effects, question states) keep parsing their input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
3.7 KiB
Python
74 lines
3.7 KiB
Python
"""Questions are answered in any state (side answer): mid-scale the pending question comes back with its
|
||
buttons; in a crisis the answer carries the emergency contacts and the crisis stays open."""
|
||
|
||
from app.core import clock
|
||
from app.db import repo, session
|
||
from app.services.contracts import NoopMonitoring
|
||
from tests.test_dialog_knowledge import TOKEN, buttons, engine, joined, press, say, state # noqa: F401
|
||
|
||
|
||
class _InCrisis(NoopMonitoring):
|
||
async def is_in_crisis(self, token: str) -> bool: # an open acute alert, as RuleMonitoring would report
|
||
return True
|
||
|
||
|
||
async def test_question_mid_scale_is_answered_and_question_returns(engine): # noqa: F811
|
||
await press(engine, "menu:checkin") # some flow with buttons; then force a scale for determinism
|
||
async with session.get_clinical_session() as s:
|
||
await repo.set_dialog_state(s, token=TOKEN, state="idle", data={"consent": True}, now=clock.now())
|
||
from app.dialog.contracts import Event
|
||
|
||
first = await engine.handle(TOKEN, Event(type="system", system="scale_due", params={"scale": "phq9"}))
|
||
assert buttons(first), "scale question with buttons expected"
|
||
st_before, _ = await state()
|
||
replies = await say(engine, "Через сколько начнёт действовать лекарство?")
|
||
st_after, data = await state()
|
||
assert st_after == st_before # still inside the scale
|
||
assert "2–4 недели" in joined(replies) or "врач" in joined(replies).lower()
|
||
assert buttons(replies), "the pending question is shown again with its buttons"
|
||
assert "Вернёмся к вопросу" in joined(replies)
|
||
assert data.get("last_prompt")
|
||
|
||
|
||
async def test_question_in_crisis_gets_answer_and_contacts(engine): # noqa: F811
|
||
engine._monitoring = _InCrisis()
|
||
async with session.get_clinical_session() as s:
|
||
await repo.set_dialog_state(
|
||
s, token=TOKEN, state="crisis", data={"consent": True, "crisis": {"open": True}}, now=clock.now()
|
||
)
|
||
replies = await say(engine, "Через сколько начнёт действовать лекарство?")
|
||
st, _ = await state()
|
||
assert st == "crisis"
|
||
kinds = [r.kind for r in replies]
|
||
assert "crisis" in kinds and len(replies) >= 2
|
||
assert "112" in joined(replies)
|
||
|
||
|
||
async def test_non_question_mid_scale_still_goes_to_the_scale(engine): # noqa: F811
|
||
from app.dialog.contracts import Event
|
||
|
||
await engine.handle(TOKEN, Event(type="system", system="scale_due", params={"scale": "phq9"}))
|
||
replies = await say(engine, "ну так себе")
|
||
assert "Вернёмся к вопросу" not in joined(replies)
|
||
|
||
|
||
async def test_crisis_any_text_gets_a_reply_with_contacts(engine): # noqa: F811
|
||
engine._monitoring = _InCrisis()
|
||
async with session.get_clinical_session() as s:
|
||
await repo.set_dialog_state(
|
||
s, token=TOKEN, state="crisis", data={"consent": True, "crisis": {"open": True}}, now=clock.now()
|
||
)
|
||
for text in ("привет", "мне страшно", "что содержится в моих лекарствах"):
|
||
replies = await say(engine, text)
|
||
assert len(replies) >= 2, text
|
||
assert replies[-1].kind == "crisis" and "112" in joined(replies)
|
||
assert replies[0].kind != "crisis" # a real reply first, not only the stub
|
||
|
||
|
||
async def test_medicine_mention_without_question_mark_mid_scale(engine): # noqa: F811
|
||
from app.dialog.contracts import Event
|
||
|
||
await engine.handle(TOKEN, Event(type="system", system="scale_due", params={"scale": "phq9"}))
|
||
replies = await say(engine, "что содержится в моих лекарствах")
|
||
assert "Вернёмся к вопросу" in joined(replies) and buttons(replies)
|