feat: canonical flow directory with sync engine (files are source of truth)

This commit is contained in:
Jonas Miederer 2026-09-07 08:59:56 +00:00
parent 7d5ade6b6a
commit c65e3ed332
16 changed files with 4167 additions and 42 deletions

View file

@ -4,6 +4,7 @@ from __future__ import annotations
import json
from collections.abc import AsyncIterator, Iterator
from pathlib import Path
from uuid import UUID
import httpx
@ -16,6 +17,7 @@ from app.settings import settings
from . import runner, store
from .deploy import import_from_langflow
from .sync import lfx_id_for, sync_from_directory
from .langflow_client import (
LangflowClient,
LangflowError,
@ -44,6 +46,7 @@ from .schemas import (
FlowVersionRead,
RunRead,
RunRequest,
SyncReport,
)
flows_router = APIRouter(prefix="/api/flows", tags=["flows"])
@ -70,6 +73,7 @@ def _read_definition(d) -> FlowDefinitionRead:
name=d.name,
description=d.description,
status=d.status,
source_path=d.source_path,
continuation_flow_id=d.continuation_flow_id,
created_at=d.created_at,
)
@ -134,6 +138,18 @@ def list_flows(session: Session = Depends(get_db)):
return [_read_definition(d) for d in store.list_definitions(session)]
@flows_router.post("/sync", response_model=SyncReport)
async def sync_flows(
session: Session = Depends(get_db),
lfx: LfxClient = Depends(get_lfx),
):
"""Reconcile backend/flows/*.json into the DB + LFX (add/update/delete)."""
try:
return await sync_from_directory(session, lfx, Path(settings.flows_dir))
except FileNotFoundError as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
@flows_router.get("/{flow_id}", response_model=FlowDefinitionRead)
def get_flow(flow_id: UUID, session: Session = Depends(get_db)):
try:
@ -178,8 +194,12 @@ async def deploy_version(
except store.NotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
try:
# Deterministic LFX id: same (definition, version) always maps to the
# same registration, no matter which path deployed it.
uploaded = await lfx.upload_flow(
version.langflow_json, flow_id=str(version.id), replace=True
version.langflow_json,
flow_id=lfx_id_for(flow_id, version_no),
replace=True,
)
except LfxInvalidFlow as exc:
raise HTTPException(status_code=422, detail=str(exc)) from exc