Workflow Integration Enhancements#825
Merged
Merged
Conversation
## Summary This PR adds several improvements to the Cloudflare Workflows integration for Agents: - **Fix tracking table updates** - Workflow callbacks now properly update the `cf_agents_workflows` tracking table in real-time (fixes #821) - **Workflow control methods** - Add `terminateWorkflow()`, `pauseWorkflow()`, `resumeWorkflow()`, and `restartWorkflow()` for managing workflow lifecycle - **Cursor-based pagination** - `getWorkflows()` now returns paginated results with `total` count and `nextCursor` for efficient querying of large workflow lists - **Enhanced workflows demo** - Multi-workflow support with real-time updates, pagination UI, and workflow control buttons ## Changes ### Core SDK (`packages/agents`) - `onWorkflowCallback()` now updates the tracking table when receiving progress/complete/error callbacks - Added `terminateWorkflow(workflowId)` - Terminate a running workflow - Added `pauseWorkflow(workflowId)` - Pause a running workflow - Added `resumeWorkflow(workflowId)` - Resume a paused workflow - Added `restartWorkflow(workflowId, options?)` - Restart a workflow from the beginning - Updated `getWorkflows()` to return `WorkflowPage` with cursor-based pagination: ```typescript type WorkflowPage = { workflows: WorkflowInfo[]; total: number; nextCursor: string | null; }; ``` - Added observability events: `workflow:terminated`, `workflow:paused`, `workflow:resumed`, `workflow:restarted` ### Workflows Demo (`examples/workflows`) - Support for triggering and managing multiple concurrent workflows - Real-time progress updates via WebSocket broadcasts - Pagination with "Load More" functionality (page size of 5) - Workflow control buttons: Pause, Resume, Restart, Terminate - Approve/Reject for human-in-the-loop workflows - Dark mode UI with Cloudflare orange accents - Persisted UI state for `waitingForApproval` status via `metadata.uiState` ### Documentation (`docs/workflows.md`) - Added API reference for new workflow control methods - Added pagination examples for `getWorkflows()` - Documented local dev limitations with link to #823 ### Tests - Added tests for tracking table updates from callbacks - Added tests for pagination (cursor, total, nextCursor) - Added tests for orderBy (asc/desc) - Added tests for workflow control method error cases ## Notes to Reviewers 1. **Local dev limitation**: The workflow control methods (`terminate`, `pause`, `resume`, `restart`) don't work in local dev with `wrangler dev` due to Miniflare limitations. They work when deployed to Cloudflare. Error messages point users to #823 for tracking. 2. **Waiting status workaround**: When a workflow calls `waitForEvent()`, Cloudflare's API still reports status as "running". We work around this by persisting `waitingForApproval` in `metadata.uiState`. I've reached out to the Workflows team about exposing a native "waiting" status - this would let us remove the workaround. Tracking here #824 3. **Pagination cursor encoding**: Cursors encode `createdAt` timestamp in seconds (matching SQLite storage) to avoid off-by-one errors when paginating. 4. **Breaking change (pre-release)**: `getWorkflows()` now returns `WorkflowPage` instead of `WorkflowInfo[]`. Since workflows haven't shipped yet, this is fine. 5. **Demo architecture**: The demo uses client-side pagination state with server-side broadcasts for real-time updates. Each client manages its own loaded pages while receiving live updates for any workflow changes.
🦋 Changeset detectedLatest commit: 0ab5f6f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
This comment was marked as resolved.
This comment was marked as resolved.
Clear persisted UI state on workflow restart, add robust pagination cursor parsing with descriptive errors, and protect workflow status updates from race-condition overwrites.
Details:
- examples/workflows/src/server.ts: Call clearUIState(workflowId) before restarting a workflow to ensure UI state is reset.
- packages/agents/src/index.ts: Wrap atob/JSON parsing in try/catch and validate cursor structure, throwing a clear "Invalid pagination cursor" error for malformed input. Add WHERE ... AND status NOT IN ('terminated', 'paused') to UPDATE queries for "complete" and "error" callbacks to avoid overwriting terminal states.
- packages/agents/src/tests/worker.ts: Add restartWorkflowWithOptions helper to forward restart options (used in tests).
- packages/agents/src/tests/workflow.test.ts: Add tests to (a) check acceptance of resetTracking option / note on preserving timestamps, and (b) assert descriptive errors are thrown for malformed or structurally invalid pagination cursors.
These changes improve robustness against corrupted pagination cursors and race conditions, and ensure UI state is cleared when restarting workflows.
Remove the separate pre-count and early-return when deleting workflows, and return the actual number of rows deleted from the SQL cursor (cursor.rowsWritten). This avoids an extra COUNT query and provides an accurate deletion result.
agents-git-bot Bot
pushed a commit
to cloudflare/cloudflare-docs
that referenced
this pull request
Feb 1, 2026
This update comprehensively documents the new Workflow Integration features added in cloudflare/agents#825: - New AgentWorkflow base class for tight Agent-Workflow integration - Workflow tracking in Agent SQLite database with cf_agents_workflows table - Lifecycle callbacks: onWorkflowProgress, onWorkflowComplete, onWorkflowError, onWorkflowEvent - New workflow control methods: terminateWorkflow, pauseWorkflow, resumeWorkflow, restartWorkflow - Cursor-based pagination for getWorkflows() with WorkflowPage return type - Bidirectional communication patterns (Workflow ↔ Agent) - State synchronization via step.updateAgentState and step.mergeAgentState - Human-in-the-loop approval flow with waitForApproval helper - Comprehensive patterns and examples for common use cases Breaking change: getWorkflows() now returns WorkflowPage instead of array (pre-release). Note: Workflow control methods not yet supported in local dev - work when deployed. Related: cloudflare/agents#825, cloudflare/agents#823
Contributor
Author
|
I addressed all valid claude code feedback |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
This PR adds several improvements to the Cloudflare Workflows integration for Agents:
cf_agents_workflowstracking table in real-time (fixes Workflow Tracking Table Not Updated by AgentWorkflow Callbacks #821)terminateWorkflow(),pauseWorkflow(),resumeWorkflow(), andrestartWorkflow()for managing workflow lifecyclegetWorkflows()now returns paginated results withtotalcount andnextCursorfor efficient querying of large workflow listsChanges
Core SDK (
packages/agents)onWorkflowCallback()now updates the tracking table when receiving progress/complete/error callbacksterminateWorkflow(workflowId)- Terminate a running workflowpauseWorkflow(workflowId)- Pause a running workflowresumeWorkflow(workflowId)- Resume a paused workflowrestartWorkflow(workflowId, options?)- Restart a workflow from the beginninggetWorkflows()to returnWorkflowPagewith cursor-based pagination:typescript type WorkflowPage = { workflows: WorkflowInfo[]; total: number; nextCursor: string | null; };workflow:terminated,workflow:paused,workflow:resumed,workflow:restartedWorkflows Demo (
examples/workflows)waitingForApprovalstatus viametadata.uiStateDocumentation (
docs/workflows.md)getWorkflows()terminate(),pause(),resume(), andrestart()workflow methods not supported in local development #823Tests
Notes to Reviewers
Local dev limitation: The workflow control methods (
terminate,pause,resume,restart) don't work in local dev withwrangler devdue to Miniflare limitations. They work when deployed to Cloudflare. Error messages point users to workflows:terminate(),pause(),resume(), andrestart()workflow methods not supported in local development #823 for tracking.Waiting status workaround: When a workflow calls
waitForEvent(), Cloudflare's API still reports status as "running". We work around this by persistingwaitingForApprovalinmetadata.uiState. I've reached out to the Workflows team about exposing a native "waiting" status - this would let us remove the workaround. Tracking here Track upstream: Workflows API "waiting for event" status #824Pagination cursor encoding: Cursors encode
createdAttimestamp in seconds (matching SQLite storage) to avoid off-by-one errors when paginating.Breaking change (pre-release):
getWorkflows()now returnsWorkflowPageinstead ofWorkflowInfo[]. Since workflows haven't shipped yet, this is fine.Demo architecture: The demo uses client-side pagination state with server-side broadcasts for real-time updates. Each client manages its own loaded pages while receiving live updates for any workflow changes.