# 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.attributeUtils import registerModelLabels 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 # --------------------------------------------------------------------------- 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}, ) mandateId: str = Field( description="Mandate ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False}, ) featureInstanceId: str = Field( description="Feature instance ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False}, ) label: str = Field( description="User-friendly workflow name", json_schema_extra={"frontend_type": "text", "frontend_required": True}, ) description: Optional[str] = Field( default=None, description="Workflow description", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) tags: List[str] = Field( default_factory=list, description="Tags for categorization", json_schema_extra={"frontend_type": "tags", "frontend_required": False}, ) isTemplate: bool = Field( default=False, description="Whether this workflow is a template", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False}, ) 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}, ) templateScope: Optional[str] = Field( default=None, description="Template scope: user, instance, mandate, system (AutoTemplateScope)", json_schema_extra={"frontend_type": "select", "frontend_required": False}, ) 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}, ) 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}, ) active: bool = Field( default=True, description="Whether workflow is active", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False}, ) 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}, ) notifyOnFailure: bool = Field( default=True, description="Send notification (in-app + email) when a run fails", json_schema_extra={"frontend_type": "checkbox", "frontend_required": False}, ) # 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}, ) 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}, ) registerModelLabels( "AutoWorkflow", {"en": "Workflow", "de": "Workflow", "fr": "Workflow"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "mandateId": {"en": "Mandate ID", "de": "Mandanten-ID", "fr": "ID du mandat"}, "featureInstanceId": {"en": "Feature Instance ID", "de": "Feature-Instanz-ID", "fr": "ID instance"}, "label": {"en": "Label", "de": "Bezeichnung", "fr": "Libellé"}, "description": {"en": "Description", "de": "Beschreibung", "fr": "Description"}, "tags": {"en": "Tags", "de": "Tags", "fr": "Tags"}, "isTemplate": {"en": "Is Template", "de": "Ist Vorlage", "fr": "Est modèle"}, "templateSourceId": {"en": "Template Source", "de": "Vorlagen-Quelle", "fr": "Source du modèle"}, "templateScope": {"en": "Template Scope", "de": "Vorlagen-Bereich", "fr": "Portée du modèle"}, "sharedReadOnly": {"en": "Shared Read-Only", "de": "Freigabe nur-lesen", "fr": "Partage lecture seule"}, "currentVersionId": {"en": "Current Version", "de": "Aktuelle Version", "fr": "Version actuelle"}, "active": {"en": "Active", "de": "Aktiv", "fr": "Actif"}, "eventId": {"en": "Event ID", "de": "Event-ID", "fr": "ID événement"}, "graph": {"en": "Graph", "de": "Graph", "fr": "Graphe"}, "invocations": {"en": "Starts / Entry points", "de": "Starts / Einstiegspunkte", "fr": "Points d'entrée"}, }, ) # --------------------------------------------------------------------------- # AutoVersion # --------------------------------------------------------------------------- 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}, ) workflowId: str = Field( description="FK -> AutoWorkflow", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) versionNumber: int = Field( default=1, description="Incrementing version number", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) status: str = Field( default=AutoWorkflowStatus.DRAFT.value, description="Version status: draft, published, archived", json_schema_extra={"frontend_type": "select", "frontend_required": False}, ) 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}, ) 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}, ) publishedAt: Optional[float] = Field( default=None, description="Timestamp when version was published", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False}, ) 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}, ) registerModelLabels( "AutoVersion", {"en": "Workflow Version", "de": "Workflow-Version", "fr": "Version workflow"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "workflowId": {"en": "Workflow ID", "de": "Workflow-ID", "fr": "ID workflow"}, "versionNumber": {"en": "Version", "de": "Version", "fr": "Version"}, "status": {"en": "Status", "de": "Status", "fr": "Statut"}, "graph": {"en": "Graph", "de": "Graph", "fr": "Graphe"}, "invocations": {"en": "Entry Points", "de": "Einstiegspunkte", "fr": "Points d'entrée"}, "publishedAt": {"en": "Published At", "de": "Veröffentlicht am", "fr": "Publié le"}, "publishedBy": {"en": "Published By", "de": "Veröffentlicht von", "fr": "Publié par"}, }, ) # --------------------------------------------------------------------------- # AutoRun # --------------------------------------------------------------------------- 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}, ) workflowId: str = Field( description="Workflow ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) 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}, ) status: str = Field( default=AutoRunStatus.RUNNING.value, description="Status: running, paused, completed, failed, cancelled", json_schema_extra={"frontend_type": "text", "frontend_required": False}, ) trigger: Dict[str, Any] = Field( default_factory=dict, description="Trigger info (type, entryPointId, payload, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) startedAt: Optional[float] = Field( default=None, description="Run start timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False}, ) completedAt: Optional[float] = Field( default=None, description="Run completion timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False}, ) nodeOutputs: Dict[str, Any] = Field( default_factory=dict, description="Outputs from executed nodes", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) 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}, ) resumeContext: Dict[str, Any] = Field( default_factory=dict, description="Context for resume (connectionMap, inputSources, etc.)", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) error: Optional[str] = Field( default=None, description="Error message if failed", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": True, "frontend_required": False}, ) costTokens: int = Field( default=0, description="Total tokens consumed by AI nodes", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) costCredits: float = Field( default=0.0, description="Total credits consumed", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) registerModelLabels( "AutoRun", {"en": "Workflow Run", "de": "Workflow-Ausführung", "fr": "Exécution workflow"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "workflowId": {"en": "Workflow ID", "de": "Workflow-ID", "fr": "ID workflow"}, "versionId": {"en": "Version ID", "de": "Versions-ID", "fr": "ID version"}, "status": {"en": "Status", "de": "Status", "fr": "Statut"}, "trigger": {"en": "Trigger", "de": "Auslöser", "fr": "Déclencheur"}, "startedAt": {"en": "Started At", "de": "Gestartet am", "fr": "Démarré le"}, "completedAt": {"en": "Completed At", "de": "Abgeschlossen am", "fr": "Terminé le"}, "nodeOutputs": {"en": "Node Outputs", "de": "Node-Ausgaben", "fr": "Sorties nœuds"}, "currentNodeId": {"en": "Current Node", "de": "Aktueller Knoten", "fr": "Nœud actuel"}, "resumeContext": {"en": "Resume Context", "de": "Wiederaufnahme-Kontext", "fr": "Contexte reprise"}, "error": {"en": "Error", "de": "Fehler", "fr": "Erreur"}, "costTokens": {"en": "Tokens Used", "de": "Verbrauchte Tokens", "fr": "Tokens utilisés"}, "costCredits": {"en": "Credits Used", "de": "Verbrauchte Credits", "fr": "Crédits utilisés"}, }, ) # --------------------------------------------------------------------------- # AutoStepLog # --------------------------------------------------------------------------- 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}, ) runId: str = Field( description="FK -> AutoRun", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) nodeId: str = Field( description="Node ID in the graph", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) nodeType: str = Field( description="Node type (e.g. ai.chat, email.send)", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) status: str = Field( default=AutoStepStatus.PENDING.value, description="Step status: pending, running, completed, failed, skipped", json_schema_extra={"frontend_type": "text", "frontend_required": False}, ) inputSnapshot: Dict[str, Any] = Field( default_factory=dict, description="Snapshot of inputs at execution time", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) output: Dict[str, Any] = Field( default_factory=dict, description="Node output", json_schema_extra={"frontend_type": "textarea", "frontend_required": False}, ) error: Optional[str] = Field( default=None, description="Error message if step failed", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": True, "frontend_required": False}, ) startedAt: Optional[float] = Field( default=None, description="Step start timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False}, ) completedAt: Optional[float] = Field( default=None, description="Step completion timestamp", json_schema_extra={"frontend_type": "datetime", "frontend_readonly": True, "frontend_required": False}, ) durationMs: Optional[int] = Field( default=None, description="Execution duration in milliseconds", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) tokensUsed: int = Field( default=0, description="Tokens consumed by this step", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) retryCount: int = Field( default=0, description="Number of retries executed", json_schema_extra={"frontend_type": "number", "frontend_readonly": True, "frontend_required": False}, ) registerModelLabels( "AutoStepLog", {"en": "Step Log", "de": "Schritt-Protokoll", "fr": "Journal d'étape"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "runId": {"en": "Run ID", "de": "Lauf-ID", "fr": "ID exécution"}, "nodeId": {"en": "Node ID", "de": "Knoten-ID", "fr": "ID nœud"}, "nodeType": {"en": "Node Type", "de": "Knotentyp", "fr": "Type nœud"}, "status": {"en": "Status", "de": "Status", "fr": "Statut"}, "inputSnapshot": {"en": "Input Snapshot", "de": "Eingabe-Snapshot", "fr": "Snapshot entrée"}, "output": {"en": "Output", "de": "Ausgabe", "fr": "Sortie"}, "error": {"en": "Error", "de": "Fehler", "fr": "Erreur"}, "startedAt": {"en": "Started At", "de": "Gestartet am", "fr": "Démarré le"}, "completedAt": {"en": "Completed At", "de": "Abgeschlossen am", "fr": "Terminé le"}, "durationMs": {"en": "Duration (ms)", "de": "Dauer (ms)", "fr": "Durée (ms)"}, "tokensUsed": {"en": "Tokens Used", "de": "Verbrauchte Tokens", "fr": "Tokens utilisés"}, "retryCount": {"en": "Retry Count", "de": "Wiederholungen", "fr": "Nombre de tentatives"}, }, ) # --------------------------------------------------------------------------- # AutoTask # --------------------------------------------------------------------------- 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}, ) runId: str = Field( description="FK -> AutoRun", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) workflowId: str = Field( description="Workflow ID", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) nodeId: str = Field( description="Node ID in the graph", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": True}, ) 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}, ) 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}, ) 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}, ) status: str = Field( default=AutoTaskStatus.PENDING.value, description="Status: pending, completed, cancelled, expired", json_schema_extra={"frontend_type": "text", "frontend_required": False}, ) 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}, ) expiresAt: Optional[float] = Field( default=None, description="Expiration timestamp for the task", json_schema_extra={"frontend_type": "datetime", "frontend_required": False}, ) registerModelLabels( "AutoTask", {"en": "Task", "de": "Aufgabe", "fr": "Tâche"}, { "id": {"en": "ID", "de": "ID", "fr": "ID"}, "runId": {"en": "Run ID", "de": "Lauf-ID", "fr": "ID exécution"}, "workflowId": {"en": "Workflow ID", "de": "Workflow-ID", "fr": "ID workflow"}, "nodeId": {"en": "Node ID", "de": "Knoten-ID", "fr": "ID nœud"}, "nodeType": {"en": "Node Type", "de": "Knotentyp", "fr": "Type nœud"}, "config": {"en": "Config", "de": "Konfiguration", "fr": "Configuration"}, "assigneeId": {"en": "Assignee", "de": "Zugewiesen an", "fr": "Assigné à"}, "status": {"en": "Status", "de": "Status", "fr": "Statut"}, "result": {"en": "Result", "de": "Ergebnis", "fr": "Résultat"}, "expiresAt": {"en": "Expires At", "de": "Läuft ab am", "fr": "Expire le"}, }, ) # --------------------------------------------------------------------------- # Backward-compatible aliases for transition period # --------------------------------------------------------------------------- Automation2Workflow = AutoWorkflow Automation2WorkflowRun = AutoRun Automation2HumanTask = AutoTask