482 lines
21 KiB
Python
482 lines
21 KiB
Python
# 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
|