Files
PTSRaiAgent/tests/test_dialog_side_answer.py
T
ElebobaandClaude Opus 5.5 dd67905626
CI / ruff · pytest (pull_request) Successful in 2m22s
fix: chat replies in any situation — no false crisis re-fire, answers in crisis, medicine questions anywhere
- 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>
2026-10-04 18:23:03 +03:00

74 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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)