Skip to content

add workflow generation history persistence - #13638

Draft
hannahblair wants to merge 16 commits into
mainfrom
workflow-history
Draft

add workflow generation history persistence#13638
hannahblair wants to merge 16 commits into
mainfrom
workflow-history

Conversation

@hannahblair

Copy link
Copy Markdown
Collaborator

Description

Please include a concise summary, in clear English, of the changes in this pull request. If it closes an issue, please mention it here.

Closes: #(issue)

AI Disclosure

We encourage the use of AI tooling in creating PRs, but the any non-trivial use of AI needs be disclosed. E.g. if you used Claude to write a first draft, you should mention that. Trivial tab-completion doesn't need to be disclosed. You should self-review all PRs, especially if they were generated with AI.

  • I used AI to... [fill here]
  • I did not use AI

🎯 PRs Should Target Issues

Before your create a PR, please check to see if there is an existing issue for this change. If not, please create an issue before you create this PR, unless the fix is very small.

Not adhering to this guideline will result in the PR being closed.

Testing and Formatting Your Code

  1. PRs will only be merged if tests pass on CI. We recommend at least running the backend tests locally, please set up your Gradio environment locally and run the backed tests: bash scripts/run_backend_tests.sh

  2. Please run these bash scripts to automatically format your code: bash scripts/format_backend.sh, and (if you made any changes to non-Python files) bash scripts/format_frontend.sh

@gradio-pr-bot

gradio-pr-bot commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

🪼 branch checks and previews

Name Status URL
Spaces ready! Spaces preview
Website ready! Website preview
Storybook ready! Storybook preview
🦄 Changes detected! Details

Install Gradio from this PR

pip install https://huggingface.co/buckets/gradio/pypi-previews/resolve/6314f556436acaeb8139a292f5c0041b1bd4ef96/gradio-6.20.0-py3-none-any.whl

Install Gradio Python Client from this PR

pip install "gradio-client @ git+https://github.com/gradio-app/gradio@6314f556436acaeb8139a292f5c0041b1bd4ef96#subdirectory=client/python"

Import Gradio JS Client from this PR via CDN

import { Client } from "https://huggingface.co/buckets/gradio/npm-previews/resolve/6314f556436acaeb8139a292f5c0041b1bd4ef96/browser.js";

@gradio-pr-bot

Copy link
Copy Markdown
Collaborator

🦄 change detected

This Pull Request includes changes to the following packages.

Package Version
@gradio/workflowcanvas minor
gradio minor

  • add workflow generation history persistence

Something isn't right?

  • Maintainers can change the version label to modify the version bump.
  • If the bot has failed to detect any changes, or if this pull request needs to update multiple packages to different versions or requires a more comprehensive changelog entry, maintainers can update the changelog file directly.

@hannahblair

hannahblair commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

just getting this ready for review, but i'm wondering whether we should allow dataset and bucket connection or just keep it to bucket connection. exclusively buckets will gate history persistence to pro subs (but be a better UX experience as discussed) @abidlabs cc @AK391

@abidlabs

Copy link
Copy Markdown
Member

just getting this ready for review, but i'm wondering whether we should allow dataset and bucket connection or just keep it to bucket connection. exclusively buckets will gate history persistence to pro subs (but be a better UX experience as discussed) @abidlabs cc @AK391

imo better to have a single path, so I would be in favor of just Buckets. @hannahblair maybe I'm misunderstanding what you are saying, but you don't need to have PRO account to create Buckets

@hannahblair

Copy link
Copy Markdown
Collaborator Author

just getting this ready for review, but i'm wondering whether we should allow dataset and bucket connection or just keep it to bucket connection. exclusively buckets will gate history persistence to pro subs (but be a better UX experience as discussed) @abidlabs cc @AK391

imo better to have a single path, so I would be in favor of just Buckets. @hannahblair maybe I'm misunderstanding what you are saying, but you don't need to have PRO account to create Buckets

oh i misremembered! exclusively buckets is the way go then

@hannahblair
hannahblair requested a review from Copilot July 24, 2026 13:00

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

