Skip to content

feat: workflowState + andForEach selector/map#985

Merged
omeraplak merged 6 commits into
mainfrom
feat/workflowstate-and-foreach-map
Jan 23, 2026
Merged

feat: workflowState + andForEach selector/map#985
omeraplak merged 6 commits into
mainfrom
feat/workflowstate-and-foreach-map

Conversation

@omeraplak

@omeraplak omeraplak commented Jan 23, 2026

Copy link
Copy Markdown
Member

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

What is the new behavior?

fixes (issue)

Notes for reviewers


Summary by cubic

Implement workflowState with setWorkflowState (shared state across steps, persisted across suspend/resume, passable via run options and REST) and enhance andForEach with an items selector and optional map. Update types, tests, and docs to support these features.

Written for commit 128b2d8. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Shared workflow state available in step contexts with a setter, persisted across suspend/resume
    • Enhanced foreach: optional items selector and per-item map to reshape items while preserving parent data
  • Documentation

    • New Workflow State guide; updated Execute API and foreach docs and examples; added changelog entry
  • Tests

    • Tests for workflowState persistence and foreach selector/map behaviors (including error cases)

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot

changeset-bot Bot commented Jan 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 128b2d8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

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

@ghost

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Jan 23, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a shared, persistent workflowState (readable + setWorkflowState updater) threaded through execution, suspend/resume checkpoints, storage, snapshots, and step contexts; and generalizes andForEach to accept an items selector and optional map to reshape per-item input before inner-step execution.

Changes

