studio / app /models /workflow.py
Ava2lon's picture
Upload 2 files
b47633b verified
Raw
History Blame
12.7 kB
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator
class Position(BaseModel):
x: float
y: float
class CredentialReference(BaseModel):
id: str | None = None
name: str
type: str
class WorkflowNodeData(BaseModel):
model_config = ConfigDict(extra="allow")
label: str = Field(min_length=1, max_length=128)
type: str = Field(min_length=1, max_length=256)
typeVersion: float = Field(default=1, ge=0)
category: Literal[
"trigger", "core", "ai", "database", "communication", "cloud", "developer"
]
subtitle: str | None = Field(default=None, max_length=256)
parameters: dict[str, Any] = Field(default_factory=dict)
credentials: dict[str, CredentialReference] | None = None
disabled: bool = False
issues: int = 0
class WorkflowNode(BaseModel):
id: str = Field(min_length=1, max_length=128)
type: str = "workflow"
position: Position
data: WorkflowNodeData
selected: bool | None = None
class WorkflowEdge(BaseModel):
id: str = Field(min_length=1, max_length=256)
source: str
target: str
type: str = "smoothstep"
animated: bool = False
sourceHandle: str | None = None
targetHandle: str | None = None
class WorkflowMeta(BaseModel):
model_config = ConfigDict(extra="allow")
description: str | None = None
generatedBy: str | None = None
version: int | None = None
tags: list[str] = Field(default_factory=list)
class WorkflowDocument(BaseModel):
id: str | None = None
name: str = Field(min_length=1, max_length=160)
active: bool = False
nodes: list[WorkflowNode] = Field(default_factory=list, max_length=1000)
edges: list[WorkflowEdge] = Field(default_factory=list, max_length=5000)
settings: dict[str, Any] = Field(default_factory=dict)
meta: WorkflowMeta = Field(default_factory=WorkflowMeta)
pinData: dict[str, Any] = Field(default_factory=dict)
@field_validator("nodes")
@classmethod
def unique_node_ids(cls, nodes: list[WorkflowNode]) -> list[WorkflowNode]:
ids = [node.id for node in nodes]
if len(ids) != len(set(ids)):
raise ValueError("Node IDs must be unique")
return nodes
@field_validator("edges")
@classmethod
def unique_edge_ids(cls, edges: list[WorkflowEdge]) -> list[WorkflowEdge]:
ids = [edge.id for edge in edges]
if len(ids) != len(set(ids)):
raise ValueError("Edge IDs must be unique")
return edges
class GenerateWorkflowRequest(BaseModel):
prompt: str = Field(min_length=10, max_length=20_000)
provider: Literal["openai", "gemini", "openrouter", "deterministic"] | None = None
model: str | None = Field(
default=None,
min_length=1,
max_length=200,
pattern=r"^[A-Za-z0-9][A-Za-z0-9._:/-]*$",
)
class GenerateWorkflowResponse(BaseModel):
workflow: WorkflowDocument
explanation: str
warnings: list[str] = Field(default_factory=list)
class WorkflowRequest(BaseModel):
workflow: WorkflowDocument
class ValidationIssue(BaseModel):
code: str
severity: Literal["error", "warning", "info"]
message: str
nodeId: str | None = None
suggestion: str | None = None
class ValidationResult(BaseModel):
valid: bool
score: int = Field(ge=0, le=100)
issues: list[ValidationIssue]
class OptimizationSuggestion(BaseModel):
title: str
description: str
impact: Literal["low", "medium", "high"]
nodeIds: list[str] = Field(default_factory=list)
class OptimizationResponse(BaseModel):
workflow: WorkflowDocument
suggestions: list[OptimizationSuggestion]
class ChatRequest(BaseModel):
message: str = Field(min_length=1, max_length=20_000)
workflow: WorkflowDocument
conversation_id: str | None = None
class ChatResponse(BaseModel):
message: str
workflow: WorkflowDocument | None = None
actions: list[str] = Field(default_factory=list)
class ExpressionRequest(BaseModel):
description: str = Field(min_length=2, max_length=4000)
context: dict[str, Any] = Field(default_factory=dict)
class ExpressionResponse(BaseModel):
expression: str
explanation: str
alternatives: list[str] = Field(default_factory=list)
class ImportRequest(BaseModel):
content: str = Field(min_length=2, max_length=5_000_000)
source: Literal["json", "clipboard", "url", "github"] = "json"
class ExportRequest(BaseModel):
workflow: WorkflowDocument
format: Literal["n8n", "internal"] = "n8n"
class SaveRequest(BaseModel):
workflow: WorkflowDocument
project_id: str | None = None
change_summary: str = Field(default="Manual save", max_length=500)
class SaveResponse(BaseModel):
id: str
version: int
saved_at: str
class SimulationRequest(BaseModel):
workflow: WorkflowDocument
input_data: dict[str, Any] = Field(default_factory=dict)
class NodeRunResult(BaseModel):
node_id: str
node_name: str
status: Literal["success", "skipped", "error"]
duration_ms: int = Field(ge=0)
input_data: dict[str, Any] = Field(default_factory=dict)
output_data: dict[str, Any] = Field(default_factory=dict)
error: str | None = None
class SimulationResponse(BaseModel):
status: Literal["success", "error"]
duration_ms: int = Field(ge=0)
trace: list[NodeRunResult]
output_data: dict[str, Any] = Field(default_factory=dict)
warnings: list[str] = Field(default_factory=list)
class TestAssertion(BaseModel):
path: str = Field(min_length=1, max_length=500)
operator: Literal["equals", "not_equals", "exists", "contains"] = "equals"
expected: Any = None
class WorkflowTestCase(BaseModel):
name: str = Field(min_length=1, max_length=160)
input_data: dict[str, Any] = Field(default_factory=dict)
assertions: list[TestAssertion] = Field(default_factory=list, max_length=100)
class TestWorkflowRequest(BaseModel):
workflow: WorkflowDocument
cases: list[WorkflowTestCase] = Field(min_length=1, max_length=100)
class TestCaseResult(BaseModel):
name: str
passed: bool
failures: list[str] = Field(default_factory=list)
duration_ms: int = Field(ge=0)
class TestWorkflowResponse(BaseModel):
passed: int
failed: int
results: list[TestCaseResult]
class CostEstimate(BaseModel):
executions_per_month: int
estimated_api_calls: int
estimated_ai_tokens: int
estimated_monthly_usd: float
assumptions: list[str]
rate_limit_warnings: list[str] = Field(default_factory=list)
class CostEstimateRequest(BaseModel):
workflow: WorkflowDocument
executions_per_month: int = Field(default=1000, ge=1, le=100_000_000)
class WorkflowDiffRequest(BaseModel):
before: WorkflowDocument
after: WorkflowDocument
class WorkflowDiff(BaseModel):
added_nodes: list[str] = Field(default_factory=list)
removed_nodes: list[str] = Field(default_factory=list)
modified_nodes: list[str] = Field(default_factory=list)
moved_nodes: list[str] = Field(default_factory=list)
added_edges: int = 0
removed_edges: int = 0
class ShareRequest(BaseModel):
workflow_id: str
permission: Literal["view", "copy"] = "view"
expires_in_days: int | None = Field(default=30, ge=1, le=365)
class ShareResponse(BaseModel):
id: str
url: str
permission: Literal["view", "copy"]
expires_at: datetime | None = None
class SharedWorkflowResponse(BaseModel):
workflow: WorkflowDocument
permission: Literal["view", "copy"]
expires_at: datetime | None = None
class VersionSummary(BaseModel):
id: str
version: int
change_summary: str | None = None
created_at: str
created_by: str
class RestoreVersionRequest(BaseModel):
version: int = Field(ge=1)
class CommentRequest(BaseModel):
workflow_id: str
body: str = Field(min_length=1, max_length=10_000)
node_id: str | None = Field(default=None, max_length=128)
class WorkflowComment(BaseModel):
id: str
workflow_id: str
user_id: str
node_id: str | None = None
body: str
resolved_at: str | None = None
created_at: str
class DeploymentRequest(BaseModel):
workflow: WorkflowDocument
activate: bool = False
class DeploymentResponse(BaseModel):
status: Literal["deployed", "preview"]
remote_workflow_id: str | None = None
message: str
class LineageField(BaseModel):
field: str
source_nodes: list[str] = Field(default_factory=list)
consumer_nodes: list[str] = Field(default_factory=list)
classification: Literal["public", "internal", "personal", "financial", "secret"]
class LineageResponse(BaseModel):
fields: list[LineageField]
node_dependencies: dict[str, list[str]]
sensitive_paths: list[str] = Field(default_factory=list)
class ContractRequest(BaseModel):
workflow: WorkflowDocument
sample_data: dict[str, Any] = Field(default_factory=dict)
expected_schema: dict[str, Literal["string", "number", "boolean", "object", "array", "null"]]
class ContractResponse(BaseModel):
valid: bool
inferred_schema: dict[str, str]
violations: list[str] = Field(default_factory=list)
class QualityResponse(BaseModel):
overall: int = Field(ge=0, le=100)
scores: dict[str, int]
findings: list[ValidationIssue]
class IntentDriftRequest(BaseModel):
workflow: WorkflowDocument
requirement: str = Field(min_length=10, max_length=20_000)
class IntentDriftResponse(BaseModel):
alignment_score: int = Field(ge=0, le=100)
covered_terms: list[str]
missing_terms: list[str]
class ReplayRequest(BaseModel):
workflow: WorkflowDocument
node_id: str = Field(min_length=1, max_length=128)
input_data: dict[str, Any] = Field(default_factory=dict)
class EnvironmentPromotionRequest(BaseModel):
workflow: WorkflowDocument
environment: Literal["development", "staging", "production"]
values: dict[str, str | int | float | bool] = Field(default_factory=dict)
class EnvironmentPromotionResponse(BaseModel):
workflow: WorkflowDocument
environment: str
replacements: int
unresolved: list[str] = Field(default_factory=list)
class ReleasePlanRequest(BaseModel):
workflow: WorkflowDocument
strategy: Literal["shadow", "canary", "synthetic"]
traffic_percentage: int = Field(default=10, ge=0, le=100)
success_threshold: float = Field(default=0.99, ge=0, le=1)
max_error_rate: float = Field(default=0.02, ge=0, le=1)
class ReleasePlanResponse(BaseModel):
strategy: str
status: Literal["draft", "blocked"]
requires_approval: bool = True
steps: list[str]
rollback_conditions: list[str]
warnings: list[str] = Field(default_factory=list)
class WorkflowPackageRequest(BaseModel):
workflow: WorkflowDocument
tests: list[WorkflowTestCase] = Field(default_factory=list)
contracts: dict[str, Any] = Field(default_factory=dict)
environments: dict[str, dict[str, Any]] = Field(default_factory=dict)
class WorkflowPackageResponse(BaseModel):
manifest: dict[str, Any]
workflow: WorkflowDocument
tests: list[WorkflowTestCase]
contracts: dict[str, Any]
environments: dict[str, dict[str, Any]]
class DocumentationResponse(BaseModel):
markdown: str
class RoiRequest(BaseModel):
workflow: WorkflowDocument
executions_per_month: int = Field(default=1000, ge=1, le=100_000_000)
minutes_saved_per_execution: float = Field(default=5, ge=0, le=100_000)
hourly_rate_usd: float = Field(default=30, ge=0, le=100_000)
sla_minutes: float = Field(default=60, gt=0, le=1_000_000)
class RoiResponse(BaseModel):
hours_saved: float
labor_value_usd: float
estimated_operating_cost_usd: float
net_value_usd: float
estimated_duration_ms: int
sla_headroom_percent: float
class WebhookInspectRequest(BaseModel):
payload: dict[str, Any]
redact: bool = True
class WebhookInspectResponse(BaseModel):
payload: dict[str, Any]
schema_map: dict[str, str]
redacted_fields: list[str]
class DependencyImpactRequest(BaseModel):
workflow: WorkflowDocument
dependency: str = Field(min_length=1, max_length=500)
class DependencyImpactResponse(BaseModel):
affected_nodes: list[str]
downstream_nodes: list[str]
severity: Literal["none", "low", "medium", "high"]
class SelfHealRequest(BaseModel):
workflow: WorkflowDocument
errors: list[str] = Field(default_factory=list, max_length=100)
class SelfHealResponse(BaseModel):
proposed_workflow: WorkflowDocument
changes: list[str]
quality_before: int
quality_after: int
requires_approval: bool = True