"""Intelligent evaluation tables (智能评估).""" from datetime import datetime from typing import Any, Optional import sqlalchemy as sa from sqlmodel import Field, SQLModel from agenteval.storage.db.core import _json_dumps, _json_loads, new_uuid, utc_now class IntelligentEvalDB(SQLModel, table=True): """Intelligent evaluation (智能评估) — independent entity, peer to Campaign.""" __tablename__ = "intelligent_evals" __table_args__ = (sa.Index("ix_intelligent_evals_status", "status"),) id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) name: str target_id: str = Field(foreign_key="eval_targets.id") status: str = "draft" # User input (四件套) goal: str = "" seeds: str = "{}" intent: str = "" role_description: str = "" # Coarse plan (OpenClaw produces) plan: Optional[str] = None plan_feedback: Optional[str] = None # Time window time_window_hours: int = 24 # Report report: Optional[str] = None # Timestamps created_at: Optional[datetime] = Field(default_factory=utc_now) updated_at: Optional[datetime] = Field(default_factory=utc_now) started_at: Optional[datetime] = None completed_at: Optional[datetime] = None def get_seeds(self) -> dict[str, Any]: return _json_loads(self.seeds) def set_seeds(self, seeds: dict[str, Any]) -> None: self.seeds = _json_dumps(seeds) def get_plan(self) -> Optional[dict[str, Any]]: return _json_loads(self.plan) if self.plan else None def set_plan(self, plan: dict[str, Any]) -> None: self.plan = _json_dumps(plan) def get_report(self) -> Optional[dict[str, Any]]: return _json_loads(self.report) if self.report else None def set_report(self, report: dict[str, Any]) -> None: self.report = _json_dumps(report) class IntelligentEvalSessionDB(SQLModel, table=True): """A virtual-user session within an intelligent evaluation.""" __tablename__ = "intelligent_eval_sessions" id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) eval_id: str = Field(index=True, foreign_key="intelligent_evals.id") target_id: str = Field(foreign_key="eval_targets.id") persona: str = "{}" goal: str = "" dimension: Optional[str] = None status: str = "running" verdict: Optional[str] = None turn_count: int = 0 created_at: Optional[datetime] = Field(default_factory=utc_now) closed_at: Optional[datetime] = None def get_persona(self) -> dict[str, Any]: return _json_loads(self.persona) def set_persona(self, persona: dict[str, Any]) -> None: self.persona = _json_dumps(persona) def get_verdict(self) -> Optional[dict[str, Any]]: return _json_loads(self.verdict) if self.verdict else None def set_verdict(self, verdict: dict[str, Any]) -> None: self.verdict = _json_dumps(verdict) class IntelligentEvalMessageDB(SQLModel, table=True): """One chat message inside an intelligent eval session.""" __tablename__ = "intelligent_eval_messages" id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) session_id: str = Field(index=True, foreign_key="intelligent_eval_sessions.id") role: str = "user" content: str = "" latency_ms: Optional[int] = None created_at: Optional[datetime] = Field(default_factory=utc_now) class IntelligentEvalTaskQueueDB(SQLModel, table=True): """Task queue for intelligent evaluations (任务队列). Platform scans executing evals every minute and enqueues tasks for OpenClaw workers to pick up. """ __tablename__ = "intelligent_eval_task_queue" id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) eval_id: str = Field(index=True, foreign_key="intelligent_evals.id") # Task status status: str = Field(index=True) # pending / assigned / completed / failed priority: int = Field(index=True) # Lower is higher priority reason: str # Why this task needs attention (e.g., "slot_due", "all_sessions_completed") # Retry budget (ADR-0011): each stale requeue increments; >= MAX caps to failed attempts: int = Field(default=0) # Assignment info assigned_cron_id: Optional[str] = None assigned_at: Optional[datetime] = None # Completion info completed_at: Optional[datetime] = None error: Optional[str] = None # Timestamps created_at: Optional[datetime] = Field(default_factory=utc_now) updated_at: Optional[datetime] = Field(default_factory=utc_now) __table_args__ = ( sa.Index("idx_task_queue_status_priority", "status", "priority"), sa.Index("idx_task_queue_eval_status", "eval_id", "status"), sa.Index("idx_task_queue_assigned_at", "assigned_at"), ) class IntelligentEvalConfigSnapshotDB(SQLModel, table=True): """Config snapshot for intelligent evaluations (配置快照). Automatically saved when eval is created, plan is submitted, or config is updated. """ __tablename__ = "intelligent_eval_config_snapshots" id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) eval_id: str = Field(index=True, foreign_key="intelligent_evals.id") # Snapshot type snapshot_type: str # created / plan_submitted / config_updated # Config snapshot goal: str seeds: str # JSON intent: str role_description: str time_window_hours: int plan: Optional[str] = None # JSON, coarse plan snapshot # Metadata created_at: Optional[datetime] = Field(default_factory=utc_now) created_by: str = "user" # user / openclaw __table_args__ = (sa.Index("idx_config_snapshots_eval_created", "eval_id", "created_at"),) def get_seeds(self) -> dict[str, Any]: return _json_loads(self.seeds) def set_seeds(self, seeds: dict[str, Any]) -> None: self.seeds = _json_dumps(seeds) def get_plan(self) -> Optional[dict[str, Any]]: return _json_loads(self.plan) if self.plan else None def set_plan(self, plan: dict[str, Any]) -> None: self.plan = _json_dumps(plan) class IntelligentEvalDecisionLogDB(SQLModel, table=True): """Decision log for intelligent evaluations (决策日志). Records every decision made by OpenClaw workers (execute_session / wait / start_analysis). """ __tablename__ = "intelligent_eval_decision_logs" id: Optional[str] = Field(default_factory=new_uuid, primary_key=True) eval_id: str = Field(index=True, foreign_key="intelligent_evals.id") # Decision info decision_type: str # execute_session / wait / start_analysis reason: str # Why this decision was made context: str # JSON, decision context (current time slot, completed sessions, etc.) # Execution info cron_id: str # Which cron made this decision # Timestamp created_at: Optional[datetime] = Field(default_factory=utc_now) __table_args__ = (sa.Index("idx_decision_logs_eval_created", "eval_id", "created_at"),) def get_context(self) -> dict[str, Any]: return _json_loads(self.context) def set_context(self, context: dict[str, Any]) -> None: self.context = _json_dumps(context)