# Copyright (c) 2025 Patrick Motsch # All rights reserved. """GraphicalEditor models with Auto-prefix: AutoWorkflow, AutoVersion, AutoRun, AutoStepLog, AutoTask.""" from enum import Enum from typing import Dict, Any, List, Optional from pydantic import BaseModel, Field from modules.datamodels.datamodelBase import PowerOnModel from modules.shared.i18nRegistry import i18nModel import uuid # --------------------------------------------------------------------------- # Enums # --------------------------------------------------------------------------- class AutoWorkflowStatus(str, Enum): DRAFT = "draft" PUBLISHED = "published" ARCHIVED = "archived" class AutoRunStatus(str, Enum): RUNNING = "running" PAUSED = "paused" COMPLETED = "completed" FAILED = "failed" CANCELLED = "cancelled" class AutoStepStatus(str, Enum): PENDING = "pending" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" SKIPPED = "skipped" class AutoTaskStatus(str, Enum): PENDING = "pending" COMPLETED = "completed" CANCELLED = "cancelled" EXPIRED = "expired" class AutoTemplateScope(str, Enum): USER = "user" INSTANCE = "instance" MANDATE = "mandate" SYSTEM = "system" # --------------------------------------------------------------------------- # AutoWorkflow # --------------------------------------------------------------------------- @i18nModel("Workflow") class AutoWorkflow(PowerOnModel): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "ID"}, ) mandateId: str = Field( description="Mandate ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Mandanten-ID"}, ) featureInstanceId: str = Field( description="Feature instance ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Feature-Instanz-ID"}, ) label: str = Field( description="User-friendly workflow name", json_schema_extra={"frontend_type": "text", "frontend_required": True, "label": "Bezeichnung"}, ) description: Optional[str] = Field( default=None, description="Workflow description", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Beschreibung"}, ) tags: List[str] = Field( default_factory=list, description="Tags for categorization", json_schema_extra={"frontend_type": "tags", "frontend_required": False, "label": "Tags"}, ) isTemplate: bool = Field( default=False, description="Whether this workflow is a template", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False, "label": "Ist Vorlage"}, ) templateSourceId: Optional[str] = Field( default=None, description="ID of the template this workflow was created from", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Vorlagen-Quelle"}, ) templateScope: Optional[str] = Field( default=None, description="Template scope: user, instance, mandate, system (AutoTemplateScope)", json_schema_extra={"frontend_type": "select", "frontend_required": False, "label": "Vorlagen-Bereich"}, ) sharedReadOnly: bool = Field( default=False, description="If true, shared template is read-only for non-owners", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False, "label": "Freigabe nur-lesen"}, ) currentVersionId: Optional[str] = Field( default=None, description="ID of the currently published AutoVersion", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Aktuelle Version"}, ) active: bool = Field( default=True, description="Whether workflow is active", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False, "label": "Aktiv"}, ) eventId: Optional[str] = Field( default=None, description="Scheduler event ID for incremental sync", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Event-ID"}, ) notifyOnFailure: bool = Field( default=True, description="Send notification (in-app + email) when a run fails", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False, "label": "Bei Fehler benachrichtigen"}, ) # Legacy fields kept for backward compatibility during transition graph: Dict[str, Any] = Field( default_factory=dict, description="Graph with nodes and connections (legacy; prefer AutoVersion.graph)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Graph"}, ) invocations: List[Dict[str, Any]] = Field( default_factory=list, description="Entry points / starts (manual, form, schedule, webhook, ...)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Starts / Einstiegspunkte"}, ) # --------------------------------------------------------------------------- # AutoVersion # --------------------------------------------------------------------------- @i18nModel("Workflow-Version") class AutoVersion(PowerOnModel): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "ID"}, ) workflowId: str = Field( description="FK -> AutoWorkflow", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Workflow-ID"}, ) versionNumber: int = Field( default=1, description="Incrementing version number", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Version"}, ) status: str = Field( default=AutoWorkflowStatus.DRAFT.value, description="Version status: draft, published, archived", json_schema_extra={"frontend_type": "select", "frontend_required": False, "label": "Status"}, ) graph: Dict[str, Any] = Field( default_factory=dict, description="Graph with nodes and connections (incl. node parameters)", json_schema_extra={"frontend_type": "textarea", "frontend_required": True, "label": "Graph"}, ) invocations: List[Dict[str, Any]] = Field( default_factory=list, description="Entry points / starts for this version", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Einstiegspunkte"}, ) publishedAt: Optional[float] = Field( default=None, description="Timestamp when version was published", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False, "label": "Veröffentlicht am"}, ) publishedBy: Optional[str] = Field( default=None, description="User ID who published this version", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Veröffentlicht von"}, ) # --------------------------------------------------------------------------- # AutoRun # --------------------------------------------------------------------------- @i18nModel("Workflow-Ausführung") class AutoRun(PowerOnModel): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "ID"}, ) workflowId: str = Field( description="Workflow ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Workflow-ID"}, ) mandateId: Optional[str] = Field( default=None, description="Mandate ID for cross-feature querying", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Mandanten-ID"}, ) ownerId: Optional[str] = Field( default=None, description="User ID who triggered this run", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Auslöser"}, ) versionId: Optional[str] = Field( default=None, description="AutoVersion ID used for this run", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Versions-ID"}, ) status: str = Field( default=AutoRunStatus.RUNNING.value, description="Status: running, paused, completed, failed, cancelled", json_schema_extra={"frontend_type": "text", "frontend_required": False, "label": "Status"}, ) trigger: Dict[str, Any] = Field( default_factory=dict, description="Trigger info (type, entryPointId, payload, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Auslöser"}, ) startedAt: Optional[float] = Field( default=None, description="Run start timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False, "label": "Gestartet am"}, ) completedAt: Optional[float] = Field( default=None, description="Run completion timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False, "label": "Abgeschlossen am"}, ) nodeOutputs: Dict[str, Any] = Field( default_factory=dict, description="Outputs from executed nodes", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Node-Ausgaben"}, ) currentNodeId: Optional[str] = Field( default=None, description="Node ID when paused (human task / email wait)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "Aktueller Knoten"}, ) resumeContext: Dict[str, Any] = Field( default_factory=dict, description="Context for resume (connectionMap, inputSources, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Wiederaufnahme-Kontext"}, ) error: Optional[str] = Field( default=None, description="Error message if failed", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": True, "frontend_required": False, "label": "Fehler"}, ) costTokens: int = Field( default=0, description="Total tokens consumed by AI nodes", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Verbrauchte Tokens"}, ) costCredits: float = Field( default=0.0, description="Total credits consumed", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Verbrauchte Credits"}, ) # --------------------------------------------------------------------------- # AutoStepLog # --------------------------------------------------------------------------- @i18nModel("Schritt-Protokoll") class AutoStepLog(PowerOnModel): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "ID"}, ) runId: str = Field( description="FK -> AutoRun", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Lauf-ID"}, ) nodeId: str = Field( description="Node ID in the graph", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Knoten-ID"}, ) nodeType: str = Field( description="Node type (e.g. ai.chat, email.send)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Knotentyp"}, ) status: str = Field( default=AutoStepStatus.PENDING.value, description="Step status: pending, running, completed, failed, skipped", json_schema_extra={"frontend_type": "text", "frontend_required": False, "label": "Status"}, ) inputSnapshot: Dict[str, Any] = Field( default_factory=dict, description="Snapshot of inputs at execution time", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Eingabe-Snapshot"}, ) output: Dict[str, Any] = Field( default_factory=dict, description="Node output", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Ausgabe"}, ) error: Optional[str] = Field( default=None, description="Error message if step failed", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": True, "frontend_required": False, "label": "Fehler"}, ) startedAt: Optional[float] = Field( default=None, description="Step start timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False, "label": "Gestartet am"}, ) completedAt: Optional[float] = Field( default=None, description="Step completion timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False, "label": "Abgeschlossen am"}, ) durationMs: Optional[int] = Field( default=None, description="Execution duration in milliseconds", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Dauer (ms)"}, ) tokensUsed: int = Field( default=0, description="Tokens consumed by this step", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Verbrauchte Tokens"}, ) retryCount: int = Field( default=0, description="Number of retries executed", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False, "label": "Wiederholungen"}, ) # --------------------------------------------------------------------------- # AutoTask # --------------------------------------------------------------------------- @i18nModel("Aufgabe") class AutoTask(PowerOnModel): id: str = Field( default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False, "label": "ID"}, ) runId: str = Field( description="FK -> AutoRun", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Lauf-ID"}, ) workflowId: str = Field( description="Workflow ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Workflow-ID"}, ) nodeId: str = Field( description="Node ID in the graph", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Knoten-ID"}, ) nodeType: str = Field( description="Node type: form, approval, upload, comment, review, selection, confirmation", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True, "label": "Knotentyp"}, ) config: Dict[str, Any] = Field( default_factory=dict, description="Node config (form schema, approval text, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Konfiguration"}, ) assigneeId: Optional[str] = Field( default=None, description="User ID assigned to complete the task", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": False, "label": "Zugewiesen an"}, ) status: str = Field( default=AutoTaskStatus.PENDING.value, description="Status: pending, completed, cancelled, expired", json_schema_extra={"frontend_type": "text", "frontend_required": False, "label": "Status"}, ) result: Optional[Dict[str, Any]] = Field( default=None, description="Task result (form data, approval decision, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False, "label": "Ergebnis"}, ) expiresAt: Optional[float] = Field( default=None, description="Expiration timestamp for the task", json_schema_extra={"frontend_type": "datetime", "frontend_required": False, "label": "Läuft ab am"}, ) # --------------------------------------------------------------------------- # Backward-compatible aliases for transition period # --------------------------------------------------------------------------- Automation2Workflow = AutoWorkflow Automation2WorkflowRun = AutoRun Automation2HumanTask = AutoTask