"""Candidate plans. Models emit RoleDemand; the server binds real agents.""" from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field from app.report_collaboration.contracts.enums import ReportCostLevel, ReportPlanStatus class PlanRole(BaseModel): model_config = ConfigDict(extra="forbid") key: str display_name: str responsibility: str angle: str | None = None class QualityGateSpec(BaseModel): model_config = ConfigDict(extra="forbid") id: str label: str description: str | None = None class PlanValidation(BaseModel): model_config = ConfigDict(extra="forbid") ok: bool errors: list[str] = Field(default_factory=list) class PlanNode(BaseModel): """User-visible node summary. Execution bodies never travel on this type.""" model_config = ConfigDict(extra="forbid") id: str label: str role_key: str | None = None role_display_name: str | None = None angle: str | None = None depends_on: list[str] = Field(default_factory=list) mission: str | None = None output_artifact_type: str | None = None input_artifact_types: list[str] = Field(default_factory=list) allowed_tools: list[str] = Field(default_factory=list) acceptance_criteria: list[str] = Field(default_factory=list) class PlanEdge(BaseModel): model_config = ConfigDict(extra="forbid") source: str target: str label: str | None = None class RoleDemand(BaseModel): """Planner output before the assembler binds catalog agents and budgets.""" model_config = ConfigDict(extra="forbid") role_key: str display_name: str angle: str | None = None mission: str depends_on_roles: list[str] = Field(default_factory=list) output_artifact_type: str suggested_tools: list[str] = Field(default_factory=list) class ReportPlanCandidate(BaseModel): model_config = ConfigDict(extra="forbid") id: str proposal_group_id: str title: str strategy: str summary: str rationale: str recommended: bool = False estimated_duration_seconds: int estimated_cost_level: ReportCostLevel requirement_revision: int roles: list[PlanRole] = Field(default_factory=list) nodes: list[PlanNode] = Field(default_factory=list) edges: list[PlanEdge] = Field(default_factory=list) quality_gates: list[QualityGateSpec] = Field(default_factory=list) report_structure_id: str | None = None validation: PlanValidation revision: int status: ReportPlanStatus