kirche-einfach/backend/app/flows/schemas.py

139 lines
3.7 KiB
Python

"""Pydantic contracts for the flows API."""
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, Field
class FlowDefinitionCreate(BaseModel):
name: str = Field(min_length=1, max_length=200)
description: str = Field(default="", max_length=2000)
continuation_flow_id: UUID | None = None
class FlowDefinitionRead(BaseModel):
id: UUID
name: str
description: str
status: str
# backend/flows filename this definition syncs from (None if API-created).
source_path: str | None = None
continuation_flow_id: UUID | None
created_at: datetime
class FlowVersionCreate(BaseModel):
langflow_json: dict
author: str = Field(default="", max_length=200)
class FlowVersionRead(BaseModel):
id: UUID
flow_id: UUID
version_no: int
langflow_json: dict
lfx_flow_id: str | None
deployed_at: datetime | None
author: str
created_at: datetime
input_schema: dict | None = None
class InputSchemaRead(BaseModel):
"""Form schema of the latest deployed version (RJSF renders it)."""
flow_id: UUID
version_no: int
json_schema: dict
ui_schema: dict = Field(default_factory=dict)
# Set when the flow has no CustomInput node: render a free-text box.
fallback: str | None = None
class RunRequest(BaseModel):
"""Start a flow run. `input` is the domain payload handed to the flow."""
input: dict = Field(default_factory=dict)
version_no: int | None = None
tenant_id: str = Field(default="default", max_length=200)
session_id: str | None = None
# Base URL the flow uses for callbacks (e.g. approval tasks).
# Defaults to settings.callback_base_url; tests point it at a live server.
callback_base_url: str | None = None
continuation_flow_id: UUID | None = None
class RunRead(BaseModel):
id: UUID
version_id: UUID
tenant_id: str
status: str
input: dict | None
output: dict | None
session_id: str | None
created_at: datetime
finished_at: datetime | None
class ApprovalCreate(BaseModel):
"""Callback contract: a flow reports a terminal approval state."""
run_id: UUID
title: str = Field(default="", max_length=500)
payload: dict = Field(default_factory=dict)
continuation_flow_id: UUID | None = None
class ApprovalRead(BaseModel):
id: UUID
run_id: UUID
version_id: UUID
tenant_id: str
title: str
payload: dict
continuation_flow_id: UUID | None
approver: str | None
status: str
decision_note: str
created_at: datetime
decided_at: datetime | None
class FlowImportRequest(BaseModel):
"""Import a flow from the Langflow authoring server by its Langflow id."""
langflow_flow_id: str = Field(min_length=1)
name: str | None = Field(default=None, max_length=200)
author: str = Field(default="", max_length=200)
deploy: bool = True
class FlowImportRead(BaseModel):
definition: FlowDefinitionRead
version: FlowVersionRead
class DecisionRequest(BaseModel):
decision: str = Field(pattern="^(approve|reject)$")
approver: str = Field(default="", max_length=200)
note: str = Field(default="", max_length=2000)
callback_base_url: str | None = None
class DecisionRead(BaseModel):
task: ApprovalRead
continuation_run: RunRead | None
class SyncReport(BaseModel):
"""Result of reconciling backend/flows/*.json into DB + LFX.
Lists hold filename stems; errors maps filename to reason.
"""
added: list[str] = Field(default_factory=list)
updated: list[str] = Field(default_factory=list)
deleted: list[str] = Field(default_factory=list)
skipped: list[str] = Field(default_factory=list)
errors: dict[str, str] = Field(default_factory=dict)