SIGN IN SIGN UP

feat(bundles): lfx-confluent bundle + watsonx.data components (IBM streamhouse) (#14612)

* fix(ci): assert the base wheel's real console script name (#14571)

The "Base Distribution Wheel" job verified that the base-only environment
exposes a `langflow` console script and no `langflow-base` one. That is
inverted: `langflow-base` declares `langflow-base = langflow.langflow_launcher:main`,
while the `langflow` script belongs to the root `langflow` distribution --
which the same step explicitly forbids from that environment. The assertion
could never pass, and the follow-on boot step invoked `bin/langflow`, which
does not exist there either.

These expectations were carried over from the langflow-core wheel this job
used to test (#14352) and were never re-pointed at langflow-base. Swap both
script assertions, give them failure messages so a future break is not a bare
AssertionError, and boot the server via `bin/langflow-base`, matching
`docker/build_and_push_base.Dockerfile`.

* fix(ci): assert the base console script the 1.12 line actually ships (main) (#14586)

fix(ci): assert the base console script the 1.12 line actually ships

Ports #14584 to main. main inherited the stale `langflow-base` assertion from
#14571 when the back-merge (#14581) paired it with release-1.12.0's post-#14339
pyproject, where the base wheel declares `langflow`:

    # src/backend/base/pyproject.toml
    [project.scripts]
    langflow = "langflow.langflow_launcher:main"

Both branches have to carry this. The nightly tag push only succeeds while main
and the release branch have identical .github/workflows content -- GitHub
screens App-token pushes for workflow changes and GITHUB_TOKEN cannot carry
`workflows`, so any drift re-breaks create-nightly-tag.

Taken as release-1.12.0's copy of the file verbatim rather than re-applying the
edit, so the two branches are byte-identical by construction.

* fix(tests): measure the flow persistence barrier from the reload, not before it (#14587)

Windows Playwright shards 30/70 and 31/70 were the only failing jobs in nightly
run 31867911970; all 70 Linux shards passed, including the Linux shards running
the same spec. Five of bulk-delete-sessions.spec.ts's fourteen tests failed with

    Flow <uuid> did not finish model refresh and autosave persistence within 30000ms

reloadAndWaitForFlowPersistence created its deadline setTimeout before calling
page.reload(), so the 30s budget had to cover the page load as well as the
model refresh and autosave it is actually there to observe. Playwright serves
the editor from a Vite dev server (`npm start`), so a reload replays ~3.5k
unbundled module requests. Measured from the blob-report traces on Windows:

    trace      page.reload()   GET /flows/{id}   POST custom_component/update
    e3fe6e22        19.0s           t+27.6s          t+29.7s (1.06s)
    1a49b9dd        21.5s           t+28.9s          t+47.5s (10.8s)
    f6f421a4        34.9s              --                 --

The third reload outlasts the whole budget on its own, so that run could never
pass. Arm the deadline after the reload resolves and raise it to TIMEOUTS.long;
the worst observed post-reload cost was ~37s, and the test timeout is 5min
while these tests run 65-95s.

The barrier reaches 38 call sites across 30 spec files, so this was a latent
flake for every Windows spec that configures the loopback provider, not just
the two shards that happened to pair two playground chat builds on one runner.

* fix(ci): grant the label job pull-requests write (#14590)

Every "Label PR" run has failed since #14540 -- 67 successes and no failures
before it, 16 failures after (the successes since are runs where the job's `if:`
skips it, e.g. merge_group and bot PRs):

    POST /repos/langflow-ai/langflow/issues/14588/labels
    403 Resource not accessible by integration

#14540 added a `permissions:` block to this workflow. Before that there was
none, so it inherited the repository default, which includes pull-requests
write. Labelling a *pull request* needs that scope: the `issues` permission only
covers real issues even though the REST path is `/issues/{n}/labels`. GitHub
says so in the response itself:

    x-accepted-github-permissions: issues=write; pull_requests=write

Also unblocks Namchee/conventional-pr in the same workflow, which cannot post
its report under a read-only pull-requests scope.

* perf(tests): seed the loopback provider into starter templates instead of reloading (#14589)

`configureLoopbackOpenAI` patched the persisted flow behind the running editor
and then reloaded the page so the editor would pick the change up. Playwright
serves the app from a Vite dev server, so that reload replays ~3.5k unbundled
module requests: 19-35s on Windows CI, and it happens once per test across 38
call sites.

Nothing forces the configuration to arrive out of band. `useAddFlow` posts the
starter template the browser fetched from `/api/v1/flows/basic_examples/`, so
serving that catalog already pointed at the loopback fixture makes the flow
*born* configured — the editor and the database never diverge and there is
nothing to reload for.

`seedLoopbackProvider(page)` installs that route and must run before the first
navigation, since React Query caches the catalog for the session.
`configureLoopbackOpenAI` then takes a fast path when the flow it reads is
already configured, and keeps the patch-and-reload path otherwise, so a spec
that does not seed (or builds its flow from a blank canvas) is unaffected. The
fallback warns rather than staying silent, so the optimization cannot rot
unnoticed across the seeded specs.

The one thing that can still write these nodes without a reload is the model
refresh `useApplyFlowToCanvas` fires on mount, so the fast path waits for it.
Refreshes carry no flow in their URL — `buildRefreshPayload` stamps
`_frontend_node_flow_id` onto the template — so `modelRefreshFlowId` attributes
them, and the tracker is armed before navigation to avoid a retroactive wait.

The shared mutation and predicates move into `loopback-provider-policy.mjs`
alongside the existing `flow-editor-persistence-policy.mjs`, pure and unit
tested, so the route seeder and the patch path cannot drift apart.

Not rolled out to specs that build from a blank canvas (`decisionFlow`,
`similarity`, `Youtube Analysis`) — seeding the template catalog does nothing
for them. Deliberately opt-in rather than folded into `openStarterProject`:
`live/llm-provider-smoke.spec.ts` uses that helper and must reach a real
provider, which is exactly the failure mode #14540 fixed for the live config.

Measured locally on macOS, bulk-delete-sessions.spec.ts (8 tests, 2 workers):
2.8m before, 1.6m after, all passing both ways. macOS reloads are far cheaper
than the 19-35s measured on Windows, so the CI saving should be larger.

* fix(tests): finish the public build before closing the popup; widen the messages loading-state wait (#14595)

Nightly 31907290063 (main @ b40b405e) failed exactly two Playwright shards.

Windows 24/70 - messages.a11y "scans the named loading state": the expect
after `page.goto("/settings/messages")` used the default 5s. The trace shows
goto returning at `load`, then auto_login (1.6-3.0s) -> whoami -> config ->
the lazy settings route; the messages query mounted 7.0s / 7.5s after goto,
1.4s / 1.7s after the expect gave up. The aria snapshot at failure was the
app-level "Loading..." page, not SessionView's status. Use TIMEOUTS.standard,
which the identical held-response loading scan in knowledge-bases.a11y
already uses.

Linux 41/70 - publish-flow: the spec sent a message in the shareable
playground popup and closed it 30ms later, while the public build was still
in flight. Aborting that request mid-write made the backend terminate its
aiosqlite connections under cancellation; the trace + backend log show a
~60s window where every SQLite writer stalled (the un-publish PATCH never
answered, the retry's auto_login hung 34s+, the sibling worker's build took
71s instead of 0.66s) while reads kept answering in ms. Wait for the build
to finish (Stop visible -> hidden via the shared sendPlaygroundMessage
helper) before closing the popup, which also proves the published playground
completes a run rather than merely starting one.

Verified locally against the full Playwright stack: both tests pass.

* ci: run backend tests for provider bundle changes (#14605)

The `python` path filter never learned about `src/bundles/**` after the
bundle metapackage split. Since #13614 gated `test-backend` on
`path-filter.outputs.python == 'true'`, a PR that only touches a provider
bundle reports `python=false` and skips the entire backend suite -
including the bundle's own tests under `src/bundles/*/tests/`.

Add `src/bundles/**` to the `python` filter so bundle-only PRs run the
backend suite (and `test-templates`, which shares the same output).

* feat(bundles): add lfx-confluent bundle and watsonx.data components for the IBM streamhouse

Langflow already orchestrates agents over IBM's data at rest (OpenRAG on
watsonx.data) but had no surface for data in motion. This adds first-class
components for IBM's streaming lakehouse -- IBM Confluent (Kafka, Tableflow,
Real-Time Context Engine) and IBM watsonx.data (Presto, remote MCP server) --
using only open protocols (Kafka wire protocol, Iceberg REST, MCP over
Streamable HTTP, Presto DBAPI).

New bundle `lfx-confluent` (src/bundles/confluent, sidebar "IBM Confluent"):
- ConfluentContextEngineComponent: preset MCP toolset for the Real-Time
  Context Engine (list_topics / get_metadata / query_data) for Agents.
- ConfluentKafkaProducerComponent: publish Message/Data/DataFrame rows to a
  topic; delivery report output.
- ConfluentKafkaConsumerComponent: bounded batch (limit + timeout) into a
  DataFrame; json/string/avro/json_schema (Schema Registry) values.
- ConfluentTableflowReaderComponent: read Tableflow Iceberg tables via the
  Tableflow REST catalog with pyiceberg (row filter, projection, limit,
  snapshot); list tables.
Deps: confluent-kafka[avro,json,schemaregistry], pyiceberg, pyarrow (lazy
imports; bundle loads without them). Registered in the `bundles` extra,
uv sources, and workspace members.

`lfx-ibm` 0.1.5 -> 0.2.0:
- WatsonxDataPrestoComponent: SQL on watsonx.data Presto (presto-python-client;
  ibmlhapikey/IAM API key or basic auth; CA bundle; row cap) -> DataFrame.
- WatsonxDataMCPComponent: preset MCP toolset for the watsonx.data remote MCP
  server (/api/v2/mcp/; bearer token or IBM Cloud API-key IAM exchange).

Core: new `lfx.base.mcp.preset.MCPPresetComponent` -- a base for components
that wrap a fixed remote MCP server as an Agent toolset. Reuses
`lfx.base.mcp.util.update_tools` (SSRF-checked Streamable HTTP with SSE
fallback), the `add_tool_output` + `_get_tools()` Tool-Mode pattern, a direct
"Response" output, and a live tool-dropdown refresh. Lives in lfx.base rather
than a bundle because the extension loader registers every *Component class
found in a bundle module.

Security: every tenant-supplied endpoint / bootstrap host goes through
`validate_connector_url_for_ssrf`; Confluent IDs are validated as plain
tokens before URL interpolation; secrets are SecretStrInput.

Frontend: Confluent icon, WatsonxData icon alias, "IBM Confluent" sidebar
bundle entry (+ sidebar test).

Docs: new bundles-confluent page (component reference plus zero-code recipes:
Context Engine via MCP Tools, HTTP Sink -> webhook trigger, Flink Streaming
Agent -> Langflow flow-as-tool, Tableflow -> watsonx.data), watsonx.data
sections on the IBM bundle page, sidebar + install-partial entries.

Tests: 230 bundle tests (src/bundles/confluent/tests, src/bundles/ibm/tests)
and 12 core tests (src/lfx/tests/unit/base/mcp/test_preset.py); all mocked,
no network. Live smoke tests against Confluent Cloud / watsonx.data are a
follow-up (need credentials).

Lock note: pyiceberg (>=0.10) caps cachetools <7, so uv.lock moves cachetools
7.1.6 -> 6.2.6; nothing in the workspace requires >=7 (only >=6 via
ibm-watsonx-ai).

* docs(bundles): use file-relative links between the IBM and IBM Confluent bundle pages

bundles-confluent only exists in the next docs version; an absolute
/bundles-confluent link from the versioned IBM page resolved against the
released docs and broke the docs draft build. File-relative links resolve
per version (same pattern as ../Develop/memory-bases.mdx).

* chore: trigger CI

* fix(lfx): skip teardown-less services during fork-safety teardown; address review feedback on the confluent/ibm bundles

---------

Co-authored-by: Viktor Avelino <64113566+viktoravelino@users.noreply.github.com>
Co-authored-by: Deon Sanchez <69873175+deon-sanchez@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Co-authored-by: Hamza Rashid <74062092+HzaRashid@users.noreply.github.com>
Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com>
Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com>
Co-authored-by: 李政达 <li18903778339@gmail.com>
Co-authored-by: 李政达 <1242427577@qq.com>
Co-authored-by: Saad Mirza <saadmirza009@gmail.com>
Co-authored-by: Saad ur Rehman <saad.urrehman@cleura.com>
Co-authored-by: olayinkaadelakun <olayinka.adelakun@ibm.com>
Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local>
Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com>
Co-authored-by: Viktor Avelino <viktor.avelino@gmail.com>
Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.4em-ca.ibm.com>
Co-authored-by: Janardan Singh Kavia <janardankavia@ibm.com>
Co-authored-by: Janardan S Kavia <janardanskavia@Janardans-MacBook-Pro.local>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabrielf.almeida90@gmail.com>
Co-authored-by: Debojit Kaushik <Kaushik.debojit@gmail.com>
Co-authored-by: keval shah <kevalvirat@gmail.com>
Co-authored-by: Tarcio <rodriguestarcio.adv@gmail.com>
Co-authored-by: Zhengcy05 <1825478405@qq.com>
Co-authored-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Adam-Aghili <149833988+Adam-Aghili@users.noreply.github.com>
Co-authored-by: Oxygen56 <jiangth99@163.com>
Co-authored-by: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com>
E
Eric Hare committed
c2c154749cd0d92e421bf83596f97186876bcf95
Parent: 99ea904
Committed by GitHub <noreply@github.com> on 8/17/2026, 11:44:36 PM