Concolidate tests
This commit is contained in:
parent
061b8450a6
commit
5976cebe8c
6 changed files with 338 additions and 4284 deletions
|
|
@ -251,40 +251,6 @@ async def test_chat_agent_search_tool(allow_model_requests, temp_db_path):
|
||||||
assert len(result.output) > 0
|
assert len(result.output) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
@pytest.mark.vcr()
|
|
||||||
async def test_chat_agent_search_with_state_key(allow_model_requests, temp_db_path):
|
|
||||||
"""Test search tool emits keyed state when state_key is set."""
|
|
||||||
async with HaikuRAG(temp_db_path, create=True) as client:
|
|
||||||
await client.create_document(
|
|
||||||
content=DOCLAYNET_CLASS_LABELS,
|
|
||||||
uri="doclaynet-labels",
|
|
||||||
title="DocLayNet Class Labels",
|
|
||||||
)
|
|
||||||
await client.create_document(
|
|
||||||
content=DOCLAYNET_ANNOTATION,
|
|
||||||
uri="doclaynet-annotation",
|
|
||||||
title="DocLayNet Annotation",
|
|
||||||
)
|
|
||||||
|
|
||||||
agent = create_chat_agent(Config)
|
|
||||||
session_state = ChatSessionState(session_id="test-search")
|
|
||||||
deps = ChatDeps(
|
|
||||||
client=client,
|
|
||||||
config=Config,
|
|
||||||
session_state=session_state,
|
|
||||||
state_key=AGUI_STATE_KEY,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await agent.run(
|
|
||||||
"Search for documents about class labels",
|
|
||||||
deps=deps,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result.output is not None
|
|
||||||
assert len(result.output) > 0
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.vcr()
|
@pytest.mark.vcr()
|
||||||
async def test_chat_agent_search_tool_with_filter(allow_model_requests, temp_db_path):
|
async def test_chat_agent_search_tool_with_filter(allow_model_requests, temp_db_path):
|
||||||
|
|
@ -501,35 +467,6 @@ async def test_chat_agent_ask_adds_citations(allow_model_requests, temp_db_path)
|
||||||
assert len(session_state.qa_history) >= 1
|
assert len(session_state.qa_history) >= 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
@pytest.mark.vcr()
|
|
||||||
async def test_chat_agent_ask_with_state_key(allow_model_requests, temp_db_path):
|
|
||||||
"""Test ask tool emits keyed state when state_key is set."""
|
|
||||||
async with HaikuRAG(temp_db_path, create=True) as client:
|
|
||||||
await client.create_document(
|
|
||||||
content=DOCLAYNET_CLASS_LABELS,
|
|
||||||
uri="doclaynet-labels",
|
|
||||||
title="DocLayNet Class Labels",
|
|
||||||
)
|
|
||||||
|
|
||||||
agent = create_chat_agent(Config)
|
|
||||||
session_state = ChatSessionState(session_id="test-ask-keyed")
|
|
||||||
deps = ChatDeps(
|
|
||||||
client=client,
|
|
||||||
config=Config,
|
|
||||||
session_state=session_state,
|
|
||||||
state_key=AGUI_STATE_KEY,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await agent.run(
|
|
||||||
"What is the highest count class in the DocLayNet dataset?",
|
|
||||||
deps=deps,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result.output is not None
|
|
||||||
assert len(session_state.qa_history) >= 1
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.vcr()
|
@pytest.mark.vcr()
|
||||||
async def test_chat_agent_ask_triggers_background_summarization(
|
async def test_chat_agent_ask_triggers_background_summarization(
|
||||||
|
|
@ -801,3 +738,186 @@ def test_search_tool_citation_registry_logic():
|
||||||
"chunk-c": 3,
|
"chunk-c": 3,
|
||||||
"chunk-d": 4,
|
"chunk-d": 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Prior Answer Recall Tests
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosine_similarity_identical_vectors():
|
||||||
|
"""Test cosine similarity returns 1.0 for identical vectors."""
|
||||||
|
from haiku.rag.agents.chat.agent import _cosine_similarity
|
||||||
|
|
||||||
|
vec = [1.0, 2.0, 3.0]
|
||||||
|
assert _cosine_similarity(vec, vec) == pytest.approx(1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosine_similarity_orthogonal_vectors():
|
||||||
|
"""Test cosine similarity returns 0.0 for orthogonal vectors."""
|
||||||
|
from haiku.rag.agents.chat.agent import _cosine_similarity
|
||||||
|
|
||||||
|
vec1 = [1.0, 0.0, 0.0]
|
||||||
|
vec2 = [0.0, 1.0, 0.0]
|
||||||
|
assert _cosine_similarity(vec1, vec2) == pytest.approx(0.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosine_similarity_opposite_vectors():
|
||||||
|
"""Test cosine similarity returns -1.0 for opposite vectors."""
|
||||||
|
from haiku.rag.agents.chat.agent import _cosine_similarity
|
||||||
|
|
||||||
|
vec1 = [1.0, 2.0, 3.0]
|
||||||
|
vec2 = [-1.0, -2.0, -3.0]
|
||||||
|
assert _cosine_similarity(vec1, vec2) == pytest.approx(-1.0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosine_similarity_zero_vector():
|
||||||
|
"""Test cosine similarity handles zero vectors gracefully."""
|
||||||
|
from haiku.rag.agents.chat.agent import _cosine_similarity
|
||||||
|
|
||||||
|
vec = [1.0, 2.0, 3.0]
|
||||||
|
zero = [0.0, 0.0, 0.0]
|
||||||
|
assert _cosine_similarity(vec, zero) == 0.0
|
||||||
|
assert _cosine_similarity(zero, vec) == 0.0
|
||||||
|
assert _cosine_similarity(zero, zero) == 0.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_prior_answer_relevance_threshold_constant():
|
||||||
|
"""Test PRIOR_ANSWER_RELEVANCE_THRESHOLD is set to expected value."""
|
||||||
|
from haiku.rag.agents.chat.agent import PRIOR_ANSWER_RELEVANCE_THRESHOLD
|
||||||
|
|
||||||
|
assert PRIOR_ANSWER_RELEVANCE_THRESHOLD == 0.7
|
||||||
|
|
||||||
|
|
||||||
|
def test_prior_answer_matching_above_threshold():
|
||||||
|
"""Test that similar questions (above threshold) are matched."""
|
||||||
|
from haiku.rag.agents.chat.agent import (
|
||||||
|
PRIOR_ANSWER_RELEVANCE_THRESHOLD,
|
||||||
|
_cosine_similarity,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Simulate two nearly identical question embeddings
|
||||||
|
question_embedding = [0.5, 0.5, 0.5, 0.5]
|
||||||
|
prior_embedding = [0.51, 0.49, 0.5, 0.5] # Very similar
|
||||||
|
|
||||||
|
similarity = _cosine_similarity(question_embedding, prior_embedding)
|
||||||
|
assert similarity >= PRIOR_ANSWER_RELEVANCE_THRESHOLD
|
||||||
|
|
||||||
|
|
||||||
|
def test_prior_answer_matching_below_threshold():
|
||||||
|
"""Test that dissimilar questions (below threshold) are not matched."""
|
||||||
|
from haiku.rag.agents.chat.agent import (
|
||||||
|
PRIOR_ANSWER_RELEVANCE_THRESHOLD,
|
||||||
|
_cosine_similarity,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Simulate two different question embeddings
|
||||||
|
question_embedding = [1.0, 0.0, 0.0, 0.0]
|
||||||
|
prior_embedding = [0.0, 1.0, 0.0, 0.0] # Orthogonal = very different
|
||||||
|
|
||||||
|
similarity = _cosine_similarity(question_embedding, prior_embedding)
|
||||||
|
assert similarity < PRIOR_ANSWER_RELEVANCE_THRESHOLD
|
||||||
|
|
||||||
|
|
||||||
|
def test_qa_response_embedding_cache():
|
||||||
|
"""Test that QAResponse stores and retrieves question_embedding correctly."""
|
||||||
|
embedding = [0.1, 0.2, 0.3, 0.4]
|
||||||
|
qa = QAResponse(
|
||||||
|
question="What is X?",
|
||||||
|
answer="X is Y.",
|
||||||
|
confidence=0.9,
|
||||||
|
question_embedding=embedding,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert qa.question_embedding == embedding
|
||||||
|
# Embedding should be excluded from serialization (AG-UI state)
|
||||||
|
serialized = qa.model_dump()
|
||||||
|
assert "question_embedding" not in serialized
|
||||||
|
|
||||||
|
|
||||||
|
def test_qa_response_embedding_default_none():
|
||||||
|
"""Test that QAResponse.question_embedding defaults to None."""
|
||||||
|
qa = QAResponse(
|
||||||
|
question="What is X?",
|
||||||
|
answer="X is Y.",
|
||||||
|
confidence=0.9,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert qa.question_embedding is None
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Background Task Cancellation Tests
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_summarization_task_cancellation():
|
||||||
|
"""Test that new summarization tasks cancel previous ones for same session."""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from haiku.rag.agents.chat.agent import _summarization_tasks
|
||||||
|
|
||||||
|
# Clear any existing tasks
|
||||||
|
_summarization_tasks.clear()
|
||||||
|
|
||||||
|
session_id = "test-cancel-session"
|
||||||
|
|
||||||
|
# Create a slow task that simulates summarization
|
||||||
|
async def slow_task():
|
||||||
|
await asyncio.sleep(10) # Would take 10 seconds
|
||||||
|
|
||||||
|
# Start first task
|
||||||
|
task1 = asyncio.create_task(slow_task())
|
||||||
|
_summarization_tasks[session_id] = task1
|
||||||
|
|
||||||
|
# Simulate what happens when second ask comes in - cancel first task
|
||||||
|
if session_id in _summarization_tasks:
|
||||||
|
_summarization_tasks[session_id].cancel()
|
||||||
|
|
||||||
|
# Yield to let cancellation propagate
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
|
||||||
|
# Start second task
|
||||||
|
task2 = asyncio.create_task(slow_task())
|
||||||
|
_summarization_tasks[session_id] = task2
|
||||||
|
|
||||||
|
# First task should be cancelled
|
||||||
|
assert task1.cancelled() or task1.done()
|
||||||
|
|
||||||
|
# Second task should be running
|
||||||
|
assert not task2.done()
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
task2.cancel()
|
||||||
|
try:
|
||||||
|
await task2
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
_summarization_tasks.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_summarization_task_cleanup_on_completion():
|
||||||
|
"""Test that completed tasks are cleaned up from _summarization_tasks."""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from haiku.rag.agents.chat.agent import _summarization_tasks
|
||||||
|
|
||||||
|
_summarization_tasks.clear()
|
||||||
|
|
||||||
|
session_id = "test-cleanup-session"
|
||||||
|
|
||||||
|
# Create a fast task
|
||||||
|
async def fast_task():
|
||||||
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
|
task = asyncio.create_task(fast_task())
|
||||||
|
_summarization_tasks[session_id] = task
|
||||||
|
task.add_done_callback(lambda t: _summarization_tasks.pop(session_id, None))
|
||||||
|
|
||||||
|
# Wait for completion
|
||||||
|
await task
|
||||||
|
|
||||||
|
# Task should be cleaned up
|
||||||
|
assert session_id not in _summarization_tasks
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,7 @@ class TestSummarizeSession:
|
||||||
"""Tests for summarize_session function."""
|
"""Tests for summarize_session function."""
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.vcr()
|
async def test_summarize_session_empty_history(self):
|
||||||
async def test_summarize_session_empty_history(self, allow_model_requests):
|
|
||||||
"""Test summarize_session with empty qa_history returns empty string."""
|
"""Test summarize_session with empty qa_history returns empty string."""
|
||||||
from haiku.rag.agents.chat.context import summarize_session
|
from haiku.rag.agents.chat.context import summarize_session
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,48 +376,43 @@ def test_chat_deps_state_setter_ignores_session_context():
|
||||||
assert deps.session_state.session_context.summary == "Server-side context"
|
assert deps.session_state.session_context.summary == "Server-side context"
|
||||||
|
|
||||||
|
|
||||||
def test_citation_registry_get_or_assign_index_first_chunk():
|
def test_citation_registry_index_assignment():
|
||||||
"""Test get_or_assign_index assigns index 1 to first chunk."""
|
"""Test get_or_assign_index basic index assignment behavior.
|
||||||
|
|
||||||
|
Verifies:
|
||||||
|
- First chunk gets index 1
|
||||||
|
- Second unique chunk gets index 2
|
||||||
|
- Same chunk_id always returns same index
|
||||||
|
"""
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
from haiku.rag.agents.chat.state import ChatSessionState
|
||||||
|
|
||||||
session_state = ChatSessionState(session_id="test")
|
session_state = ChatSessionState(session_id="test")
|
||||||
index = session_state.get_or_assign_index("chunk-abc")
|
|
||||||
assert index == 1
|
|
||||||
|
|
||||||
|
# First chunk gets index 1
|
||||||
def test_citation_registry_get_or_assign_index_second_chunk():
|
|
||||||
"""Test get_or_assign_index assigns incremental indices to new chunks."""
|
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
|
||||||
|
|
||||||
session_state = ChatSessionState(session_id="test")
|
|
||||||
index1 = session_state.get_or_assign_index("chunk-abc")
|
index1 = session_state.get_or_assign_index("chunk-abc")
|
||||||
index2 = session_state.get_or_assign_index("chunk-def")
|
|
||||||
assert index1 == 1
|
assert index1 == 1
|
||||||
|
|
||||||
|
# Second unique chunk gets index 2
|
||||||
|
index2 = session_state.get_or_assign_index("chunk-def")
|
||||||
assert index2 == 2
|
assert index2 == 2
|
||||||
|
|
||||||
|
# Same chunk_id returns same index (not incremented)
|
||||||
def test_citation_registry_get_or_assign_index_same_chunk():
|
index1_again = session_state.get_or_assign_index("chunk-abc")
|
||||||
"""Test get_or_assign_index returns same index for same chunk_id."""
|
assert index1_again == 1
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
|
||||||
|
|
||||||
session_state = ChatSessionState(session_id="test")
|
|
||||||
index1 = session_state.get_or_assign_index("chunk-abc")
|
|
||||||
index2 = session_state.get_or_assign_index("chunk-abc")
|
|
||||||
assert index1 == index2 == 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_citation_registry_get_or_assign_index_stability():
|
def test_citation_registry_stability():
|
||||||
"""Test citation indices are stable across multiple calls."""
|
"""Test citation indices are stable across multiple calls in any order."""
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
from haiku.rag.agents.chat.state import ChatSessionState
|
||||||
|
|
||||||
session_state = ChatSessionState(session_id="test")
|
session_state = ChatSessionState(session_id="test")
|
||||||
|
|
||||||
# First call assigns indices 1, 2, 3
|
# First round assigns indices 1, 2, 3
|
||||||
idx_a = session_state.get_or_assign_index("chunk-a")
|
idx_a = session_state.get_or_assign_index("chunk-a")
|
||||||
idx_b = session_state.get_or_assign_index("chunk-b")
|
idx_b = session_state.get_or_assign_index("chunk-b")
|
||||||
idx_c = session_state.get_or_assign_index("chunk-c")
|
idx_c = session_state.get_or_assign_index("chunk-c")
|
||||||
|
|
||||||
# Second round - existing chunks keep their indices
|
# Second round - existing chunks keep their indices regardless of order
|
||||||
assert session_state.get_or_assign_index("chunk-b") == idx_b
|
assert session_state.get_or_assign_index("chunk-b") == idx_b
|
||||||
assert session_state.get_or_assign_index("chunk-a") == idx_a
|
assert session_state.get_or_assign_index("chunk-a") == idx_a
|
||||||
assert session_state.get_or_assign_index("chunk-c") == idx_c
|
assert session_state.get_or_assign_index("chunk-c") == idx_c
|
||||||
|
|
@ -427,38 +422,28 @@ def test_citation_registry_get_or_assign_index_stability():
|
||||||
assert idx_d == 4
|
assert idx_d == 4
|
||||||
|
|
||||||
|
|
||||||
def test_citation_registry_serialization():
|
def test_citation_registry_serialization_roundtrip():
|
||||||
"""Test citation_registry is included in model_dump for AG-UI state."""
|
"""Test citation_registry serializes and deserializes correctly for AG-UI state."""
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
from haiku.rag.agents.chat.state import ChatSessionState
|
||||||
|
|
||||||
session_state = ChatSessionState(session_id="test")
|
# Create state and assign indices
|
||||||
session_state.get_or_assign_index("chunk-a")
|
original = ChatSessionState(session_id="test")
|
||||||
session_state.get_or_assign_index("chunk-b")
|
original.get_or_assign_index("chunk-a")
|
||||||
|
original.get_or_assign_index("chunk-b")
|
||||||
|
|
||||||
state_dict = session_state.model_dump()
|
# Serialize
|
||||||
|
state_dict = original.model_dump()
|
||||||
assert "citation_registry" in state_dict
|
assert "citation_registry" in state_dict
|
||||||
assert state_dict["citation_registry"] == {"chunk-a": 1, "chunk-b": 2}
|
assert state_dict["citation_registry"] == {"chunk-a": 1, "chunk-b": 2}
|
||||||
|
|
||||||
|
# Deserialize (simulating AG-UI state restoration)
|
||||||
def test_citation_registry_deserialization():
|
restored = ChatSessionState.model_validate(state_dict)
|
||||||
"""Test citation_registry is restored from dict."""
|
|
||||||
from haiku.rag.agents.chat.state import ChatSessionState
|
|
||||||
|
|
||||||
# Simulate state from AG-UI using model_validate (proper Pydantic deserialization)
|
|
||||||
session_state = ChatSessionState.model_validate(
|
|
||||||
{
|
|
||||||
"session_id": "test",
|
|
||||||
"citations": [],
|
|
||||||
"qa_history": [],
|
|
||||||
"citation_registry": {"chunk-a": 1, "chunk-b": 2},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Existing chunks should return their persisted indices
|
# Existing chunks should return their persisted indices
|
||||||
assert session_state.get_or_assign_index("chunk-a") == 1
|
assert restored.get_or_assign_index("chunk-a") == 1
|
||||||
assert session_state.get_or_assign_index("chunk-b") == 2
|
assert restored.get_or_assign_index("chunk-b") == 2
|
||||||
# New chunk should get next index
|
# New chunk should get next index
|
||||||
assert session_state.get_or_assign_index("chunk-c") == 3
|
assert restored.get_or_assign_index("chunk-c") == 3
|
||||||
|
|
||||||
|
|
||||||
def test_chat_deps_state_getter_includes_citation_registry():
|
def test_chat_deps_state_getter_includes_citation_registry():
|
||||||
|
|
|
||||||
|
|
@ -62,3 +62,125 @@ def test_research_plan_rejects_too_many_sub_questions():
|
||||||
|
|
||||||
with pytest.raises(ValidationError, match="Cannot have more than 12"):
|
with pytest.raises(ValidationError, match="Cannot have more than 12"):
|
||||||
ResearchPlan(sub_questions=[f"q{i}" for i in range(13)])
|
ResearchPlan(sub_questions=[f"q{i}" for i in range(13)])
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Conversational Graph Tests
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_conversational_graph_returns_graph():
|
||||||
|
"""Test build_conversational_graph returns a valid Graph instance."""
|
||||||
|
from pydantic_graph.beta import Graph
|
||||||
|
|
||||||
|
from haiku.rag.agents.research.graph import build_conversational_graph
|
||||||
|
|
||||||
|
graph = build_conversational_graph()
|
||||||
|
assert graph is not None
|
||||||
|
assert isinstance(graph, Graph)
|
||||||
|
|
||||||
|
|
||||||
|
def test_conversational_answer_model():
|
||||||
|
"""Test ConversationalAnswer model can be created with all fields."""
|
||||||
|
from haiku.rag.agents.research.models import Citation, ConversationalAnswer
|
||||||
|
|
||||||
|
citation = Citation(
|
||||||
|
index=1,
|
||||||
|
document_id="doc-1",
|
||||||
|
chunk_id="chunk-1",
|
||||||
|
document_uri="test.md",
|
||||||
|
document_title="Test Doc",
|
||||||
|
content="Test content",
|
||||||
|
)
|
||||||
|
|
||||||
|
answer = ConversationalAnswer(
|
||||||
|
answer="The answer is 42.",
|
||||||
|
citations=[citation],
|
||||||
|
confidence=0.95,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert answer.answer == "The answer is 42."
|
||||||
|
assert len(answer.citations) == 1
|
||||||
|
assert answer.confidence == 0.95
|
||||||
|
|
||||||
|
|
||||||
|
def test_conversational_answer_default_values():
|
||||||
|
"""Test ConversationalAnswer uses correct default values."""
|
||||||
|
from haiku.rag.agents.research.models import ConversationalAnswer
|
||||||
|
|
||||||
|
answer = ConversationalAnswer(answer="Just the answer.")
|
||||||
|
|
||||||
|
assert answer.answer == "Just the answer."
|
||||||
|
assert answer.citations == []
|
||||||
|
assert answer.confidence == 1.0
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_context_for_prompt_basic():
|
||||||
|
"""Test format_context_for_prompt with basic context."""
|
||||||
|
from haiku.rag.agents.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.agents.research.graph import format_context_for_prompt
|
||||||
|
|
||||||
|
context = ResearchContext(original_question="What is X?")
|
||||||
|
result = format_context_for_prompt(context)
|
||||||
|
|
||||||
|
assert "<context>" in result
|
||||||
|
assert "What is X?" in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_context_for_prompt_with_session_context():
|
||||||
|
"""Test format_context_for_prompt includes session_context as background."""
|
||||||
|
from haiku.rag.agents.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.agents.research.graph import format_context_for_prompt
|
||||||
|
|
||||||
|
context = ResearchContext(
|
||||||
|
original_question="What is Y?",
|
||||||
|
session_context="Previous discussion about topic Z.",
|
||||||
|
)
|
||||||
|
result = format_context_for_prompt(context)
|
||||||
|
|
||||||
|
assert "<background>" in result
|
||||||
|
assert "Previous discussion" in result
|
||||||
|
assert "What is Y?" in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_context_for_prompt_excludes_pending_questions():
|
||||||
|
"""Test format_context_for_prompt can exclude pending questions."""
|
||||||
|
from haiku.rag.agents.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.agents.research.graph import format_context_for_prompt
|
||||||
|
|
||||||
|
context = ResearchContext(
|
||||||
|
original_question="Main question?",
|
||||||
|
sub_questions=["Sub Q1?", "Sub Q2?"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# With pending questions (default)
|
||||||
|
with_pending = format_context_for_prompt(context, include_pending_questions=True)
|
||||||
|
assert "Sub Q1?" in with_pending
|
||||||
|
|
||||||
|
# Without pending questions (for synthesis)
|
||||||
|
without_pending = format_context_for_prompt(
|
||||||
|
context, include_pending_questions=False
|
||||||
|
)
|
||||||
|
assert "Sub Q1?" not in without_pending
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_context_for_prompt_with_prior_answers():
|
||||||
|
"""Test format_context_for_prompt includes prior_answers."""
|
||||||
|
from haiku.rag.agents.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.agents.research.graph import format_context_for_prompt
|
||||||
|
from haiku.rag.agents.research.models import SearchAnswer
|
||||||
|
|
||||||
|
context = ResearchContext(original_question="Main question?")
|
||||||
|
context.add_qa_response(
|
||||||
|
SearchAnswer(
|
||||||
|
query="Sub question?",
|
||||||
|
answer="The answer is here.",
|
||||||
|
confidence=0.9,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
result = format_context_for_prompt(context)
|
||||||
|
|
||||||
|
assert "<prior_answers>" in result
|
||||||
|
assert "Sub question?" in result
|
||||||
|
assert "The answer is here." in result
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue