New router intelligence modules (26 files): alert_ingest/store, audit_store, architecture_pressure, backlog_generator/store, cost_analyzer, data_governance, dependency_scanner, drift_analyzer, incident_* (5 files), llm_enrichment, platform_priority_digest, provider_budget, release_check_runner, risk_* (6 files), signature_state_store, sofiia_auto_router, tool_governance New services: - sofiia-console: Dockerfile, adapters/, monitor/nodes/ops/voice modules, launchd, react static - memory-service: integration_endpoints, integrations, voice_endpoints, static UI - aurora-service: full app suite (analysis, job_store, orchestrator, reporting, schemas, subagents) - sofiia-supervisor: new supervisor service - aistalk-bridge-lite: Telegram bridge lite - calendar-service: CalDAV calendar service with reminders - mlx-stt-service / mlx-tts-service: Apple Silicon speech services - binance-bot-monitor: market monitor service - node-worker: STT/TTS memory providers New tools (9): agent_email, browser_tool, contract_tool, observability_tool, oncall_tool, pr_reviewer_tool, repo_tool, safe_code_executor, secure_vault New crews: agromatrix_crew (10 modules: depth_classifier, doc_facts, doc_focus, farm_state, light_reply, llm_factory, memory_manager, proactivity, reflection_engine, session_context, style_adapter, telemetry) Tests: 85+ test files for all new modules Made-with: Cursor
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
"""
|
||
Tests for Fact Lock: якщо session має doc_facts і питання про прибуток —
|
||
ask_about_document НЕ повинна викликатись.
|
||
"""
|
||
import sys
|
||
import os
|
||
import asyncio
|
||
from unittest.mock import AsyncMock, patch, MagicMock
|
||
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||
|
||
from crews.agromatrix_crew import session_context as sc
|
||
from crews.agromatrix_crew.doc_facts import can_answer_from_facts
|
||
|
||
|
||
FACTS = {
|
||
"profit_uah": 5_972_016.0,
|
||
"fertilizer_uah": 1_521_084.0,
|
||
"area_ha": 497.0,
|
||
}
|
||
|
||
|
||
def _setup_session(chat_id: str, facts: dict):
|
||
sc._STORE[chat_id] = {
|
||
**sc._default_session(),
|
||
"doc_facts": facts,
|
||
"updated_at": __import__("time").time(),
|
||
}
|
||
|
||
|
||
def test_can_answer_profit():
|
||
ok, keys = can_answer_from_facts("скільки прибутку у звіті?", FACTS)
|
||
assert ok is True
|
||
assert "profit_uah" in keys
|
||
|
||
|
||
def test_can_answer_fertilizer():
|
||
ok, keys = can_answer_from_facts("витрати на добрива?", FACTS)
|
||
assert ok is True
|
||
assert "fertilizer_uah" in keys
|
||
|
||
|
||
def test_cannot_answer_unknown():
|
||
facts_without_seed = {"area_ha": 497.0}
|
||
ok, keys = can_answer_from_facts("скільки витратили на насіння?", facts_without_seed)
|
||
assert ok is False
|
||
|
||
|
||
def test_session_has_doc_facts():
|
||
chat_id = "test_chat_fact_lock"
|
||
_setup_session(chat_id, FACTS)
|
||
session = sc.load_session(chat_id)
|
||
assert session.get("doc_facts") == FACTS
|
||
|
||
|
||
def test_fact_reuse_bypasses_rag():
|
||
"""
|
||
Перевіряємо що can_answer_from_facts повертає True і RAG можна пропустити.
|
||
Це unit-тест логіки bypass; інтеграційний тест потребує мока run.handle_message.
|
||
"""
|
||
chat_id = "test_bypass_rag"
|
||
_setup_session(chat_id, FACTS)
|
||
session = sc.load_session(chat_id)
|
||
facts = session.get("doc_facts", {})
|
||
|
||
question = "яка сума прибутку у звіті кукурудза?"
|
||
ok, keys = can_answer_from_facts(question, facts)
|
||
|
||
# Якщо ok=True — run.py НЕ викликає RAG (за логікою Fact Lock)
|
||
assert ok is True, f"Expected fact reuse, keys={keys}"
|