| 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 |
|
|