Skip to content

Python: add checkpointing support to AgentFrameworkWorkflow.run() in agent-framework-ag-ui#6646

Open
vaibhav-patel wants to merge 7 commits into
microsoft:mainfrom
vaibhav-patel:fix/6632-agui-workflow-checkpointing
Open

Python: add checkpointing support to AgentFrameworkWorkflow.run() in agent-framework-ag-ui#6646
vaibhav-patel wants to merge 7 commits into
microsoft:mainfrom
vaibhav-patel:fix/6632-agui-workflow-checkpointing

Conversation

@vaibhav-patel

Copy link
Copy Markdown
Contributor

Summary

Fixes #6632. Adds workflow checkpointing to the ag-ui adapter's
AgentFrameworkWorkflow.run(), bringing it to parity with the core
agent_framework.Workflow.run() checkpointing API.

run() now accepts two optional keyword arguments:

  • checkpoint_storage: CheckpointStorage | None — enables checkpoint creation at each
    superstep (forwarded to the core workflow).
  • checkpoint_id: str | None — resumes a run from a persisted checkpoint.

This delegates to the existing core capability rather than reinventing it, so the public
surface mirrors Workflow.run(checkpoint_storage=..., checkpoint_id=...).

Details

  • Resume honors the core API contract: message is never passed alongside
    checkpoint_id; incoming messages are forwarded only as request-info responses
    (so responses + checkpoint_id is a restore-then-send).
  • Params may also be supplied via the input_data keys __ag_ui_checkpoint_storage /
    __ag_ui_checkpoint_id, letting the FastAPI endpoint (which calls run(input_data)
    positionally) opt in without a signature change; explicit keyword args take precedence.
  • Workflow checkpointing is independent from AG-UI thread-snapshot persistence; resume
    bypasses snapshot-hydration early-returns to reach the core restore path.

Backward compatibility

The existing run(RunAgentInput) / run(input_data) signature is preserved — the new
params are optional and default to None, and the non-checkpoint path still calls
run_workflow_stream(input_data, workflow) with its original two-argument convention.

Tests

New focused tests cover checkpoint creation, resume-from-checkpoint, input-data-keyed
params, and the unchanged default path. Full ag-ui suite green (824 passed); ruff
lint/format clean; no new pyright errors.

…ag-ui

The ag-ui AgentFrameworkWorkflow.run() previously accepted only a
RunAgentInput payload and exposed no way to use the core workflow's
checkpointing/state-persistence, unlike the core agent-framework workflow
implementations. This left ag-ui workflows without resumable execution.

Add optional checkpoint_storage and checkpoint_id keyword arguments to
run(), threaded through run_workflow_stream() into the core Workflow.run().
This delegates to the existing core capability instead of reinventing it and
keeps the public surface consistent with Workflow.run():

- checkpoint_storage enables checkpoint creation at each superstep boundary.
- checkpoint_id resumes a run from a persisted checkpoint; incoming messages
  are forwarded only as request-info responses (never as a new start-executor
  message) to honor the core's message/checkpoint_id mutual exclusivity, and
  responses + checkpoint_id performs a restore-then-send in one call.

Both can also be supplied via the input_data keys __ag_ui_checkpoint_storage
and __ag_ui_checkpoint_id so the FastAPI endpoint (which calls run(input_data)
positionally) can opt in without changing its call site; explicit keyword
arguments take precedence. Checkpoint resume bypasses the AG-UI thread snapshot
hydration early-returns so it always reaches the core restore path.

Backward compatible: run(input_data) keeps working unchanged, and the
non-checkpoint path still calls run_workflow_stream(input_data, workflow) with
its original two-argument convention. Adds focused tests covering checkpoint
creation, resume-from-checkpoint, input-data-keyed params, and the unchanged
default path.

Fixes microsoft#6632.
Copilot AI review requested due to automatic review settings June 20, 2026 11:30
@moonbox3 moonbox3 added the python Usage: [Issues, PRs], Target: Python label Jun 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds workflow checkpointing support to the agent-framework-ag-ui adapter so AgentFrameworkWorkflow.run() can create checkpoints and resume from a persisted checkpoint_id, mirroring the core agent_framework.Workflow.run() API.

