Files
app/tests/test_synthesizer_agent.py
Albert 89273619c2 feat: implement AI agent layer with LangChain integration
- Create InterviewerAgent with Socratic questioning and RAG context
  - Build SynthesizerAgent for transcript segmentation and link generation
  - Integrate Google Gemini models (Flash for interviewing, Pro for synthesis)
  - Add structured output parsing for Zettel extraction and linking
  - Implement session termination detection with [END_SESSION] token
  - Add conversation context formatting and similarity-based neighbor filtering
  - Add vector service tests with mocked ChromaDB and embeddings
  - Test interviewer agent RAG conversations and session termination
  - Test synthesizer agent transcript formatting and neighbor analysis
  - Add prompt loader tests for external prompt system
  - Test all repository CRUD operations and database transactions
2025-08-17 01:47:04 +00:00

162 lines
7.0 KiB
Python

"""Test synthesizer agent functionality - simplified version."""
import pytest
import uuid
from unittest.mock import MagicMock, patch
from datetime import datetime
from app.services.synthesizer import SynthesizerAgent
from app.services.vector import VectorService
from app.data.models import Note
from langchain_core.documents import Document
class TestSynthesizerAgent:
"""Test SynthesizerAgent functionality with simplified mocking."""
@pytest.fixture
def mock_vector_service(self):
"""Create a mock vector service."""
return MagicMock(spec=VectorService)
@pytest.fixture
def sample_transcript(self):
"""Create a sample conversation transcript."""
return [
{"role": "user", "content": "I want to explore AI ethics"},
{"role": "assistant", "content": "What aspects of AI ethics concern you most?"},
{"role": "user", "content": "I'm worried about bias in algorithms"}
]
@pytest.fixture
def sample_note(self):
"""Create a sample note for linking."""
return Note(
id=uuid.uuid4(),
title="Algorithmic Bias",
content="AI systems can perpetuate discrimination when trained on biased datasets.",
tags=["ai", "bias", "ethics"],
session_id=uuid.uuid4(),
created_at=datetime.utcnow()
)
@pytest.fixture
def sample_neighbors(self):
"""Create sample neighboring documents."""
return [
Document(
page_content="Machine learning fairness requires careful consideration.",
metadata={"title": "ML Fairness", "tags": "ml,fairness", "similarity_score": 0.8}
),
Document(
page_content="Privacy-preserving AI techniques protect user data.",
metadata={"title": "Privacy in AI", "tags": "privacy,ai", "similarity_score": 0.6}
)
]
def test_synthesizer_initialization(self, mock_vector_service):
"""Test that SynthesizerAgent initializes correctly."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI') as mock_llm:
agent = SynthesizerAgent(mock_vector_service)
assert agent.vector_service is mock_vector_service
assert agent.llm is not None
# Verify it uses the Pro model with lower temperature
mock_llm.assert_called_once()
call_args = mock_llm.call_args
assert call_args.kwargs['temperature'] == 0.3
def test_format_transcript_for_segmentation(self, mock_vector_service, sample_transcript):
"""Test transcript formatting for segmentation."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
result = agent._format_transcript_for_segmentation(sample_transcript)
assert "User:" in result
assert "AI Interviewer:" in result
assert "AI ethics" in result
assert "bias" in result.lower()
def test_format_transcript_for_segmentation_empty(self, mock_vector_service):
"""Test transcript formatting with empty transcript."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
result = agent._format_transcript_for_segmentation([])
assert "Empty conversation transcript" in result
def test_format_neighbors(self, mock_vector_service, sample_neighbors):
"""Test neighbor formatting for linking."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
result = agent._format_neighbors(sample_neighbors)
assert "Note 1:" in result
assert "Note 2:" in result
assert "ML Fairness" in result
assert "Privacy in AI" in result
assert "Similarity Score:" in result
assert "0.800" in result # Formatted similarity score
def test_format_neighbors_empty(self, mock_vector_service):
"""Test neighbor formatting with no neighbors."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
result = agent._format_neighbors([])
assert "No existing notes found" in result
def test_format_neighbors_with_metadata(self, mock_vector_service):
"""Test neighbor formatting handles missing metadata gracefully."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
neighbors = [
Document(
page_content="Content without much metadata",
metadata={} # Missing title, tags, similarity_score
)
]
result = agent._format_neighbors(neighbors)
assert "Note 1:" in result
assert "Content without much metadata" in result
assert "Similarity Score: 0.000" in result # Default value
def test_transcript_formatting_preserves_conversation_flow(self, mock_vector_service):
"""Test that transcript formatting preserves the conversation flow."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI'):
agent = SynthesizerAgent(mock_vector_service)
transcript = [
{"role": "user", "content": "First message"},
{"role": "assistant", "content": "First response"},
{"role": "user", "content": "Second message"},
{"role": "assistant", "content": "Second response"}
]
result = agent._format_transcript_for_segmentation(transcript)
# Check order is preserved
lines = result.split('\n\n')
assert len(lines) == 4
assert "User: First message" in lines[0]
assert "AI Interviewer: First response" in lines[1]
assert "User: Second message" in lines[2]
assert "AI Interviewer: Second response" in lines[3]
def test_agent_uses_correct_model_config(self, mock_vector_service):
"""Test that the agent is configured with the correct model settings."""
with patch('app.services.synthesizer.ChatGoogleGenerativeAI') as mock_llm_class:
with patch('app.services.synthesizer.settings') as mock_settings:
mock_settings.LLM_PRO_MODEL = "test-pro-model"
mock_settings.GOOGLE_API_KEY = "test-key"
agent = SynthesizerAgent(mock_vector_service)
# Verify the LLM was initialized with correct parameters
mock_llm_class.assert_called_once_with(
model="test-pro-model",
google_api_key="test-key",
temperature=0.3
)