import unittest import json import re from unittest.mock import MagicMock, patch from app import build_agent_prompt, chat_agent_stream # Import backend tool function to verify it exists try: from spiritual_bridge import get_oracle_data except ImportError: get_oracle_data = None class TestAgentTools(unittest.TestCase): def test_prompt_contains_tool_definitions(self): """Verify the system prompt includes instructions for the Oracle tool.""" prompt = build_agent_prompt("hello", [], []) self.assertIn("oracle_consultation", prompt) self.assertIn("", prompt) self.assertIn("Arguments: {\"topic\": \"str\"}", prompt) def test_tool_parsing_regex(self): """Verify the regex logic (implicitly tested via chat_agent_stream logic) can handle variations.""" # The logic is embedded in chat_agent_stream, so we simulate the stream content # We manually test the regex used in app.py to ensure it's robust sample_text = 'Some thought... {"name": "oracle_consultation", "arguments": {"topic": "life"}}' match = re.search(r"(.*?)", sample_text, re.DOTALL) self.assertIsNotNone(match) data = json.loads(match.group(1)) self.assertEqual(data["name"], "oracle_consultation") self.assertEqual(data["arguments"]["topic"], "life") @patch('app.get_oracle_data') def test_oracle_dispatch_mock(self, mock_oracle): """Verify valid tool calls trigger the backend function.""" mock_oracle.return_value = {"mock": "result"} with patch('app.get_llm') as mock_llm, \ patch('app.TextIteratorStreamer') as mock_streamer, \ patch('app.retrieve_relevant_chunks') as mock_rag, \ patch('app.detect_language', return_value="English"): mock_llm.return_value = (MagicMock(), MagicMock()) mock_rag.return_value = [] # Simulate Model Stream: Tool Call -> Pause -> (Tool Exec) -> Summary mock_inst = mock_streamer.return_value mock_inst.__iter__.side_effect = [ iter(['{"name": "oracle_consultation", "arguments": {"topic": "love"}}']), iter(["The Oracle says love is infinite."]) ] gen = chat_agent_stream("help me", [], None, None) list(gen) # Exhaust mock_oracle.assert_called_once() call_args = mock_oracle.call_args[1] self.assertEqual(call_args["topic"], "love") def test_unknown_tool_handling(self): """Verify the system handles fictional tools gracefully.""" with patch('app.get_llm') as mock_llm, \ patch('app.TextIteratorStreamer') as mock_streamer, \ patch('app.retrieve_relevant_chunks') as mock_rag, \ patch('app.detect_language', return_value="English"): mock_llm.return_value = (MagicMock(), MagicMock()) mock_rag.return_value = [] mock_inst = mock_streamer.return_value # Model tries to call 'weather_tool' which doesn't exist mock_inst.__iter__.side_effect = [ iter(['{"name": "weather_tool", "arguments": {}}']), iter(["I cannot do that."]) ] gen = chat_agent_stream("weather?", [], None, None) list(gen) # Use mock to verify we didn't crash. # In a real integration test we'd check the history for error messages, # but chat_agent_stream yields text tokens, so we just ensure it completes. @unittest.skipIf(get_oracle_data is None, "Spiritual bridge not installed") def test_oracle_dispatch_real_integration(self): """Integration Test: Actually call spiritual_bridge logic (no mocks).""" # This tests if the underlying function runs without error given valid inputs. # It relies on the presence of gematria.db/etc in the daily-psalms-api folder or similar setup. # We catch exceptions to prevent failing CI if DBs are missing, but verify logic. try: result = get_oracle_data(name="TestUser", topic="Testing", date_str="2025-01-01") # Result could be an error dict if DB is missing, or a real result. self.assertIsInstance(result, dict) # Ensure it structured correctly if "error" not in result: self.assertIn("wisdom_nodes", result) except Exception as e: self.fail(f"Real execution of get_oracle_data failed with error: {e}") if __name__ == "__main__": unittest.main()