Files
learningcircuit--local-deep…/tests/chat/test_chat_accumulated_context.py
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

291 lines
9.7 KiB
Python

"""
Tests for accumulated context management.
Tests context accumulation, merging, and limits.
"""
import json
class TestAccumulatedContextInitialization:
"""Tests for accumulated context initialization."""
def test_new_session_has_empty_accumulated_context(
self, authenticated_client
):
"""Test that new sessions have initialized empty context."""
response = authenticated_client.post(
"/api/chat/sessions",
json={"initial_query": "Test"},
content_type="application/json",
)
session_id = json.loads(response.data)["session_id"]
get_resp = authenticated_client.get(f"/api/chat/sessions/{session_id}")
data = json.loads(get_resp.data)
ctx = data["session"].get("accumulated_context", {})
# Should have initialized fields
if ctx: # If API returns it
assert isinstance(ctx.get("key_entities", []), list)
assert isinstance(ctx.get("topics", []), list)
class TestAccumulatedContextStructure:
"""Tests for accumulated context data structure."""
def test_context_structure_from_manager(self):
"""Test context structure created by ChatContextManager."""
from src.local_deep_research.chat.context import ChatContextManager
messages = [
{"role": "user", "content": "Test query", "message_type": "query"}
]
accumulated = {
"key_entities": ["entity1", "entity2"],
"topics": ["topic1"],
"summary": "Previous summary",
}
manager = ChatContextManager("test-session", messages, accumulated)
# Entities and topics should be accessible
entities = manager._get_key_entities()
topics = manager._get_topics()
assert "entity1" in entities
assert "entity2" in entities
assert "topic1" in topics
def test_context_limits_entities(self):
"""Test that entities are limited to 20."""
from src.local_deep_research.chat.context import ChatContextManager
# Create more than 20 entities
many_entities = [f"entity{i}" for i in range(30)]
accumulated = {"key_entities": many_entities}
manager = ChatContextManager("test-session", [], accumulated)
entities = manager._get_key_entities()
assert len(entities) <= 20
def test_context_limits_topics(self):
"""Test that topics are limited to 10."""
from src.local_deep_research.chat.context import ChatContextManager
# Create more than 10 topics
many_topics = [f"topic{i}" for i in range(15)]
accumulated = {"topics": many_topics}
manager = ChatContextManager("test-session", [], accumulated)
topics = manager._get_topics()
assert len(topics) <= 10
class TestContextMerging:
"""Tests for merging context updates."""
def test_merge_entities_deduplicates(self):
"""Test that merging entities removes duplicates."""
from src.local_deep_research.chat.context import ChatContextManager
accumulated = {"key_entities": ["entity1", "entity2"]}
manager = ChatContextManager("test-session", [], accumulated)
# Get updates with overlapping and new entities
updates = manager.extract_context_updates("Content about entity1")
# new_entities would normally contain extracted entities;
# verify the structure is present
assert "new_entities" in updates
class TestContextSummary:
"""Tests for context summary handling."""
def test_summary_created_from_content(self):
"""Test that summaries are created from content."""
from src.local_deep_research.chat.context import ChatContextManager
manager = ChatContextManager("test-session", [], {})
content = """First paragraph with some introduction.
Second paragraph with main content that should be captured.
Third paragraph with more details."""
summary = manager._create_summary(content)
# Should capture meaningful content
assert len(summary) > 0
assert len(summary) <= 310 # Max 300 + "..."
def test_summary_skips_headers(self):
"""Test that summary skips markdown headers."""
from src.local_deep_research.chat.context import ChatContextManager
manager = ChatContextManager("test-session", [], {})
content = """# Header Title
This is the actual content paragraph that should be included in the summary.
## Another Header
More content here."""
summary = manager._create_summary(content)
# Should skip headers and get content
assert not summary.startswith("#")
def test_summary_handles_short_paragraphs(self):
"""Test that summary handles content with short paragraphs."""
from src.local_deep_research.chat.context import ChatContextManager
manager = ChatContextManager("test-session", [], {})
content = """Short.
Another short.
This is a longer paragraph that meets the minimum length requirement for inclusion in the summary."""
summary = manager._create_summary(content)
# Should get the longer paragraph
assert "longer paragraph" in summary
class TestContextWithRealMessages:
"""Tests with realistic message patterns."""
def test_context_with_multiple_turns(self, authenticated_client):
"""Test context building with multiple conversation turns."""
# Create session
create_resp = authenticated_client.post(
"/api/chat/sessions",
json={"initial_query": "What is machine learning?"},
content_type="application/json",
)
session_id = json.loads(create_resp.data)["session_id"]
# Simulate multi-turn conversation
turns = [
"Tell me about supervised learning",
"How does neural network training work?",
"Explain backpropagation",
"What are common activation functions?",
"Compare ReLU and sigmoid",
]
for turn in turns:
authenticated_client.post(
f"/api/chat/sessions/{session_id}/messages",
json={"content": turn, "trigger_research": False},
content_type="application/json",
)
# Get all messages
messages_resp = authenticated_client.get(
f"/api/chat/sessions/{session_id}/messages"
)
data = json.loads(messages_resp.data)
# All messages should be retrievable
assert len(data["messages"]) == 5
def test_context_preserves_message_order(self, authenticated_client):
"""Test that context preserves message ordering."""
# Create session
create_resp = authenticated_client.post(
"/api/chat/sessions",
json={"initial_query": "Test"},
content_type="application/json",
)
session_id = json.loads(create_resp.data)["session_id"]
# Add numbered messages
for i in range(5):
authenticated_client.post(
f"/api/chat/sessions/{session_id}/messages",
json={
"content": f"Message number {i}",
"trigger_research": False,
},
content_type="application/json",
)
# Get messages
messages_resp = authenticated_client.get(
f"/api/chat/sessions/{session_id}/messages"
)
data = json.loads(messages_resp.data)
# Verify order
for i, msg in enumerate(data["messages"]):
assert f"Message number {i}" in msg["content"]
assert msg["sequence_number"] == i + 1
class TestEdgeCases:
"""Edge case tests for accumulated context."""
def test_empty_accumulated_context_handled(self):
"""Test handling of None/empty accumulated context."""
from src.local_deep_research.chat.context import ChatContextManager
manager1 = ChatContextManager("test", [], None)
manager2 = ChatContextManager("test", [], {})
# Both should work without errors
ctx1 = manager1.build_research_context()
ctx2 = manager2.build_research_context()
assert ctx1["key_entities"] == []
assert ctx2["key_entities"] == []
def test_special_characters_in_context(self):
"""Test handling of special characters in context."""
from src.local_deep_research.chat.context import ChatContextManager
accumulated = {
"key_entities": ["<script>", "O'Reilly", '"quotes"'],
"topics": ["C++ programming", "async/await"],
"summary": 'Discussion of <html> & "special" chars',
}
manager = ChatContextManager("test", [], accumulated)
context = manager.build_research_context()
# Should handle without crashing and preserve entities/topics
assert "<script>" in context["key_entities"]
assert "C++ programming" in context["topics"]
def test_unicode_in_context(self):
"""Test handling of unicode in context."""
from src.local_deep_research.chat.context import ChatContextManager
messages = [
{"role": "user", "content": "你好世界", "message_type": "query"},
{
"role": "assistant",
"content": "Привет мир",
"message_type": "response",
},
]
accumulated = {
"key_entities": ["日本語", "العربية"],
"topics": ["한국어"],
}
manager = ChatContextManager("test", messages, accumulated)
context = manager.build_research_context()
# Should handle unicode
assert "日本語" in context["key_entities"]
assert "한국어" in context["topics"]