Commit 7896b9f
feat(bundles): metapackage split (Phase A) — engine-only lfx, lfx-bundles long tail, 5 graduated partner packages (langflow-ai#13563)
* feat(extension): add manifest-less lfx.bundles discovery + precedence tier
Foundation for the bundle metapackage split (1.11). Adds a third
@official-slot discovery source: a distribution declaring the
[project.entry-points."lfx.bundles"] group ships a package whose immediate
subdirectories are each a manifest-less bundle, folder-walked and registered
at @official with no extension.json (the langchain-community model).
- new loader/_bundles_root.py::load_lfx_bundles_extensions, mirroring
discover_inline_bundles but sourcing roots from the lfx.bundles entry-point
group via find_spec and reusing _load_bundle_directory
- discovery precedence becomes installed > seed > lfx_bundles > dev > inline
so a manifest-shipping lfx-<provider> always shadows the same-named
provider in the metapackage (lets a provider graduate with no lockstep
release), emitting the existing bundle-shadowed warning
- new bundle-discovery-malformed warning code, emitted on warnings (never
flips ok / aborts startup) for unresolvable declarations and invalid
provider folder names
- exported via loader/__init__ and the lfx.extension PEP-562 lazy surface
10 new tests in test_load_lfx_bundles.py; full extension unit suite (449)
passes; ruff + format clean; mypy clean on the new module.
* docs(bundles): changelog entry for the lfx.bundles discovery surface
The BUNDLE_API.md changelog gate diffs each PR's branch against main, so
the entry covering this PR's surface additions (lfx.bundles discovery,
the lfx_bundles precedence tier, bundle-discovery-malformed) must live
on this branch, not only further up the stack. Text is verbatim from the
graduate-partners commit so the stacked merge dedupes trivially.
* fix(extension): reject plain-module lfx.bundles targets; correct validate wording
CodeRabbit review fixes on #13563:
- _spec_package_dir no longer falls back to a plain module's parent
directory -- a single-file entry-point target now emits the
bundle-discovery-malformed warning instead of folder-walking unrelated
sibling directories as bundles (+ regression test)
- BUNDLE_API.md / loader docstring no longer say manifest-less providers
are 'exempt from lfx extension validate'; they are not valid validator
input (validate requires a manifest and reports manifest-not-found)
* fix(extension): review fixes — shadowed metapackage providers never import; typed manifest-less reload refusal
Review findings on #13563:
- A manifest-less provider whose bundle name is already claimed by a
higher-precedence @official source (installed/seed) is now skipped
WITHOUT importing: all @official sources share the
_lfx_ext.official.<bundle>.* sys.modules namespace, so importing the
losing copy overwrote the winner's live modules even though
_resolve_bundle_shadowing dropped its components afterwards. The
orchestrator passes the claimed-name map (built by the new
_claimed_official_bundles helper, mirroring the resolver's winner
rule); the skipped copy still emits the typed bundle-shadowed warning.
This collision is the expected post-graduation state, not an error.
- Manifest-less records now carry a manifestless provenance flag
(additive field on LoadResult + BundleRecord). The reload pipeline
refuses them with the new typed reload-manifestless-unsupported code
instead of routing through load_extension and failing with a
misleading manifest-not-found. Hot reload of metapackage providers
is a process-restart concern (pip-installed content); a loader-based
reload path can follow if QA wants it.
BUNDLE_API.md changelog entry extended for both surface changes.
* fix(extension): harden lfx.bundles discovery per review — broad find_spec guard, namespace portions, per-mode error codes
Review findings from ogabrielluiz on #13563:
- find_spec on a dotted declaration imports the PARENT package, whose
__init__ can raise anything; a non-Import error escaped the old catch
tuple and (through the palette cache's catch-all) wiped every source's
components for the boot. Catch Exception and degrade to the malformed
sentinel; comment corrected.
- Namespace packages: walk ALL submodule_search_locations portions (one
root per portion) instead of only locations[0], and dedupe resolved
roots by path so duplicate entry-point declarations (or overlapping
portions) never walk a directory twice and self-shadow.
_spec_package_dir -> _spec_package_dirs.
- Split bundle-discovery-malformed into one code per failure mode,
mirroring the inline tier: bundles-provider-name-invalid (rename the
directory), bundles-root-unreadable (check permissions), keeping
bundle-discovery-malformed for unresolvable declarations (fix the
entry-point). Same-tier duplicates get duplicate-lfx-bundles-provider
instead of overloading bundle-shadowed, whose rendered template
(format_extension_error renders templates, not ad-hoc messages) was
wrong on both counts for that case.
- The claimed-bundles cross-source skip now emits bundle-shadowed on
errors (matching _resolve_bundle_shadowing) so filtering by code never
mixes severities; bundle-shadowed is already in the CLI warn-only set.
3 new regression tests (raising parent package, namespace portions,
duplicate entry points); BUNDLE_API changelog updated.
* feat(bundles): create lfx-bundles metapackage skeleton (#13564)
* feat(bundles): add lfx-bundles metapackage skeleton
Creates the manifest-less lfx-bundles distribution (the langchain-community
model) that the long-tail providers will move into. Empty skeleton for now;
the bulk move (scripts/migrate/consolidate_bundles.py) populates the provider
folders + per-provider extras later.
- src/bundles/lfx-bundles: a single pyproject declaring the lfx.bundles
entry-point (lfx_bundles = "lfx_bundles"), an lfx>=1.10.0,<2.0.0 pin, and a
generated (currently empty) `all` extra; plus a bare lfx_bundles namespace
package and a README documenting the model + install stories
- wired into the root workspace via the existing bundle marker blocks:
dep lfx-bundles[all]>=1.0,<2.0, uv source, and member
- hyphen dir name so release.yml's src/bundles/*/pyproject.toml glob builds
it with zero workflow change
Verified: the wheel builds (entry_points.txt carries the lfx.bundles group);
load_lfx_bundles_extensions (PR-1) discovers the entry point and the empty
skeleton registers zero providers with no error.
* fix(ci): nightly bundle rename follows [extras] refs and self-refs
Two gaps in update_bundle_versions.py around extras suffixes, both fatal
or silently wrong for the first nightly carrying the lfx-bundles
metapackage:
- update_root_pyproject_for_bundle's dep regex required the version
specifier immediately after the name, so "lfx-bundles[all]>=1.0,<2.0"
(a MAIN dep) was left unrewritten while the workspace member was
renamed to lfx-bundles-nightly; uv lock then tries to resolve stable
lfx-bundles from PyPI, where it does not exist. The same gap silently
left "lfx-docling[local]>=0.1.0" optional-dep refs pointing at the
stable distribution. The regex now tolerates an [extras] group and
carries it into the replacement.
- rename_bundle_pyproject skipped self-referencing extras, so the
metapackage's generated `all` extra kept 45 "lfx-bundles[<provider>]"
members after the rename, pulling the stable distribution (same
lfx_bundles import package, install collision) once published. Self
refs now follow the rename, idempotently.
Tests drive the real script module, mirroring test_bundle_lfx_pin.py.
This closes the PR-2 audit item flagged when the metapackage was
introduced. The canonical-pre-release cutover would retire the nightly
rename entirely; until it lands, the rename must be correct.
* fix(bundles): address review — drop orphaned nightly bundle-rename script, fix README install stories
- Delete scripts/ci/update_bundle_versions.py and its tests: the nightly
bundle-rename track it served was retired by the canonical pre-release
cutover (src/bundles/NIGHTLY.md) and no workflow or Makefile target on
main or any release branch invokes it. Stale doc references in
sync_bundle_lfx_pin.py and test_bundle_lfx_pin.py updated to match.
- README: split the install section into what works today (langflow, bare
lfx) vs what arrives with the bulk move / engine-only split
(lfx[bundles], per-provider lfx-bundles[<provider>] extras), and note
the generated all extra is empty until the first provider tranche lands.
* ci(bundles): cross-bundle test matrix (lfx contract axis) (#13566)
* ci(bundles): add cross-bundle test matrix (lfx contract axis)
Tests every extracted bundle (the lfx-bundles metapackage + each graduated
lfx-<provider>) against the lfx contract surface it depends on -- overdue
since 1.10 left 4 independently-versioned bundles depending on lfx.
- .github/workflows/cross-bundle-test.yml: discovers bundles via the same
src/bundles/*/pyproject.toml glob release.yml uses, then per
(bundle x python 3.10/3.13): installs the in-repo lfx + the bundle, imports
the declared entry-point package, asserts lfx.bundles discovery is
error-free (for the metapackage), runs `lfx extension validate` for
manifest bundles, and runs the bundle's own tests/.
- Triggers: pull_request (src/bundles, src/lfx), workflow_dispatch, a weekly
schedule, and workflow_call.
The lfx-minor axis seeds with the in-repo lfx (the 1.10 line is unpublished);
when minors publish, add the version dimension (oldest+latest get full tests,
every supported minor gets contract-smoke) per the epic's cost-control shape.
Verified: the workflow YAML parses and the contract-smoke logic imports a
real bundle (lfx_arxiv) cleanly.
* fix(ci): cross-bundle smoke tolerates extras-less SDK degradation
Review findings on the cross-bundle matrix:
- CRITICAL: the contract smoke asserted zero discovery errors, but the CI
venv installs lfx-bundles WITHOUT per-provider extras, so providers whose
modules import their SDK at top level degrade with module-import-failed --
the expected graceful-degradation contract. The smoke now fails only on
structural codes and reports the degraded-module count. (Graduated partner
bundles carry their deps directly, not as extras, so their steps are
unaffected.)
- the scheduled run now actually delivers the exhaustive grid the header
promised (all supported Pythons on schedule; oldest+latest on PRs)
- concurrency group with cancel-in-progress on PRs so stacked bundle PRs
don't queue N-bundles x N-pythons jobs per push
* ci(bundles): tomli fallback for the py3.10 cross-bundle smoke
tomllib is stdlib only from Python 3.11, so the contract-smoke heredoc
failed with ModuleNotFoundError on every py3.10 matrix leg. Install the
tomli backport into the smoke venv and import it as a fallback.
* fix(test): coherent sys.modules restore in the ibm without_ibm_db fixture
The cross-bundle matrix's py3.10 leg exposed test-ordering pollution in
the ibm bundle suite: without_ibm_db monkeypatch-deleted three lfx_ibm
modules and re-imported them mid-test, but entries created during the
test survive teardown (delitem with raising=False records nothing for
keys it didn't find) and re-imported parents never regain the submodule
attribute bindings that mock.patch target resolution walks on Python
3.10 (3.11+ mock resolves via sys.modules and tolerates the
incoherence). Two fixture uses in sequence left the tree inconsistent
and 29 later watsonx tests failed with AttributeError on the package.
Snapshot, drop, and restore the entire lfx_ibm module tree wholesale
instead. Full suite now passes on both 3.10 and 3.13.
* feat(lfx): add lfx[bundles] extra and keep lfx engine-only (#13565)
* feat(bundles): add lfx-bundles metapackage skeleton
Creates the manifest-less lfx-bundles distribution (the langchain-community
model) that the long-tail providers will move into. Empty skeleton for now;
the bulk move (scripts/migrate/consolidate_bundles.py) populates the provider
folders + per-provider extras later.
- src/bundles/lfx-bundles: a single pyproject declaring the lfx.bundles
entry-point (lfx_bundles = "lfx_bundles"), an lfx>=1.10.0,<2.0.0 pin, and a
generated (currently empty) `all` extra; plus a bare lfx_bundles namespace
package and a README documenting the model + install stories
- wired into the root workspace via the existing bundle marker blocks:
dep lfx-bundles[all]>=1.0,<2.0, uv source, and member
- hyphen dir name so release.yml's src/bundles/*/pyproject.toml glob builds
it with zero workflow change
Verified: the wheel builds (entry_points.txt carries the lfx.bundles group);
load_lfx_bundles_extensions (PR-1) discovers the entry point and the empty
skeleton registers zero providers with no error.
* feat(lfx): add lfx[bundles] extra and keep lfx engine-only
lfx ships no bundles by default. The new optional extra pulls the long-tail
metapackage for users who want the provider components without the full
langflow server install.
- src/lfx/pyproject.toml: [project.optional-dependencies]
bundles = ["lfx-bundles[all]>=1.0,<2.0"]; intentionally NO lfx[all]
- pip install lfx -> engine only
pip install "lfx[bundles]" -> engine + the lfx-bundles long tail
(documented as a headless/serverless deployment footnote, not a headline)
Verified against the built lfx wheel METADATA: lfx-bundles appears only under
`extra == "bundles"`, never in core Requires-Dist, so the engine-only default
is preserved.
* fix(ci): nightly bundle rename follows [extras] refs and self-refs
Two gaps in update_bundle_versions.py around extras suffixes, both fatal
or silently wrong for the first nightly carrying the lfx-bundles
metapackage:
- update_root_pyproject_for_bundle's dep regex required the version
specifier immediately after the name, so "lfx-bundles[all]>=1.0,<2.0"
(a MAIN dep) was left unrewritten while the workspace member was
renamed to lfx-bundles-nightly; uv lock then tries to resolve stable
lfx-bundles from PyPI, where it does not exist. The same gap silently
left "lfx-docling[local]>=0.1.0" optional-dep refs pointing at the
stable distribution. The regex now tolerates an [extras] group and
carries it into the replacement.
- rename_bundle_pyproject skipped self-referencing extras, so the
metapackage's generated `all` extra kept 45 "lfx-bundles[<provider>]"
members after the rename, pulling the stable distribution (same
lfx_bundles import package, install collision) once published. Self
refs now follow the rename, idempotently.
Tests drive the real script module, mirroring test_bundle_lfx_pin.py.
This closes the PR-2 audit item flagged when the metapackage was
introduced. The canonical-pre-release cutover would retire the nightly
rename entirely; until it lands, the rename must be correct.
* ci(bundles): freeze lfx/components against new top-level providers (#13567)
* feat(bundles): add lfx-bundles metapackage skeleton
Creates the manifest-less lfx-bundles distribution (the langchain-community
model) that the long-tail providers will move into. Empty skeleton for now;
the bulk move (scripts/migrate/consolidate_bundles.py) populates the provider
folders + per-provider extras later.
- src/bundles/lfx-bundles: a single pyproject declaring the lfx.bundles
entry-point (lfx_bundles = "lfx_bundles"), an lfx>=1.10.0,<2.0.0 pin, and a
generated (currently empty) `all` extra; plus a bare lfx_bundles namespace
package and a README documenting the model + install stories
- wired into the root workspace via the existing bundle marker blocks:
dep lfx-bundles[all]>=1.0,<2.0, uv source, and member
- hyphen dir name so release.yml's src/bundles/*/pyproject.toml glob builds
it with zero workflow change
Verified: the wheel builds (entry_points.txt carries the lfx.bundles group);
load_lfx_bundles_extensions (PR-1) discovers the entry point and the empty
skeleton registers zero providers with no error.
* ci(bundles): freeze lfx/components against new top-level providers
After the metapackage split, new providers go to lfx-bundles (or a graduated
lfx-<provider>), never in-tree. Adds an additions-only CI gate.
- scripts/ci/check_components_frozen.py: stdlib gate comparing the live
top-level dir listing of src/lfx/src/lfx/components/ against a committed
baseline; fails on any directory not in the baseline. Removals are allowed
so M4 shim cleanup (which shrinks the set) never trips it.
- scripts/ci/frozen_component_dirs.txt: the 111-dir baseline.
- .github/workflows/lint-py.yml: new freeze-components job runs the gate
(stdlib-only, no uv sync).
Verified locally: passes on the baseline, fails (exit 1) on a simulated new
provider directory with an actionable message, passes again after cleanup.
* fix(ci): freeze gate counts only dirs shipping __init__.py
Review finding: a stray directory holding only __pycache__ bytecode (left
behind by a branch switch) tripped the additions-only gate locally. A
directory without __init__.py is not a provider; ignore it.
* fix(ci): nightly bundle rename follows [extras] refs and self-refs
Two gaps in update_bundle_versions.py around extras suffixes, both fatal
or silently wrong for the first nightly carrying the lfx-bundles
metapackage:
- update_root_pyproject_for_bundle's dep regex required the version
specifier immediately after the name, so "lfx-bundles[all]>=1.0,<2.0"
(a MAIN dep) was left unrewritten while the workspace member was
renamed to lfx-bundles-nightly; uv lock then tries to resolve stable
lfx-bundles from PyPI, where it does not exist. The same gap silently
left "lfx-docling[local]>=0.1.0" optional-dep refs pointing at the
stable distribution. The regex now tolerates an [extras] group and
carries it into the replacement.
- rename_bundle_pyproject skipped self-referencing extras, so the
metapackage's generated `all` extra kept 45 "lfx-bundles[<provider>]"
members after the rename, pulling the stable distribution (same
lfx_bundles import package, install collision) once published. Self
refs now follow the rename, idempotently.
Tests drive the real script module, mirroring test_bundle_lfx_pin.py.
This closes the PR-2 audit item flagged when the metapackage was
introduced. The canonical-pre-release cutover would retire the nightly
rename entirely; until it lands, the rename must be correct.
* feat(bundles): move 45 long-tail providers into lfx-bundles + graduate 5 partner packages (#13568)
* feat(bundles): add lfx-bundles metapackage skeleton
Creates the manifest-less lfx-bundles distribution (the langchain-community
model) that the long-tail providers will move into. Empty skeleton for now;
the bulk move (scripts/migrate/consolidate_bundles.py) populates the provider
folders + per-provider extras later.
- src/bundles/lfx-bundles: a single pyproject declaring the lfx.bundles
entry-point (lfx_bundles = "lfx_bundles"), an lfx>=1.10.0,<2.0.0 pin, and a
generated (currently empty) `all` extra; plus a bare lfx_bundles namespace
package and a README documenting the model + install stories
- wired into the root workspace via the existing bundle marker blocks:
dep lfx-bundles[all]>=1.0,<2.0, uv source, and member
- hyphen dir name so release.yml's src/bundles/*/pyproject.toml glob builds
it with zero workflow change
Verified: the wheel builds (entry_points.txt carries the lfx.bundles group);
load_lfx_bundles_extensions (PR-1) discovers the entry point and the empty
skeleton registers zero providers with no error.
* feat(bundles): consolidate first long-tail tranche into lfx-bundles
Adds scripts/migrate/consolidate_bundles.py (the inverse of port_bundle.py --
moves in-tree providers into the manifest-less lfx-bundles metapackage) and
runs it on a verified 5-provider tranche: tavily, exa, wikipedia, yahoosearch,
wolframalpha.
Per provider the script:
- moves src/lfx/src/lfx/components/<p>/ -> lfx_bundles/<p>/ (lowercase names);
- leaves a fail-soft import shim (first line `# lfx-bundles-shim`) so
`from lfx.components.<p> import X` keeps working when lfx-bundles is
installed, and raises an actionable ImportError otherwise;
- merges the provider's third-party deps into a PEP 685-normalized lfx-bundles
extra and regenerates the `all` aggregate. Dep parity holds: `uv sync` is a
no-op because those deps were already pulled via langflow-base[complete];
- appends the 4-entry migration block per Component class (28 entries) so saved
flows referencing lfx.components.<p>.<Class> migrate to
ext:<p>:<Class>@official.
To avoid double registration, the in-tree component walk
(_load_components_dynamically) now skips shimmed provider dirs, and
component_index.json is regenerated (355->348 components, 95->90 modules); the
moved providers load only at @official via lfx.bundles discovery.
Verified: discovery finds all 5 at @official with no errors; shims resolve;
`import lfx.components` still works; the index drops the 7 moved component
entries (residual `tools`-category name refs resolve via the shim); ruff clean.
First tranche proves the engine; the remaining long-tail scales by extending
PROVIDER_DEPS (each provider's deps verified individually -- the careful part).
* feat(bundles): consolidate 30-provider tranche 2 into lfx-bundles
Extends PROVIDER_DEPS with 30 individually-verified providers and runs the
consolidation: vector stores (chroma, clickhouse, couchbase, milvus, mongodb,
pgvector, pinecone, qdrant, supabase, upstash, weaviate), model providers
(groq, mistral, ollama, perplexity, sambanova), and tools/memory/data (apify,
assemblyai, confluence, firecrawl, git, glean, icosacomputing, mem0, needle,
scrapegraph, serpapi, unstructured, youtube, zep).
Dep verification (the careful part): every spec comes from langflow-base's
per-provider extras or its direct dependencies; langchain-community providers
carry the wrapper plus the SDK the wrapper lazy-imports (e.g. pgvector,
atlassian-python-api); requests is declared explicitly where imported (it is
only transitive in today's env); pinecone keeps its python_version<'3.14'
marker verbatim. Tranche excludes: providers with langflow imports (vlmrun),
provider-specific lfx.base dirs (composio/huggingface/langwatch), case-
sensitive names (FAISS/Notion), the openai-SDK family (azure/aiml/deepseek/
litellm/lmstudio/novita/openrouter/vllm/xai/cometapi -- cleaner after PR-8),
and the partner set.
Dep parity verified at the resolution level: the uv.lock diff is +220 lines of
lfx-bundles extras metadata with ZERO packages added or removed (`name =` diff
empty), so pip install langflow resolves the identical set.
Also: 192 append-only migration entries (48 classes x 4, zero bare-name
ambiguities); component_index.json regenerated 348->300 components / 90->60
modules (exactly the moved set, no stale standalone entries); mongodb_atlas.py
SLF001 per-file-ignore and the mem0/mongodb detect-secrets baseline entries
migrated to the new paths (lint/secrets exceptions travel with moved files);
35 bundles now discover at @official with 55 components; shims verified across
categories; 449 extension tests pass.
* feat(bundles): consolidate openai-SDK family tranche 3 into lfx-bundles
10 providers that ride the langchain-openai wrapper, deferred from tranche 2
until the partner graduation settled the openai-SDK dep story: aiml, azure,
cometapi, deepseek, litellm, lmstudio, novita, openrouter, vllm, xai.
Dep verification: every provider declares langchain-openai>=1.1.6; the openai
SDK is declared only where a component imports it directly (aiml, deepseek,
litellm, lmstudio, vllm, xai -- wrapper-transitive elsewhere); requests
declared where imported (cometapi, deepseek, novita, xai); lmstudio's lazy
NVIDIAEmbeddings path gets langchain-nvidia-ai-endpoints~=1.0.0. The litellm
component drives LiteLLM-served endpoints through the OpenAI client and does
NOT import the litellm package -- langflow-base's litellm extra stays put.
These providers use the lazy _dynamic_imports __init__ shape; it survives the
move unchanged (import_mod resolves via __spec__.parent and
lfx.components._importing remains a core helper).
Dep parity: uv.lock diff has zero package additions/removals (all specs
already resolved via langflow-base[complete]).
Also: 56 append-only migration entries (14 classes x 4, zero ambiguities);
component_index.json regenerated 300->286 components / 60->50 modules (exactly
the moved set); detect-secrets baseline re-keyed; 45 bundles now discover at
@official with 69 components; shims verified (azure/xai/litellm/deepseek);
ruff clean.
* fix(ci): nightly bundle rename follows [extras] refs and self-refs
Two gaps in update_bundle_versions.py around extras suffixes, both fatal
or silently wrong for the first nightly carrying the lfx-bundles
metapackage:
- update_root_pyproject_for_bundle's dep regex required the version
specifier immediately after the name, so "lfx-bundles[all]>=1.0,<2.0"
(a MAIN dep) was left unrewritten while the workspace member was
renamed to lfx-bundles-nightly; uv lock then tries to resolve stable
lfx-bundles from PyPI, where it does not exist. The same gap silently
left "lfx-docling[local]>=0.1.0" optional-dep refs pointing at the
stable distribution. The regex now tolerates an [extras] group and
carries it into the replacement.
- rename_bundle_pyproject skipped self-referencing extras, so the
metapackage's generated `all` extra kept 45 "lfx-bundles[<provider>]"
members after the rename, pulling the stable distribution (same
lfx_bundles import package, install collision) once published. Self
refs now follow the rename, idempotently.
Tests drive the real script module, mirroring test_bundle_lfx_pin.py.
This closes the PR-2 audit item flagged when the metapackage was
introduced. The canonical-pre-release cutover would retire the nightly
rename entirely; until it lands, the rename must be correct.
* feat(bundles): graduate partner set to standalone lfx-<provider> packages (#13573)
* feat(bundles): graduate partner set to standalone lfx-<provider> packages
Extracts the five partner/flagship providers into manifest-shipping
distributions: lfx-openai, lfx-anthropic, lfx-amazon, lfx-datastax,
lfx-cohere. Each ships extension.json (lfx.compat ["1"]), a
langflow.extensions entry-point, an lfx>=1.10.0,<2.0.0 pin, and is wired into
the root workspace marker blocks. Zero flow impact by the bundle-name
invariant: ext:<provider>:<Class>@official ids are unchanged.
Mechanics:
- adopts the five-phase scripts/migrate/port_bundle.py from
feat/bundle-mass-extraction (handles shared-base moves, consumer rewrites,
surgical index updates, migration-table appends) and runs it per partner
with --migration-release 1.11.0
- datastax's shared lfx.base.datastax moves into lfx_datastax.base; its
backend unit tests move to src/bundles/datastax/tests (74 pass); its ruff
per-file-ignore and its check_component_env_writes ALLOWLIST entry travel;
10 repo consumers rewritten (incl. the vector_store_rag starter project)
- amazon_bedrock_converse.py legacy langflow.* imports rewritten to the lfx.*
equivalents (thin re-export aliases; behavior-identical) pre-extraction
- runtime deps pinned from langflow-base's extras / direct deps (wrapper-
guaranteed SDKs stay transitive, parity-exact); --remove-base-extra dropped
the openai/anthropic/cohere/aws extras from langflow-base[complete] in favor
of the bundle pins; the astradb extra stays (also used outside datastax)
- in-tree dirs replaced with marker shims pointing at lfx_<p>.components.<p>
(skipped by the in-tree walk; legacy from lfx.components.<p> imports keep
working); lfx/components/__init__.py entries kept, consistent with the
consolidated providers
- validate.py: accept classes whose base is a *derived* Component base
(LCVectorStoreComponent / LCToolComponent / ...) -- they inherit the
class-level outputs declaration and only override the output method, which
the AST-only check could not see; bare Component subclasses keep the strict
build/outputs requirement (+ regression test)
- BUNDLE_API.md changelog entries added for the branch's surface changes: the
lfx.bundles manifest-less discovery group + precedence tier +
bundle-discovery-malformed code (from the foundation PR) and the validator
acceptance above
- 100 append-only migration entries (20 classes x 5 partners x 4 shapes);
component_index.json surgically updated 300->280 components / 60->55
modules, sha256 recomputed and verified
- detect-secrets baseline re-keyed for moved partner files
Dep parity: lock diff adds only the five lfx-* package names; no third-party
package added or removed. One benign transitive re-resolution: anthropic SDK
0.105.2 -> 0.109.0 (allowed by langchain-anthropic's range on both sides).
Verified: all five register at @official via the installed-manifest tier
(extension_id/distribution = lfx-<p>, 20 components); manifest-less
lfx_bundles unchanged (35 bundles, disjoint); all 5 shims import; engine-safe;
`lfx extension validate` passes for all five; 450 extension unit tests, 60
pilot-upgrade migration tests, 74 moved datastax tests pass; ruff clean.
* fix(bundles): shim lfx.base.datastax so stored-flow imports keep resolving
The datastax graduation moved lfx.base.datastax into lfx_datastax.base,
but saved flows and starter templates (Hybrid Search RAG,
TemplateAssistant) embed `from lfx.base.datastax.astradb_base import
AstraDBBaseComponent` inside their stored component code fields, which
is re-executed verbatim at flow build time. Without a shim that import
raises ModuleNotFoundError and the flows fail to build
(test-starter-projects red).
Mirror the lfx.components shim contract: module-aliasing to
lfx_datastax.base, narrow except that only translates a missing bundle
(transitive dep failures re-raise untouched), marker-tagged single-file
dir, removed at M4 together with the components shims.
* chore(bundles): bounded version ranges for curated lfx-* packages (#13576)
langflow's pyproject is the release-coordination point now that lfx and the
lfx-* bundles release independently. Every curated lfx-* dependency declares a
BOUNDED range (>=A,<B), never an exact pin -- exact pins in reusable library
metadata create resolver conflicts for downstreams that depend on a different
version. Exact pins for reproducibility live in uv.lock and the release-build
manifests.
- the 4 pilots + 5 graduated partners: >=0.1.0 -> >=0.1.0,<1.0.0 (bundles
follow their own 0.1.x cadence)
- lfx-bundles[all]>=1.0,<2.0 unchanged (versions with the metapackage
contract)
- the three lfx-docling[...] optional-dependency refs bounded the same way
- policy documented inline in the bundle-deps marker block; the cross-bundle
CI matrix verifies the ranges resolve together across the supported lfx axis
Verified: uv lock resolves with zero package/version changes (bounds are
metadata-only today); the nightly rename's dep regex already matches the
bounded form.
* test(bundles): lock the in-tree shim contract + breakage audit (#13577)
* chore(bundles): bounded version ranges for curated lfx-* packages
langflow's pyproject is the release-coordination point now that lfx and the
lfx-* bundles release independently. Every curated lfx-* dependency declares a
BOUNDED range (>=A,<B), never an exact pin -- exact pins in reusable library
metadata create resolver conflicts for downstreams that depend on a different
version. Exact pins for reproducibility live in uv.lock and the release-build
manifests.
- the 4 pilots + 5 graduated partners: >=0.1.0 -> >=0.1.0,<1.0.0 (bundles
follow their own 0.1.x cadence)
- lfx-bundles[all]>=1.0,<2.0 unchanged (versions with the metapackage
contract)
- the three lfx-docling[...] optional-dependency refs bounded the same way
- policy documented inline in the bundle-deps marker block; the cross-bundle
CI matrix verifies the ranges resolve together across the supported lfx axis
Verified: uv lock resolves with zero package/version changes (bounds are
metadata-only today); the nightly rename's dep regex already matches the
bounded form.
* test(bundles): lock the in-tree shim contract + breakage audit
Locks the five-point contract for the 50 lfx-bundles import shims under
lfx/components/ (45 metapackage + 5 graduated partners):
1. first line is the `# lfx-bundles-shim` marker (keys the in-tree walk's
double-registration skip);
2. a shim dir is exactly one __init__.py -- no impls, no deps;
3. sys.modules module-aliasing (submodule trees resolve);
4. bundle missing -> actionable ModuleNotFoundError whose wording is part
of the contract ("pip install lfx-bundles" / "pip install lfx-<p>");
5. a missing *transitive* dep re-raises untouched.
Test shape (env-adaptive by design -- the lfx test env prunes the venv, so
nothing here assumes bundles are installed):
- source-level sweep of every real shim, parameterized (no imports);
- hermetic mechanism tests against a synthetic shim + synthetic target
(alias-resolves / locked-message / transitive-reraise);
- the walk-skip detector and the marker sweep must agree exactly;
- one adaptive live test on lfx.components.tavily exercising whichever
branch the running env is in.
106 tests pass in the pruned lfx env (where the live test exercises the
bare-engine locked-message branch).
Breakage audit (gh code search, recorded in the PR): ~20-25 public repos
reference lfx.components.*; the majority are langflow forks (vendored tree,
unaffected by packaging). Genuine library consumers exist and the moved
providers have real surface (openai: 11 external repos, datastax: 17) --
covered by the shims wherever bundles are co-installed (every
`pip install langflow`). Decision: deprecation warnings NOT warranted now;
revisit at M4 (shim removal), where one loud minor release before removal
is the right shape.
* test(bundles): extend the shim contract sweep to lfx.base shims
The datastax graduation moved lfx.base.datastax into lfx_datastax.base
and left a module-aliasing shim behind (stored flow code fields embed
the legacy import and are re-executed verbatim at build time). Sweep
lfx/base for marker shims with the same source-level contract as the
components sweep: one-file stub, module-aliasing to the bundle's base
subpackage, narrow name-checked except, locked install message.
* docs(bundles): install shapes, override rule, bundle_api_version (#13578)
Documents the deliberately small user-facing rule surface of the metapackage
split (1.11):
- extensions-overview.mdx: the two install stories (pip install langflow =
everything, same as today; pip install lfx = engine only, bring your own
bundles); the bundle-name-is-identity invariant; the current package table
(lfx-bundles metapackage + the 5 partner packages + the 4 pilots); the
legacy-import shim behavior with the locked ModuleNotFoundError wording and
the migration recipe for direct lfx users (switch to lfx[bundles] or pin
lfx-<provider> packages); the override rule ("ship a manifest -- a manifest
always wins", with the bundle-shadowed warning); bundle_api_version as the
single compat number (lfx.compat ["1"]; manifest-less packages ride their
PEP 508 lfx pin) and the no-version-arithmetic rule.
- deployment-lfx-compatibility.mdx: lfx[bundles] as the headless/serverless
deployment footnote (engine + lfx-bundles[all]; slimmer per-provider
alternative; intentionally no lfx[all]).
Both files verified MDX-safe (no unbackticked angle brackets).
* fix(bundles): stack-review fixes — symlink containment, idempotency, docs accuracy (#13579)
* chore(bundles): bounded version ranges for curated lfx-* packages
langflow's pyproject is the release-coordination point now that lfx and the
lfx-* bundles release independently. Every curated lfx-* dependency declares a
BOUNDED range (>=A,<B), never an exact pin -- exact pins in reusable library
metadata create resolver conflicts for downstreams that depend on a different
version. Exact pins for reproducibility live in uv.lock and the release-build
manifests.
- the 4 pilots + 5 graduated partners: >=0.1.0 -> >=0.1.0,<1.0.0 (bundles
follow their own 0.1.x cadence)
- lfx-bundles[all]>=1.0,<2.0 unchanged (versions with the metapackage
contract)
- the three lfx-docling[...] optional-dependency refs bounded the same way
- policy documented inline in the bundle-deps marker block; the cross-bundle
CI matrix verifies the ranges resolve together across the supported lfx axis
Verified: uv lock resolves with zero package/version changes (bounds are
metadata-only today); the nightly rename's dep regex already matches the
bounded form.
* test(bundles): lock the in-tree shim contract + breakage audit
Locks the five-point contract for the 50 lfx-bundles import shims under
lfx/components/ (45 metapackage + 5 graduated partners):
1. first line is the `# lfx-bundles-shim` marker (keys the in-tree walk's
double-registration skip);
2. a shim dir is exactly one __init__.py -- no impls, no deps;
3. sys.modules module-aliasing (submodule trees resolve);
4. bundle missing -> actionable ModuleNotFoundError whose wording is part
of the contract ("pip install lfx-bundles" / "pip install lfx-<p>");
5. a missing *transitive* dep re-raises untouched.
Test shape (env-adaptive by design -- the lfx test env prunes the venv, so
nothing here assumes bundles are installed):
- source-level sweep of every real shim, parameterized (no imports);
- hermetic mechanism tests against a synthetic shim + synthetic target
(alias-resolves / locked-message / transitive-reraise);
- the walk-skip detector and the marker sweep must agree exactly;
- one adaptive live test on lfx.components.tavily exercising whichever
branch the running env is in.
106 tests pass in the pruned lfx env (where the live test exercises the
bare-engine locked-message branch).
Breakage audit (gh code search, recorded in the PR): ~20-25 public repos
reference lfx.components.*; the majority are langflow forks (vendored tree,
unaffected by packaging). Genuine library consumers exist and the moved
providers have real surface (openai: 11 external repos, datastax: 17) --
covered by the shims wherever bundles are co-installed (every
`pip install langflow`). Decision: deprecation warnings NOT warranted now;
revisit at M4 (shim removal), where one loud minor release before removal
is the right shape.
* docs(bundles): install shapes, override rule, bundle_api_version
Documents the deliberately small user-facing rule surface of the metapackage
split (1.11):
- extensions-overview.mdx: the two install stories (pip install langflow =
everything, same as today; pip install lfx = engine only, bring your own
bundles); the bundle-name-is-identity invariant; the current package table
(lfx-bundles metapackage + the 5 partner packages + the 4 pilots); the
legacy-import shim behavior with the locked ModuleNotFoundError wording and
the migration recipe for direct lfx users (switch to lfx[bundles] or pin
lfx-<provider> packages); the override rule ("ship a manifest -- a manifest
always wins", with the bundle-shadowed warning); bundle_api_version as the
single compat number (lfx.compat ["1"]; manifest-less packages ride their
PEP 508 lfx pin) and the no-version-arithmetic rule.
- deployment-lfx-compatibility.mdx: lfx[bundles] as the headless/serverless
deployment footnote (engine + lfx-bundles[all]; slimmer per-provider
alternative; intentionally no lfx[all]).
Both files verified MDX-safe (no unbackticked angle brackets).
* fix(bundles): review fixes — symlink containment, idempotency, docs accuracy
Fixes from the multi-agent stack review (kept as a separate PR so the
reviewed PRs' diffs stay frozen for QA's independent pass):
- _bundles_root.py: directory-level symlink containment — a provider dir
that resolves outside the bundle root is skipped with a typed
bundle-discovery-malformed warning, mirroring the seed-directory walk's
is_within rule (+ regression test). Anchors the trust boundary to the
installed package tree.
- consolidate_bundles.py: migration-append idempotency guard — entries are
deduped on full content so a partially-failed earlier run cannot duplicate
rows on re-run (table stays append-only).
- langflow-base pyproject: documented WHY the aws extra is deliberately
retained after the lfx-amazon graduation (boto3 also backs the server's
own S3 storage backend and lfx's S3 ingestion — review suggested removing
it; that would regress S3 storage support).
- extensions-overview.mdx: note that `lfx extension list` shows
manifest-shipping extensions only; manifest-less packages load at startup
but are not listed.
93 loader+migration tests pass (incl. the new symlink test); ruff clean.
* refactor(bundles): stabilize import_mod as a public BUNDLE_API utility
The lazy-import helper that bundle packages call from their
__getattr__-based __init__.py files lived at lfx.components._importing -- an
internal path with no stability contract, imported by 35 separately-installed
bundle __init__ files (30 lfx-bundles providers + the 5 graduated partners).
- canonical home is now lfx.utils.lazy_import.import_mod (code unchanged);
lfx.components._importing re-exports it so in-tree callers and any external
code on the old path keep working
- all 35 bundle-side imports rewritten to the stable path
- BUNDLE_API.md: surface table entry + changelog (additive)
- contract tests: re-export identity, both call forms, the AttributeError
conversion
Verified: identity holds across both paths; lazy __init__ loads work through
the new path for both bundle families; 110 tests pass; ruff clean.
* fix(bundles): tombstone the broken legacy ZepChatMemory build method (#13580)
build_message_history targeted the zep-python v1 SDK (ZepClient +
zep_python.langchain.ZepChatMessageHistory); both were removed in
zep-python 2.x and the zep extra pins 2.0.2, so the method has been
unable to run for as long as the pin has existed -- its ImportError
guard misleadingly told users to 'pip install zep-python' (already
installed). The component is legacy=True with helpers.Memory as its
designated replacement, so rather than hand-write a new integration
against the 2.x SDK, the method now raises a clear RuntimeError
pointing at the Message History component.
Flow identity is preserved: class/component name, display_name,
description, inputs and the memory output are byte-identical, so saved
flows keep loading, i18n locale keys are unchanged, and
migration_table.json needs no edits. New bundle tests pin the stub
contract (identity, actionable error, no zep_python import).
* test(bundles): extend the shim contract sweep to lfx.base shims
The datastax graduation moved lfx.base.datastax into lfx_datastax.base
and left a module-aliasing shim behind (stored flow code fields embed
the legacy import and are re-executed verbatim at build time). Sweep
lfx/base for marker shims with the same source-level contract as the
components sweep: one-file stub, module-aliasing to the bundle's base
subpackage, narrow name-checked except, locked install message.
* test(bundles): extras-drift guard for the lfx-bundles metapackage
Risk-2 of the metapackage split: the generated `all` extra and the
per-provider extras must never drift by hand-edit, or `pip install
langflow` silently loses a provider's deps. Guard the four invariants:
extras <-> provider dirs (PEP 685-normalized), `all` == the exact
self-ref set, normalized keys collision-free, and the metapackage
provider set disjoint from the graduated partner distributions.
* fix(extension): symlink-escaped providers reject with path-escape, matching the documented contract
The lfx.bundles provider containment check (stack-review symlink fix)
emitted bundle-discovery-malformed, whose template and hint describe a
broken entry-point declaration. The changelog's path-safety entry
already documents symlink escapes as path-escape on every other
discovery path; use the same code here. Also resolves the semantic
merge conflict with the per-mode code split (the removed
_malformed_error location kwarg).
* fix(tests): repoint lfx tests off moved providers; complete provider fallback map
CI fail-fast had been masking these: the LFX test job runs in an
engine-only env where openai/anthropic/chroma are now bundle-package
shims, so every test that used them as the example category failed on
all Python versions (3.14 just reported first), and the backend Group 2
leg failed collecting test_lfx_bundles_extras.py on Python 3.10.
- flow_requirements: complete _PROVIDER_PACKAGE_FALLBACKS for the nine
moved model providers (OpenAI, Anthropic, Amazon Bedrock, Groq,
Google Generative AI, SambaNova, IBM watsonx.ai, Ollama + existing
Azure OpenAI). In engine-only installs MODEL_PROVIDERS_DICT registers
only in-tree providers, so the dynamic source-inspection path cannot
resolve moved providers; the static fallbacks keep lfx run/serve
requirements inference working. A dict hit still wins.
- test_dynamic_imports / test_import_utils: use composio (still-in-tree
lazy category with its SDK absent in the bare env) as the example
category instead of openai/anthropic/chroma; patch import_module at
its canonical home lfx.utils.lazy_import.
- flow-builder tests (build_flow_from_spec, flow_builder_tools,
propose_field_edit): specs use LanguageModelComponent (in-tree)
instead of OpenAIModel.
- test_lfx_bundles_extras: tomli fallback for Python 3.10 (tomllib is
stdlib 3.11+; pytest guarantees tomli on <3.11).
Full lfx unit suite: 4550 passed. Backend extras+pin tests: 24 passed.
* fix(tests): repoint MCP client-server tests off graduated OpenAIModel key
Same fail-fast-masked class as 14dfa7f268, backend side: since the
partner graduation, extension components register in /api/v1/all under
their namespaced ids (ext:openai:OpenAIModelComponent@official), so the
bare 'OpenAIModel' key these tests hardcoded no longer exists on any
Python version (the 'py3.14-only' Group 2 failure was the only leg that
ran; 3.10 was cancelled by fail-fast). The MCP feature itself is fine —
search returns the namespaced ids and add_component accepts them.
- Use LanguageModelComponent (in-tree, stable bare key; SecretStr
api_key, real_time_refresh fields, advanced 'stream', LanguageModel
output) for the redaction/configure/search/describe/spec tests.
- configure_dynamic_field: model_name -> api_key (the refresh field on
LanguageModelComponent).
- prompt-template-variables spec: drop the model node — server-side
validation builds the graph and a model without an API key fails its
build; the test's subject is the dynamic {var} fields.
Full file: 69 passed.
* Update test_mongodb_atlas.py
* Frontend tests
* Frontend test updates
* fix: restore loading.py and tableAutoCellRender to base-branch state
Commit 9df9475615 ('Frontend test updates') accidentally reverted both
files to their pre-#9902 state, removing the no_env_fallback contract in
load_from_env_vars / update_table_params_with_load_from_db_fields, the
defensive params.pop('code') in build_custom_component, and the
localValue/updateGlobalVariableCell handling in tableAutoCellRender.
The base branch's regression tests (test_loading_no_env_fallback.py,
test_loading_custom_component_code_param.py, tableAutoCellRender
index.test.tsx) were kept, so the reversion failed them.
* ci(bundles): make freeze gate reachable on PRs; review follow-ups
- Move the freeze-components job from lint-py.yml (workflow_call/
workflow_dispatch only -- never invoked, so the gate could not block a
PR) into extension-migration-checks.yml, which already triggers on
pull_request for src/lfx/src/lfx/components/**. Add the gate's script
and baseline to the path filter.
- Add timeout-minutes to the cross-bundle-test jobs so a hung install or
test leg cannot occupy a runner for the 360-minute default.
- _discover_shimmed_component_dirs: read only the first line of each
__init__.py instead of the whole file -- the shim marker contract is
line 1 (enforced by test_shim_source_contract), and this prevents a
non-shim file with the marker after leading blank lines from being
misclassified and silently skipped from the in-tree walk.
* fix(bundles): restore legacy-name resolution for ext components; sync starter projects
Saved flows reference moved providers by their legacy palette identity --
either the bare class name (TavilySearchComponent) or the component's
name attribute (AstraDB, Chroma, needle, OllamaModel). After the provider
move neither resolved to a current template on the backend:
- lfx.utils.component_aliases now derives the bare class name (and its
Component-stripped form) from ext:<bundle>:<Class>@<slot> keys,
mirroring the frontend's getTemplateAliases. Ext templates carry
name=None / _type='Component', so the key is the only source.
- _decorate_template_with_extension now stamps template['name'] with the
component's legacy identity (name attr, falling back to class name).
In-tree palette entries expose it as the dict key; ext entries are
keyed by namespaced id, so without this both alias maps lose the only
bridge from node types like 'AstraDB' to the current template.
Without these, the starter-project updater could not match moved-provider
nodes, so their embedded code stayed one whitespace change behind the
bundle sources -- every such flow showed the update-all banner, and
because tool-mode nodes' saved outputs ([component_as_tool]) differ from
the template's natural outputs the update was flagged breaking, opening
the confirmation modal instead of toasting 'successfully updated':
deterministic timeouts in the starter-project Playwright specs (shards
29/30/36/37). Regenerated the 13 affected starter projects with
scripts/ci/update_starter_projects.py (idempotent; code_hash hex strings
in the regenerated JSONs are detect-secrets false positives).
Also converts test_groq_integration.py to the captured-module
patch.object pattern (same module-identity trap as test_mongodb_atlas:
dotted-name @patch can land on a different materialization of the moved
module than the one that defined the class, leaving the real
get_groq_models in the instance's globals -- order-dependent failure in
unit-test Group 5).
* fix(bundles): keep importable module paths in starter projects
The starter-project updater syncs node metadata from the live templates
(NODE_FORMAT_ATTRIBUTES includes 'metadata'), and ext components report
their runtime sys.modules namespace there (_lfx_ext.official.<p>.<m>) --
a path that only exists inside a running extension loader. Persisting it
broke test_template_field_order_matches_component in both template jobs
('No module named _lfx_ext'): the test imports metadata.module to
instantiate the component, and the migration table likewise keys on the
legacy lfx.components.<provider> form that the bundle shims keep
importable.
_merge_node_metadata now preserves the node's stored module when the
live template's is a runtime _lfx_ext.* path, while still syncing the
rest of the metadata (e.g. dependencies). Starter projects regenerated
from the pre-pollution state with the fixed updater: the only diff vs
the previous regen is the 20 module lines reverting to the legacy
importable form. Regression tests added for both merge directions.
* feat: add Oracle integration (#13502)
* Add Oracle Integration
* [autofix.ci] apply automated fixes
* Fix styleUtils problem
* fix(oracledb): address review feedback
* fix(oracledb): apply formatting
* Fix component index
* refactor(oracledb): convert Oracle integration to lfx-oracle extension bundle
Port the in-tree lfx.components.oracledb provider into a standalone
Extension Bundle distribution (src/bundles/oracle, dist lfx-oracle,
package lfx_oracle, bundle name 'oracle') per src/bundles/PORTING.md:
- Move the four components + connection helper into the bundle; deps
(oracledb, langchain-oracledb, langchain-community) move from the
langflow-base[oracledb] extra into the bundle's pyproject
- Add migration-table entries mapping legacy bare class names and
lfx.components.oracledb.* import paths to ext:oracle:<Class>@official
- Add test_pilot_oracle_upgrade.py integration coverage (mirrors ibm)
- Move backend unit tests into src/bundles/oracle/tests with bundle
import paths; drop the empty ComponentTestBaseWithoutClient
version-fixture scaffolding (component is new in 1.11.0)
- Declare explicit outputs on OracleVectorStoreComponent (mirrors
LCVectorStoreComponent) so lfx extension validate passes
- Regenerate component index (oracledb category removed) and uv.lock;
wire workspace member/dep/source in root pyproject
- Frontend sidebar entry renamed oracledb -> oracle; docs page renamed
to bundles-oracle following the extracted-bundle convention
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Hare <ericrhare@gmail.com>
* feat(lfx): fail-fast dependency preflight for `lfx run` (#13680)
Detect a flow's required third-party packages before the graph load and
fail fast with an actionable `pip install ...` message when any are
missing, instead of a deep ModuleNotFoundError mid-build. Addresses the
'export a flow, run it on a bare pip install lfx, it fails' confusion
introduced by the bundle split.
- flow_requirements: add find_missing_dependencies / _is_installed /
format_missing_dependencies_error (best-effort, reuses the existing
flow analyzer).
- run.base: _preflight_dependencies helper + check_dependencies gate in
run_flow (JSON flows only; .py uses PEP 723; fail-open on analysis
errors so a runnable flow is never blocked by the check itself).
- CLI: --check-dependencies/--no-check-dependencies on `lfx run`.
- tests: unit (find_missing_dependencies/format) + integration (run_flow
+ _preflight_dependencies).
* feat(bundles): move spider + toolguard provider components into lfx-bundles
Two provider components were still living inside otherwise-core directories
(file-level stragglers from the metapackage split). Both are portable
(lfx-only imports) and gated by dedicated optional SDKs, so they belong in
the lfx-bundles metapackage rather than lfx core:
- SpiderTool (langchain_utilities/spider.py) -> lfx_bundles/spider/, dep
spider-client (`spider` extra).
- PoliciesComponent + policies/ submodule (models_and_agents) ->
lfx_bundles/toolguard/, dep toolguard (`toolguard` extra).
Changes:
- Move the files into lfx_bundles/<name>/; rewrite policies' absolute
self-imports (lfx.components.models_and_agents.policies -> lfx_bundles.toolguard.policies).
- Drop SpiderTool / PoliciesComponent from the core langchain_utilities /
models_and_agents lazy-import registries.
- Add `spider` and `toolguard` extras to lfx-bundles pyproject + the generated
`all` aggregate; uv.lock re-resolved (uv lock --check clean).
- Append migration entries (4 per class) mapping the historical
lfx.components.* paths to ext:spider:SpiderTool@official /
ext:toolguard:PoliciesComponent@official so saved flows migrate.
- Regenerate component_index.json (both classes drop out of core; 263
components / 45 categories).
- Repoint the toolguard policies tests to lfx_bundles.toolguard (60 pass).
The toolguard deadlock-warmer (_warm_circular_imports) is unaffected: it warms
toolguard.runtime directly and runs single-threaded before the unified
component fan-out that loads bundle components.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]
* feat(bundles): consolidate cleanlab, twelvelabs, jigsawstack into lfx-bundles
First directory-level batch of the core-tail consolidation (validates the
consolidate_bundles.py path end-to-end after the spider/toolguard file-level
extractions). All three are flat, lfx-only, single-SDK providers:
- cleanlab -> lfx_bundles/cleanlab (cleanlab-tlm) 3 components
- twelvelabs -> lfx_bundles/twelvelabs (twelvelabs) 7 components
- jigsawstack -> lfx_bundles/jigsawstack (jigsawstack) 11 components
Via scripts/migrate/consolidate_bundles.py --apply: moves each dir into the
metapackage + leaves a fail-soft shim, merges per-provider extras and regen
`all`, appends the 4-entry migration block per class (84 entries, 0 ambiguous).
Component index regenerated (45->42 categories, 263->242 core components);
uv.lock re-resolved; twelvelabs test repointed to lfx_bundles.twelvelabs (passes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(bundles): consolidate vector/datastore + community-wrapper providers into lfx-bundles
Second directory-level batch (8 providers, 12 components) via
consolidate_bundles.py --apply:
- baidu (qianfan + langchain-community), redis (redis + community),
elastic (elasticsearch + langchain-elasticsearch + opensearch-py)
- bing, cloudflare, maritalk, searchapi, vectara (langchain-community REST wrappers)
Moves each dir into lfx-bundles + fail-soft shim, merges per-provider extras
and regen `all`, appends 4-entry migration block per class (48 entries, 0
ambiguous). Component index regenerated (42->34 categories, 242->230 core
components); uv.lock re-resolved.
Test fixups:
- Repoint baidu/elastic/searchapi backend tests to lfx_bundles.<provider>.
- test_dynamic_imports (lfx isolated suite) used the now-bundled searchapi as
its fixture; bundles aren't installed in the engine-only lfx env, so switch
it to the core langchain_utilities.FakeEmbeddingsComponent (same
langchain_community optional-import path). 131 shim tests + 21 dynamic-import
tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [autofix.ci] apply automated fixes
* feat(bundles): consolidate homeassistant, olivya, agentql REST providers into lfx-bundles
Third batch (3 providers, 4 components) via consolidate_bundles.py --apply.
These are thin REST wrappers with no dedicated vendor SDK:
- homeassistant (requests) -> lfx_bundles/homeassistant 2 components
- olivya (httpx, lfx core) -> lfx_bundles/olivya 1 component
- agentql (httpx, lfx core) -> lfx_bundles/agentql 1 component
Moves + shims + per-provider extras + `all` regen; 16 migration entries (0
ambiguous). Component index 34->31 categories, 230->226 components; uv.lock
re-resolved. No tests reference these providers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(bundles): consolidate google, vertexai, altk, codeagents into lfx-bundles
Fourth directory-level batch (4 providers, 14 components) via
consolidate_bundles.py. google/vertexai (langchain-google-*), altk
(agent-lifecycle-toolkit), codeagents (smolagents + OpenDsStar); platform/py
markers copied verbatim from langflow-base extras. 56 migration entries (0
ambiguous); index 31->27 categories, 226->212 components. Backend tests
repointed; starter projects embedding moved components regenerated via the
validator. SKIP=detect-secrets: only flags are regenerated code_hash hex
(false positives).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(lfx): decouple dynamic-import unit tests from soon-to-be-bundled providers
test_dynamic_imports.py and test_import_utils.py used composio/nvidia/huggingface
as the "lazy category whose SDK is absent in the engine-only lfx env" fixture.
That couples the import-mechanism tests to specific providers — they have broken
each time a provider graduated to a bundle (openai/anthropic/chroma -> composio,
now composio et al.).
Switch to stable in-tree core categories:
- files_and_knowledge.KnowledgeComponent for the "missing-dep" path (its module
imports langchain_chroma / langflow, absent in bare lfx) — works for both the
import_mod direct calls and the lfx.components hierarchy access.
- helpers / processing for the "imports cleanly" and "module not found" paths.
No behavior change; 43 tests pass in the isolated lfx env. This unblocks moving
composio, huggingface, nvidia, cuga into lfx-bundles without breaking these tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(bundles): consolidate composio, huggingface, nvidia, cuga into lfx-bundles
Fifth batch (4 providers, 71 components) via consolidate_bundles.py --apply,
unblocked by the prior dynamic-import test decoupling:
- composio -> lfx_bundles/composio (composio + composio-langchain) 63 components
- huggingface -> lfx_bundles/huggingface (langchain-huggingface[marker], huggingface-hub, community) 2 components
- nvidia -> lfx_bundles/nvidia (langchain-nvidia-ai-endpoints, nv-ingest-client[py3.12], gassist[win32]) 5 components
- cuga -> lfx_bundles/cuga (cuga; platform/py markers) 1 component
Markers copied verbatim from langflow-base extras (uv lock --check clean).
284 migration entries (0 ambiguous); component index 27->23 categories,
212->141 components.
Tests: relocate the dedicated lfx-isolated tests for the now-bundled components
to the backend suite (test_nvidia_component.py, test_cuga_session_id_fallback.py)
repointed to lfx_bundles.<provider>; repoint backend composio/huggingface/cuga
imports + a cuga patch target; pragma a fake test api_key. 43 decoupled lfx
import tests pass post-move. SKIP=detect-secrets: only flags are regenerated
component_index code_hash hex (false positives).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [autofix.ci] apply automated fixes
* feat(bundles): consolidate langwatch evaluator into lfx-bundles
langwatch -> lfx_bundles/langwatch (1 component). The LangWatchComponent is a
pure httpx REST wrapper (its only non-core touchpoint is lfx.base.langwatch.utils,
which is also httpx-based) — the langwatch SDK extra in langflow-base is for the
tracing service, not this component, so the bundle declares no extra deps.
Moves + shim + `all` regen; 4 migration entries (0 ambiguous). Component index
23->22 categories, 141->140 components. Backend langwatch test repointed
(16 passed). SKIP=detect-secrets: only flags are regenerated component_index
code_hash hex (false positives).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(bundles): consolidate FAISS, Notion into lfx-bundles (lowercase-slug support)
Uppercase source dirs need lowercase bundle slugs (BUNDLE_NAME_RE is
lowercase-only). Enhance consolidate_bundles.py with bundle_slug(provider) =
provider.lower(): the bundle dir, ext id, shim target, and extra key use the
lowercased slug, while the migration import_path keeps the historical
lfx.components.<Provider> casing so saved flows still resolve. Identity for
already-lowercase providers (no change to prior entries).
- FAISS -> lfx_bundles/faiss (faiss-cpu[py-split] + langchain-community) 1 component
- Notion -> lfx_bundles/notion (requests + Markdown) 8 components
test_bundle_shims.py: derive the expected bundle name by lowercasing the shim
dir name (FAISS shim aliases lfx_bundles.faiss) — 159 shim tests pass.
Relocate the lfx-isolated FAISS test to backend/vectorstores (repointed to
lfx_bundles.faiss.faiss). 36 migration entries (0 ambiguous); index 22->20
categories, 140->131 components. SKIP=detect-secrets: regenerated code_hash hex.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(bundles): fold vectorstores LocalDBComponent into the chroma bundle
The lone LocalDBComponent is Chroma-backed (eager `from langchain_chroma import
Chroma`), so it belongs in the existing `chroma` bundle rather than a new one —
its deps are already covered by the chroma extra (no new deps).
- Move vectorstores/local_db.py -> lfx_bundles/chroma/local_db.py; register
LocalDBComponent in the chroma bundle's lazy registry.
- Replace lfx.components.vectorstores with a CROSS-BUNDLE shim aliasing
lfx_bundles.chroma (dir != bundle).
- Migration: lfx.components.vectorstores[.local_db].LocalDBComponent ->
ext:chroma:LocalDBComponent@official (4 entries, 0 ambiguous).
- test_bundle_shims.py: add a cross-bundle map {vectorstores: chroma} so the
shim contract validates (161 shim tests pass).
- Repoint the backend LocalDB test (import + patch target) to lfx_bundles.chroma;
test_all_modules_importable resolves it via the shim.
Component index 20->19 categories, 131->130 components. SKIP=detect-secrets:
regenerated code_hash hex (false positives).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [autofix.ci] apply automated fixes
* feat(bundles): remove unbundleable vlmrun + notdiamond components from lfx core
Per the core-tail audit, four providers couldn't be bundled. vlmrun (imports
`from langflow`, violating the lfx engine boundary) and notdiamond (its
`notdiamond` SDK isn't in the lockfile or any extra, so it can't run) have no
engine references, no starter flows, and no migration-table entries — they're
effectively dead in every distribution, so remove them outright.
(crewai and agentics are kept: crewai is woven into 3 starter-project example
flows, and the core Agent hard-depends on agentics.helpers.model_config — both
need deliberate upstream/refactor work, not deletion.)
- Delete src/lfx/.../components/{vlmrun,notdiamond}/ and drop them fro…1 parent f85a32a commit 7896b9f
580 files changed
Lines changed: 36732 additions & 108509 deletions
File tree
- .github/workflows
- docker
- docs
- docs
- Components
- Deployment
- Develop
- scripts
- ci
- lint
- migrate
- src
- backend
- base
- langflow
- api/utils
- initial_setup
- starter_projects
- tests
- integration
- components
- astra
- output_parsers
- unit
- api
- v1
- base/tools
- components
- bundles
- composio
- google
- langwatch
- twelvelabs
- codeagents
- data_source
- flow_controls
- languagemodels
- models_and_agents
- search
- vectorstores
- groq
- initial_setup
- starter_projects
- services/deployment
- bundles
- amazon
- src/lfx_amazon
- components
- amazon
- anthropic
- src/lfx_anthropic
- components
- anthropic
- cohere
- src/lfx_cohere
- components
- cohere
- datastax
- src/lfx_datastax
- base
- components
- datastax
- tests
- ibm
- src/lfx_ibm
- tests
- lfx-bundles
- src/lfx_bundles
- agentql
- aiml
- altk
- apify
- assemblyai
- azure
- baidu
- bing
- chroma
- cleanlab
- clickhouse
- cloudflare
- codeagents
- cometapi
- composio
- confluence
- couchbase
- cuga
- deepseek
- elastic
- exa
- faiss
- git
- glean
- google
- groq
- homeassistant
- huggingface
- icosacomputing
- jigsawstack
- langwatch
- litellm
- lmstudio
- maritalk
- mem0
- milvus
- mistral
- mongodb
- needle
- notdiamond
- notion
- novita
- nvidia
- olivya
- ollama
- openrouter
- perplexity
- pgvector
- pinecone
- qdrant
- redis
- sambanova
- scrapegraph
- searchapi
- serpapi
- spider
- supabase
- tavily
- twelvelabs
- unstructured
- upstash
- vectara
- vertexai
- vllm
- vlmrun
- weaviate
- wikipedia
- wolframalpha
- xai
- yahoosearch
- youtube
- zep
- tests
- openai
- src/lfx_openai
- components
- openai
- oracle
- src/lfx_oracle
- components/oracle
- tests
- frontend
- src
- CustomNodes
- GenericNode/components
- NodeInputField
- NodeOutputfield
- utils
- components/core/canvasControlsComponent/__tests__
- icons
- Oracle
- utils
- __tests__
- tests
- core/integrations
- extended/regression
- lfx
- src/lfx
- _assets
- base
- datastax
- models
- cli
- components
- FAISS
- Notion
- agentql
- aiml
- altk
- amazon
- anthropic
- apify
- assemblyai
- azure
- baidu
- bing
- chroma
- cleanlab
- clickhouse
- cloudflare
- codeagents
- cohere
- cometapi
- composio
- confluence
- couchbase
- cuga
- datastax
- deepseek
- elastic
- exa
- git
- glean
- google
- groq
- homeassistant
- huggingface
- icosacomputing
- jigsawstack
- langchain_utilities
- langwatch
- litellm
- lmstudio
- maritalk
- mem0
- milvus
- mistral
- models_and_agents
- mongodb
- needle
- notdiamond
- novita
- nvidia
- olivya
- ollama
- openai
- openrouter
- perplexity
- pgvector
- pinecone
- qdrant
- redis
- sambanova
- scrapegraph
- searchapi
- serpapi
- spider
- supabase
- tavily
- twelvelabs
- unstructured
- upstash
- vectara
- vectorstores
- vertexai
- vllm
- vlmrun
- weaviate
- wikipedia
- wolframalpha
- xai
- yahoosearch
- youtube
- zep
- extension
- loader
- migration
- interface
- run
- utils
- tests
- integration/extension
- unit
- base
- components
- custom/component
- extension
- loader
- migration
- graph
- edge
- graph
- run
- utils
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
| |||
84 | 86 | | |
85 | 87 | | |
86 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
7 | 12 | | |
8 | 13 | | |
9 | 14 | | |
| |||
0 commit comments