Adds generation history persistence for gr.Workflow, storing per-run records (and media) in a Hugging Face Hub bucket and surfacing that history in the workflow canvas UI for browsing/reloading past runs.

Changes:

  • Backend: introduce WorkflowHistory, add history parameter to Workflow, and wire server/client paths to list/connect/push history records (plus server-side endpoint recording via workflow_api).
  • Frontend: add History panel + connect dialog, and push a history record after successful workflow execution.
  • Robustness: handle missing inputs/outputs in workflow migration, broaden pipeline tag detection, and add an HTTP 422 compatibility fallback.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/test_workflow_history.py Adds unit tests for history record building and bucket upload/list behaviors.
js/workflowcanvas/workflow/WorkflowHistoryPanel.svelte New UI panel to browse and reload saved generations from a bucket.
js/workflowcanvas/workflow/WorkflowHistoryConnect.svelte New UI dialog to connect/auto-create a history bucket.
js/workflowcanvas/workflow/WorkflowCanvas.svelte Integrates history UI + pushes history records on successful runs.
js/workflowcanvas/workflow/workflow-migration.ts Ensures legacy shape always has inputs/outputs arrays.
js/workflowcanvas/workflow/workflow-executor.ts Falls back to node.task when pipeline_tag is missing.
gradio/workflow.py Adds history plumbing + server endpoints (list/connect/push) and minor related backend updates.
gradio/workflow_history.py New implementation of bucket-backed history persistence (records + media).
gradio/workflow_api.py Records server-side endpoint executions into history when enabled.
gradio/routes.py Uses a safer 422 status constant fallback for compatibility.
.changeset/late-poets-see.md Declares minor bumps for gradio and @gradio/workflowcanvas.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread js/workflowcanvas/workflow/WorkflowHistoryConnect.svelte Outdated
Comment thread js/workflowcanvas/workflow/WorkflowHistoryPanel.svelte
Comment on lines +1708 to +1723
const genInputs: Record<
string,
{ value: any; type: string; label: string }
> = {};
for (const ref of wfToRun.references) {
const node = legacyView.nodes.find((n) => n.id === ref.id);
if (!node) continue;
const outPort = node.outputs[0];
if (!outPort) continue;
const captured = capturedOutputs[ref.id];
const value = captured
? ((captured.find((o) => o.portId === outPort.id) ?? captured[0])
?.value ?? null)
: (node.data?.[outPort.id] ?? null);
genInputs[ref.id] = { value, type: outPort.type, label: node.label };
}
Comment thread gradio/workflow.py
Comment on lines +1759 to +1772
def list_history(
data=None,
_request: Optional[Request] = None,
_token: Optional[OAuthToken] = None,
) -> str:
"""Return recent generation records for the History panel."""
if self._wh is None:
return json.dumps({"records": [], "repo_id": None})
subgraph = data[0] if data else None
limit = (
int(data[1]) if data and len(data) > 1 and data[1] is not None else 50
)
records = self._wh.list(limit=limit, subgraph=subgraph or None)
return json.dumps({"records": records, "repo_id": self._wh.repo_id})
Comment thread gradio/workflow.py
Comment on lines +1832 to +1851
def push_history(
data=None,
_request: Optional[Request] = None,
_token: Optional[OAuthToken] = None,
) -> str:
"""Accept a pre-built record from a client-side run and push it to Hub.

data[0]: JSON string of the history record dict.
"""
if self._wh is None:
return json.dumps({"ok": False, "reason": "no_history"})
try:
record = json.loads(data[0]) if data else {}
if not record.get("id"):
return json.dumps({"ok": False, "reason": "invalid_record"})
self._wh.push(record)
return json.dumps({"ok": True})
except Exception as e:
logger.debug("push_history failed: %s", e, exc_info=True)
return json.dumps({"ok": False, "reason": str(e)})
bucket_id=self.repo_id,
add=[(fh.read(), path_in_repo)],
)
return f"https://huggingface.co/buckets/{self.repo_id}/{path_in_repo}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants