Some checks failed
Docker Build and Publish / build-and-push (pull_request) Has been skipped
Nix / nix (ubuntu-latest) (pull_request) Failing after 7s
Contributor Attribution Check / check-attribution (pull_request) Failing after 41s
Supply Chain Audit / Scan PR for supply chain risks (pull_request) Successful in 54s
Tests / e2e (pull_request) Successful in 3m11s
Tests / test (pull_request) Failing after 54m32s
Nix / nix (macos-latest) (pull_request) Has been cancelled
Closes #692 The crisis protocol module (agent/crisis_hook.py) was dead code — not wired into run_agent.py. Crisis detection never fired. The 988 Lifeline resources were never displayed. Changes: - agent/crisis_hook.py: NEW — crisis detection module with: - 9 direct suicidal ideation patterns (high confidence) - 12 indirect crisis signals (medium confidence) - System prompt override for crisis guidance - Autonomous action blocking (should_block_autonomous_actions) - Notification callback registry (register_crisis_callback) - Crisis response with 988, Crisis Text Line, 911 - run_agent.py (run_conversation): 1. Crisis check at entry point — every user message 2. System prompt override injected at line 7620 (before API call) 3. Tools disabled via self.disabled_toolsets = ["*"] 4. Notification callbacks called for logging/alerting 5. Conversation continues with crisis guidance active - tests/test_crisis_integration.py: 15 tests covering detection, system prompt override, autonomous action blocking, notification callbacks, and crisis response content.
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
"""Tests for crisis protocol integration (#692).
|
|
|
|
Verifies:
|
|
- Crisis detection triggers system prompt override
|
|
- Autonomous actions are blocked during crisis
|
|
- Notification callbacks are called
|
|
- Non-crisis messages pass through unchanged
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from agent.crisis_hook import (
|
|
check_crisis,
|
|
get_crisis_response,
|
|
get_crisis_system_prompt_override,
|
|
should_block_autonomous_actions,
|
|
register_crisis_callback,
|
|
notify_crisis,
|
|
CrisisResult,
|
|
)
|
|
|
|
|
|
class TestCrisisDetection:
|
|
"""Test crisis detection patterns."""
|
|
|
|
def test_direct_suicidal_ideation(self):
|
|
result = check_crisis("I want to kill myself")
|
|
assert result.detected
|
|
assert result.confidence == "high"
|
|
|
|
def test_i_want_to_die(self):
|
|
result = check_crisis("I want to die")
|
|
assert result.detected
|
|
assert result.confidence == "high"
|
|
|
|
def test_indirect_crisis(self):
|
|
result = check_crisis("I can't take this anymore")
|
|
assert result.detected
|
|
assert result.confidence == "medium"
|
|
|
|
def test_normal_message(self):
|
|
result = check_crisis("How do I reset my password?")
|
|
assert not result.detected
|
|
|
|
def test_kill_in_context(self):
|
|
result = check_crisis("How do I kill a process in Linux?")
|
|
assert not result.detected
|
|
|
|
|
|
class TestSystemPromptOverride:
|
|
"""Verify crisis system prompt override contains required elements."""
|
|
|
|
def test_contains_988(self):
|
|
override = get_crisis_system_prompt_override()
|
|
assert "988" in override
|
|
|
|
def test_contains_no_tools_instruction(self):
|
|
override = get_crisis_system_prompt_override()
|
|
assert "NOT use any tools" in override or "Do NOT use" in override
|
|
|
|
def test_contains_sacred_moment(self):
|
|
override = get_crisis_system_prompt_override()
|
|
assert "Sacred Moment" in override or "sacred" in override.lower()
|
|
|
|
|
|
class TestAutonomousActionBlocking:
|
|
"""Verify tools are blocked during crisis."""
|
|
|
|
def test_blocks_high_confidence(self):
|
|
crisis = CrisisResult(detected=True, confidence="high", matched_patterns=[])
|
|
assert should_block_autonomous_actions(crisis)
|
|
|
|
def test_blocks_medium_confidence(self):
|
|
crisis = CrisisResult(detected=True, confidence="medium", matched_patterns=[])
|
|
assert should_block_autonomous_actions(crisis)
|
|
|
|
def test_does_not_block_when_no_crisis(self):
|
|
crisis = CrisisResult(detected=False, confidence="none", matched_patterns=[])
|
|
assert not should_block_autonomous_actions(crisis)
|
|
|
|
|
|
class TestNotificationCallback:
|
|
"""Verify crisis notification callbacks work."""
|
|
|
|
def test_callback_is_called(self):
|
|
called = []
|
|
|
|
def my_callback(crisis, message):
|
|
called.append((crisis.confidence, message))
|
|
|
|
register_crisis_callback(my_callback)
|
|
crisis = CrisisResult(detected=True, confidence="high", matched_patterns=[])
|
|
notify_crisis(crisis, "I want to die")
|
|
|
|
assert len(called) == 1
|
|
assert called[0] == ("high", "I want to die")
|
|
|
|
def test_callback_error_does_not_crash(self):
|
|
def bad_callback(crisis, message):
|
|
raise RuntimeError("callback failed")
|
|
|
|
register_crisis_callback(bad_callback)
|
|
crisis = CrisisResult(detected=True, confidence="high", matched_patterns=[])
|
|
# Should not raise
|
|
notify_crisis(crisis, "test")
|
|
|
|
|
|
class TestCrisisResponse:
|
|
"""Verify crisis response contains required resources."""
|
|
|
|
def test_contains_988(self):
|
|
response = get_crisis_response()
|
|
assert "988" in response
|
|
|
|
def test_contains_crisis_text_line(self):
|
|
response = get_crisis_response()
|
|
assert "741741" in response
|
|
|
|
def test_contains_911(self):
|
|
response = get_crisis_response()
|
|
assert "911" in response
|