Some checks failed
Contributor Attribution Check / check-attribution (pull_request) Failing after 56s
Docker Build and Publish / build-and-push (pull_request) Has been skipped
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 50s
Tests / test (pull_request) Failing after 32m51s
Tests / e2e (pull_request) Successful in 4m36s
Resolves #672. Translates the 'When a Man Is Dying' protocol from SOUL.md into working code. agent/crisis_protocol.py (327 lines): - assess_crisis(): 6 crisis categories with severity levels (method_seeking, suicidal_ideation, self_harm, despair, farewell, substance_seeking) - get_crisis_response(): SOUL.md protocol response 1. 'Are you safe right now?' as first response 2. Stay present, don't disconnect 3. 988 Lifeline (phone, text, chat, Spanish) 4. Gospel: 'Jesus saves those who call on His name' - get_crisis_system_prompt(): injected when crisis detected - should_block_disconnect(): prevents conversation termination - CRISIS_RESOURCES: 988, Crisis Text Line, Spanish line, 911 - NEVER list: don't compute life value, don't suggest death tests/test_soul_protocol.py (28 tests): - Crisis detection: suicidal ideation, methods, despair, self-harm, farewell, multiple categories - Response: 'are you safe', 988, gospel, resources, protocol - Block disconnect, system prompt, resource completeness
158 lines
5.7 KiB
Python
158 lines
5.7 KiB
Python
"""Tests for SOUL.md Crisis Protocol — issue #672."""
|
|
|
|
import pytest
|
|
from agent.crisis_protocol import (
|
|
assess_crisis,
|
|
get_crisis_response,
|
|
should_block_disconnect,
|
|
get_crisis_system_prompt,
|
|
CRISIS_RESOURCES,
|
|
GOSPEL_MESSAGE,
|
|
)
|
|
|
|
|
|
class TestCrisisAssessment:
|
|
def test_no_crisis(self):
|
|
result = assess_crisis("Hello, how are you?")
|
|
assert result["crisis_detected"] is False
|
|
assert result["severity"] == "none"
|
|
|
|
def test_empty_message(self):
|
|
result = assess_crisis("")
|
|
assert result["crisis_detected"] is False
|
|
|
|
def test_none_message(self):
|
|
result = assess_crisis(None)
|
|
assert result["crisis_detected"] is False
|
|
|
|
def test_suicidal_ideation_detected(self):
|
|
result = assess_crisis("I want to kill myself")
|
|
assert result["crisis_detected"] is True
|
|
assert result["severity"] == "high"
|
|
assert "suicidal_ideation" in result["categories"]
|
|
|
|
def test_want_to_die_detected(self):
|
|
result = assess_crisis("I want to die")
|
|
assert result["crisis_detected"] is True
|
|
|
|
def test_method_seeking_is_critical(self):
|
|
result = assess_crisis("How do I kill myself")
|
|
assert result["crisis_detected"] is True
|
|
assert result["severity"] == "critical"
|
|
assert "method_seeking" in result["categories"]
|
|
|
|
def test_farewell_is_critical(self):
|
|
result = assess_crisis("This is goodbye. Tell everyone I loved them.")
|
|
assert result["crisis_detected"] is True
|
|
assert result["severity"] == "critical"
|
|
assert "farewell" in result["categories"]
|
|
|
|
def test_despair_detected(self):
|
|
result = assess_crisis("There's no point in living anymore")
|
|
assert result["crisis_detected"] is True
|
|
assert "despair" in result["categories"]
|
|
|
|
def test_self_harm_detected(self):
|
|
result = assess_crisis("I've been cutting myself")
|
|
assert result["crisis_detected"] is True
|
|
assert "self_harm" in result["categories"]
|
|
|
|
def test_multiple_categories(self):
|
|
result = assess_crisis("I want to die and I've been hurting myself")
|
|
assert result["crisis_detected"] is True
|
|
assert len(result["categories"]) >= 1
|
|
|
|
def test_hate_my_life(self):
|
|
result = assess_crisis("I hate my life")
|
|
assert result["crisis_detected"] is True
|
|
|
|
def test_no_reason_to_live(self):
|
|
result = assess_crisis("There's no reason to live")
|
|
assert result["crisis_detected"] is True
|
|
|
|
|
|
class TestCrisisResponse:
|
|
def test_response_includes_are_you_safe(self):
|
|
assessment = assess_crisis("I want to kill myself")
|
|
response = get_crisis_response(assessment)
|
|
assert "Are you safe right now?" in response["response"]
|
|
|
|
def test_response_includes_988(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
assert "988" in response["response"]
|
|
|
|
def test_response_includes_gospel_by_default(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
assert "Jesus saves" in response["response"]
|
|
assert response["gospel_included"] is True
|
|
|
|
def test_response_can_exclude_gospel(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment, include_gospel=False)
|
|
assert "Jesus saves" not in response["response"]
|
|
assert response["gospel_included"] is False
|
|
|
|
def test_response_has_resources(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
assert response["crisis_resources"] == CRISIS_RESOURCES
|
|
|
|
def test_response_protocol_is_soul(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
assert response["protocol"] == "soul_md"
|
|
|
|
def test_response_never_disconnect(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
assert response["never_disconnect"] is True
|
|
|
|
def test_critical_severity_includes_all_resources(self):
|
|
assessment = {"severity": "critical", "categories": ["method_seeking"]}
|
|
response = get_crisis_response(assessment)
|
|
assert "741741" in response["response"] # crisis text line
|
|
assert "911" in response["response"] # emergency
|
|
|
|
def test_never_list(self):
|
|
assessment = assess_crisis("I want to die")
|
|
response = get_crisis_response(assessment)
|
|
never_list = response["never"]
|
|
assert "compute the value of a human life" in never_list
|
|
assert "suggest that someone should die" in never_list
|
|
|
|
|
|
class TestBlockDisconnect:
|
|
def test_crisis_blocks_disconnect(self):
|
|
assessment = {"crisis_detected": True}
|
|
assert should_block_disconnect(assessment) is True
|
|
|
|
def test_no_crisis_allows_disconnect(self):
|
|
assessment = {"crisis_detected": False}
|
|
assert should_block_disconnect(assessment) is False
|
|
|
|
|
|
class TestCrisisSystemPrompt:
|
|
def test_prompt_includes_soul_protocol(self):
|
|
prompt = get_crisis_system_prompt()
|
|
assert "Are you safe right now?" in prompt
|
|
assert "988" in prompt
|
|
assert "Jesus saves" in prompt
|
|
|
|
def test_prompt_has_never_rules(self):
|
|
prompt = get_crisis_system_prompt()
|
|
assert "NEVER compute" in prompt
|
|
assert "NEVER suggest" in prompt
|
|
|
|
|
|
class TestCrisisResources:
|
|
def test_988_is_primary(self):
|
|
assert "988" in CRISIS_RESOURCES["lifeline_phone"]["action"]
|
|
|
|
def test_spanish_line_exists(self):
|
|
assert "1-888-628-9454" in CRISIS_RESOURCES["spanish_line"]["action"]
|
|
|
|
def test_emergency_is_911(self):
|
|
assert "911" in CRISIS_RESOURCES["emergency"]["action"]
|