Changes:

  • Extended AgentFrameworkWorkflow.run() to accept checkpoint_storage / checkpoint_id (and optionally read them from input_data), ensuring checkpoint resumes bypass snapshot-only hydration paths.
  • Updated run_workflow_stream() to forward checkpointing parameters to the core workflow and to avoid pre-run early-returns that would otherwise skip restores.
  • Added focused tests covering checkpoint creation, resume, input-data-keyed params, and the unchanged default path.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
python/packages/ag-ui/agent_framework_ag_ui/_workflow.py Adds checkpoint kwargs to AgentFrameworkWorkflow.run() and plumbs them through to the stream runner, while preserving existing snapshot behavior.
python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py Extends run_workflow_stream() with checkpoint parameters and ensures checkpoint resumes reach workflow.run(checkpoint_id=...).
python/packages/ag-ui/tests/ag_ui/test_workflow_agent.py Adds checkpointing tests for the AG-UI workflow wrapper.

Comment thread python/packages/ag-ui/tests/ag_ui/test_workflow_agent.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/ag-ui/agent_framework_ag_ui
   _workflow.py2151692%71, 134, 139, 178, 217–218, 300, 387, 389, 391–393, 395, 420–422
   _workflow_run.py6837589%86, 100, 102, 104, 107, 173, 260–263, 312, 323, 328, 353, 389–392, 420, 425, 453, 463, 474, 479, 482, 495, 505, 508, 513, 516, 531–533, 538, 540–541, 545, 547, 564, 570–571, 581–582, 586–587, 611–612, 645, 653, 694, 714, 730, 745, 876–890, 922–923, 960–961, 1032, 1072, 1091
TOTAL44183526688% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
8863 33 💤 0 ❌ 0 🔥 2m 25s ⏱️

@moonbox3

moonbox3 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@vaibhav-patel please also look at the failing code quality CI/CD checks thanks

…responses; fix CI lint/typing

A checkpoint-only resume no longer clobbers the stored AG-UI thread snapshot:
the snapshot builder is seeded with the prior stored history so the saved
snapshot keeps the earlier replayable transcript plus the newly produced output.

Resume responses are now coerced against the post-restore pending requests on a
checkpoint restore, so a JSON function_approval_response resumes through AG-UI
after a cold restore instead of failing with a response-type mismatch.

Also update the test-double workflow run() overrides to match the new keyword-only
parent signature and re-sort the workflow test imports so ruff and the typing
checkers pass.
@vaibhav-patel

Copy link
Copy Markdown
Contributor Author

@moonbox3 CI is green now — fixed the I001 import-sort in test_workflow_agent.py, and the "Invalid override of method run" failures (mypy/pyrefly/ty/zuban) by updating the three test-double run() overrides in test_endpoint.py to accept **kwargs so they're LSP-compatible with the new keyword-only parent signature. ruff check, ruff format --check, all five typing checkers, and the full ag-ui suite (892 passed) pass locally.

Thanks for the thorough review — the two resume bugs you reproduced are fixed too (details on the inline threads).

@moonbox3 moonbox3 requested a review from eavanvalkenburg July 13, 2026 00:27
if restore_from_checkpoint is None:
return
try:
await restore_from_checkpoint(checkpoint_id, checkpoint_storage)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we avoid restoring the checkpoint twice to inspect its pending requests? This pre-restore invokes every executor's on_checkpoint_restore() hook, then workflow.run(checkpoint_id=..., responses=...) restores again and invokes the hooks a second time. Custom restore hooks are not required to be idempotent, so this can duplicate restoration work or fail workflows that correctly expect one restore per resume. Could the response coercion be handled through a core/public restore-and-send path without executing user restore hooks twice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Feature]: Add Checkpointing Support to AgentFrameworkWorkflow.run() in agent-framework-ag-ui

3 participants