Artifex/control_plane/projects/ui_services.py
2026-08-15 20:56:56 +07:00

121 lines
11 KiB
Python

from __future__ import annotations
from collections import Counter
from django.db.models import Count, Q
from agents.control_room import AgentControlRoomService
from agents.lifecycle import LifecycleInspectionService
from agents.roadmap import RoadmapService
from agents.scenario_lab import ScenarioLabService
from control_plane.agents.models import AgentRun, AgentVersion, ProgenyExperiment, ProgenyInvestigation, ProgenySignal, PromotionStatus
from control_plane.events.models import Event
from control_plane.projects.models import ExplorationOpportunity, Project, RoadmapHorizon, ScenarioFinding, ScenarioRun, ScenarioSuite, StewardFinding, StewardRun, Task, TaskStatus
from control_plane.resources.models import ModelRequest, Resource
from graph.models import ExecutionGraphVersionStatus, GraphApproval, GraphApprovalStatus, GraphRun, GraphRunStatus
class ControlPlaneUIService:
def dashboard(self) -> dict[str, object]:
projects = Project.objects.all()
graph_runs = GraphRun.objects.select_related("execution_graph_version__graph", "project").order_by("-created_at")
steward_findings = StewardFinding.objects.all()
progeny_signals = ProgenySignal.objects.all()
control_room = AgentControlRoomService()
agent_health = [control_room.get_agent_health(version.id)["status"] for version in AgentVersion.objects.filter(promotion_status=PromotionStatus.CHAMPION)]
return {
"project_summary": {"total": projects.count(), "active": projects.exclude(status__in=["FINISHED", "FAILED"]).count(), "blocked_failed": projects.filter(status__in=["BLOCKED", "FAILED"]).count(), "recent_completed": projects.filter(status="FINISHED").order_by("-updated_at")[:5]},
"execution_summary": {"active": graph_runs.filter(status__in=[GraphRunStatus.PENDING, GraphRunStatus.RUNNING, GraphRunStatus.PAUSED]).count(), "failed": graph_runs.filter(status=GraphRunStatus.FAILED).count(), "recent_success": graph_runs.filter(status=GraphRunStatus.COMPLETE)[:5], "champion_task_graph": self._champion_graph("task_execution")},
"steward_summary": {"enrolled_projects": Project.objects.filter(steward_enrollments__status="ACTIVE").distinct().count(), "open_findings": steward_findings.exclude(status__in=["RESOLVED", "DISMISSED"]).count(), "high_findings": steward_findings.filter(severity__in=["HIGH", "CRITICAL"]).exclude(status__in=["RESOLVED", "DISMISSED"]).count()},
"progeny_summary": {"unresolved_signals": progeny_signals.filter(status="OPEN").count(), "open_investigations": ProgenyInvestigation.objects.filter(status="OPEN").count(), "challengers": AgentVersion.objects.filter(promotion_status=PromotionStatus.CHALLENGER).count(), "pending_experiment_decisions": ProgenyExperiment.objects.filter(status__in=["DRAFT", "RUNNING"]).count()},
"agent_summary": {"agent_count": AgentVersion.objects.values("agent").distinct().count(), "watch_degraded": sum(1 for status in agent_health if status in ["WATCH", "DEGRADED"]), "active_runs": AgentRun.objects.filter(status__in=["QUEUED", "RUNNING"]).count()},
"approval_count": GraphApproval.objects.filter(status=GraphApprovalStatus.PENDING).count(),
"recent": {"events": Event.objects.order_by("-created_at")[:10], "tasks": Task.objects.order_by("-updated_at")[:10], "graph_runs": graph_runs[:10], "findings": steward_findings.order_by("-updated_at")[:10], "investigations": ProgenyInvestigation.objects.order_by("-updated_at")[:10]},
}
def project_list(self) -> list[dict[str, object]]:
rows = []
for project in Project.objects.order_by("name"):
rows.append({"project": project, "current_milestone": project.milestones.order_by("order", "created_at").last(), "task_total": project.tasks.count(), "task_complete": project.tasks.filter(status=TaskStatus.COMPLETE).count(), "steward_state": project.steward_enrollments.order_by("-created_at").first(), "open_findings": project.steward_findings.exclude(status__in=["RESOLVED", "DISMISSED"]).count(), "latest_graph_run": project.graph_runs.order_by("-created_at").first(), "warnings": self.project_warnings(project)})
return rows
def project_workspace(self, project: Project) -> dict[str, object]:
lifecycle = LifecycleInspectionService().project_lifecycle_view(project)
return {"project": project, "plan": project.plans.order_by("-version").first(), "milestones": project.milestones.prefetch_related("features__tasks", "tasks").order_by("order", "created_at"), "tasks": project.tasks.select_related("milestone", "feature").order_by("milestone__order", "priority", "created_at"), "graph_runs": project.graph_runs.select_related("execution_graph_version__graph", "task").order_by("-created_at")[:20], "commits": project.commits.order_by("-created_at")[:10], "roadmap": RoadmapService().project_roadmap_view(project), "lifecycle": lifecycle, "scenario_coverage": ScenarioLabService().coverage(project), "activity": Event.objects.filter(project=project).order_by("-created_at")[:20], "warnings": self.project_warnings(project)}
def graph_run_detail(self, graph_run: GraphRun) -> dict[str, object]:
nodes = list(graph_run.node_runs.select_related("agent_version__agent", "model_request").order_by("created_at", "visit_index"))
traversals = list(graph_run.edge_traversals.order_by("created_at"))
return {"graph_run": graph_run, "nodes": nodes, "traversals": traversals, "approvals": graph_run.approvals.order_by("-created_at"), "model_request_count": sum(1 for node in nodes if node.model_request_id)}
def task_detail(self, task: Task) -> dict[str, object]:
return {"task": task, "dependencies": [edge.depends_on for edge in task.dependency_edges.select_related("depends_on")], "attempts": task.attempts.select_related("coder").order_by("attempt_number"), "graph_runs": task.graph_runs.select_related("execution_graph_version__graph").order_by("-created_at"), "tests": task.test_runs.order_by("-created_at"), "reviews": task.reviews.order_by("-created_at"), "commits": task.commits.order_by("-created_at")}
def steward(self, project: Project | None = None) -> dict[str, object]:
findings = StewardFinding.objects.select_related("project").order_by("-updated_at")
runs = StewardRun.objects.select_related("project").order_by("-created_at")
if project:
findings = findings.filter(project=project)
runs = runs.filter(project=project)
return {"findings": findings[:100], "runs": runs[:50]}
def progeny(self) -> dict[str, object]:
signals = ProgenySignal.objects.select_related("project", "agent_version__agent", "execution_graph_version__graph", "graph_node_run").order_by("-created_at")
grouped = Counter(signals.filter(status="OPEN").values_list("grouping_key", flat=True))
return {"signals": signals[:100], "groups": grouped.most_common(50), "investigations": ProgenyInvestigation.objects.order_by("-created_at")[:50], "experiments": ProgenyExperiment.objects.order_by("-created_at")[:50]}
def roadmap_board(self, project: Project | None = None) -> dict[str, object]:
items = Project.objects.none()
qs = project.roadmap_items if project else None
board = {}
for horizon in RoadmapHorizon.values:
board[horizon] = (qs.filter(horizon=horizon) if qs else __import__("control_plane.projects.models", fromlist=["RoadmapItem"]).RoadmapItem.objects.filter(horizon=horizon)).select_related("project").order_by("-composite_score", "-priority")
return board
def scenario_lab(self, project: Project | None = None) -> dict[str, object]:
suites = ScenarioSuite.objects.select_related("project").order_by("-created_at")
runs = ScenarioRun.objects.select_related("project", "scenario").order_by("-created_at")
findings = ScenarioFinding.objects.select_related("project", "scenario").order_by("-created_at")
if project:
suites = suites.filter(project=project)
runs = runs.filter(project=project)
findings = findings.filter(project=project)
coverage = Counter(ScenarioRun.objects.filter(project=project).values_list("scenario__scenario_type", flat=True) if project else ScenarioRun.objects.values_list("scenario__scenario_type", flat=True))
return {"suites": suites[:50], "runs": runs[:100], "findings": findings[:100], "coverage": dict(coverage)}
def resources(self) -> dict[str, object]:
rows = []
for resource in Resource.objects.order_by("name"):
requests = resource.model_requests.order_by("-created_at")
latencies = [value for value in requests.exclude(latency_ms=None).values_list("latency_ms", flat=True)[:50]]
rows.append({"resource": resource, "recent_requests": requests[:10], "request_count": requests.count(), "median_latency": sorted(latencies)[len(latencies) // 2] if latencies else None})
return {"resources": rows}
def approvals(self) -> dict[str, object]:
return {"approvals": GraphApproval.objects.select_related("graph_run__project", "graph_run__execution_graph_version__graph", "node_run").filter(status=GraphApprovalStatus.PENDING).order_by("created_at")}
def activity(self, project: Project | None = None) -> dict[str, object]:
events = Event.objects.select_related("project", "task").order_by("-created_at")
if project:
events = events.filter(project=project)
return {"events": events[:200]}
def project_brain(self, project: Project) -> dict[str, object]:
return {"project": project, "decisions": project.decisions.order_by("-created_at"), "plans": project.plans.order_by("-version"), "artifacts": project.artifacts.filter(artifact_type__icontains="PLAN").order_by("-created_at")}
def archaeologist(self, project: Project) -> dict[str, object]:
archaeology = project.artifacts.filter(artifact_type__icontains="ARCH").order_by("-created_at")
return {"project": project, "observed": project.architecture_summary, "artifacts": archaeology, "findings": project.findings.order_by("-created_at")[:50]}
def project_warnings(self, project: Project) -> list[str]:
warnings = []
if project.graph_runs.filter(status=GraphRunStatus.FAILED).exists():
warnings.append("failed graph runs")
if project.tasks.filter(status__in=[TaskStatus.BLOCKED, TaskStatus.FAILED]).exists():
warnings.append("blocked or failed tasks")
if project.steward_findings.filter(severity__in=["HIGH", "CRITICAL"]).exclude(status__in=["RESOLVED", "DISMISSED"]).exists():
warnings.append("high severity findings")
return warnings
def _champion_graph(self, name: str):
return __import__("graph.models", fromlist=["ExecutionGraphVersion"]).ExecutionGraphVersion.objects.filter(graph__name=name, status=ExecutionGraphVersionStatus.CHAMPION).select_related("graph").first()