Cohort / File(s) Summary
Core public types & re-exports
packages/core/src/workflow/types.ts, packages/core/src/workflow/index.ts, packages/core/src/index.ts
Add WorkflowStateStore and WorkflowStateUpdater types; re-export them; surface optional workflowState on run/resume/create option shapes and APIs.
Runtime state & persistence
packages/core/src/workflow/internal/state.ts, packages/core/src/memory/types.ts, packages/core/src/workflow/core.ts, packages/core/src/workflow/internal/types.ts, packages/core/src/workflow/internal/utils.ts
Thread an observable workflowState through the state manager, initialize from run options, persist/restore it in checkpoints/snapshots, and provide setWorkflowState plumbing to update and propagate state.
Execution context & chain signatures
packages/core/src/workflow/context.ts, packages/core/src/workflow/chain.ts
Expose workflowState and setWorkflowState on execution/step contexts and update chain overloads (andThen/andWhen/andTap/andAgent/andForEach, etc.) so execute/context hooks receive state and updater.
andForEach feature & types
packages/core/src/workflow/steps/types.ts, packages/core/src/workflow/steps/and-foreach.ts, packages/core/src/workflow/steps/index.ts, packages/core/src/workflow/steps/and-foreach.spec.ts
Generalize foreach to support optional items selector and map function, add MAP_DATA generic, map each item to per-item input before invoking inner step, update types/exports, and add tests for selector/map behavior and error handling.
Mocks & tests
packages/core/src/test-utils/mocks/workflows.ts, packages/core/src/workflow/core.spec.ts
Add workflowState and setWorkflowState to mock execution context; add a test verifying workflowState persistence across steps and example usage of setWorkflowState.
Server API & docs
packages/server-core/src/schemas/agent.schemas.ts, website/docs/*, website/sidebars.ts, website/static/llms.txt
Add optional workflowState to server execution request schema; new docs page and doc updates for Workflow State and ExecuteContext (workflowState + setWorkflowState); update andForEach docs/examples; add sidebar and docs link.
Changelog
.changeset/bright-poems-read.md
Add change note documenting workflowState and andForEach selector/map usage with examples.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ServerAPI
  participant WorkflowCore
  participant MemoryStore
  participant Step

  Client->>ServerAPI: Execute request (options, workflowState?)
  ServerAPI->>WorkflowCore: start execution (options, workflowState)
  WorkflowCore->>WorkflowCore: initialize executionContext.workflowState
  WorkflowCore->>Step: execute step (context with workflowState, setWorkflowState)
  Step->>WorkflowCore: setWorkflowState(updater)
  WorkflowCore->>WorkflowCore: apply updater -> new workflowState
  WorkflowCore->>MemoryStore: persist checkpoint (data, state, workflowState)
  Note over MemoryStore,WorkflowCore: on suspend/resume, workflowState restored from checkpoint
  WorkflowCore->>Client: return result (including final workflowState snapshot)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 ✨ I nibble code and hop with glee,

workflowState now flows for me,
setWorkflowState plants seeds that grow,
AndForEach maps each petal so,
Steps hop along in tidy rows.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: workflowState + andForEach selector/map' directly and clearly summarizes the main changes: two new features (workflowState and enhanced andForEach) in a concise, readable format.
Description check ✅ Passed PR description includes all required sections: checklist with commit message compliance, bug/feature items (tests, docs, changesets), current/new behavior, and reviewer notes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 1 file

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.changeset/bright-poems-read.md:
- Around line 5-11: The changeset text is in Turkish but the repository appears
to prefer a consistent language; update the .changeset/bright-poems-read.md
content to match the project's language standard: either translate the Turkish
lines to English (preserving the symbols workflowState, setWorkflowState,
andForEach, items, map) if the project uses English, or confirm and note in the
changeset that Turkish is acceptable; ensure the README-style heading and bullet
points are translated/adjusted accordingly so the mention of workflowState,
setWorkflowState, andForEach items/map remains accurate.

Comment thread .changeset/bright-poems-read.md
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jan 23, 2026

Copy link
Copy Markdown

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: 128b2d8
Status: ✅  Deploy successful!
Preview URL: https://be287781.voltagent.pages.dev
Branch Preview URL: https://feat-workflowstate-and-forea.voltagent.pages.dev

View logs

@omeraplak omeraplak changed the title chore: add changeset feat: workflowState + andForEach selector/map Jan 23, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/workflow/core.ts`:
- Around line 1646-1652: setWorkflowState currently updates stateManager,
executionContext.workflowState, and stepContext.workflowState but leaves
stepContext.state.workflowState (and therefore context.state.workflowState)
stale; update the implementation of setWorkflowState (the setter assigned on
stepContext) to also assign the computed nextState to
stepContext.state.workflowState (and to executionContext.state.workflowState if
present) immediately after computing nextState so reads of
context.state.workflowState within the same step return the new value.
🧹 Nitpick comments (3)
website/docs/api/endpoints/workflows.md (1)

231-238: Clarify workflowState persistence/serialization in docs.

Consider a short note that workflowState is persisted across suspend/resume and should contain JSON-serializable data (and avoid secrets/large payloads). This prevents confusion about what’s safe to store.

✏️ Suggested doc tweak
 | `context` | object | Additional context data |
-| `workflowState` | object | Shared state available to workflow steps |
+| `workflowState` | object | Shared state available to workflow steps (persisted across suspend/resume; JSON-serializable) |

Also applies to: 243-250

packages/core/src/memory/types.ts (1)

131-135: Consider a JSON-serializable type for workflowState.

Since checkpoint data is typically persisted, using a JSON-safe type improves guarantees and prevents accidental storage of non-serializable values.

♻️ Proposed typing refinement
+type JsonValue =
+  | string
+  | number
+  | boolean
+  | null
+  | JsonValue[]
+  | { [key: string]: JsonValue };
+
     checkpoint?: {
       stepExecutionState?: any;
       completedStepsData?: any[];
-      workflowState?: Record<string, unknown>;
+      workflowState?: Record<string, JsonValue>;
     };
packages/core/src/workflow/internal/state.ts (1)

131-143: Consider cloning initial workflowState to avoid external mutation.

workflowState is stored by reference from run options; a shallow clone prevents accidental mutations from outside the workflow lifecycle.

♻️ Proposed tweak
-      workflowState: config?.workflowState ?? {},
+      workflowState: { ...(config?.workflowState ?? {}) },

Comment thread packages/core/src/workflow/core.ts

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/core/src/workflow/core.ts`:
- Around line 813-814: The Workflow state from options (workflowStateStore /
options?.workflowState) is captured but never persisted into Memory V2 for runs
that never suspend; update the record creation path and the terminal-update
paths (completed, cancelled, error) to include and store the current
workflowState on create and on terminal updates so /state reflects the latest
shared state — locate where Memory V2 execution records are created/updated and
add the workflowState payload from workflowStateStore to those create and update
calls.

Comment thread packages/core/src/workflow/core.ts

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/workflow/core.ts (1)

1332-1355: Persist workflowState on suspension updates, not only in checkpoints.
Suspended executions update Memory V2 without the latest top‑level workflowState, so /state can reflect stale data until completion. Consider persisting the current workflowState alongside the suspension update.

🛠️ Suggested fix (persist top-level workflowState on suspend)
-  const saveSuspensionState = async (
+  const saveSuspensionState = async (
     suspensionData: any,
     executionId: string,
     memory: MemoryV2,
     logger: Logger,
     events: Array<{
       id: string;
       type: string;
       name?: string;
       from?: string;
       startTime: string;
       endTime?: string;
       status?: string;
       input?: any;
       output?: any;
       metadata?: Record<string, unknown>;
       context?: Record<string, unknown>;
     }>,
+    workflowState?: WorkflowStateStore,
   ): Promise<void> => {
     try {
       logger.trace(`Storing suspension checkpoint for execution ${executionId}`);
       await memory.updateWorkflowState(executionId, {
         status: "suspended",
+        workflowState,
         suspension: suspensionData
           ? {
               suspendedAt: suspensionData.suspendedAt,
               reason: suspensionData.reason,
               stepIndex: suspensionData.suspendedStepIndex,
               lastEventSequence: suspensionData.lastEventSequence,
               checkpoint: suspensionData.checkpoint,
               suspendData: suspensionData.suspendData,
             }
           : undefined,
         events,
         updatedAt: new Date(),
       });
       logger.trace(`Successfully stored suspension checkpoint for execution ${executionId}`);
     } catch (error) {
       logger.error(`Failed to save suspension state for execution ${executionId}:`, { error });
     }
   };
-              await saveSuspensionState(
+              await saveSuspensionState(
                 suspensionData,
                 executionId,
                 executionMemory,
                 runLogger,
                 collectedEvents,
+                stateManager.state.workflowState,
               );
-              await saveSuspensionState(
+              await saveSuspensionState(
                 suspensionMetadata,
                 executionId,
                 executionMemory,
                 runLogger,
                 collectedEvents,
+                stateManager.state.workflowState,
               );

Also applies to: 1495-1502

@omeraplak
omeraplak merged commit 85f8611 into main Jan 23, 2026
23 checks passed
@omeraplak
omeraplak deleted the feat/workflowstate-and-foreach-map branch January 23, 2026 22:07
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.

1 participant