Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions backend/apps/slack/common/handlers/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from apps.ai.agent.agent import AgenticRAGAgent
from apps.slack.blocks import markdown
from apps.slack.common.question_detector import QuestionDetector

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -38,6 +39,10 @@ def process_ai_query(query: str) -> str | None:
str | None: The AI response or None if error occurred.

"""
question_detector = QuestionDetector()
if not question_detector.is_owasp_question(text=query):
return get_default_response()

agent = AgenticRAGAgent()
result = agent.run(query=query)
return result["answer"]
Expand All @@ -56,3 +61,13 @@ def get_error_blocks() -> list[dict]:
"Please try again later or contact support if the issue persists."
)
]


def get_default_response() -> str:
"""Get default response for non-OWASP questions.

Returns:
str: A default response for non-OWASP questions.

"""
return "Please ask questions related to OWASP."
49 changes: 45 additions & 4 deletions backend/tests/apps/slack/common/handlers/ai_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

import pytest

from apps.slack.common.handlers.ai import get_blocks, get_error_blocks, process_ai_query
from apps.slack.common.handlers.ai import (
get_blocks,
get_default_response,
get_error_blocks,
process_ai_query,
)


class TestAiHandler:
Expand Down Expand Up @@ -63,51 +68,87 @@ def test_get_blocks_with_empty_response(self, mock_get_error_blocks, mock_proces
assert result == error_blocks

@patch("apps.slack.common.handlers.ai.AgenticRAGAgent")
def test_process_ai_query_success(self, mock_agent_class):
@patch("apps.slack.common.handlers.ai.QuestionDetector")
def test_process_ai_query_success(self, mock_question_detector_class, mock_agent_class):
"""Test successful AI query processing with AgenticRAGAgent."""
query = "What is OWASP?"
expected_response = "OWASP is a security organization..."

mock_question_detector = Mock()
mock_question_detector.is_owasp_question.return_value = True
mock_question_detector_class.return_value = mock_question_detector

mock_agent = Mock()
mock_agent.run.return_value = {"answer": expected_response}
mock_agent_class.return_value = mock_agent

result = process_ai_query(query)

mock_question_detector_class.assert_called_once()
mock_question_detector.is_owasp_question.assert_called_once_with(text=query)
mock_agent_class.assert_called_once()
mock_agent.run.assert_called_once_with(query=query)
assert result == expected_response

@patch("apps.slack.common.handlers.ai.AgenticRAGAgent")
def test_process_ai_query_failure(self, mock_agent_class):
@patch("apps.slack.common.handlers.ai.QuestionDetector")
def test_process_ai_query_failure(self, mock_question_detector_class, mock_agent_class):
"""Test AI query processing failure raises exception."""
query = "What is OWASP?"

mock_question_detector = Mock()
mock_question_detector.is_owasp_question.return_value = True
mock_question_detector_class.return_value = mock_question_detector

mock_agent = Mock()
mock_agent.run.side_effect = Exception("AI service error")
mock_agent_class.return_value = mock_agent

with pytest.raises(Exception, match="AI service error"):
process_ai_query(query)

mock_question_detector_class.assert_called_once()
mock_question_detector.is_owasp_question.assert_called_once_with(text=query)
mock_agent_class.assert_called_once()
mock_agent.run.assert_called_once_with(query=query)

@patch("apps.slack.common.handlers.ai.AgenticRAGAgent")
def test_process_ai_query_returns_none(self, mock_agent_class):
@patch("apps.slack.common.handlers.ai.QuestionDetector")
def test_process_ai_query_returns_none(self, mock_question_detector_class, mock_agent_class):
"""Test AI query processing when agent returns no answer."""
query = "What is OWASP?"

mock_question_detector = Mock()
mock_question_detector.is_owasp_question.return_value = True
mock_question_detector_class.return_value = mock_question_detector

mock_agent = Mock()
mock_agent.run.return_value = {"answer": None}
mock_agent_class.return_value = mock_agent

result = process_ai_query(query)

mock_question_detector_class.assert_called_once()
mock_question_detector.is_owasp_question.assert_called_once_with(text=query)
mock_agent_class.assert_called_once()
mock_agent.run.assert_called_once_with(query=query)
assert result is None

@patch("apps.slack.common.handlers.ai.QuestionDetector")
def test_process_ai_query_non_owasp_question(self, mock_question_detector_class):
"""Test AI query processing when question is not OWASP-related."""
query = "What is the weather today?"

mock_question_detector = Mock()
mock_question_detector.is_owasp_question.return_value = False
mock_question_detector_class.return_value = mock_question_detector

result = process_ai_query(query)

mock_question_detector_class.assert_called_once()
mock_question_detector.is_owasp_question.assert_called_once_with(text=query)
assert result == get_default_response()

@patch("apps.slack.common.handlers.ai.markdown")
def test_get_error_blocks(self, mock_markdown):
"""Test error blocks generation."""
Expand Down