Commit Graph

14132 Commits

Author SHA1 Message Date
d642f88adc feat(a2a): enforce the apikey scheme the agent card advertises
When a flow's folder requires apikey auth, the JSON-RPC route now requires a valid
langflow API key in the x-api-key header whose owner is the flow owner, before any
dispatch (covers message/send, message/stream, tasks/get, tasks/resubscribe). Flows
in none folders stay public (the A2A public-agent model); the discovery card stays
public by spec.

Uses check_key directly rather than api_key_security, which under AUTO_LOGIN returns
the superuser for a missing key and would bypass the gate. The key is scoped to
flow.user_id since the flow runs as its owner. The auth_type read is extracted into a
shared folder_auth_type helper so card-advertise and route-enforce can't drift.
2026-06-25 18:46:16 -03:00
f86119b7d0 feat(a2a): stream message/stream and tasks/resubscribe over SSE
Advertises the streaming capability on both the handler card (the SDK's @validate
gate) and the discovery card, which mounts message/stream and tasks/resubscribe
through the existing dispatcher. message/stream replays the run lifecycle
(submitted -> working -> artifact -> completed) as SSE frames by re-emitting the
same executor events; tasks/resubscribe re-attaches to a live run and returns a
spec error for terminal/cross-worker tasks (tasks/get covers terminal reads).

Per-token deltas and durable cross-worker re-attach are follow-ups. Tests cover
the advertised capability, the SSE lifecycle, and that resubscribe to a finished
task ends with an error frame rather than hanging.
2026-06-25 18:20:56 -03:00
763d736a04 feat(a2a): durable DB-backed A2A task store
Replaces the in-memory module-singleton task store with DurableTaskStore, a
DB-backed a2a-sdk TaskStore that persists each protobuf Task as a JSON blob in a
new a2a_tasks table (composite PK (id, owner), JSONB on postgres). Tasks now
survive a restart and are visible across workers; save() uses a writing session,
get() a read-only one.

Adds the A2ATask model + alembic migration, and tests covering save/get
round-trip, owner scoping, and a real_services test that runs the migration and
the store on both sqlite and postgres.
2026-06-25 17:32:30 -03:00
327e0478cd feat(a2a): add message/send JSON-RPC endpoint for agent flows
Adds POST /api/v1/a2a/{flow_id}/jsonrpc serving the A2A JSON-RPC surface:
message/send runs the flow through the v2 sync surface and returns a
terminal Task, and tasks/get reads it back from an in-memory store. Gated
behind LANGFLOW_A2A_ENABLED and the per-flow agent type + a2a_enabled flag,
like the card route.

The protocol-pure executor (a2a_executor.py) holds no langflow imports and
reaches the flow via an injected run_flow callable, so the protocol layer
stays extractable to lfx. Unexpected build/run failures are logged
server-side and surface a generic message to the unauthenticated caller;
multi-output flows emit each text channel instead of dropping them.
2026-06-25 16:07:40 -03:00
cc7259d675 feat(a2a): add agent-card discovery endpoint behind LANGFLOW_A2A_ENABLED
Public GET /api/v1/a2a/{flow_id}/.well-known/agent-card.json serving a
spec-valid A2A agent card for agent-typed, a2a_enabled flows. Gated by
LANGFLOW_A2A_ENABLED (default off) via a per-request guard; the router is
mounted unconditionally so the flag can flip at runtime. Reflects folder
apikey auth onto securitySchemes (reflect-only; F6 enforces). The card
degrades to an empty input schema on unbuildable flows and ignores
malformed a2a_card_overrides instead of 500ing the public endpoint.

Adds a2a-sdk as a direct langflow-base dependency.
2026-06-25 15:06:37 -03:00
f5f6ee566e fix(lfx): restore synchronous AllTypesDict.get_type_dict
cz/hitl-v2 regressed the release-1.11.0 fix: get_type_dict called the
async get_all_types_dict synchronously, so the sync _build_dict received
an un-awaited coroutine and the first Graph.from_payload raised
"'coroutine' object is not a mapping" — breaking json_schema_from_flow
and MCP tool-schema generation. Restore the sync build_custom_components
path (identical to release-1.11.0) and its regression test.
2026-06-25 15:06:23 -03:00
c2876c5d72 feat(a2a): add flow_type categorization and A2A flow columns
Add an explicit flow_type enum (workflow|agent), a2a_enabled, and
a2a_card_overrides to the Flow model via an additive migration following
the access_type precedent. Surface the fields in the flow create/read/update
schemas, add a flow_type filter to the list endpoint, and add a
suggest_flow_type auto-detect helper (UI suggestion only, never the stored
source of truth).

This is F1, the foundation of the A2A protocol support epic.
2026-06-25 13:44:57 -03:00
469e7156bc test: skip durable saver HITL round trip on Python 3.10 2026-06-24 10:37:29 -03:00
c1a5b28af6 Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/hitl-v2 2026-06-24 09:41:36 -03:00
2673566adf test: stabilize durable checkpoint saver test under parallel load 2026-06-24 09:40:57 -03:00
71c7b30234 [autofix.ci] apply automated fixes 2026-06-23 23:48:26 +00:00
b52f31eb9f Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/hitl-v2 2026-06-23 20:45:23 -03:00
09822e8736 refactor: fail loud on non-scoped durable checkpoint scans 2026-06-23 20:43:40 -03:00
83b1e726d4 [autofix.ci] apply automated fixes 2026-06-23 23:37:29 +00:00
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