228 lines
6.5 KiB
Python
228 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import math
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
WorkflowDefinitionStatus = Literal["draft", "active", "archived"]
|
|
DefinitionScopeType = Literal["system", "tenant", "group", "user"]
|
|
DefinitionKind = Literal["flow", "template"]
|
|
|
|
|
|
class WorkflowPosition(BaseModel):
|
|
x: float = 0
|
|
y: float = 0
|
|
|
|
@field_validator("x", "y")
|
|
@classmethod
|
|
def finite_coordinate(cls, value: float) -> float:
|
|
if not math.isfinite(value):
|
|
raise ValueError("Graph coordinates must be finite.")
|
|
return value
|
|
|
|
|
|
class WorkflowNode(BaseModel):
|
|
id: str = Field(min_length=1, max_length=120)
|
|
type: str = Field(min_length=1, max_length=120)
|
|
label: str = Field(default="", max_length=300)
|
|
position: WorkflowPosition = Field(default_factory=WorkflowPosition)
|
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowEdge(BaseModel):
|
|
id: str = Field(min_length=1, max_length=120)
|
|
source: str = Field(min_length=1, max_length=120)
|
|
target: str = Field(min_length=1, max_length=120)
|
|
source_port: str = Field(default="output", min_length=1, max_length=120)
|
|
target_port: str = Field(default="input", min_length=1, max_length=120)
|
|
|
|
|
|
class WorkflowGraph(BaseModel):
|
|
schema_version: Literal[1] = 1
|
|
nodes: list[WorkflowNode] = Field(default_factory=list, max_length=150)
|
|
edges: list[WorkflowEdge] = Field(default_factory=list, max_length=300)
|
|
|
|
|
|
class WorkflowGraphValidationRequest(BaseModel):
|
|
graph: WorkflowGraph
|
|
|
|
|
|
class WorkflowDiagnosticResponse(BaseModel):
|
|
severity: Literal["error", "warning"]
|
|
code: str
|
|
message: str
|
|
node_id: str | None = None
|
|
field: str | None = None
|
|
|
|
|
|
class WorkflowGraphValidationResponse(BaseModel):
|
|
valid: bool
|
|
diagnostics: list[WorkflowDiagnosticResponse]
|
|
|
|
|
|
class WorkflowPortResponse(BaseModel):
|
|
id: str
|
|
label: str
|
|
required: bool
|
|
multiple: bool
|
|
minimum_connections: int
|
|
|
|
|
|
class WorkflowConfigFieldResponse(BaseModel):
|
|
id: str
|
|
label: str
|
|
kind: str
|
|
required: bool
|
|
description: str | None
|
|
options: list[tuple[str, str]]
|
|
|
|
|
|
class WorkflowNodeTypeResponse(BaseModel):
|
|
type: str
|
|
category: str
|
|
category_label: str
|
|
label: str
|
|
description: str
|
|
icon: str
|
|
input_ports: list[WorkflowPortResponse]
|
|
output_ports: list[WorkflowPortResponse]
|
|
config_fields: list[WorkflowConfigFieldResponse]
|
|
default_config: dict[str, Any]
|
|
|
|
|
|
class WorkflowNodeLibraryResponse(BaseModel):
|
|
id: str
|
|
version: str
|
|
allows_cycles: bool
|
|
nodes: list[WorkflowNodeTypeResponse]
|
|
|
|
|
|
class WorkflowDefinitionRevisionResponse(BaseModel):
|
|
id: str
|
|
revision: int
|
|
schema_version: int
|
|
graph: WorkflowGraph
|
|
content_hash: str
|
|
library_id: str
|
|
library_version: str
|
|
created_by: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class WorkflowActionDecisionResponse(BaseModel):
|
|
allowed: bool
|
|
reason: str | None = None
|
|
source_path: list[dict[str, Any]] = Field(default_factory=list)
|
|
requirements: list[str] = Field(default_factory=list)
|
|
details: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowGovernanceResponse(BaseModel):
|
|
scope_type: DefinitionScopeType
|
|
scope_id: str | None
|
|
definition_kind: DefinitionKind
|
|
inherit_to_lower_scopes: bool
|
|
allow_start: bool
|
|
allow_reuse: bool
|
|
allow_automation: bool
|
|
derived_from_definition_id: str | None
|
|
derived_from_revision: int | None
|
|
derived_from_hash: str | None
|
|
derivation_provenance: dict[str, Any] = Field(default_factory=dict)
|
|
actions: dict[str, WorkflowActionDecisionResponse]
|
|
automation_runtime_available: bool = False
|
|
automation_runtime_reason: str | None = None
|
|
|
|
|
|
class WorkflowDefinitionResponse(BaseModel):
|
|
id: str
|
|
tenant_id: str | None
|
|
key: str
|
|
name: str
|
|
description: str | None
|
|
status: WorkflowDefinitionStatus
|
|
current_revision: int
|
|
active_revision: int | None
|
|
metadata: dict[str, Any]
|
|
created_by: str | None
|
|
updated_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
revision: WorkflowDefinitionRevisionResponse
|
|
governance: WorkflowGovernanceResponse
|
|
|
|
|
|
class WorkflowDefinitionListResponse(BaseModel):
|
|
definitions: list[WorkflowDefinitionResponse]
|
|
|
|
|
|
class WorkflowDefinitionRevisionListResponse(BaseModel):
|
|
revisions: list[WorkflowDefinitionRevisionResponse]
|
|
|
|
|
|
class WorkflowDefinitionCreateRequest(BaseModel):
|
|
key: str | None = Field(
|
|
default=None,
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z0-9][A-Za-z0-9_-]*$",
|
|
)
|
|
name: str = Field(min_length=1, max_length=300)
|
|
description: str | None = Field(default=None, max_length=4_000)
|
|
graph: WorkflowGraph
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
scope_type: DefinitionScopeType = "tenant"
|
|
scope_id: str | None = Field(default=None, max_length=36)
|
|
definition_kind: DefinitionKind = "flow"
|
|
inherit_to_lower_scopes: bool = False
|
|
allow_start: bool = True
|
|
allow_reuse: bool = False
|
|
allow_automation: bool = False
|
|
|
|
|
|
class WorkflowDefinitionUpdateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
description: str | None = Field(default=None, max_length=4_000)
|
|
graph: WorkflowGraph
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
expected_revision: int = Field(ge=1)
|
|
scope_type: DefinitionScopeType = "tenant"
|
|
scope_id: str | None = Field(default=None, max_length=36)
|
|
definition_kind: DefinitionKind = "flow"
|
|
inherit_to_lower_scopes: bool = False
|
|
allow_start: bool = True
|
|
allow_reuse: bool = False
|
|
allow_automation: bool = False
|
|
|
|
|
|
class WorkflowDefinitionDeriveRequest(BaseModel):
|
|
key: str | None = Field(
|
|
default=None,
|
|
min_length=1,
|
|
max_length=120,
|
|
pattern=r"^[A-Za-z0-9][A-Za-z0-9_-]*$",
|
|
)
|
|
name: str = Field(min_length=1, max_length=300)
|
|
description: str | None = Field(default=None, max_length=4_000)
|
|
source_revision: int | None = Field(default=None, ge=1)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
scope_type: DefinitionScopeType = "tenant"
|
|
scope_id: str | None = Field(default=None, max_length=36)
|
|
definition_kind: DefinitionKind = "flow"
|
|
inherit_to_lower_scopes: bool = False
|
|
allow_start: bool = True
|
|
allow_reuse: bool = False
|
|
allow_automation: bool = False
|
|
|
|
|
|
class WorkflowDefinitionActivateRequest(BaseModel):
|
|
revision: int | None = Field(default=None, ge=1)
|
|
|
|
|
|
class WorkflowDefinitionDeleteResponse(BaseModel):
|
|
deleted: bool
|
|
definition_id: str
|