Add pillar coverage guardrails for today workflow plans

This commit is contained in:
ي
2026-03-01 21:58:20 +05:30
parent f8f7ddeb2a
commit e7935af42a
2 changed files with 229 additions and 4 deletions

View File

@@ -0,0 +1,105 @@
from types import SimpleNamespace
import pytest
from services.intelligence.agents.core_agent_framework import TaskProposal
from services import today_workflow_service as svc
class DummyActivity:
def __init__(self, *args, **kwargs):
pass
def start_run(self, *args, **kwargs):
return SimpleNamespace(id="run-1")
def log_event(self, *args, **kwargs):
return None
def finish_run(self, *args, **kwargs):
return None
class DummyAgent:
def __init__(self, proposals):
self._proposals = proposals
async def propose_daily_tasks(self, grounding):
return self._proposals
def _mock_orchestrator_with_agents(proposals):
return SimpleNamespace(
agents={
"content": DummyAgent(proposals),
"seo": None,
"social": None,
"competitor": None,
}
)
def _covered_pillars(result):
return {task["pillarId"] for task in result["tasks"]}
@pytest.mark.asyncio
async def test_generate_agent_enhanced_plan_preserves_full_committee_coverage(monkeypatch):
proposals = [
TaskProposal("P", "desc", "plan", "high", 10, "content", "why", {}, "navigate", "/content-planning-dashboard"),
TaskProposal("G", "desc", "generate", "high", 10, "content", "why", {}, "navigate", "/blog-writer"),
TaskProposal("Pu", "desc", "publish", "high", 10, "content", "why", {}, "navigate", "/scheduler-dashboard"),
TaskProposal("A", "desc", "analyze", "high", 10, "content", "why", {}, "navigate", "/seo-dashboard"),
TaskProposal("E", "desc", "engage", "high", 10, "content", "why", {}, "navigate", "/linkedin-writer"),
TaskProposal("R", "desc", "remarket", "high", 10, "content", "why", {}, "navigate", "/facebook-writer"),
]
async def _get_orchestrator(user_id):
return _mock_orchestrator_with_agents(proposals)
monkeypatch.setattr(svc, "build_grounding_context", lambda db, user_id, date: {})
monkeypatch.setattr(svc.orchestration_service, "get_or_create_orchestrator", _get_orchestrator)
result = await svc.generate_agent_enhanced_plan(db=None, user_id="u1", date="2026-01-01")
assert _covered_pillars(result) == set(svc.PILLAR_IDS)
assert len(result["tasks"]) == len(proposals)
@pytest.mark.asyncio
async def test_generate_agent_enhanced_plan_backfills_missing_committee_pillars(monkeypatch):
proposals = [
TaskProposal("P", "desc", "plan", "high", 10, "content", "why", {}, "navigate", "/content-planning-dashboard"),
TaskProposal("G", "desc", "generate", "high", 10, "content", "why", {}, "navigate", "/blog-writer"),
]
async def _get_orchestrator(user_id):
return _mock_orchestrator_with_agents(proposals)
monkeypatch.setattr(svc, "build_grounding_context", lambda db, user_id, date: {})
monkeypatch.setattr(svc.orchestration_service, "get_or_create_orchestrator", _get_orchestrator)
result = await svc.generate_agent_enhanced_plan(db=None, user_id="u1", date="2026-01-01")
assert _covered_pillars(result) == set(svc.PILLAR_IDS)
assert {"P", "G"}.issubset({task["title"] for task in result["tasks"]})
@pytest.mark.asyncio
async def test_generate_agent_enhanced_plan_full_fallback_path_still_covers_all_pillars(monkeypatch):
async def _get_orchestrator(user_id):
return _mock_orchestrator_with_agents([])
monkeypatch.setattr(svc, "build_grounding_context", lambda db, user_id, date: {})
monkeypatch.setattr(svc.orchestration_service, "get_or_create_orchestrator", _get_orchestrator)
monkeypatch.setattr(svc, "AgentActivityService", DummyActivity)
def _raise_llm(*args, **kwargs):
raise RuntimeError("LLM down")
monkeypatch.setattr(svc, "llm_text_gen", _raise_llm)
result = await svc.generate_agent_enhanced_plan(db=None, user_id="u1", date="2026-01-01")
assert _covered_pillars(result) == set(svc.PILLAR_IDS)
assert len(result["tasks"]) >= len(svc.PILLAR_IDS)