-
Notifications
You must be signed in to change notification settings - Fork 9.8k
feat: durable background execution + HITL suspend/resume schema #13633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 141 commits
Commits
Show all changes
147 commits
Select commit
Hold shift + click to select a range
88560cb
feat: native v2 workflows endpoint with pluggable stream protocols
ogabrielluiz 95f9102
feat(api): add output_text and session_id to v2 workflow response
ogabrielluiz 461e593
test(api/v2): cover output_text and session_id on the v2 workflow res…
ogabrielluiz 37d8a78
feat(api/v2): structured output with resolution reason on v2 response
ogabrielluiz f3c06ef
feat(api/v2): add request-side output selection (output_ids)
ogabrielluiz a1b9cb7
feat(api/v2): emit per-output events on the langflow stream
ogabrielluiz d696cae
feat(api/v2): durable background execution service (store + default b…
ogabrielluiz 23a4884
test(background-execution): rename hard_proof marker to real_services
ogabrielluiz 3a7b8e7
Merge remote-tracking branch 'origin/release-1.10.0' into feat/v2-wor…
ogabrielluiz 8cba565
fix(api/v2): enforce no-code-execution gate on public workflow endpoint
ogabrielluiz 2e214d7
fix(api/v2): reconstruct background workflow status from job-keyed ve…
ogabrielluiz 53660b3
Merge release-1.11.0 into feat/v2-workflows-agui
ogabrielluiz 80b105a
Merge release-1.11.0 (via feat/v2-workflows-agui) into feat/v2-workfl…
ogabrielluiz 0c88299
fix(api/v2): merge workflow AG-UI cancellation hardening LE-1389
ogabrielluiz c84e965
fix(api/v2): signal cross-worker workflow stops LE-1389
ogabrielluiz 54fc550
fix(api/v2): report unconfirmed workflow stops LE-1389
ogabrielluiz 0aab6f8
Merge origin/feat/v2-workflows-agui into codex/v2-workflows-agui-merge
ogabrielluiz 60469a6
fix(api/v2): keep background workflows out of polling watchdog LE-1389
ogabrielluiz 6f5de50
fix(api/v2): buffer parallel messages in the AG-UI translator instead…
ogabrielluiz d96157e
Merge remote-tracking branch 'origin/feat/v2-workflows-agui' into HEAD
ogabrielluiz c03466e
fix(api/v2): gate AG-UI message finalization on non-partial state and…
ogabrielluiz f7c4024
Merge remote-tracking branch 'origin/feat/v2-workflows-agui' into HEAD
ogabrielluiz 38dc899
Fix AG-UI workflow lifecycle edges
ogabrielluiz 93d59c8
Merge branch 'feat/v2-workflows-agui' of https://github.com/langflow-…
ogabrielluiz 3a124dd
[autofix.ci] apply automated fixes
autofix-ci[bot] 6c8b912
HITL suspend/resume schema, durable slice cleanup, graph checkpoint c…
Cristhianzl 1841018
durable job-scoped graph checkpoint store (LE-1441)
Cristhianzl 49d9fd4
LE 1442
Cristhianzl 484aac4
resume-by-re-enqueue facade + job_id threading (LE-1446, partial)
Cristhianzl 44db894
resume-by-re-enqueue for suspended HITL runs (LE-1446)
Cristhianzl 2f0be57
HumanInput node for mid-flow human decisions (LE-1449, component)
Cristhianzl 998a1fb
resume wiring for HumanInput suspend/resume + routing tests (LE-1449)
Cristhianzl 78baed8
fix(frontend): enable downlevelIteration for jest Set/Map iteration
ogabrielluiz 76bc8ee
fix(api/v2): surface inactivated branch vertices over AG-UI
ogabrielluiz 91f650c
fix(api/v2): dedupe repeated inactive node deltas in AG-UI stream
ogabrielluiz 05830e2
Merge feat/v2-workflows-agui into feat/v2-workflows-bg-default
ogabrielluiz 0e209c9
fix(api/v2): no duplicate WORKFLOW job row on durable background runs
ogabrielluiz e0176f9
test(api/v2): update stale workflow-stop tests for the durable design
ogabrielluiz fbe8a7c
human-in-the-loop pause/resume for v2 background runs
Cristhianzl e5a9e36
fix(api/v2): move FrameSourceFactory alias under TYPE_CHECKING
ogabrielluiz 33cd3ba
test(lfx): register background-execution Settings fields in the field…
ogabrielluiz 98aa98d
fix(api/v2): restore "end" side-channel event in AG-UI workflow stream
ogabrielluiz 5c42b85
Code reviewer
Cristhianzl 161cd84
hitl on canvas
Cristhianzl 02e06fe
fix(api/v2): apply request tweaks on the streaming and background paths
ogabrielluiz b3d3a22
fix(api/v2): return background run output from completed status
ogabrielluiz b4b8fbd
fix human in the loop not saving on canvas after refreshing page
Cristhianzl 66c4431
add checkpointer checker id
Cristhianzl 971dc47
hitl LFX cli
Cristhianzl 91a093a
hitl trace screen
Cristhianzl 7a884d8
fix(api/v2): address review findings on the v2 workflows endpoint
ogabrielluiz 3a46d44
test(lfx): register public_flow_rate_limit_per_minute in settings com…
ogabrielluiz a21d0d9
refactor(v2 workflows): split workflow.py and address review blockers
ogabrielluiz eceba12
fix tool calling and trace user experience
Cristhianzl cf03530
gh suggestions
Cristhianzl 7a967a1
merge fix
Cristhianzl eb25939
[autofix.ci] apply automated fixes
autofix-ci[bot] f22a02d
chore: auto-bake note keys and regenerate backend locales/en.json [sk…
github-actions[bot] b0cf060
gh suggestions fixes
Cristhianzl af77c78
fix: HITL badge persistence and resume sync
Cristhianzl a14253b
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 8fe3e2f
fix: suppress build toast on HITL resume
Cristhianzl 7116ea1
refactor(lfx): extract v2 workflow contract layer into lfx.workflow
ogabrielluiz 8fd1281
fix: restore SQLite signal_type enum rebuild; regen index, reformat
Cristhianzl fcbd1ed
fix: resolve biome errors on HITL-touched frontend files
Cristhianzl 02d47c3
fix: deepcopy output fallback and settings field count
Cristhianzl 6fd2e3c
fix: deepcopy output fallback and settings field count
Cristhianzl e407c04
test: mock check_and_handle_pause in build cancel test
Cristhianzl e8e8f6e
[autofix.ci] apply automated fixes
autofix-ci[bot] 7931905
Merge feat/lfx-v2-shared-layer into feat/v2-workflows-bg-default
ogabrielluiz dd350f3
fix: persist HITL trace state to survive page refresh
Cristhianzl 8881846
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 6731c63
fix: persist HITL gate + output as backend spans
Cristhianzl d63f606
merge fix
Cristhianzl 83b1e72
[autofix.ci] apply automated fixes
autofix-ci[bot] 09822e8
refactor: fail loud on non-scoped durable checkpoint scans
Cristhianzl b52f31e
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 71c7b30
[autofix.ci] apply automated fixes
autofix-ci[bot] 2673566
test: stabilize durable checkpoint saver test under parallel load
Cristhianzl c1a5b28
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 469e715
test: skip durable saver HITL round trip on Python 3.10
Cristhianzl 60632aa
chore: merge bg-default into cz/hitl-v2 (lfx shared layer + execution…
ogabrielluiz eef308c
fix(background-execution): prevent worker deadlock on stop() under Py…
ogabrielluiz 39a1bc4
fix(background-execution): prevent worker deadlock on stop() under Py…
ogabrielluiz 2364ecf
fix(components): skip Human Input pause when unconnected
Cristhianzl 9421aaa
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl fe7a717
feat(frontend): inline naming input for new User Actions
Cristhianzl 12638ab
feat(api): block HITL flows on v1 run with clear error
Cristhianzl ba85bf5
[autofix.ci] apply automated fixes
autofix-ci[bot] cef8e44
feat(mcp): surface HITL flows as isError on tool call
Cristhianzl f7b89f3
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 4bd946b
ruff style and checker
Cristhianzl 2e93aa0
add hitl chain edge case
Cristhianzl 3cc447c
i18n: translate Human Input UI chrome
Cristhianzl e5e84f0
[autofix.ci] apply automated fixes
autofix-ci[bot] c7bc0bd
fix(frontend): HITL canvas card, input and scroll
Cristhianzl 79f6180
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 7b95308
add zindex on hitl node
Cristhianzl 8e2af20
feat(lfx): document CLI HITL limits, warn non-TTY
Cristhianzl 48376d8
fix: reject HITL flows in nested flow runs
Cristhianzl 27900f8
improve run flow ux
Cristhianzl fdf4444
fix(mcp): raise on isError tool results
Cristhianzl 7d0aa58
block mcp execution with hitl
Cristhianzl 8d679a5
initial commit lfx hitl
Cristhianzl 6ef80dd
feat(lfx): durable HITL background on lfx serve
Cristhianzl 333680b
merge: sync release-1.11.0 into cz/hitl-v2
ogabrielluiz d5ff101
code review improvements
Cristhianzl 273cc32
merge: bring cz/hitl-v2 durable lfx serve HITL into the sync branch
ogabrielluiz ed716f3
merge: bring latest cz/hitl-v2 (durable lfx serve HITL + review fixes…
ogabrielluiz 4ea85ab
[autofix.ci] apply automated fixes
autofix-ci[bot] 6b2ba1b
Merge remote-tracking branch 'origin/release-1.11.0' into cz/hitl-v2-…
ogabrielluiz 2f884cb
fix flow store e2e error
Cristhianzl 00210f7
merge: sync release-1.11.0 into feat/v2-workflows-bg-default
ogabrielluiz 39d5bb0
Merge remote-tracking branch 'origin/cz/hitl-v2-seam-sync' into cz/hi…
ogabrielluiz c98878b
Merge pull request #13985 from langflow-ai/cz/hitl-v2-seam-sync
ogabrielluiz dfa218f
merge: update cz/hitl-v2 with its base (feat/v2-workflows-bg-default)
ogabrielluiz c436a3b
[autofix.ci] apply automated fixes
autofix-ci[bot] 116d804
Merge branch 'release-1.11.0' into feat/v2-workflows-bg-default
ogabrielluiz 473e147
fix(background-execution): keep ephemeral frames on reattach, pin psy…
ogabrielluiz 51c527e
fix(frontend): playground HITL flows pause again
Cristhianzl 77e513d
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 3a68242
merge fix
Cristhianzl 4387293
fix: never finalize a SUSPENDED job (+drift guard)
Cristhianzl 16a7cc4
fix ruff style and checker
Cristhianzl ee6b4c5
fix(lfx): mount /events SSE route on durable serve
Cristhianzl 1acc166
remove handles from unecessary fields
Cristhianzl 1680d27
feat(hitl): expiry event and broken-edge warning
Cristhianzl 79b0b48
merge fix
Cristhianzl 47b3869
chore: auto-bake note keys and regenerate backend locales/en.json [sk…
github-actions[bot] c53da15
fix ruff style checker
Cristhianzl 9bf0d65
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 5f3835f
[autofix.ci] apply automated fixes
autofix-ci[bot] 53c6b68
fix(frontend): drop unused ContentType import
Cristhianzl 0b1e540
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 09c62c7
fix card duplication
Cristhianzl 8a00b9e
merge fix
Cristhianzl fbd7af2
initial JSONs
Cristhianzl df47f79
chore: auto-bake note keys and regenerate backend locales/en.json [sk…
github-actions[bot] c70aa36
merge message id on alembic
Cristhianzl 7084349
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl a67a98e
Merge remote-tracking branch 'origin/release-1.11.0' into cz/hitl-v2
erichare 13fc71b
fix(hitl): resume frozen flows, reject stale ids
Cristhianzl 0ba3ca4
Merge branch 'cz/hitl-v2' of github.com:langflow-ai/langflow into cz/…
Cristhianzl 0421009
fix tests fe
Cristhianzl 605c1cb
Merge release-1.11.0 into cz/hitl-v2
erichare 02e05cf
Merge branch 'release-1.11.0' into cz/hitl-v2
erichare 602223f
fix: refresh agentic MCP snapshots after release sync
erichare File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
25 changes: 25 additions & 0 deletions
25
...ckend/base/langflow/alembic/versions/5e6d61582763_merge_message_user_id_and_hitl_heads.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """merge message user id and hitl heads | ||
|
|
||
| Revision ID: 5e6d61582763 | ||
| Revises: 47aca8c17d23, 9cbe2f682e12 | ||
| Create Date: 2026-07-13 17:00:00.000000 | ||
|
|
||
| Phase: EXPAND | ||
|
|
||
| """ | ||
|
|
||
| from collections.abc import Sequence | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = "5e6d61582763" # pragma: allowlist secret | ||
| down_revision: str | None = ("47aca8c17d23", "9cbe2f682e12") # pragma: allowlist secret | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| pass | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| pass |
25 changes: 25 additions & 0 deletions
25
...d/base/langflow/alembic/versions/9cbe2f682e12_merge_hitl_checkpoints_and_release_heads.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """merge hitl checkpoints and release heads | ||
|
|
||
| Phase: EXPAND (no DDL - merge point only) | ||
|
|
||
| Revision ID: 9cbe2f682e12 | ||
| Revises: 9d5e24d777bf, a1f4c9d27b30 | ||
| Create Date: 2026-07-13 10:43:02.800991 | ||
|
|
||
| """ | ||
|
|
||
| from collections.abc import Sequence | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = "9cbe2f682e12" | ||
| down_revision: str | None = ("9d5e24d777bf", "a1f4c9d27b30") | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| pass | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| pass |
52 changes: 52 additions & 0 deletions
52
src/backend/base/langflow/alembic/versions/a1f4c9d27b30_add_job_checkpoints_table.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| """add job_checkpoints table for durable suspend/resume checkpoints. | ||
|
|
||
| Stores one opaque, already-serialized checkpoint blob per (job_id, kind): the | ||
| graph producer writes JSON, the agent saver (LE-1447) writes base64(msgpack). | ||
| UNIQUE(job_id, kind) keeps a single live checkpoint per kind. | ||
|
|
||
| Revision ID: a1f4c9d27b30 | ||
| Revises: c7412b389256 | ||
| Create Date: 2026-06-15 09:00:00.000000 | ||
|
|
||
| Phase: EXPAND | ||
| """ | ||
|
|
||
| from collections.abc import Sequence | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
| revision: str = "a1f4c9d27b30" # pragma: allowlist secret | ||
| down_revision: str | None = "c7412b389256" # pragma: allowlist secret | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| from langflow.utils import migration | ||
|
|
||
| conn = op.get_bind() | ||
| if not migration.table_exists("job_checkpoints", conn): | ||
| op.create_table( | ||
| "job_checkpoints", | ||
| sa.Column("id", sa.Uuid(), nullable=False), | ||
| sa.Column("job_id", sa.Uuid(), nullable=False), | ||
| sa.Column("kind", sa.String(), nullable=False), | ||
| sa.Column("blob", sa.Text(), nullable=False), | ||
| sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), | ||
| sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False), | ||
| sa.PrimaryKeyConstraint("id"), | ||
| sa.UniqueConstraint("job_id", "kind", name="uq_job_checkpoints_job_id_kind"), | ||
| ) | ||
| with op.batch_alter_table("job_checkpoints", schema=None) as batch_op: | ||
| # No index on ``id``: the PRIMARY KEY already provides a unique index, so a separate | ||
| # ix_job_checkpoints_id would be dead duplicate DDL. | ||
| batch_op.create_index(batch_op.f("ix_job_checkpoints_job_id"), ["job_id"], unique=False) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| from langflow.utils import migration | ||
|
|
||
| conn = op.get_bind() | ||
| if migration.table_exists("job_checkpoints", conn): | ||
| op.drop_table("job_checkpoints") |
50 changes: 50 additions & 0 deletions
50
...nd/base/langflow/alembic/versions/c7412b389256_hitl_suspended_status_and_pause_resume_.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| """hitl suspended status and pause resume signals. | ||
|
|
||
| Adds JobStatus.SUSPENDED to job_status_enum and SignalType.PAUSE/RESUME to | ||
| execution_signal_type_enum so a run can suspend for human input and resume. | ||
|
|
||
| Revision ID: c7412b389256 | ||
| Revises: 8ce44e4858c6 | ||
| Create Date: 2026-06-09 16:19:43.372632 | ||
|
|
||
| Phase: EXPAND | ||
| """ | ||
|
|
||
| from collections.abc import Sequence | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
| revision: str = "c7412b389256" # pragma: allowlist secret | ||
| down_revision: str | None = "8ce44e4858c6" # pragma: allowlist secret | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
| _OLD_SIGNAL_ENUM = sa.Enum("stop", name="execution_signal_type_enum") | ||
| _NEW_SIGNAL_ENUM = sa.Enum("stop", "pause", "resume", name="execution_signal_type_enum") | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| bind = op.get_bind() | ||
| if bind.dialect.name == "postgresql": | ||
| # ALTER TYPE ... ADD VALUE cannot run inside the migration env's transaction. | ||
| with op.get_context().autocommit_block(): | ||
| op.execute("ALTER TYPE job_status_enum ADD VALUE IF NOT EXISTS 'suspended'") | ||
| op.execute("ALTER TYPE execution_signal_type_enum ADD VALUE IF NOT EXISTS 'pause'") | ||
| op.execute("ALTER TYPE execution_signal_type_enum ADD VALUE IF NOT EXISTS 'resume'") | ||
| else: | ||
| # SQLite rebuilds the column so its reflected VARCHAR length matches the model's widened | ||
| # Enum(stop, pause, resume); without it the model/migration consistency check (autogenerate) | ||
| # reports a phantom VARCHAR(4) -> Enum diff. job_status_enum needs no rebuild here. | ||
| with op.batch_alter_table("execution_signals", recreate="always") as batch_op: | ||
| batch_op.alter_column( | ||
| "signal_type", | ||
| existing_type=_OLD_SIGNAL_ENUM, | ||
| type_=_NEW_SIGNAL_ENUM, | ||
| existing_nullable=False, | ||
| ) | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| # EXPAND: enum ADD VALUE is irreversible without rebuilding the type, so a no-op. | ||
| pass | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LE-1438 says the SQLite upgrade body is a no-op since the enums are stored as VARCHAR, but this branch does a full table rebuild with recreate='always'. The base migration created signal_type via plain sa.Enum and create_constraint defaults to False in SQLAlchemy 2.x, so there's no CHECK constraint to widen and the rebuild is dead DDL. It's also inconsistent: if execution_signals needed a rebuild, job.status would too, and that's left untouched. Could you make the SQLite branch a pass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed — made the SQLite branch a
pass. Confirmed the base migration createdsignal_typewith a plainsa.Enum(no CHECK constraint), so there was nothing to widen and the rebuild was dead DDL.