Commit Graph

18164 Commits

Author SHA1 Message Date
b3d3a22e22 fix(api/v2): return background run output from completed status
A completed background run's GET status returned a bare COMPLETED with an
empty `outputs` and a null `output`. The COMPLETED branch reconstructs
from `vertex_builds` keyed by job_id, which the durable path does not
write, so reconstruction raised ValueError and fell through to an empty
response; the result was only retrievable via a /events re-attach.

The runner now captures the terminal `output` events (the langflow
adapter's normalized ComponentOutput payloads) into `Job.result`, and the
status COMPLETED branch rebuilds the `outputs` map and resolved `output`
from them via `workflow_response_from_output_events`, matching the sync
response. agui-protocol runs emit no `output` events, so their status
stays result-less (the result remains on the /events log).
2026-06-16 18:58:17 -03:00
02e06fe6f3 fix(api/v2): apply request tweaks on the streaming and background paths
The v2 workflows endpoint applied `tweaks` only on mode=sync. The stream
and background paths build the graph via the v1 build-vertex loop
(`generate_flow_events`), which never received the tweaks, so they were
silently dropped. The confusing symptom: a model passed via tweaks
surfaced as "A model selection is required", and any per-component
override was ignored on non-sync runs.

Thread `parsed.tweaks` into `generate_flow_events` and apply them to the
built graph via `vertex.update_raw_params`. We do not use the lfx
`process_tweaks_on_graph` helper because it only sets `vertex.params`,
which does not persist to runtime (the same bug
`lfx.base.tools.run_flow._process_tweaks_on_graph` works around). No-tweaks
runs are unchanged (guarded by `if tweaks`). Adds a streaming regression
test that overrides ChatInput via tweaks and asserts the value drives the run.
2026-06-16 17:35:25 -03:00
98aa98df97 fix(api/v2): restore "end" side-channel event in AG-UI workflow stream
The durable background-execution rewrite of workflow.py reverted
`side_channel_events` to its pre-"end" form, dropping the "end" event
from the AG-UI side-channel. That event carries `build_duration` to the
playground chat-view, and the message metadata badge only renders when
`hasDuration || hasTokens`. With build_duration gone the badge vanished,
failing the token-usage and shareable-playground "Finished In" regression
tests. Re-add "end" so the streaming playground path delivers it again.
2026-06-16 14:35:31 -03:00
33cd3baa58 test(lfx): register background-execution Settings fields in the field-count gate
The durable background-execution work added six Settings fields
(background_max_concurrency, background_job_timeout, background_lease_ttl_s,
background_heartbeat_interval_s, background_watchdog_interval_s, test_redis_url)
without updating EXPECTED_FIELDS, so test_field_count_unchanged failed 152 != 146.
These are intentional bg-exec config; add them to the gate.
2026-06-15 20:15:02 -03:00
e5a9e36527 fix(api/v2): move FrameSourceFactory alias under TYPE_CHECKING
As a module-level runtime value, FrameSourceFactory = Callable[..., Any] is a
GenericAlias that passes isinstance(obj, type) but makes issubclass(obj, Service)
raise on Python 3.10/3.14. The service factory scans this module for Service
subclasses (services/factory.py:90), so the runtime alias crashed service
initialization on those interpreters with 'issubclass() arg 1 must be a class'
-> 'Could not initialize services', erroring out dozens of unrelated tests at
setup (3.13 was unaffected, which is why local runs passed).

The alias is only referenced in a lazy annotation (from __future__ import
annotations), so moving it + the Callable import under TYPE_CHECKING removes it
from the runtime namespace with no behavior change.

Verified: alias absent from runtime module namespace, factory scan finds
BackgroundExecutionService cleanly, durable service tests 26/26 pass.
2026-06-15 19:38:48 -03:00
e0176f9c04 test(api/v2): update stale workflow-stop tests for the durable design
These 3 tests targeted the removed queue-service stop helper
(_cancel_workflow_queue_job / get_queue_service), inherited via the
agui->bg-default merge and failing with AttributeError across the stack:

- test_stop_workflow_success: adapted to the durable stop path
  (revoke_task -> stop_job -> update_job_status(CANCELLED)).
- test_stop_workflow_allowed_for_legacy_job_with_no_user_id (IDOR): adapted to
  the durable mechanism; still asserts the ownership check does not block a
  legacy user_id=None row.
- test_stop_workflow_returns_503_when_queue_cancel_cannot_be_confirmed: dropped
  — the durable stop writes a best-effort STOP signal and always finalizes
  CANCELLED; the queue-service 'cannot confirm -> 503' path no longer exists.

test_workflow.py now passes 24/24.
2026-06-15 17:03:44 -03:00
0e209c97ef fix(api/v2): no duplicate WORKFLOW job row on durable background runs
A v2 background run created TWO JobType.WORKFLOW rows for one flow execution:
the durable row (submit()'s job_id, owned by JobRunner) plus an orphan keyed by
the run_id generate_flow_events mints, because the build pipeline's
track_job_status defaults True and the durable frame source never passed False.
The flow ran once (double bookkeeping), but every background run left a phantom
WORKFLOW row + job_events and double-fired the memory-base hook, skewing metrics.

Thread track_job_status through _stream_event_frames; pass False only from the
background frame source (the durable runner already owns the row + fires the
hook with the durable job_id). Stream/public paths keep default True. Also gate
build.py's memory-base hook fire behind track_job_status so background doesn't
double-fire. Adds a regression test (RED before fix: found 2 rows).
2026-06-15 16:33:42 -03:00
05830e2c6c Merge feat/v2-workflows-agui into feat/v2-workflows-bg-default
Resolves the workflow.py / test_workflow_agui.py conflict in favor of the
durable background-execution design: the in-memory _BackgroundRun buffer,
_BACKGROUND_RUNS registry, and their tests are dropped (replaced by the durable
job_events store + InMemoryLiveBus + JobRunner, which already port the
load-bearing guarantees: replay-then-tail, Last-Event-ID resume, exactly-once
non-resurrecting cancellation, FAILED-vs-COMPLETED, cross-worker stop,
privacy-404). The base's AG-UI translator fixes (inactive-vertex deltas +
dedupe) and the jest downlevelIteration fix merge in cleanly.

Verified: 209 backend tests pass (services/background_execution, v2
test_workflow_agui, test_agui_translator, test_converters).
2026-06-15 14:52:22 -03:00
91f650c763 fix(api/v2): dedupe repeated inactive node deltas in AG-UI stream
build.py keeps reporting a conditionally-excluded vertex in
inactivated_vertices on every subsequent end_vertex (the excluded set
persists until the ConditionalRouter clears it), so the translator was
putting the same inactive STATE_DELTA on the wire once per remaining
vertex. Track emitted inactive nodes and skip re-emitting; drop a node
from the set when it actually runs again (build_start/end_vertex) so a
loop re-activation can still re-emit inactive later.
2026-06-15 14:11:27 -03:00
76bc8ee035 fix(api/v2): surface inactivated branch vertices over AG-UI
A branch component (If-Else, Conditional Router) reports its not-taken
vertices in build_data.inactivated_vertices, but the AG-UI translator only
emitted the branch node's own success/error status and dropped that list. The
canvas seeds every planned node as pending from vertices_sorted; skipped
vertices then get no build_start/end_vertex, so they stayed stuck on pending
instead of rendering as inactive (the v1 build path marked them INACTIVE).

The translator now appends an inactive STATE_DELTA op per inactivated vertex,
and the frontend bridge maps the new inactive status to BuildStatus.INACTIVE
and tears its edges down like a completed node. Fixes the If-Else regression
in general-bugs-reset-flow-run.spec.ts.
2026-06-15 12:12:21 -03:00
78baed8104 fix(frontend): enable downlevelIteration for jest Set/Map iteration
ts-jest compiles with target es5; without downlevelIteration, [...set] and
for...of over a Set/Map emit ES5 that yields nothing. That silently broke the
AG-UI bridge tests: runningNodeIds spread, markRunningNodesFailed, and
restoreOriginalBuildStatuses all iterated empty. Production (Vite/SWC, modern
target) was never affected; only the ts-jest harness was. Fixes the 3 failing
jest tests on this branch with no other suite changes (4994/4994 pass).
2026-06-15 12:04:19 -03:00
3a124dd711 [autofix.ci] apply automated fixes 2026-06-11 14:58:59 +00:00
93d59c8f44 Merge branch 'feat/v2-workflows-agui' of https://github.com/langflow-ai/langflow into codex/v2-workflows-agui-merge
# Conflicts:
#	src/backend/base/langflow/api/v2/agui_translator.py
#	src/backend/tests/unit/api/v2/test_agui_translator.py
2026-06-11 11:57:42 -03:00
38dc8995e9 Fix AG-UI workflow lifecycle edges 2026-06-11 11:50:43 -03:00
f7c4024b59 Merge remote-tracking branch 'origin/feat/v2-workflows-agui' into HEAD 2026-06-10 17:50:19 -03:00
c03466e98a fix(api/v2): gate AG-UI message finalization on non-partial state and purge removed buffers
A partial add_message re-fire (the agent path emits these at tool
start/end for a message it is still streaming) was treated as the
finalizer: it closed and tombstoned the id, so the post-tool answer
was dropped. Only a non-partial add_message finalizes now; state
defaults to complete, so payloads without properties are unchanged.

remove_message now purges a buffered message and tombstones its id,
so text the backend retracted is not flushed to the client later.
2026-06-10 17:49:40 -03:00
d96157e4f9 Merge remote-tracking branch 'origin/feat/v2-workflows-agui' into HEAD 2026-06-10 17:00:02 -03:00
6f5de50eb3 fix(api/v2): buffer parallel messages in the AG-UI translator instead of dropping them
Parallel components stream tokens for different message ids interleaved.
The translator tracked a single open message: the first foreign token
closed the open message and tombstoned its id, so every later event for
it was dropped and its remaining text never reached the client.

Tokens for a message that cannot take the wire now buffer until the open
message genuinely ends (its add_message finalizer), then flush in arrival
order; complete messages landing mid-stream buffer the same way instead
of interleaving a second START. end/error drain all buffers before the
terminal event. The wire still carries at most one open text message, so
the stream stays AG-UI-conformant.
2026-06-10 16:58:51 -03:00
60469a698e fix(api/v2): keep background workflows out of polling watchdog LE-1389 2026-06-10 15:34:59 -03:00
0aab6f8c04 Merge origin/feat/v2-workflows-agui into codex/v2-workflows-agui-merge 2026-06-10 15:00:54 -03:00
54fc55082f fix(api/v2): report unconfirmed workflow stops LE-1389 2026-06-10 15:00:33 -03:00
c84e965c66 fix(api/v2): signal cross-worker workflow stops LE-1389 2026-06-10 14:47:51 -03:00
0c8829944f fix(api/v2): merge workflow AG-UI cancellation hardening LE-1389 2026-06-10 13:43:11 -03:00
80b105a923 Merge release-1.11.0 (via feat/v2-workflows-agui) into feat/v2-workflows-bg-default
Port the 6 background-execution settings and background_backend_is_scaled into 1.11.0's RuntimeSettings group mixin; union the BACKGROUND_EXECUTION_SERVICE / TELEMETRY_WRITER_SERVICE additions in schema.py and deps.py.
2026-06-10 09:43:47 -03:00
53660b3df7 Merge release-1.11.0 into feat/v2-workflows-agui
Adopt 1.11.0's composed group-mixin Settings for lfx settings/base.py (all v2 settings already present in the new groups); port the Python 3.14 cors_origins ['*']->'*' fix into groups/security.py.
2026-06-10 09:22:56 -03:00
75e01157fe fix(ci): allow pre-releases when pinning the nightly in migration validation (1.11.0) (#13600)
fix(ci): allow pre-releases when pinning the nightly in migration validation

Migration Test: pip/venv (stable -> nightly) failed deterministically on
nightly run 27260425158 (twice, including a rerun):

  hint: langflow-base was requested with a pre-release marker (e.g.,
  langflow-base==1.11.0.dev1), but pre-releases weren't enabled
  (try: --prerelease=allow)

This is the first nightly publishing as a canonical .devN pre-release
of the langflow distribution (nightly -> stable bundle cutover). The
'latest' branch of the upgrade step already passes --prerelease=allow,
but the pinned-version branches do not. uv implicitly allows the
pre-release for the directly requested ==X.Y.Z.devN pin, yet langflow's
metadata pins langflow-base==X.Y.Z.devN transitively, and uv rejects
transitive pre-releases unless they are enabled - so the install fails
after the stable uninstall, sinking the migration test.

Add --prerelease=allow to both pinned-version install lines.
2026-06-10 04:50:26 -07:00
0555eeced1 fix(test): gate models.dev background refresh out of tests (#13596)
Integration tests failed twice in nightly run 27260425158 with pyleak
EventLoopBlockError - first Integration Tests 3.14, then 3.12 on the
rerun, each time in a different test. The blocking stack points at
refresh_models_dev_periodically: every app boot unconditionally starts
a lifespan task that immediately fetches https://models.dev/api.json,
so the request lands mid-test in whatever test happens to be running.
Under pyleak's asyncio debug instrumentation the fetch blocked the loop
0.797s against a 0.2s threshold. Whichever test draws the short straw
flakes - which is why it looked transient and moved between versions.

Add a LANGFLOW_MODELS_DEV_REFRESH env gate (default unchanged: enabled)
and disable it session-wide in the backend test conftest. Tests fall
back to the bundled static model lists, which is also deterministic.

Verified: with the gate set, app boot makes zero models.dev requests;
the previously failing integration test passes.
2026-06-10 04:36:38 -07:00
086e38898d fix(ci): anchor langflow-base version extraction in nightly docker build (1.11.0) (#13592)
fix(ci): anchor langflow-base version extraction in nightly docker build

The first nightly on the 1.11 workspace (tag v1.11.0.dev0, run
27253229568) failed in Build Nightly Base Package within seconds:
'Base version format is incorrect'. The extraction (uv tree, grep
langflow-base unanchored, awk field 3, first line) broke because uv
tree now prints the langflow-base workspace-root line
('langflow-base v1.11.0.dev0', two fields) before any dependency line
('langflow-base[complete] v1.11.0.dev0' under the langflow root, three
fields), so the first match yields an empty field 3 and the format
check exits 1. uv tree's stderr is discarded, which made the real
cause invisible in CI.

Anchor to the root line and take field 2 instead - the exact pattern
the langflow (main package) extraction in this same file already uses,
which is why the main-package builds passed on the same tag. Verified
both extractions print 1.11.0.dev0 against a local checkout of
v1.11.0.dev0.
2026-06-10 00:25:55 -07:00
d065523493 fix(test): raise spawn-child join timeout in test_multi_process_visibility (#13588)
The test spawns a child via multiprocessing spawn context, which
cold-imports the full langflow package (plus coverage's multiprocessing
hooks in CI) before appending a single event. The 10s join timeout is
routinely exceeded on a loaded CI runner sharing 4 vCPUs with a second
xdist worker: in nightly run 27253229568 (Unit Tests - Python 3.12 -
Group 5) the test failed all 12 executions (5 reruns x 2 step attempts),
each rerun exactly 10s apart - the join deadline, not a product bug.

Raise the liveness bound to 60s (join returns immediately when the
child exits, so the passing case is unaffected) and kill the child on
timeout so a hung spawn can't leak into later tests.
2026-06-09 23:13:35 -07:00
17447920f9 fix(ci): rebalance backend test splits with measured durations + raise unit-test step timeout (#13583)
Unit Tests - Python 3.12 - Group 3 has been failing at 98-99% on the
nightly: the job hits the nick-fields/retry 40-minute per-attempt timeout
and pytest is SIGTERM'd mid-test, so it looks like one flaky last test
when it is actually a deterministic timeout (and the internal retry plus
run-level retries can never succeed).

Root cause is twofold:

1. .test_durations was last regenerated ~May 2025 and covered only 2,219
   of ~9,500 current unit tests, so pytest-split weighted 77% of the
   suite at the 0.73s average. The expensive client-fixture tests
   (test_webhook.py, test_login.py - each pays a full create_app +
   lifespan boot per test, 60-120s late in a CI run) clustered into
   group 3's tail, making it ~8-10 minutes slower than its siblings
   (33:15 on 3.13, >40min on 3.12 which is additionally slowed by
   astrapy disabling SSL connection reuse on Python 3.12.0-11).
   The weekly store_pytest_durations workflow that should refresh the
   file has been dying at the 6-hour GitHub job limit every week (serial
   full-suite run no longer fits), so the file silently froze.

   This regenerates the file from real per-test wall-clock measured in
   the passing Python 3.13 nightly jobs (run 27246228762 attempt 1, all
   5 groups, parsed from the -vv xdist logs: per-worker start-to-start
   deltas). 9,508 tests now have measured durations; old entries are
   kept where no new measurement exists. Simulated least_duration
   split goes from one outlier group to 5 even groups (~24.6 min each)
   with the >50s tests spread 1-2 per group instead of 7 in one.

2. timeout_minutes 40 -> 50 gives headroom for matrix-cell variance
   (3.12 runs ~20% slower than 3.13) so a slightly slow cell degrades
   gracefully instead of burning 2x40min and failing the whole run.

Follow-ups (not in this PR): fix store_pytest_durations to run with
xdist or split groups so it fits the 6h limit; investigate the in-worker
degradation that makes client-fixture boots cost 8-12s early in a run
but 60-120s after ~30 minutes.
2026-06-09 21:28:02 -07:00
ee659ca38c fix(bundles): floor lfx pin at the minor line's .dev0 so nightlies resolve
The first 1.11.0.dev0 nightly failed its "Test Langflow Main CLI" step:
the fork bump's sync_bundle_lfx_pin.py re-synced every bundle floor to
lfx>=1.11.0, and PEP 440 sorts the nightly's 1.11.0.dev0 BELOW 1.11.0,
so the workspace-built bundles (whose metadata shadows the satisfiable
PyPI lfx-arxiv 0.1.1 during `uv pip install dist/*.whl`) reject the
branch's own lfx while langflow-base pins it exactly — unresolvable.

Floor at lfx>=X.Y.0.dev0,<(X+1).0.0 instead: X.Y.0.dev0 is the lowest
version PEP 440 admits in the minor line, so every devN / rcN / final
satisfies the floor while older lines and the next major stay excluded.
This closes the NIGHTLY.md activation-gate hole structurally — future
minor forks re-sync to a floor their own nightlies already satisfy.

- sync_bundle_lfx_pin.py: lfx_floor_spec emits the .dev0 floor
- port_bundle.py: mirrored _current_lfx_floor kept in step
- bundle pyprojects restamped via the script (arxiv/docling/duckduckgo/ibm)
- test_bundle_lfx_pin.py expectations updated (20/20 passing)
- NIGHTLY.md gate section annotated with the post-activation fix

uv.lock is unaffected (workspace lfx is recorded as an editable source
with no specifier — which is also why uv sync/lock passed in the same
job). The release.yml RC floor-relax sed still matches the new form;
now redundant but harmless. No bundle version bump needed: published
0.1.1 floors >=1.10.0.rc0, satisfiable by the whole 1.11 line.
2026-06-09 18:02:43 -07:00
7a784515e0 fix(lfx): restamp component index version after 1.11.0 fork bump (#13574)
The release-1.11.0 fork bumped lfx to 1.11.0 but left component_index.json's version field at 1.10.0. _read_component_index fails closed on exact version mismatch, so the bundled registry loads as None and the upgrade-gate tests fail (UpgradeFlowError: 'bundled component registry is empty or missing') across the LFX test matrix. That failure blocks the nightly's release-nightly-build job, so no canonical 1.11.0.devN is published and check-nightly-status blocks CI everywhere.

Surgical restamp: version -> 1.11.0 and recomputed sha256 (same orjson OPT_SORT_KEYS hashing and OPT_SORT_KEYS|OPT_INDENT_2 serialization as scripts/build_component_index.py). Entries unchanged. Verified the reader validation passes and the three failing tests go green.
2026-06-09 15:18:21 -07:00
fb64e45e75 chore: bump version to 1.11.0 2026-06-09 13:29:01 -07:00
13a937c5b7 feat(ci): nightly → stable bundles via canonical pre-releases + decision record [gated] (#13528)
* docs: record nightly→stable bundle cutover plan (gated on lfx 1.10.0)

Add src/bundles/NIGHTLY.md documenting why langflow-nightly currently
renames the bundles (lfx and lfx-nightly ship the same lfx/ import, so a
stable bundle would co-install both and collide) and the deferred cutover
(Approach A: canonical pre-releases; B: lfx as a bundle extra), gated on
stable lfx 1.10.0 being published to PyPI.

Also expand two docstrings in scripts/ci/update_lfx_version.py to state
the deeper install-conflict reason, not just the resolve failure. No
behavior change.

* feat(ci): nightly Approach A — canonical pre-releases, drop nightly bundles [DRAFT/gated] (#13529)

feat(ci): nightly Approach A — canonical pre-releases, drop nightly bundles

DRAFT reference implementation of the nightly→stable-bundle cutover documented
in src/bundles/NIGHTLY.md. Publishes the nightly under CANONICAL package names as
.devN pre-releases instead of separate *-nightly distributions, so the stable
lfx-* bundles resolve against a single canonical lfx (no dual-lfx install
collision) and no nightly bundle packages are produced.

- tag scripts (pypi/lfx/sdk_nightly_tag.py): count .devN against the canonical
  PyPI histories instead of the *-nightly projects
- update scripts: stop renaming to *-nightly; set .devN versions; re-pin
  inter-package deps to exact canonical dev versions; delete the bundle
  rename/repin (update_lfx_dep_in_bundles, rename_bundles_for_nightly)
- release_nightly.yml: publish canonical pre-releases; remove bundle build,
  dist-nightly-bundles artifact, publish-nightly-bundles job + its gate; verify
  canonical names; main wheel glob dist/langflow-*.whl
- nightly_build.yml: drop the bundle git-add in the tag commit
- NIGHTLY.md: Approach A marked implemented + activation gate + A1/A2 follow-ups

Held as DRAFT: do not activate until stable lfx 1.10.0 is published AND the
nightly base is the next minor (release-1.11.0). A 1.10.0.devN core sorts below
1.10.0 and would fail the bundles' >=1.10.0 floor. Stacked on #13528.

(.secrets.baseline: incidental line-number shifts for the two workflows + prune
of pre-existing stale Pokédex Agent.json entries.)

* docs(ci): drop internal 'Approach A' label from nightly cutover comments

Comment- and docstring-only change across scripts/ci/* and the two nightly
workflows; no logic change. The two workflow edits stay single-line so
.secrets.baseline line numbers are unaffected. src/bundles/NIGHTLY.md keeps
its A/B decision-record framing intentionally.

* feat(ci): make nightly consumers work with canonical pre-releases

Follow-ups from the nightly cutover that are part of its blast radius (the
nightly now publishes canonical `.devN` pre-releases, not `*-nightly`
distributions):

- version.py: derive the "Nightly" label from the `.dev` version marker, since
  the canonical `langflow`/`langflow-base` distribution matches first in the
  lookup. Keeps the startup banner and telemetry `package` field identifying
  nightlies. Adds a canonical-dev test; updates the base-dev assertion.
- ci.yml check-nightly-status: query the canonical `langflow` project and pick
  the latest `.devN` release date instead of `langflow-nightly`'s `.info.version`.
- db-migration-validation.yml: install the nightly as `langflow[postgresql]==<dev>`
  (pre-release) instead of `langflow-nightly[...]`; verify via version("langflow").
- src/lfx/README.md: nightly install is `uv pip install --pre lfx`.
- NIGHTLY.md: rewrite the follow-ups section (these are addressed; Docker image,
  A2 meta-package, and website docs remain deferred by design).

The `langflowai/langflow-nightly` Docker image name is intentionally unchanged.

* fix(ci): correct nightly verify uv tree parsing + stale base-dep regex

Addresses review of #13528:

- release_nightly.yml LFX verify: `uv tree | grep lfx | head -n1` matches the
  bundle `lfx-ibm` first → 'Name lfx-ibm does not match lfx'. Root the tree with
  `uv tree --package lfx` so the first line is the lfx package itself.
- release_nightly.yml base verify: under canonical naming `langflow-base` prints
  as a top-level `langflow-base v<ver>` line, so the old $2/$3 field parse read
  name="v0.10.0" and version="". Use `uv tree --package langflow-base` and $1/$2.
- update_lf_base_dependency.py update_base_dep: regex only accepted ~=/==, so its
  CLI entry point couldn't match the current root dep `langflow-base[complete]>=0.10.0`.
  Add >= (parity with update_uv_dependency.py). The active nightly path uses
  update_uv_dependency.py and was unaffected.

* docs(nightly): point NIGHTLY.md status at the activation gate, not draft state

Per review of #13528: this file ships inside #13528 (#13529 was folded in), so
the 'stacked on prep #13528' + 'held as a draft' framing is stale and misleading.
Reword the status block to state the real guard is the activation gate (stable
lfx 1.10.0 published AND next-minor base), not merge/draft state. Also reword the
follow-ups heading 'decide before un-drafting' -> 'decide before activating'.
2026-06-09 13:23:55 -07:00
0195a132e2 Merge release-1.10.0 into main
Non-squash union back-merge, ahead of cutting release-1.11.0 / release-1.10.1.
- Preserves main's settings-mixin refactor (#13141): release-1.10.0's 40 new
  settings ported into the per-group mixins, verified field-for-field and
  behaviorally against release's monolith.
- Keeps main's model-handling (#13191, auto-merged).
- CI workflows, docling deps, component index, starter projects, AGENTS.md,
  .secrets.baseline resolved to release-1.10.0. main: 1.9.6 -> 1.10.0.
2026-06-09 13:16:48 -07:00
2e214d77bb fix(api/v2): reconstruct background workflow status from job-keyed vertex builds
A completed background job's GET status 500'd with 'No vertex builds found
for job_id'. The background build path differed from the sync path twice:

1. generate_flow_events minted a fresh run_id instead of using job_id, so
   vertex builds were keyed by an id the status query never uses. Thread
   run_id through _stream_event_frames -> generate_flow_events and pass
   job_id from the background buffer so graph.run_id == job_id (the sync
   path already does graph.set_run_id(job_id)).

2. The SSE build loop (build_vertices) only persisted builds when log_builds
   was set and never passed job_id. Tie log_builds to job-tracked runs
   (run_id present) and pass job_id=graph.run_id on the persist call.
   Job-tracked runs also persist streaming terminal vertices so
   reconstruction is complete; the live build path (run_id is None) keeps
   its original behavior, so the v1 build path is unchanged.

Test: a real background run polled to completion, then GET status asserts a
reconstructed 200 (verified RED: 500 'No vertex builds found' before the
fix). Covers the non-streaming flow. v1 build path unchanged (35 build
tests pass); AG-UI suite 46 pass.

LE-1389
2026-06-09 16:01:04 -03:00
8cba565bd2 fix(api/v2): enforce no-code-execution gate on public workflow endpoint
The v2 public endpoint only ran validate_flow_for_current_settings and
skipped validate_public_flow_no_code_execution, which the v1
build_public_tmp path applies. A public flow containing a Python
interpreter/REPL (or the legacy Python Code Structured tool, Smart
Transform lambda) was therefore an unauthenticated server-side
code-execution primitive (report H1-3754930).

Mirror v1: import the validator and call it right after the
public-access gate. PublicFlowValidationError subclasses
CustomComponentValidationError, so the existing handler already
sanitizes it to a 400 'This flow cannot be executed.' without leaking
the blocked component class names.

Add a non-mocking test that builds a public flow with a real
PythonREPLComponent and asserts the sanitized 400 (verified RED: returns
200 without the gate).

LE-1389
2026-06-09 15:13:27 -03:00
3a7b8e7929 Merge remote-tracking branch 'origin/release-1.10.0' into feat/v2-workflows-agui
# Conflicts:
#	src/frontend/src/stores/flowStore.ts
2026-06-09 14:30:57 -03:00
8ee3493bb7 fix(observability): make grafana-loki reference stack instructions work end to end (#13454)
The reference stack README pointed LANGFLOW_LOG_FILE and LANGFLOW_LOG_DIR at
different directories, so following it produced an empty Grafana dashboard:
Langflow wrote to one path while Promtail scraped another. It also documented a
stdout-scrape alternative the shipped Promtail config does not implement.

Make the two paths consistent, require an absolute log path, correct the stdout
note, and add a no-Langflow smoke test that writes a sample record and confirms
it reaches Loki.
2026-06-09 17:14:46 +00:00
9690e69e86 fix(security): remove the disabled Python Code Structured tool component (#13560)
* fix(security): remove the disabled Python Code Structured tool component

Follow-up to #13538, which neutered PythonCodeStructuredTool to a
non-executable stub "for one release cycle, full removal later." This
completes that removal.

- Delete the component and its registration in lfx.components.tools.
- Drop its entry from the component index (num_components 355 -> 354,
  sha256 recomputed surgically) and from stable_hash_history.json.
- Remove its 18 i18n keys from every locale file.
- Replace the dedicated stub unit test with a removal test in
  test_dynamic_import_integration.py.
- Add a regressions entry to regressions/1.10.x.yaml.

The unauthenticated public-build RCE fix (report H1-3754930) is
unaffected: PythonCodeStructuredTool stays in
CODE_EXECUTION_COMPONENT_TYPES, so build_public_tmp still rejects any
saved or crafted flow that carries the type. instantiate_class execs the
node's stored `code` field regardless of whether the class still exists,
so the type-name block -- not the class -- is what closes the path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: document removal

* docs: typo

* Apply suggestion from @mendonk

Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
2026-06-09 10:16:36 -07:00
d7804149d8 docs: LF assistant ampersand and dot selectors (#13544)
* docs-lf-assistant-dot-selector

* docs-add-lfx-matrix-to-1.10-version
2026-06-09 13:04:49 +00:00
2524604a19 fix(ci): make Biome lint non-blocking for release workflow calls (correct implementation using allow-failure input)
- Revert invalid continue-on-error syntax on reusable workflow uses: job
- Add allow-failure input to ci.yml lint-frontend call
- Define allow-failure input parameter in lint-js.yml workflow_call
- Implement conditional exit-code swallow in lint-js.yml when allow-failure=true
- When release=true, Biome errors are non-blocking for release pipeline
- When release=false/unset, Biome failures block PR merge (existing ci_success gate)
2026-06-08 17:22:21 -04:00
801edf3bab Revert "fix(ci): make Biome lint non-blocking for release workflow calls (#13547)"
This reverts commit a1adb1aa6f.
2026-06-08 17:21:24 -04:00
a1adb1aa6f fix(ci): make Biome lint non-blocking for release workflow calls (#13547)
When ci.yml is called from release.yml (inputs.release == true), a
Biome failure was blocking all downstream publish and docker jobs via
needs.ci.result == 'success'. Biome was already excluded from the
ci_success gate for PR merges, but the reusable CI workflow itself
could still fail when the lint job errored.

Add continue-on-error: ${{ inputs.release == true }} to lint-frontend
so Biome failures are informational-only during release runs, while
remaining visible (and blocking ci_success) on regular PRs.
2026-06-08 17:04:51 -04:00
6610091697 fix(bundles): republish lfx-* at 0.1.1 with corrected pin + relax lfx floor for RC builds (#13542)
* fix(bundles): bump lfx-* bundles to 0.1.1 to republish with corrected lfx pin

The published 0.1.0 artifacts on PyPI carry stale lfx pins from before the lfx 0.5.0->1.10.0 version realignment:

- lfx-arxiv, lfx-duckduckgo: lfx>=0.5.0,<0.6.0 (hard-broken; the <0.6.0 cap can never resolve lfx 1.10.0)
- lfx-docling, lfx-ibm: lfx>=0.5.0 (uncapped floor/cap mismatch)

The source pin was already corrected to lfx>=1.10.0,<2.0.0 in #13516, but the bundles were never re-published. PyPI versions are immutable, so shipping the fix requires a version bump. Bump all four to 0.1.1 so the Release Bundles workflow cuts fresh wheels carrying the correct pin. Root pyproject keeps its >=0.1.0 floors (satisfied by 0.1.1); only the bundle dist versions and their uv.lock stamps change.

* fix(release): relax bundle lfx floor for pre-release builds + idempotent bundle publish

The RC pre-release run builds lfx as 1.10.0rc0, but bundles floor lfx at >=1.10.0. Under PEP 440 a pre-release sorts below the final, so 1.10.0rc0 fails >=1.10.0 and the cross-platform install test cannot resolve the bundle wheels against the RC lfx wheel.

build-base/build-main/build-lfx already rewrite their inter-package deps to the pre-release version when pre_release=true; build-bundles was the only release artifact missing that step. Add it: when pre_release=true, rewrite each bundle's lfx floor to the exact pre-release version, keeping the wide <2.0.0 BUNDLE_API cap. Stable source stays at >=1.10.0 -- only RC wheels are relaxed, at build time, so no source churn or re-tag.

Also make publish-bundles tolerate 'already exists' duplicate wheels on rerun, matching release_bundles.yml.
2026-06-08 13:18:56 -07:00
fa14076dec fix(security): block code-execution components on unauthenticated public flow builds (#13538)
* fix(security): block code-execution components on unauthenticated public flow builds (H1-3754930)

PythonCodeStructuredTool exec()'d its attacker-controlled `tool_code` field at
flow-build time. Because a PUBLIC flow can be built with no authentication via
POST /api/v1/build_public_tmp/{flow_id}/flow, that sink was reachable as an
unauthenticated server-side RCE — and other components (Python Interpreter/REPL,
Smart Transform) execute code on the same path, so removing one component alone
would not close the gap.

- Harden the public build path: build_public_tmp now rejects flows containing
  code-execution components via validate_public_flow_no_code_execution(). The
  check keys on the node `type`, so it holds regardless of the stored component
  `code`, and is enforced ONLY on the unauthenticated public path —
  authenticated /build is unchanged.
- Neuter PythonCodeStructuredTool to a non-executable compatibility stub: all
  exec()/eval() sinks removed; build_tool returns a tool that raises a
  deprecation error. The component stays registered with identical
  display_name/inputs so saved flows still load and locale keys don't change.
  It will be fully removed in a future release.

component_index.json (code_hash) is regenerated by autofix.ci.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

* fix: validate_public_flow_no_code_execution

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-08 18:57:22 +00:00
4339011b6d docs: lfx compatibility matrix and lfx serve updates (#13518)
* docs-add-existing-changes

* fix-combining-of-glyphs

* docs-lfx-compatibility

* peer-review
2026-06-08 18:26:12 +00:00
2411d8036e docs: build OpenAPI spec and cut version 1.10 (#13537)
* build-api

* bump-version-to-1.10

* fix-broken-links
2026-06-08 18:25:14 +00:00
60afa18f05 fix: serialize DataFrames in tool mode to prevent pandas truncation (#13504)
* fix: serialize DataFrames in tool mode to prevent pandas truncation

When Memory Base or Knowledge components are wired as agent tools, the DataFrame
result was returned directly without serialization. LangChain would then stringify
this for the agent observation using pandas' default repr, which truncates all
cells to 50 characters (display.max_colwidth=50), inserting "...".

This breaks the F3 agent use case where agents need to reliably recall facts from
memory. The agent receives truncated content and cannot see the full text.

The fix serializes DataFrames through the existing serialize() function, which
converts them to list[dict] format with full, untruncated content. This maintains
consistency with how other result types (Message, Data, etc.) are handled in tool mode.

- Affects: Memory Base and Knowledge components used as agent tools
- Does not affect: Component-to-component wiring or normal (non-tool) execution
- Testing: Added tests verifying DataFrames serialize to list[dict] with complete content

Improved MB GUI component  description

* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]

* [autofix.ci] apply automated fixes

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-08 15:25:02 +00:00
0087ed895c chore: remove aws scripts (#13534)
remove aws scripts
2026-06-08 15:21:33 +00:00