feat: Langflow authoring pipeline with tests

- LangflowClient (list/export, x-api-key auth, error mapping)
- import_from_langflow: export -> versioned definition -> LFX deploy
- POST /api/flows/import, GET /api/flows/langflow/available
- scripts/deploy_flow.py CLI
- 25 tests green (Langflow faked via dependency override + respx
  client tests; respx passthrough proven unreliable for LFX traffic)
This commit is contained in:
Jonas Miederer 2026-09-06 23:01:47 +00:00
parent 96c0da33c7
commit 1034206870
8 changed files with 451 additions and 0 deletions

View file

@ -166,6 +166,35 @@ def lfx_server(tmp_path_factory):
proc.kill()
@pytest.fixture()
def override_langflow():
"""Replace the Langflow dependency with a fake (real LFX stays untouched).
Usage: override_langflow(export_doc) -- the fake export_flow() returns the
doc, or raises LangflowNotFound/Unavailable for status=404/0.
"""
from app.flows.api import get_langflow
from app.flows.langflow_client import LangflowNotFound, LangflowUnavailable
from app.main import app
def _override(export_doc=None, status=200):
class FakeLangflow:
async def export_flow(self, flow_id):
if status == 404:
raise LangflowNotFound(f"flow {flow_id} not found")
if status == 0:
raise LangflowUnavailable("Langflow unreachable")
return export_doc
async def list_flows(self):
return [{"id": "fake-1", "name": "fake"}]
app.dependency_overrides[get_langflow] = lambda: FakeLangflow()
yield _override
app.dependency_overrides.pop(get_langflow, None)
@pytest.fixture(scope="session")
def live_server():
"""Real uvicorn server (ephemeral port) so LFX flows can call back