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,287 @@
"""
tests/test_stepan_v4_farm_state.py
v4 Farm State Layer:
- detect_farm_state_updates (crop, stage, issue, risk)
- update_farm_state (session merge, dedup, TTL)
- build_farm_state_prefix (format, empty cases, TTL)
- Isolation: prefix NOT added in doc/web mode
- State persists within session
"""
import time
import pytest
from crews.agromatrix_crew.farm_state import (
detect_farm_state_updates,
update_farm_state,
build_farm_state_prefix,
FARM_STATE_TTL,
)
# ─── 1. detect_farm_state_updates ────────────────────────────────────────────
class TestDetectFarmStateUpdates:
def test_crop_kukurudza(self):
u = detect_farm_state_updates("По кукурудзі що робити далі?")
assert u.get("current_crop") == "кукурудза"
def test_crop_inflection_kukurudzu(self):
u = detect_farm_state_updates("Переглянь стан кукурудзу на полі")
assert u.get("current_crop") == "кукурудза"
def test_crop_wheat(self):
u = detect_farm_state_updates("Пшениця виглядає кволою")
assert u.get("current_crop") == "пшениця"
def test_crop_sunflower(self):
u = detect_farm_state_updates("соняшник V6 посуха")
assert u.get("current_crop") == "соняшник"
def test_crop_rapeseed(self):
u = detect_farm_state_updates("ріпак — йде цвітіння")
assert u.get("current_crop") == "ріпак"
def test_stage_v6(self):
u = detect_farm_state_updates("Стадія V6, є жовтизна")
assert u.get("growth_stage") == "V6"
def test_stage_kushennya(self):
u = detect_farm_state_updates("пшениця, фаза кущення")
assert "кущення" in u.get("growth_stage", "").lower()
def test_stage_flowering(self):
u = detect_farm_state_updates("ріпак іде на цвітіння")
assert "цвітіння" in u.get("growth_stage", "").lower()
def test_issue_zhovtyzna(self):
u = detect_farm_state_updates("є жовтизна на листі")
assert "жовтизна" in u.get("recent_issue", "").lower()
def test_issue_deficit(self):
u = detect_farm_state_updates("дефіцит азоту у посівах")
assert "дефіцит" in u.get("recent_issue", "").lower()
def test_issue_shkidnyk(self):
u = detect_farm_state_updates("з'явились шкідники на кукурудзі")
assert "шкідник" in u.get("recent_issue", "").lower()
def test_risk_posuxa(self):
u = detect_farm_state_updates("на полі посуха вже 2 тижні")
assert "посуха" in u.get("risk_flags", [])
def test_risk_zamorozok(self):
u = detect_farm_state_updates("очікується заморозок вночі")
assert any("заморозок" in r for r in u.get("risk_flags", []))
def test_multiple_fields(self):
u = detect_farm_state_updates("кукурудза V6, дефіцит азоту, посуха")
assert u.get("current_crop") == "кукурудза"
assert "V6" in u.get("growth_stage", "")
assert "дефіцит" in u.get("recent_issue", "").lower()
assert any("посуха" in r for r in u.get("risk_flags", []))
def test_empty_text(self):
u = detect_farm_state_updates("")
assert u == {}
def test_no_match(self):
u = detect_farm_state_updates("привіт, як справи сьогодні?")
assert u == {}
def test_fail_safe_garbage(self):
u = detect_farm_state_updates(None) # type: ignore
assert u == {}
# ─── 2. update_farm_state ─────────────────────────────────────────────────────
class TestUpdateFarmState:
def test_creates_farm_state(self):
session = {}
update_farm_state(session, {"current_crop": "кукурудза"})
assert session["farm_state"]["current_crop"] == "кукурудза"
def test_sets_last_update_ts(self):
now = time.time()
session = {}
update_farm_state(session, {"current_crop": "соняшник"}, now_ts=now)
assert abs(session["farm_state"]["last_update_ts"] - now) < 1
def test_updates_existing(self):
session = {"farm_state": {"current_crop": "пшениця", "last_update_ts": 0.0}}
update_farm_state(session, {"current_crop": "кукурудза"})
assert session["farm_state"]["current_crop"] == "кукурудза"
def test_merges_risk_flags(self):
session = {"farm_state": {"risk_flags": ["посуха"], "last_update_ts": 0.0}}
update_farm_state(session, {"risk_flags": ["заморозок"]})
flags = session["farm_state"]["risk_flags"]
assert "посуха" in flags
assert "заморозок" in flags
def test_dedup_risk_flags(self):
session = {"farm_state": {"risk_flags": ["посуха", "спека"], "last_update_ts": 0.0}}
update_farm_state(session, {"risk_flags": ["посуха"]})
flags = session["farm_state"]["risk_flags"]
assert flags.count("посуха") == 1
def test_risk_flags_max_5(self):
session = {"farm_state": {"risk_flags": ["r1", "r2", "r3", "r4"], "last_update_ts": 0.0}}
update_farm_state(session, {"risk_flags": ["r5", "r6"]})
assert len(session["farm_state"]["risk_flags"]) <= 5
def test_empty_updates_noop(self):
session = {"farm_state": {"current_crop": "ріпак", "last_update_ts": 0.0}}
update_farm_state(session, {})
assert session["farm_state"]["current_crop"] == "ріпак"
def test_fail_safe_exception(self):
# session = None → fail-safe, no exception
update_farm_state(None, {"current_crop": "соя"}) # type: ignore
# ─── 3. build_farm_state_prefix ──────────────────────────────────────────────
class TestBuildFarmStatePrefix:
def _session_with_state(self, now: float, **kwargs) -> dict:
fs = {"last_update_ts": now}
fs.update(kwargs)
return {"farm_state": fs}
def test_empty_if_no_crop(self):
now = time.time()
s = self._session_with_state(now, growth_stage="V6")
assert build_farm_state_prefix(s) == ""
def test_basic_prefix(self):
now = time.time()
s = self._session_with_state(now, current_crop="кукурудза")
p = build_farm_state_prefix(s)
assert "кукурудза" in p
assert "[Контекст господарства]" in p
def test_includes_stage(self):
now = time.time()
s = self._session_with_state(now, current_crop="кукурудза", growth_stage="V6")
p = build_farm_state_prefix(s)
assert "V6" in p
assert "Стадія" in p
def test_includes_issue(self):
now = time.time()
s = self._session_with_state(now, current_crop="кукурудза", recent_issue="жовтизна")
p = build_farm_state_prefix(s)
assert "жовтизна" in p
assert "Проблема" in p
def test_includes_risks(self):
now = time.time()
s = self._session_with_state(now, current_crop="соняшник", risk_flags=["посуха", "спека"])
p = build_farm_state_prefix(s)
assert "посуха" in p
assert "Ризики" in p
def test_max_lines(self):
now = time.time()
s = self._session_with_state(
now,
current_crop="кукурудза",
growth_stage="V6",
recent_issue="жовтизна",
risk_flags=["посуха", "заморозок"],
)
p = build_farm_state_prefix(s)
assert len(p.splitlines()) <= 5
def test_empty_if_ttl_expired(self):
old_ts = time.time() - FARM_STATE_TTL - 10
s = self._session_with_state(old_ts, current_crop="кукурудза")
assert build_farm_state_prefix(s) == ""
def test_empty_if_no_farm_state(self):
assert build_farm_state_prefix({}) == ""
def test_fail_safe(self):
assert build_farm_state_prefix(None) == "" # type: ignore
# ─── 4. State persists within session ────────────────────────────────────────
class TestFarmStatePersistence:
def test_crop_persists_across_messages(self):
session = {}
# Перше повідомлення — встановлює crop
u1 = detect_farm_state_updates("По кукурудзі є дефіцит азоту")
update_farm_state(session, u1)
# Друге повідомлення — без crop, але є farm_state
u2 = detect_farm_state_updates("Що робити?")
update_farm_state(session, u2)
# Стан зберігся
assert session["farm_state"]["current_crop"] == "кукурудза"
def test_issue_updates_on_new_message(self):
session = {}
update_farm_state(session, {"current_crop": "пшениця", "recent_issue": "жовтизна"})
update_farm_state(session, {"recent_issue": "іржа"})
assert session["farm_state"]["recent_issue"] == "іржа"
def test_stage_updates(self):
session = {}
update_farm_state(session, {"current_crop": "кукурудза", "growth_stage": "V4"})
update_farm_state(session, {"growth_stage": "V6"})
assert session["farm_state"]["growth_stage"] == "V6"
# ─── 5. Ізоляція: prefix NOT в doc / web mode ─────────────────────────────────
def _would_inject(context_mode: str, domain: str, session: dict) -> bool:
"""Симуляція умови ін'єкції з run.py."""
if context_mode == "doc" or domain == "web":
return False
return bool(build_farm_state_prefix(session))
class TestFarmStatePrefixIsolation:
def _fresh_session(self) -> dict:
now = time.time()
session = {}
update_farm_state(session, {"current_crop": "кукурудза"}, now_ts=now)
return session
def test_not_injected_in_doc_mode(self):
s = self._fresh_session()
assert not _would_inject("doc", "doc", s)
def test_not_injected_in_web_domain(self):
s = self._fresh_session()
assert not _would_inject("general", "web", s)
def test_injected_in_general_mode(self):
s = self._fresh_session()
assert _would_inject("general", "general", s)
def test_injected_in_vision_domain(self):
s = self._fresh_session()
assert _would_inject("general", "vision", s)
def test_not_injected_if_no_crop(self):
s = {"farm_state": {"growth_stage": "V6", "last_update_ts": time.time()}}
assert not _would_inject("general", "general", s)
def test_not_injected_if_ttl_expired(self):
old_ts = time.time() - FARM_STATE_TTL - 60
s = {"farm_state": {"current_crop": "кукурудза", "last_update_ts": old_ts}}
assert not _would_inject("general", "general", s)
# ─── 6. FARM_STATE_TTL constant ──────────────────────────────────────────────
class TestConstants:
def test_farm_state_ttl_30min(self):
assert FARM_STATE_TTL == 1800.0