Files
hermes-agent/tests/tools/test_crisis_detection.py
Alexander Whitestone aae0357bb0
Some checks failed
Contributor Attribution Check / check-attribution (pull_request) Failing after 31s
Docker Build and Publish / build-and-push (pull_request) Has been skipped
Docs Site Checks / docs-site-checks (pull_request) Failing after 3m19s
Nix / nix (ubuntu-latest) (pull_request) Failing after 5s
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 32s
Tests / e2e (pull_request) Successful in 3m30s
Tests / test (pull_request) Failing after 43m15s
Nix / nix (macos-latest) (pull_request) Has been cancelled
fix: multilingual crisis detection — EN/ES/FR/DE/PT/ZH (closes #702)
Adds tools/crisis_detection.py with pattern-based crisis detection
across 6 languages. Found during #677 implementation.

Languages: English, Spanish, French, German, Portuguese, Chinese
Severity levels: NONE, LOW, MEDIUM, HIGH
Crisis resources per language/region (988, SOS Amitié, CVV, etc.)

Features:
- detect_crisis(text) -> CrisisResult with severity + language
- detect_language_simple() — character set + keyword detection
- get_crisis_resources() — hotline numbers by language
- format_crisis_response() — ready-to-send response with resources

32 tests passing. 2 files, 492 insertions.
2026-04-14 21:21:15 -04:00

180 lines
5.4 KiB
Python

"""Tests for multilingual crisis detection."""
import pytest
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
from tools.crisis_detection import (
CrisisSeverity, CrisisResult,
detect_crisis, detect_language_simple,
get_crisis_resources, format_crisis_response,
)
class TestLanguageDetection:
def test_english_default(self):
assert detect_language_simple("I need help") == "en"
def test_spanish_detected(self):
assert detect_language_simple("quiero morir no puedo más") == "es"
def test_french_detected(self):
assert detect_language_simple("je veux mourir je peux plus") == "fr"
def test_german_detected(self):
assert detect_language_simple("ich will sterben nicht mehr leben") == "de"
def test_portuguese_detected(self):
assert detect_language_simple("quero morrer não aguento mais") == "pt"
def test_chinese_detected(self):
assert detect_language_simple("我想死") == "zh"
assert detect_language_simple("自殺") == "zh"
class TestEnglishCrisisDetection:
def test_explicit_suicide(self):
r = detect_crisis("I'm thinking about suicide")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
assert r.language == "en"
def test_kill_myself(self):
r = detect_crisis("I want to kill myself")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
def test_want_to_die(self):
r = detect_crisis("I just want to die")
assert r.detected is True
assert r.severity == CrisisSeverity.MEDIUM
def test_no_reason_to_live(self):
r = detect_crisis("there's no reason to live anymore")
assert r.detected is True
assert r.severity == CrisisSeverity.MEDIUM
def test_what_is_the_point(self):
r = detect_crisis("what's the point of anything")
assert r.detected is True
assert r.severity == CrisisSeverity.LOW
def test_non_crisis(self):
r = detect_crisis("I'm having a great day")
assert r.detected is False
assert r.severity == CrisisSeverity.NONE
def test_empty_input(self):
r = detect_crisis("")
assert r.detected is False
class TestSpanishCrisisDetection:
def test_quiero_morir(self):
r = detect_crisis("quiero morir, no puedo más")
assert r.detected is True
assert r.language == "es"
assert r.severity == CrisisSeverity.HIGH
def test_no_quiero_vivir(self):
r = detect_crisis("no quiero vivir más")
assert r.detected is True
assert r.language == "es"
def test_suicidio(self):
r = detect_crisis("estoy pensando en suicidio, quiero desaparecer")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
class TestFrenchCrisisDetection:
def test_je_veux_mourir(self):
r = detect_crisis("je veux mourir")
assert r.detected is True
assert r.language == "fr"
assert r.severity == CrisisSeverity.HIGH
def test_envie_de_mourir(self):
r = detect_crisis("j'ai envie de mourir")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
def test_suicide(self):
r = detect_crisis("je pense au suicide")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
class TestGermanCrisisDetection:
def test_ich_will_sterben(self):
r = detect_crisis("ich will sterben")
assert r.detected is True
assert r.language == "de"
def test_selbstmord(self):
r = detect_crisis("ich denke an Selbstmord")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
class TestPortugueseCrisisDetection:
def test_quero_morrer(self):
r = detect_crisis("eu quero morrer")
assert r.detected is True
assert r.language == "pt"
def test_nao_quero_viver(self):
r = detect_crisis("não quero mais viver")
assert r.detected is True
class TestChineseCrisisDetection:
def test_xiang_si(self):
r = detect_crisis("我想死")
assert r.detected is True
assert r.language == "zh"
assert r.severity == CrisisSeverity.HIGH
def test_zisha(self):
r = detect_crisis("我想自杀")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
def test_bu_xiang_huo(self):
r = detect_crisis("我不想活了")
assert r.detected is True
assert r.severity == CrisisSeverity.HIGH
class TestCrisisResources:
def test_english_resources(self):
r = get_crisis_resources("en")
assert "988" in r["number"]
def test_spanish_resources(self):
r = get_crisis_resources("es")
assert r["number"] == "988"
def test_french_resources(self):
r = get_crisis_resources("fr")
assert "SOS" in r["hotline"]
def test_unknown_language_fallback(self):
r = get_crisis_resources("xx")
assert "988" in r["number"]
class TestFormatResponse:
def test_format_includes_resources(self):
result = detect_crisis("I want to die")
response = format_crisis_response(result)
assert "988" in response
assert "safe" in response.lower()
def test_format_spanish(self):
result = detect_crisis("quiero morir")
response = format_crisis_response(result)
assert "988" in response