Skip to content

Python: preserve AG-UI input on failed runs and prevent duplicate snapshot messages - #9798

Open
Ran Shemtov (ranst91) wants to merge 4 commits into
microsoft:mainfrom
CopilotKit:fix/ag-ui-snapshot-reconciliation
Open

Ran Shemtov (ranst91) wants to merge 4 commits into
microsoft:mainfrom
CopilotKit:fix/ag-ui-snapshot-reconciliation

Conversation

@ranst91

Copy link
Copy Markdown
Contributor

Motivation & Context

This change addresses three persistence gaps in the Python AG-UI adapter:

  • When incoming history omits or changes an earlier message, reconciliation can append later user messages whose IDs already exist in the saved snapshot.
  • A provider failure before the first snapshot checkpoint can leave submitted user input unsaved.
  • Converting multimodal input into snapshot binary parts drops attachment filenames.

Our original duplication case was triggered by a CopilotKit wrapper that removed historical tool messages. We fixed that wrapper separately. The reconciliation change here provides additional protection when incoming history differs from saved history.

Description & Review Guide

  • Exclude already-stored message IDs from the incoming history suffix, preserving authoritative saved content and order.
  • Checkpoint input before provider execution for configured stateless snapshot sessions. Preserve the existing behavior for provider-managed sessions.
  • Retain filenames during binary-part normalization.

Existing duplicated snapshots are not rewritten. Unfinished assistant output is not committed by the input checkpoint.

Please review the checkpoint boundary, approval continuation behavior, and preservation of message identity and attachment metadata.

Validation

At commit bf82841e7:

  • AG-UI test suite: 1,787 passed, with existing dependency/deprecation warnings.
  • Changed source passed Pyright, Ruff, and formatting checks.
  • Real-provider checks verified input preservation after rejection and tool-result persistence through cold snapshot hydration.

These checks used a custom JSON snapshot store. They do not establish coverage for every storage implementation or browser/Intelligence workflow.

Related Issue

This contribution was initiated by the AG-UI team. An agreed Microsoft issue has not yet been linked.

AI Assistance

Implementation, tests, investigation, and this description were AI-assisted. Human contributor review and responsibility acknowledgement remain pending.

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.

🟡 Changes recommended

Checkpoint persistence can lose recoverable input after session-ID rebinding and prematurely clear unresolved interrupt prompts, leaving hydration incomplete after a failure or disconnect.

2 open issues
What changed in this PR

This PR strengthens persistence in the Python AG-UI adapter so failed runs retain submitted input and differing client history does not duplicate saved messages.

Changes:

  • Filter already-stored message IDs from reconciled incoming history.
  • Checkpoint input before provider execution for configured stateless snapshot sessions.
  • Preserve attachment filenames during multimodal snapshot normalization and add regression coverage.
File Description
python/​packages/​ag-ui/​tests/​ag_ui/​test_run.py Expect submitted input to survive response invalidation.
python/​packages/​ag-ui/​tests/​ag_ui/​test_run_common.py Test deduplication when client history differs from saved history.
python/​packages/​ag-ui/​tests/​ag_ui/​test_message_adapters.py Test filename preservation across normalization.
python/​packages/​ag-ui/​tests/​ag_ui/​test_endpoint.py Cover failed-run persistence, cancellation, media, and approval-history replay.
python/​packages/​ag-ui/​agent_framework_ag_ui/​_run_common.py Exclude stored IDs from incoming history suffixes.
python/​packages/​ag-ui/​agent_framework_ag_ui/​_message_adapters.py Retain filenames in normalized binary parts.
python/​packages/​ag-ui/​agent_framework_ag_ui/​_agent_run.py Add an input checkpoint before provider execution.

Review effort: Balanced

await save_thread_snapshot(
persisted_messages=persisted_input,
state=latest_state_snapshot,
interrupt=snapshot_interrupts(),
Comment on lines +3721 to +3725
await save_thread_snapshot(
persisted_messages=persisted_input,
state=latest_state_snapshot,
interrupt=snapshot_interrupts(),
)

This branch was successfully deployed

1 active deployment
github-app-auth — 55e22a88 Deployed Oct 28, 2026 by ranst91 via add_label #26417
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.

2 participants