Files
hermes-agent/tests/test_crisis_integration.py
Alexander Whitestone 0ef80f05ce
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
fix: crisis protocol integration with conversation loop
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.
2026-04-14 21:18:33 -04:00

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