631 lines
18 KiB
Python
631 lines
18 KiB
Python
from __future__ import annotations
|
|
|
|
import math
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
|
|
|
|
WorkflowDefinitionStatus = Literal["draft", "active", "archived"]
|
|
DefinitionScopeType = Literal["system", "tenant", "group", "user"]
|
|
DefinitionKind = Literal["flow", "template"]
|
|
BpmnRuntimeKind = Literal["model_only", "native_graph", "external"]
|
|
WorkflowExecutionMode = Literal["guided", "automated", "hybrid"]
|
|
WorkflowStartOrigin = Literal[
|
|
"user",
|
|
"api",
|
|
"schedule",
|
|
"event",
|
|
"parent_workflow",
|
|
"dependency",
|
|
"retry",
|
|
"replay",
|
|
"backfill",
|
|
]
|
|
BpmnSupportLevel = Literal[
|
|
"interchange_only",
|
|
"native_mapping",
|
|
"native_execution",
|
|
]
|
|
|
|
|
|
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 WorkflowSize(BaseModel):
|
|
width: float = Field(default=100, gt=0, le=10_000)
|
|
height: float = Field(default=80, gt=0, le=10_000)
|
|
|
|
|
|
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)
|
|
size: WorkflowSize | None = None
|
|
parent_id: str | None = Field(default=None, max_length=120)
|
|
process_id: str | None = Field(default=None, max_length=120)
|
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowWaypoint(BaseModel):
|
|
x: float
|
|
y: float
|
|
|
|
@field_validator("x", "y")
|
|
@classmethod
|
|
def finite_coordinate(cls, value: float) -> float:
|
|
if not math.isfinite(value):
|
|
raise ValueError("Edge coordinates must be finite.")
|
|
return value
|
|
|
|
|
|
class WorkflowEdge(BaseModel):
|
|
id: str = Field(min_length=1, max_length=120)
|
|
type: Literal[
|
|
"bpmn.sequenceFlow",
|
|
"bpmn.messageFlow",
|
|
"bpmn.association",
|
|
"bpmn.dataInputAssociation",
|
|
"bpmn.dataOutputAssociation",
|
|
"bpmn.conversationLink",
|
|
] = "bpmn.sequenceFlow"
|
|
label: str = Field(default="", max_length=300)
|
|
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)
|
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
waypoints: list[WorkflowWaypoint] = Field(default_factory=list, max_length=500)
|
|
|
|
|
|
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)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
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]
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowNodeLibraryResponse(BaseModel):
|
|
id: str
|
|
version: str
|
|
allows_cycles: bool
|
|
nodes: list[WorkflowNodeTypeResponse]
|
|
|
|
|
|
class BpmnInspectionRequest(BaseModel):
|
|
xml: str = Field(min_length=1, max_length=1_048_576)
|
|
adapter_id: str = Field(
|
|
default="govoplan.native.bpmn",
|
|
min_length=1,
|
|
max_length=120,
|
|
)
|
|
adapter_version: str | None = Field(default=None, max_length=40)
|
|
activation: bool = False
|
|
|
|
|
|
class BpmnElementSupportResponse(BaseModel):
|
|
element_type: str
|
|
element_id: str | None = None
|
|
name: str | None = None
|
|
parent_type: str | None = None
|
|
parent_id: str | None = None
|
|
support_level: BpmnSupportLevel
|
|
|
|
|
|
class BpmnDiagnosticResponse(BaseModel):
|
|
severity: Literal["error", "warning", "info"]
|
|
code: str
|
|
message: str
|
|
element_id: str | None = None
|
|
|
|
|
|
class BpmnInspectionResponse(BaseModel):
|
|
valid_xml: bool
|
|
definitions_id: str | None = None
|
|
target_namespace: str | None = None
|
|
process_count: int
|
|
executable_process_count: int
|
|
collaboration_count: int
|
|
choreography_count: int
|
|
element_counts: dict[str, int]
|
|
support_counts: dict[str, int]
|
|
elements: list[BpmnElementSupportResponse]
|
|
diagnostics: list[BpmnDiagnosticResponse]
|
|
adapter_id: str | None = None
|
|
adapter_version: str | None = None
|
|
runtime_kind: BpmnRuntimeKind | None = None
|
|
executable: bool = False
|
|
activatable: bool = False
|
|
|
|
|
|
class BpmnAdapterProfileResponse(BaseModel):
|
|
id: str
|
|
version: str
|
|
label: str
|
|
description: str
|
|
conformance: str
|
|
runtime_kind: BpmnRuntimeKind
|
|
executable: bool
|
|
supported_elements: list[str]
|
|
supported_event_definitions: list[str]
|
|
requirements: list[str]
|
|
|
|
|
|
class BpmnSupportProfileResponse(BaseModel):
|
|
specification: str
|
|
model_namespace: str
|
|
interchange: str
|
|
native_runtime: str
|
|
native_execution_elements: list[str]
|
|
native_mapping_elements: list[str]
|
|
adapters: list[BpmnAdapterProfileResponse] = Field(default_factory=list)
|
|
|
|
|
|
class BpmnRevisionInput(BaseModel):
|
|
xml: str = Field(min_length=1, max_length=1_048_576)
|
|
adapter_id: str = Field(
|
|
default="govoplan.native.bpmn",
|
|
min_length=1,
|
|
max_length=120,
|
|
)
|
|
adapter_version: str | None = Field(default=None, max_length=40)
|
|
|
|
|
|
class BpmnRevisionSummaryResponse(BaseModel):
|
|
format: Literal["bpmn-2.0"] = "bpmn-2.0"
|
|
content_hash: str
|
|
adapter_id: str
|
|
adapter_version: str
|
|
runtime_kind: BpmnRuntimeKind
|
|
executable: bool
|
|
adapter_available: bool
|
|
|
|
|
|
class BpmnRevisionDocumentResponse(BpmnRevisionSummaryResponse):
|
|
definition_id: str
|
|
revision: int
|
|
xml: str
|
|
inspection: BpmnInspectionResponse
|
|
|
|
|
|
class BpmnCompileRequest(BaseModel):
|
|
xml: str = Field(min_length=1, max_length=1_048_576)
|
|
adapter_id: str = Field(
|
|
default="govoplan.native.bpmn",
|
|
min_length=1,
|
|
max_length=120,
|
|
)
|
|
adapter_version: str | None = Field(default=None, max_length=40)
|
|
|
|
|
|
class BpmnCompileResponse(BaseModel):
|
|
adapter: BpmnAdapterProfileResponse
|
|
graph: WorkflowGraph
|
|
inspection: BpmnInspectionResponse
|
|
|
|
|
|
class BpmnRenderRequest(BaseModel):
|
|
graph: WorkflowGraph
|
|
name: str = Field(default="", max_length=300)
|
|
|
|
|
|
class BpmnRenderResponse(BaseModel):
|
|
xml: str
|
|
inspection: BpmnInspectionResponse
|
|
|
|
|
|
class WorkflowDefinitionRevisionResponse(BaseModel):
|
|
id: str
|
|
revision: int
|
|
schema_version: int
|
|
graph: WorkflowGraph
|
|
content_hash: str
|
|
library_id: str
|
|
library_version: str
|
|
execution_mode: WorkflowExecutionMode
|
|
view_id: str | None = None
|
|
view_revision_id: str | None = None
|
|
bpmn: BpmnRevisionSummaryResponse | None = None
|
|
contribution_origin_module_version: str | None = None
|
|
contribution_schema_version: str | None = None
|
|
contribution_hash: str | None = None
|
|
contribution_metadata: dict[str, Any] = Field(default_factory=dict)
|
|
created_by: str | None
|
|
created_at: datetime
|
|
|
|
|
|
class WorkflowStandardProvenanceResponse(BaseModel):
|
|
kind: Literal["baseline", "override"]
|
|
origin_module_id: str
|
|
origin_module_version: str | None = None
|
|
definition_key: str
|
|
contribution_schema_version: str | None = None
|
|
contribution_hash: str | None = None
|
|
baseline_definition_id: str
|
|
latest_baseline_revision: int
|
|
active_baseline_revision: int | None = None
|
|
pinned_baseline_revision: int | None = None
|
|
pinned_baseline_hash: str | None = None
|
|
update_available: bool = False
|
|
reset_available: bool = False
|
|
|
|
|
|
class WorkflowStandardDiffItemResponse(BaseModel):
|
|
resource_type: Literal["graph", "node", "edge"]
|
|
resource_id: str
|
|
state: Literal[
|
|
"unchanged",
|
|
"local_only",
|
|
"upstream_only",
|
|
"same_change",
|
|
"conflict",
|
|
]
|
|
recommended_action: Literal[
|
|
"none",
|
|
"keep_local",
|
|
"adopt_upstream",
|
|
"either",
|
|
"manual_resolution",
|
|
]
|
|
changed_fields: list[str] = Field(default_factory=list)
|
|
baseline: dict[str, Any] | None = None
|
|
local: dict[str, Any] | None = None
|
|
latest: dict[str, Any] | None = None
|
|
|
|
|
|
class WorkflowStandardDiffResponse(BaseModel):
|
|
override_definition_id: str
|
|
baseline_definition_id: str
|
|
pinned_baseline_revision: int
|
|
local_revision: int
|
|
latest_baseline_revision: int
|
|
counts: dict[str, int]
|
|
conflict_count: int
|
|
auto_mergeable: bool
|
|
items: list[WorkflowStandardDiffItemResponse]
|
|
|
|
|
|
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
|
|
standard: WorkflowStandardProvenanceResponse | None = None
|
|
|
|
|
|
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
|
|
bpmn: BpmnRevisionInput | None = None
|
|
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
|
|
execution_mode: WorkflowExecutionMode = "hybrid"
|
|
view_id: str | None = Field(default=None, min_length=1, max_length=36)
|
|
view_revision_id: str | None = Field(
|
|
default=None,
|
|
min_length=1,
|
|
max_length=36,
|
|
)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_view_pin(self):
|
|
if self.view_revision_id and not self.view_id:
|
|
raise ValueError("A pinned View revision requires a View")
|
|
return self
|
|
|
|
|
|
class WorkflowDefinitionUpdateRequest(BaseModel):
|
|
name: str = Field(min_length=1, max_length=300)
|
|
description: str | None = Field(default=None, max_length=4_000)
|
|
graph: WorkflowGraph
|
|
bpmn: BpmnRevisionInput | None = None
|
|
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
|
|
execution_mode: WorkflowExecutionMode = "hybrid"
|
|
view_id: str | None = Field(default=None, min_length=1, max_length=36)
|
|
view_revision_id: str | None = Field(
|
|
default=None,
|
|
min_length=1,
|
|
max_length=36,
|
|
)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_view_pin(self):
|
|
if self.view_revision_id and not self.view_id:
|
|
raise ValueError("A pinned View revision requires a View")
|
|
return self
|
|
|
|
|
|
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
|
|
execution_mode: WorkflowExecutionMode | None = None
|
|
view_id: str | None = Field(default=None, min_length=1, max_length=36)
|
|
view_revision_id: str | None = Field(
|
|
default=None,
|
|
min_length=1,
|
|
max_length=36,
|
|
)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_view_pin(self):
|
|
if self.view_revision_id and not self.view_id:
|
|
raise ValueError("A pinned View revision requires a View")
|
|
return self
|
|
|
|
|
|
class WorkflowDefinitionActivateRequest(BaseModel):
|
|
revision: int | None = Field(default=None, ge=1)
|
|
|
|
|
|
class WorkflowDefinitionDeleteResponse(BaseModel):
|
|
deleted: bool
|
|
definition_id: str
|
|
|
|
|
|
class WorkflowTriggerResponse(BaseModel):
|
|
id: str
|
|
definition_id: str
|
|
definition_revision_id: str
|
|
node_id: str
|
|
kind: Literal["schedule", "event"]
|
|
status: str
|
|
event_type: str | None = None
|
|
next_fire_at: datetime | None = None
|
|
last_fire_at: datetime | None = None
|
|
last_status: str | None = None
|
|
last_error: str | None = None
|
|
authorization_subject_kind: Literal["delegated_user", "service_account"]
|
|
grant_scopes: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class WorkflowTriggerListResponse(BaseModel):
|
|
triggers: list[WorkflowTriggerResponse]
|
|
|
|
|
|
WorkflowInstanceStatus = Literal[
|
|
"running",
|
|
"waiting",
|
|
"completed",
|
|
"failed",
|
|
"cancelled",
|
|
]
|
|
WorkflowStepStatus = Literal[
|
|
"running",
|
|
"waiting",
|
|
"completed",
|
|
"failed",
|
|
"cancelled",
|
|
"superseded",
|
|
]
|
|
|
|
|
|
class WorkflowInstanceStartRequest(BaseModel):
|
|
idempotency_key: str = Field(min_length=1, max_length=255)
|
|
input: dict[str, Any] = Field(default_factory=dict)
|
|
correlation_id: str | None = Field(default=None, max_length=128)
|
|
|
|
|
|
class WorkflowStepActionRequest(BaseModel):
|
|
action: Literal[
|
|
"complete",
|
|
"approve",
|
|
"changes",
|
|
"reject",
|
|
"resume",
|
|
"retry",
|
|
"confirm_effect",
|
|
"confirm_absent",
|
|
"cancel",
|
|
]
|
|
output: dict[str, Any] = Field(default_factory=dict)
|
|
evidence: list[str] = Field(default_factory=list, max_length=100)
|
|
comment: str | None = Field(default=None, max_length=4_000)
|
|
|
|
|
|
class WorkflowInstanceStepResponse(BaseModel):
|
|
id: str
|
|
sequence: int
|
|
node_id: str
|
|
node_type: str
|
|
status: WorkflowStepStatus
|
|
attempt: int
|
|
input: dict[str, Any]
|
|
output: dict[str, Any]
|
|
handoff: dict[str, Any]
|
|
external_ref: str | None
|
|
started_at: datetime | None
|
|
finished_at: datetime | None
|
|
error: str | None
|
|
completed_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class WorkflowViewContextResponse(BaseModel):
|
|
view_id: str
|
|
revision_id: str | None = None
|
|
visible_surface_ids: list[str] = Field(default_factory=list)
|
|
step_id: str | None = None
|
|
node_id: str | None = None
|
|
|
|
|
|
class WorkflowInstanceEventResponse(BaseModel):
|
|
id: str
|
|
sequence: int
|
|
step_id: str | None
|
|
kind: str
|
|
actor_id: str | None
|
|
payload: dict[str, Any]
|
|
created_at: datetime
|
|
|
|
|
|
class WorkflowInstanceResponse(BaseModel):
|
|
id: str
|
|
definition_id: str
|
|
definition_name: str
|
|
definition_revision: int
|
|
definition_hash: str
|
|
execution_mode: WorkflowExecutionMode
|
|
start_origin: WorkflowStartOrigin
|
|
view_context: WorkflowViewContextResponse | None = None
|
|
status: WorkflowInstanceStatus
|
|
idempotency_key: str
|
|
correlation_id: str | None
|
|
current_step_id: str | None
|
|
input: dict[str, Any]
|
|
context: dict[str, Any]
|
|
output: dict[str, Any]
|
|
started_at: datetime
|
|
finished_at: datetime | None
|
|
cancellation_requested_at: datetime | None
|
|
error: str | None
|
|
created_by: str | None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
steps: list[WorkflowInstanceStepResponse]
|
|
events: list[WorkflowInstanceEventResponse]
|
|
replayed: bool = False
|
|
|
|
|
|
class WorkflowInstanceListResponse(BaseModel):
|
|
instances: list[WorkflowInstanceResponse]
|