# ruff: noqa: E402 from typing import List, Optional, Dict, Any, Annotated from pydantic import BaseModel, Field import operator from datetime import datetime class UserUsageData(BaseModel): user_id: str wizard_iterations_today: int = 0 tokens_used_month: int = 0 last_reset_daily: Optional[datetime] = None last_reset_monthly: Optional[datetime] = None class FinancialData(BaseModel): revenue: float = Field(0.0, description="Przychody za ostatni rok obrotowy") net_profit: float = Field(0.0, description="Zysk netto") employment: int = Field( 0, description="Liczba pełnych etatów (Roczna Jednostka Pracy)" ) assets: float = Field(0.0, description="Suma bilansowa") class InvestmentPlan(BaseModel): description: str estimated_cost: float br_evidence: bool = False green_transform: bool = False digitalization: bool = False goz_dnsh: bool = False class CompanyProfile(BaseModel): nip: str pkd_codes: List[str] = Field(default_factory=list) voivodeship: str size: str = "MŚP" # Mikro, Mała, Średnia, Duża financials: Optional[FinancialData] = None innovation_focus: List[str] = Field(default_factory=list) is_in_difficulty: bool = False br_evidence: bool = False # Dowody B+R investment_plans: List[InvestmentPlan] = Field(default_factory=list) class GrantCall(BaseModel): id: str = "" title: str institution: str = "" deadline: str max_amount: float description: str = "" relevance_score: float = 0.0 poetic_match: str = "" # Dodane dla wirtualnego poety funduszowego explanation: Optional[Dict[str, Any]] = None # Explainable AI Match url: str = Field(default="", pattern=r"^(https://.*)?$", description="Link do dokumentacji naboru (musi zaczynać się od https://)") status: str = "" last_verified: str = "" is_outdated_warning: bool = False from typing import Literal class CriticFeedback(BaseModel): is_approved: bool feedback: str severity: Literal["low", "medium", "high"] class AgentState(BaseModel): messages: Annotated[list, operator.add] profile: Optional[CompanyProfile] = None eligible_grants: Optional[List[GrantCall]] = Field(default_factory=list) checklist: Optional[Dict[str, bool]] = Field(default_factory=dict) verification_results: Optional[Dict[str, Any]] = Field(default_factory=dict) timeline_events: Optional[List[Dict]] = Field(default_factory=list) wizard_step: int = 0 current_nabor: Optional[GrantCall] = None current_agent: str = "supervisor" user_id: str tenant_id: str program_name: Optional[str] = None # 2026 Architecture Upgrades blackboard: Optional[Dict[str, Any]] = Field( default_factory=dict, description="Wspólna pamięć faktów o firmie" ) task_plan: Optional[List[str]] = Field( default_factory=list, description="Lista kroków z Planner Agent" ) interrupt_history: Optional[List[Dict[str, Any]]] = Field( default_factory=list, description="Historia przerw Human-in-the-Loop" ) document_versions: Optional[Dict[str, List[str]]] = Field( default_factory=dict, description="Wersjonowanie generowanych fragmentów" ) guard_block: bool = False # Dodatkowe pola do obsługi cyklu oceny i HitL critic_evaluation: Optional[CriticFeedback] = None critic_iterations: int = 0 max_critic_iterations: int = 2 risk_score: Optional[Dict[str, Any]] = None verification_status: str = "pending" approved_by_human: bool = False class SupervisorDecision(BaseModel): next_agent: str reason: Optional[str] = None class PlanOutput(BaseModel): steps: List[str] class RiskScoreOutput(BaseModel): score: int risks: List[str] class MatchExplanation(BaseModel): reason: str criteria: List[str] risks: str class MatchOutput(BaseModel): relevance_score: float poetic_match: str explanation: Optional[MatchExplanation] = None class ProjectQAResponse(BaseModel): answer: str = Field( description="Twoja odpowiedź na pytanie poparta faktami. Tak/Nie z wyjaśnieniem, wątpliwościami itp." ) sources: List[str] = Field( default_factory=list, description="Lista źródeł, np. Nazwa dokumentu (paragraf/strona) lub Inne zidentyfikowane źródło", ) confidence: float = Field( 0.0, description="Poziom pewności we wnioskowaniu, od 0.0 do 1.0" ) recommendation: str = Field( description="Konkretna akcja dla użytkownika, np. 'Skoryguj wydatek w budżecie' lub 'To wymaga aneksu'." )