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:
112
services/sofiia-supervisor/tests/conftest.py
Normal file
112
services/sofiia-supervisor/tests/conftest.py
Normal file
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
Shared test fixtures for sofiia-supervisor.
|
||||
|
||||
Uses httpx.MockTransport to mock gateway responses — no real network calls.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
# ─── Path bootstrap ───────────────────────────────────────────────────────────
|
||||
_svc_root = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(_svc_root))
|
||||
|
||||
|
||||
# ─── Gateway mock helpers ─────────────────────────────────────────────────────
|
||||
|
||||
class MockGatewayClient:
|
||||
"""
|
||||
Drop-in replacement for GatewayClient that intercepts call_tool and returns
|
||||
pre-configured responses without making HTTP requests.
|
||||
|
||||
Usage:
|
||||
mock_gw = MockGatewayClient()
|
||||
mock_gw.register("job_orchestrator_tool", "start_task", {"job_id": "j_001", "status": "running"})
|
||||
mock_gw.register("job_orchestrator_tool", "get_job", {"status": "succeeded", "result": {...}})
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._responses: Dict[str, List[Any]] = {} # key: "tool:action" → list of responses
|
||||
self.calls: List[Dict] = [] # recorded calls (no payload)
|
||||
|
||||
def register(self, tool: str, action: str, data: Any, *, error: Optional[str] = None, retryable: bool = False):
|
||||
"""Register a response for (tool, action). Multiple registrations → FIFO queue."""
|
||||
key = f"{tool}:{action}"
|
||||
self._responses.setdefault(key, []).append({
|
||||
"data": data, "error": error, "retryable": retryable
|
||||
})
|
||||
|
||||
def _pop(self, tool: str, action: str) -> Dict:
|
||||
key = f"{tool}:{action}"
|
||||
queue = self._responses.get(key, [])
|
||||
if queue:
|
||||
resp = queue.pop(0)
|
||||
if not queue:
|
||||
# Keep last response for further calls
|
||||
self._responses[key] = [resp]
|
||||
return resp
|
||||
return {"data": {}, "error": None, "retryable": False}
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
pass
|
||||
|
||||
async def call_tool(
|
||||
self,
|
||||
tool: str,
|
||||
action: str,
|
||||
params: Optional[Dict] = None,
|
||||
agent_id: str = "",
|
||||
workspace_id: str = "",
|
||||
user_id: str = "",
|
||||
graph_run_id: str = "",
|
||||
graph_node: str = "",
|
||||
**kwargs,
|
||||
):
|
||||
# Record call metadata (no payload logged)
|
||||
self.calls.append({
|
||||
"tool": tool,
|
||||
"action": action,
|
||||
"graph_run_id": graph_run_id,
|
||||
"graph_node": graph_node,
|
||||
"agent_id": agent_id,
|
||||
})
|
||||
|
||||
resp = self._pop(tool, action)
|
||||
from app.gateway_client import ToolCallResult
|
||||
if resp["error"]:
|
||||
return ToolCallResult(
|
||||
success=False,
|
||||
error_code="mock_error",
|
||||
error_message=resp["error"],
|
||||
retryable=resp.get("retryable", False),
|
||||
)
|
||||
return ToolCallResult(success=True, data=resp["data"])
|
||||
|
||||
|
||||
# ─── Fixtures ────────────────────────────────────────────────────────────────
|
||||
|
||||
@pytest.fixture
|
||||
def mock_gw_factory():
|
||||
"""Factory: returns a MockGatewayClient and patches app.gateway_client.GatewayClient."""
|
||||
def _make(patch_target: str = "app.gateway_client.GatewayClient"):
|
||||
return MockGatewayClient()
|
||||
return _make
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def in_memory_backend():
|
||||
from app.state_backend import MemoryStateBackend
|
||||
return MemoryStateBackend()
|
||||
|
||||
|
||||
def _run(coro):
|
||||
return asyncio.run(coro)
|
||||
Reference in New Issue
Block a user