Commit Graph

18202 Commits

Author SHA1 Message Date
d63f606159 merge fix 2026-06-23 20:32:51 -03:00
6731c63e58 fix: persist HITL gate + output as backend spans 2026-06-23 20:26:55 -03:00
88818465ee Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/hitl-v2 2026-06-23 17:28:47 -03:00
dd350f3c04 fix: persist HITL trace state to survive page refresh 2026-06-23 17:28:32 -03:00
7931905fe2 Merge feat/lfx-v2-shared-layer into feat/v2-workflows-bg-default
Adopt the lfx.workflow shared contract layer: rewire the background
execution service and the v2 routes to import adapters/converters/
agui_translator from lfx.workflow, drop the duplicated backend copies and
the superseded inline workflow_background/execution/validation split.

Reconcile the adapter/converter divergence: keep the shared layer's
cancel_events (distinct cancelled terminal, not error) and valid-derived
component status, and port the background path's is_durable + durable-event
sets and workflow_response_from_output_events.
2026-06-23 16:53:02 -03:00
e8e8f6ea1d [autofix.ci] apply automated fixes 2026-06-23 17:45:17 +00:00
e407c043d0 test: mock check_and_handle_pause in build cancel test 2026-06-23 14:43:57 -03:00
6fd2e3c8bf fix: deepcopy output fallback and settings field count 2026-06-23 13:40:08 -03:00
02d47c3a35 fix: deepcopy output fallback and settings field count 2026-06-23 13:39:54 -03:00
fcbd1ed35a fix: resolve biome errors on HITL-touched frontend files 2026-06-23 13:31:18 -03:00
8fd128136a fix: restore SQLite signal_type enum rebuild; regen index, reformat 2026-06-23 13:18:37 -03:00
7116ea1842 refactor(lfx): extract v2 workflow contract layer into lfx.workflow
Moves the protocol-agnostic pieces of the v2 workflows API out of the langflow
backend into lfx so both the backend and `lfx serve` can share one contract.
First step toward giving lfx (the production runtime) the v2 workflows API.

- Move api/v2/adapters/, agui_translator.py, and converters.py to lfx/workflow/.
  They depend only on lfx.schema.workflow and ag_ui (already an lfx dep), so lfx
  carries the contract with zero langflow imports.
- Decouple the one langflow reference: converters typed run_response against
  langflow.api.v1.schemas.RunResponse (TYPE_CHECKING only). Replaced with a local
  RunResponseLike Protocol (outputs + session_id), the only attributes used.
- Repoint the six backend v2 workflow modules to import from lfx.workflow.
- Move the five protocol-agnostic contract tests into src/lfx/tests/unit/workflow/
  (run in the lfx-only env). test_output_event_parity and test_workflow_agui stay
  in langflow (they need langflow.api.build) with repointed imports.

Coverage unchanged: 201 contract tests pass in the lfx-only env, 191 backend v2
tests pass; 392 total, same as before the move.
2026-06-23 12:54:54 -03:00
8fe3e2f9a1 fix: suppress build toast on HITL resume 2026-06-23 11:13:17 -03:00
a14253b0aa Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/hitl-v2 2026-06-23 11:04:11 -03:00
af77c781c1 fix: HITL badge persistence and resume sync 2026-06-23 11:03:44 -03:00
b0cf060966 gh suggestions fixes 2026-06-23 09:27:43 -03:00
f22a02d3cd chore: auto-bake note keys and regenerate backend locales/en.json [skip ci] 2026-06-23 10:07:33 +00:00
eb259398e5 [autofix.ci] apply automated fixes 2026-06-23 10:05:58 +00:00
7a967a14d7 merge fix 2026-06-23 07:04:54 -03:00
cf03530e6f gh suggestions 2026-06-23 06:36:56 -03:00
eceba12e7b fix tool calling and trace user experience 2026-06-22 22:03:24 -03:00
a21d0d9eab refactor(v2 workflows): split workflow.py and address review blockers
Splits the ~1.5k-line workflow.py into focused modules and folds in the
execution-timeout and error-sanitization fixes from Cristhianzl's review of #13307.

- B1: workflow.py now holds only the four route handlers. Validation guards move
  to workflow_validation, the sync/stream run loop to workflow_execution, and the
  durable background machinery to workflow_background (layered, acyclic).
- I1: add workflow_execution_timeout (default 300) and apply a single wall-clock
  ceiling across sync, stream, background, and public via _stream_event_frames. A
  timeout becomes a sanitized terminal error and marks a background job failed.
- I3: the route error handlers no longer echo raw exception text. They return a
  generic, code-tagged message and log the full exception server-side.
- R1: remove the "commented out / future scope" comments that sat over live
  dataframe-extraction code in converters.py.
- R4: drop the worker-routing internals from the reattach 409 message.

Tests cover the timeout terminal-error path and the error-body sanitization, and
the settings field-count guard is updated for the new setting.
2026-06-22 15:05:53 -03:00
3a46d44f15 test(lfx): register public_flow_rate_limit_per_minute in settings composition 2026-06-22 12:02:35 -03:00
7a884d808e fix(api/v2): address review findings on the v2 workflows endpoint
- recover session_id for completed background jobs from the persisted
  terminal message instead of always returning null, so GET status can
  continue the same chat/memory thread
- replay a user-cancel as a CUSTOM cancel marker + RUN_FINISHED (agui) and
  a `cancelled` terminal (langflow) instead of RUN_ERROR, so a re-attaching
  client no longer reads a deliberate stop as a failure
- cancel the evicted still-running buffer writer when the background-run
  registry is full, so it stops appending into a run no reader can find
- derive per-component status from the error artifact / valid flag instead
  of hardcoding COMPLETED, and stop the langflow adapter dropping `valid`
- throttle the unauthenticated public endpoint per IP and bound its
  input_value/session_id length
- document the sync-only scope of request-body globals
- document that live event re-attach is intentionally owner-only
2026-06-22 11:19:25 -03:00
91a093a00b hitl trace screen 2026-06-22 09:15:49 -03:00
971dc47fc6 hitl LFX cli 2026-06-17 16:21:56 -03:00
66c443119e add checkpointer checker id 2026-06-17 14:49:42 -03:00
b4b8fbd630 fix human in the loop not saving on canvas after refreshing page 2026-06-17 12:15:54 -03:00
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
161cd84865 hitl on canvas 2026-06-16 16:38:14 -03:00
5c42b85f76 Code reviewer 2026-06-16 15:51:20 -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
fbe8a7c38a human-in-the-loop pause/resume for v2 background runs 2026-06-15 18:10:11 -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
998a1fb350 resume wiring for HumanInput suspend/resume + routing tests (LE-1449) 2026-06-15 11:26:50 -03:00
2f0be577a6 HumanInput node for mid-flow human decisions (LE-1449, component) 2026-06-15 11:06:41 -03:00
44db894e33 resume-by-re-enqueue for suspended HITL runs (LE-1446) 2026-06-15 10:47:51 -03:00
484aac4e13 resume-by-re-enqueue facade + job_id threading (LE-1446, partial) 2026-06-15 10:29:11 -03:00
49d9fd4366 LE 1442 2026-06-15 10:28:56 -03:00
1841018070 durable job-scoped graph checkpoint store (LE-1441) 2026-06-15 09:42:06 -03:00
6c8b91254c HITL suspend/resume schema, durable slice cleanup, graph checkpoint contract 2026-06-12 13:44:49 -03:00
3a124dd711 [autofix.ci] apply automated fixes 2026-06-11 14:58:59 +00:00