Gabriel Luiz Freitas Almeida 49fc1f862f feat(lfx): introduce pluggable executor seam (#12981)
* feat(execution): scaffold execution package with test isolation fixture

* feat(execution): add core types (Unit, StepResult, RunComplete)

* feat(execution): add Executor abstract base class

* feat(execution): add identity partition function

* feat(execution): add executor registry (register/get only)

* feat(execution): add InProcessExecutor (streaming + legacy passthrough)

* feat(execution): add Coordinator with streaming run + run_to_completion

* feat(execution): default singleton with in-process pre-registered + setter

* feat(execution): route Graph.arun through coordinator (seam #1)

* feat(execution): route flow_executor through coordinator (seam #2)

* feat(execution): route CLI and run/base through coordinator (seam #3)

* feat(execution): route Loop subgraph through coordinator (seam #4)

* fix(execution): explicit legacy dispatch flag, forward fallback_to_env_vars, real-graph concurrency tests

* refactor(execution): add Coordinator.stream helper, lift imports, replace em-dash

* test(execution): shared simple_graph fixture, reset_default_coordinator helper, real-executor loop tests, behavior assertions

* refactor(execution): wrap default singletons in _Defaults holder, drop noqas

* feat(execution): make executor seam pluggable via lfx services

Introduce an ExecutorService that owns the registry and the default coordinator,
discovered through the standard lfx ServiceManager (parity with cache, database,
storage, etc). Add an executor_kind setting so the default kind can be configured
without touching code, and an lfx.executors entry-point group for third-party
executors. Entry-point discovery refuses to overwrite an existing kind so an
installed package cannot silently replace the built-in in-process executor;
explicit replacement still works through ExecutorService.register().

The lfx.execution public API (get_default_coordinator, get_default_registry,
set_default_coordinator, reset_default_coordinator) now resolves through the
service manager but keeps the same surface, so existing call sites in Graph.arun,
flow_executor, the CLI, run/base, and loop_utils are unchanged.

Also surface root-cause tracebacks in lfx.services.deps.get_service: the helper
still returns None on failure (callers like get_db_service rely on that), but it
now logs the exception so init failures stop disappearing into the void.

* test(execution): contract suite, cancellation guarantees, seam docstrings

Robustness pass on the execution seam after using it to integrate an external
executor end-to-end. Four things this pins down:

1. Reusable executor contract suite
   - tests/unit/execution/test_executor_contract.py
   - ExecutorContract with 7 universal seam guarantees: kind shape, execute()
     returns an AsyncIterator, stream ends with exactly one RunComplete,
     instance is reusable across runs, concurrent runs are isolated, consumer
     cancellation does not hang or leak, execute() signature is stable.
   - TestInProcessExecutorContract subclasses and provides fixtures. Downstream
     executors (stepflow, future remote/sandbox) get the same battery by
     subclassing and overriding two fixtures.

2. Cancellation/cleanup correctness
   - tests/unit/execution/test_cancellation.py
   - InProcessExecutor wraps graph.async_start() in try/finally with explicit
     aclose so consumer aclose cascades to the underlying graph generator.
     Previously the inner generator was abandoned and only finalized on a GC
     pass: a real leak for executors holding subprocesses or sockets.
   - Coordinator.run and Coordinator.stream propagate aclose the same way so
     the full chain (consumer -> coordinator -> executor -> graph) cleans up
     deterministically.

3. Documented seam contracts
   - Unit.runtime_options: free-form bag, "_"-prefixed keys reserved for
     executor-internal flags, common in-process keys listed.
   - StepResult.payload: untyped on purpose; each executor defines its own
     event vocabulary; consumers normalize at consumption site.
   - RunComplete.outputs: only the legacy in-process path populates it;
     streaming consumers should collect from StepResult.payload.
   - Executor ABC: lifecycle (shared instance, must be reusable, must tolerate
     concurrent execute() calls and consumer aclose).

4. Coordinator-routed E2E suite
   - tests/unit/execution/test_coordinator_e2e.py
   - Real Graph through Coordinator -> registry -> InProcessExecutor chain.
   - Asserts payload shape, RunComplete never leaks to stream() consumers,
     dispatch routes to configured kind, registry returns same instance.

Full execution suite: 63 passing. flow_executor coordinator test: passing.

* fix(execution): close async generators on early exit and harden seam tests

- run_to_completion and Coordinator.stream wrap iteration in contextlib.aclosing
  so the underlying generator is finalized when the loop returns or raises early
- execute_loop_body wraps its stream in aclosing for the same mid-iteration guarantee
- drop the unused inputs param from Coordinator.stream; the streaming path reads
  initial_inputs from runtime_options, so inputs was a silent no-op, and document it
- test_coordinator_uses_settings_executor_kind uses monkeypatch + a finalizer so a
  mid-test failure can't poison session settings
- test_registry_returns_same_executor_instance_across_runs builds a fresh graph per run
- test_set_default_coordinator_overrides_singleton restores the singleton afterward

* fix(execution): register ExecutorService factory and update seam test mocks

- register ExecutorServiceFactory in register_all_service_factories so
  EXECUTOR_SERVICE resolves at app startup; without it the seam raised
  NoFactoryRegisteredError across integration and mcp tests
- test_base.py graph.async_start mocks now default the leading positional
  param (the seam calls async_start with inputs as a keyword), fixing the
  'missing 1 required positional argument' failures
- add executor_kind to the settings composition EXPECTED_FIELDS set

* fix(execution): reject non-Executor entry-point plugins; doc corrections

- ExecutorService discovery skips a loaded entry-point object that is not an
  Executor instance instead of registering it and failing only at execute() time
- Coordinator.run docstring notes the single-Unit / single-RunComplete assumption
  that identity_partition currently guarantees
- correct two stale docstrings: Unit's session_id is honored only on the legacy
  passthrough path, and ExecutorService.teardown no longer claims the service
  manager keeps the cached instance

* fix(lfx): reset factory-registered flag on ServiceManager teardown

teardown() emptied self.factories but left factory_registered set, so
get_service()'s lazy re-registration was skipped and later lookups raised
NoFactoryRegisteredError. Once Graph.arun started routing through the
executor service, that surfaced as intermittent flow-execution 500s in the
backend unit suite whenever a sibling test had torn the global manager down.

* test(loop): accept executor kwargs in subgraph async_start mock

The loop body now runs its subgraph through get_default_coordinator().stream,
so InProcessExecutor calls async_start with inputs/max_iterations/config/
reset_output_values/fallback_to_env_vars alongside event_manager. The mock
only accepted event_manager and raised TypeError on the extra kwargs. Widen it
to **_kwargs while still capturing event_manager for the assertion.
2026-06-25 13:39:11 -07:00
2026-06-25 18:33:53 +00:00
2026-06-09 13:16:48 -07:00
2026-06-25 18:33:53 +00:00
2026-06-25 18:33:53 +00:00
2026-06-25 18:33:53 +00:00
2025-03-20 00:05:55 +00:00
2026-04-23 17:49:53 -07:00
2024-06-04 09:26:13 -03:00
2026-06-25 18:33:53 +00:00

Langflow logo

Release Notes PyPI - License PyPI - Downloads Twitter YouTube Channel Discord Server Ask DeepWiki

Langflow is a powerful platform for building and deploying AI-powered agents and workflows. It provides developers with both a visual authoring experience and built-in API and MCP servers that turn every workflow into a tool that can be integrated into applications built on any framework or stack. Langflow comes with batteries included and supports all major LLMs, vector databases and a growing library of AI tools.

Highlight features

  • Visual builder interface to quickly get started and iterate.
  • Source code access lets you customize any component using Python.
  • Interactive playground to immediately test and refine your flows with step-by-step control.
  • Multi-agent orchestration with conversation management and retrieval.
  • Deploy as an API or export as JSON for Python apps.
  • Deploy as an MCP server and turn your flows into tools for MCP clients.
  • Observability with LangSmith, LangFuse and other integrations.
  • Enterprise-ready security and scalability.

🖥️ Langflow Desktop

Langflow Desktop is the easiest way to get started with Langflow. All dependencies are included, so you don't need to manage Python environments or install packages manually. Available for Windows and macOS.

📥 Download Langflow Desktop

Quickstart

Requires Python 3.103.14 and uv (recommended package manager).

Install

From a fresh directory, run:

uv pip install langflow -U

The latest Langflow package is installed. For more information, see Install and run the Langflow OSS Python package.

Run

To start Langflow, run:

uv run langflow run

Langflow starts at http://127.0.0.1:7860.

That's it! You're ready to build with Langflow! 🎉

📦 Other install options

Run from source

If you've cloned this repository and want to contribute, run this command from the repository root:

make run_cli

For more information, see DEVELOPMENT.md.

Docker

Start a Langflow container with default settings:

docker run -p 7860:7860 langflowai/langflow:latest

Langflow is available at http://localhost:7860/. For configuration options, see the Docker deployment guide.

🛡️ Security

For security information, see our Security Policy.

🚀 Deployment

Langflow is completely open source and you can deploy it to all major deployment clouds. To learn how to deploy Langflow, see our Langflow deployment guides.

Stay up-to-date

Star Langflow on GitHub to be instantly notified of new releases.

Star Langflow

👋 Contribute

We welcome contributions from developers of all levels. If you'd like to contribute, please check our contributing guidelines and help make Langflow more accessible.


Star History Chart

❤️ Contributors

langflow contributors

Description
Langflow is a powerful tool for building and deploying AI-powered agents and workflows.
Readme MIT 2.3 GiB
Languages
Python 64.5%
TypeScript 23.4%
JavaScript 11.4%
CSS 0.3%
Makefile 0.2%
Other 0.1%