feat(platform): add new services, tools, tests and crews modules

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
This commit is contained in:
Apple
2026-03-03 07:14:14 -08:00
parent e9dedffa48
commit 129e4ea1fc
241 changed files with 69349 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
"""
Tests for Doc Focus Gate (v3.5):
- PROMPT A: doc_focus fields in session, is_doc_focus_active, TTL
- PROMPT B: _is_doc_question, context_mode arbitration
- PROMPT C: auto-clear on vision/URL domain
- PROMPT D: /doc on|off|status operator commands
- PROMPT 1: domain override — explicit doc-token beats vision
- PROMPT 2: TTL auto-expire (simulated)
- PROMPT 3: context bleed guard
"""
import sys
import os
import time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "gateway-bot"))
# ── PROMPT A: session_context ────────────────────────────────────────────────
def test_default_session_has_doc_focus():
from crews.agromatrix_crew.session_context import _default_session
s = _default_session()
assert "doc_focus" in s
assert s["doc_focus"] is False
assert "doc_focus_ts" in s
assert s["doc_focus_ts"] == 0.0
def test_is_doc_focus_active_false_by_default():
from crews.agromatrix_crew.session_context import _default_session, is_doc_focus_active
s = _default_session()
assert is_doc_focus_active(s) is False
def test_is_doc_focus_active_true_when_set():
from crews.agromatrix_crew.session_context import is_doc_focus_active
now = time.time()
s = {"doc_focus": True, "doc_focus_ts": now}
assert is_doc_focus_active(s, now) is True
def test_is_doc_focus_active_expired():
from crews.agromatrix_crew.session_context import is_doc_focus_active, DOC_FOCUS_TTL
old_ts = time.time() - DOC_FOCUS_TTL - 1 # протух
s = {"doc_focus": True, "doc_focus_ts": old_ts}
assert is_doc_focus_active(s) is False
def test_is_doc_focus_active_just_within_ttl():
from crews.agromatrix_crew.session_context import is_doc_focus_active, DOC_FOCUS_TTL
now = time.time()
recent_ts = now - DOC_FOCUS_TTL + 5 # 5 секунд до завершення
s = {"doc_focus": True, "doc_focus_ts": recent_ts}
assert is_doc_focus_active(s, now) is True
def test_update_session_doc_focus():
from crews.agromatrix_crew.session_context import update_session, load_session, clear_session
chat_id = "test_doc_focus_chat"
clear_session(chat_id)
now = time.time()
update_session(chat_id, "test", depth="deep", doc_focus=True, doc_focus_ts=now)
s = load_session(chat_id)
assert s["doc_focus"] is True
assert abs(s["doc_focus_ts"] - now) < 1.0
clear_session(chat_id)
def test_update_session_doc_focus_off():
from crews.agromatrix_crew.session_context import update_session, load_session, clear_session
chat_id = "test_doc_focus_off_chat"
clear_session(chat_id)
now = time.time()
# Спочатку вмикаємо
update_session(chat_id, "test", depth="deep", doc_focus=True, doc_focus_ts=now)
# Потім вимикаємо
update_session(chat_id, "test2", depth="deep", doc_focus=False, doc_focus_ts=0.0)
s = load_session(chat_id)
assert s["doc_focus"] is False
clear_session(chat_id)
def test_is_doc_focus_active_fail_safe():
from crews.agromatrix_crew.session_context import is_doc_focus_active
# Broken session
assert is_doc_focus_active(None) is False
assert is_doc_focus_active({}) is False
assert is_doc_focus_active({"doc_focus": True}) is False # немає ts → вважається протухлим
# ── PROMPT B: _is_doc_question ───────────────────────────────────────────────
def test_is_doc_question_explicit():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("що у звіті?") is True
assert _is_doc_question("прибуток у документі") is True
assert _is_doc_question("відкрий звіт") is True
assert _is_doc_question("в цьому документі є дані?") is True
def test_is_doc_question_financial_with_doc_anchor():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("прибуток зі звіту") is True
assert _is_doc_question("витрати у файлі xlsx") is True
assert _is_doc_question("скільки грн/га в документі") is True
def test_is_doc_question_url_returns_false():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("https://www.cropscience.bayer.ua/Products") is False
assert _is_doc_question("вивчи каталог https://bayer.com") is False
def test_is_doc_question_vision_returns_false():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("що з листям?") is False
assert _is_doc_question("плями на рослині — що це?") is False
assert _is_doc_question("шкідник на фото") is False
def test_is_doc_question_web_intent_returns_false():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("вивчи каталог засобів захисту") is False
assert _is_doc_question("переглянь сторінку сайту") is False
def test_is_doc_question_general_false():
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("привіт") is False
assert _is_doc_question("що ти вмієш?") is False
assert _is_doc_question("план на тиждень") is False
# ── PROMPT B: _detect_domain ─────────────────────────────────────────────────
def test_detect_domain_vision():
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("що з листям?") == "vision"
assert _detect_domain("плями на рослині") == "vision"
assert _detect_domain("хвороба кукурудзи") == "vision"
def test_detect_domain_web():
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("https://bayer.com") == "web"
assert _detect_domain("вивчи каталог сайту") == "web"
def test_detect_domain_doc():
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("що у звіті?") == "doc"
assert _detect_domain("прибуток у документі") == "doc"
def test_detect_domain_general():
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("привіт") == "general"
assert _detect_domain("як справи?") == "general"
# ── PROMPT C: auto-clear logic ────────────────────────────────────────────────
def test_doc_focus_clear_on_vision():
"""Симулюємо логіку auto-clear: domain=vision → doc_focus=False."""
from crews.agromatrix_crew.doc_focus import _detect_domain
from crews.agromatrix_crew.session_context import is_doc_focus_active
now = time.time()
session = {"doc_focus": True, "doc_focus_ts": now}
text = "що з листям на фото?"
domain = _detect_domain(text)
assert domain == "vision"
# Логіка з run.py:
if domain in ("vision", "web"):
session["doc_focus"] = False
session["doc_focus_ts"] = 0.0
assert is_doc_focus_active(session, now) is False
def test_doc_focus_clear_on_url():
"""URL message → doc_focus скидається."""
from crews.agromatrix_crew.doc_focus import _detect_domain
from crews.agromatrix_crew.session_context import is_doc_focus_active
now = time.time()
session = {"doc_focus": True, "doc_focus_ts": now}
text = "ще будь ласка вивчи каталог засобів захисту рослин фірми BAYER https://www.cropscience.bayer.ua"
domain = _detect_domain(text)
assert domain == "web"
if domain in ("vision", "web"):
session["doc_focus"] = False
session["doc_focus_ts"] = 0.0
assert is_doc_focus_active(session, now) is False
def test_doc_focus_preserved_on_doc_question():
"""Doc питання → doc_focus не скидається."""
from crews.agromatrix_crew.doc_focus import _detect_domain, _is_doc_question
from crews.agromatrix_crew.session_context import is_doc_focus_active
now = time.time()
session = {"doc_focus": True, "doc_focus_ts": now}
text = "який прибуток у звіті?"
domain = _detect_domain(text)
assert domain == "doc"
# Vision/web auto-clear не спрацьовує
assert domain not in ("vision", "web")
# doc_focus залишається
assert is_doc_focus_active(session, now) is True
# ── PROMPT D: /doc commands ───────────────────────────────────────────────────
def test_doc_command_status_no_session():
from crews.agromatrix_crew.session_context import clear_session
from crews.agromatrix_crew.doc_focus import handle_doc_focus
clear_session("doc_test_chat_99")
result = handle_doc_focus("status", chat_id="doc_test_chat_99")
assert result is not None
msg = result.get("message", "") or str(result)
assert "doc_focus=off" in msg or "off" in msg
def test_doc_command_on():
from crews.agromatrix_crew.session_context import clear_session, load_session
from crews.agromatrix_crew.doc_focus import handle_doc_focus
chat_id = "doc_on_test_chat"
clear_session(chat_id)
result = handle_doc_focus("on", chat_id=chat_id)
assert result is not None
msg = result.get("message", "") or str(result)
assert "on" in msg
# Сесія має відображати зміну
from crews.agromatrix_crew.session_context import _STORE
s = _STORE.get(chat_id) or {}
assert s.get("doc_focus") is True
def test_doc_command_off():
from crews.agromatrix_crew.session_context import _STORE, clear_session
from crews.agromatrix_crew.doc_focus import handle_doc_focus
chat_id = "doc_off_test_chat"
_STORE[chat_id] = {"doc_focus": True, "doc_focus_ts": time.time(), "updated_at": time.time()}
result = handle_doc_focus("off", chat_id=chat_id)
assert result is not None
msg = result.get("message", "") or str(result)
assert "off" in msg
s = _STORE.get(chat_id) or {}
assert s.get("doc_focus") is False
clear_session(chat_id)
def test_doc_command_no_chat_id():
from crews.agromatrix_crew.doc_focus import handle_doc_focus
result = handle_doc_focus("on", chat_id=None)
msg = result.get("message", "") or str(result)
assert "chat_id" in msg.lower() or "required" in msg.lower()
def test_doc_command_status_shows_ttl():
from crews.agromatrix_crew.session_context import _STORE, clear_session
from crews.agromatrix_crew.doc_focus import handle_doc_focus
chat_id = "doc_status_ttl_test"
now = time.time()
_STORE[chat_id] = {"doc_focus": True, "doc_focus_ts": now, "active_doc_id": "abc123",
"doc_facts": {"profit_uah": 5000000}, "updated_at": now}
result = handle_doc_focus("status", chat_id=chat_id)
msg = result.get("message", "") or str(result)
assert "on" in msg
assert "ttl_left" in msg
assert "abc123" in msg
assert "profit_uah" in msg
clear_session(chat_id)
# ── PROMPT 1: domain override ────────────────────────────────────────────────
def test_detect_domain_explicit_doc_beats_vision():
"""Explicit doc-токен ('по звіту', 'у файлі') перемагає vision навіть якщо є рослини/листя."""
from crews.agromatrix_crew.doc_focus import _detect_domain
# Скрін таблиці + питання по звіту
assert _detect_domain("по звіту: що з листям?") == "doc"
assert _detect_domain("у файлі є дані по хворобі рослин?") == "doc"
assert _detect_domain("в документі — плями чи хвороба?") == "doc"
def test_detect_domain_empty_text_is_vision():
"""Порожній текст (caption відсутній) → vision (фото без caption)."""
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("") == "vision"
assert _detect_domain(" ") == "vision"
def test_detect_domain_url_beats_explicit_doc():
"""URL завжди виграє навіть якщо є explicit doc-токен."""
from crews.agromatrix_crew.doc_focus import _detect_domain
assert _detect_domain("по звіту https://bayer.com/products") == "web"
def test_is_doc_question_explicit_doc_token_beats_vision():
"""_is_doc_question повертає True якщо explicit doc-токен, навіть якщо є vision-слова."""
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("по звіту є дані про шкідника?") is True
assert _is_doc_question("у файлі листя згадується?") is True
assert _is_doc_question("в документі хвороба кукурудзи?") is True
def test_is_doc_question_vision_only_without_doc_token():
"""Vision без explicit doc-токена → False."""
from crews.agromatrix_crew.doc_focus import _is_doc_question
assert _is_doc_question("що з листям на фото?") is False
assert _is_doc_question("є хвороба чи шкідник?") is False
# ── PROMPT 2: TTL auto-expire ────────────────────────────────────────────────
def test_ttl_auto_expire_logic():
"""Симулюємо: doc_focus=True але TTL протух → expire."""
from crews.agromatrix_crew.session_context import is_doc_focus_active, DOC_FOCUS_TTL
now = time.time()
old_ts = now - DOC_FOCUS_TTL - 60 # на хвилину старіше TTL
session = {
"doc_focus": True,
"doc_focus_ts": old_ts,
"active_doc_id": "some_doc",
}
# is_doc_focus_active має повернути False
assert is_doc_focus_active(session, now) is False
# Логіка expire з run.py:
expired_age = round(now - (session.get("doc_focus_ts") or 0.0))
if session.get("doc_focus") and not is_doc_focus_active(session, now):
session["doc_focus"] = False
session["doc_focus_ts"] = 0.0
assert session["doc_focus"] is False
assert session["doc_focus_ts"] == 0.0
assert expired_age > DOC_FOCUS_TTL
def test_ttl_not_expired_within_window():
"""doc_focus не скидається якщо TTL ще не минув."""
from crews.agromatrix_crew.session_context import is_doc_focus_active, DOC_FOCUS_TTL
now = time.time()
recent_ts = now - (DOC_FOCUS_TTL / 2) # половина TTL
session = {"doc_focus": True, "doc_focus_ts": recent_ts}
assert is_doc_focus_active(session, now) is True
# Expire logic не спрацьовує
if session.get("doc_focus") and not is_doc_focus_active(session, now):
session["doc_focus"] = False
assert session["doc_focus"] is True
# ── PROMPT 3: context bleed guard ────────────────────────────────────────────
def _apply_bleed_guard(styled_response: str, context_mode: str) -> str:
"""Копія логіки context bleed guard з run.py для тестів."""
import re as _re
if context_mode == "general":
_BLEED_RE = _re.compile(
r"у\s+(?:цьому|наданому|даному)\s+документі"
r"\s+(?:цьому|наданому|даному)\s+документі"
r"|у\s+(?:цьому\s+)?звіті|в\s+(?:цьому\s+)?звіті",
_re.IGNORECASE | _re.UNICODE,
)
if _BLEED_RE.search(styled_response):
return "Щоб відповісти точно, уточни: це питання про звіт чи про інше?"
return styled_response
def test_bleed_guard_replaces_doc_phrase_in_general_mode():
"""В general-mode фраза 'у цьому документі' заміняється на нейтральне питання."""
response = "У цьому документі немає інформації про каталог BAYER."
result = _apply_bleed_guard(response, "general")
assert "цьому документі" not in result
assert "уточни" in result
def test_bleed_guard_replaces_zvit_phrase():
"""В general-mode фраза 'у звіті' також блокується."""
response = "У звіті немає даних про засоби захисту."
result = _apply_bleed_guard(response, "general")
assert "уточни" in result
def test_bleed_guard_no_replacement_in_doc_mode():
"""В doc-mode doc-фрази дозволені."""
response = "У цьому документі прибуток: 5 972 016 грн."
result = _apply_bleed_guard(response, "doc")
assert result == response
def test_bleed_guard_no_replacement_without_doc_phrase():
"""Відповідь без doc-фраз не змінюється в general-mode."""
response = "Це рослина кукурудзи, виглядає здоровою."
result = _apply_bleed_guard(response, "general")
assert result == response
def test_bleed_guard_case_insensitive():
"""Блокування не залежить від регістру."""
response = "В Цьому Документі відсутня ця інформація."
result = _apply_bleed_guard(response, "general")
assert "уточни" in result
def test_bleed_guard_variant_phrases():
"""Різні варіанти фрази блокуються."""
phrases = [
"у наданому документі немає",
"В даному документі відсутні",
"у цьому звіті є лише",
"в цьому звіті міститься",
]
for p in phrases:
result = _apply_bleed_guard(p, "general")
assert "уточни" in result, f"Not blocked: {p!r}"