Skip to content

fix(workflow): persist user context and harden resume state handling#1048

Merged
omeraplak merged 3 commits intoVoltAgent:mainfrom
chrisisagile:fix/workflowUserIdTracking
Feb 11, 2026
Merged

fix(workflow): persist user context and harden resume state handling#1048
omeraplak merged 3 commits intoVoltAgent:mainfrom
chrisisagile:fix/workflowUserIdTracking

Conversation

@chrisisagile
Copy link
Contributor

@chrisisagile chrisisagile commented Feb 11, 2026

Summary

  • persist userId and conversationId in workflow state at execution creation time
  • fix resume to read top-level workflowState.userId / workflowState.conversationId with metadata fallback
  • make resume input selection robust by falling back to workflow-start event input when top-level workflowState.input is missing
  • add regression tests for workflow state persistence and resume edge cases

Tests

  • pnpm -F @voltagent/core test -- src/workflow/core.spec.ts
  • pnpm -F @voltagent/core test -- src/workflow/suspend-resume.spec.ts

Closes #1047


Summary by cubic

Persisted userId and conversationId in workflow state and hardened resume handling with reliable input fallback. Fixes unreliable resumes and ensures correct user tracking, addressing Linear #1047.

  • New Features

    • Save userId and conversationId to workflowState at execution creation.
  • Bug Fixes

    • Resume reads top-level userId/conversationId with metadata fallback.
    • Prefer persisted input; fall back to workflow-start event payload; error when neither exists.
    • Strengthened tests with a type guard for resume error assertions; added patch changeset for @voltagent/core.

Written for commit d2ff385. Summary will update on new commits.

Summary by CodeRabbit

  • Tests

    • Added tests covering persistence of user and conversation identifiers and resume scenarios for recovering missing input.
  • Improvements

    • Resume flow now more robust: prefers explicit user/context values, falls back to stored metadata, and can recover input from the original start data when needed.

@changeset-bot
Copy link

changeset-bot bot commented Feb 11, 2026

🦋 Changeset detected

Latest commit: d2ff385

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

Persist userId and conversationId into initial workflow state and enhance resume logic to prefer persisted state input, falling back to the workflow-start event input; resume also derives user/context from top-level state with metadata fallbacks.

Changes

Cohort / File(s) Summary
Workflow creation & tests
packages/core/src/workflow/core.ts, packages/core/src/workflow/core.spec.ts
Include userId and conversationId from execution options when creating initial workflow state in Memory V2; add test to assert these fields are persisted.
Resume logic & tests
packages/core/src/workflow/registry.ts, packages/core/src/workflow/suspend-resume.spec.ts
Resume now derives userId/conversationId from workflowState with fallback to metadata.*; input resolution prefers workflowState.input but falls back to the workflow-start event's input when missing. Added tests covering these paths and failure when input is absent.
Release notes
.changeset/smart-carpets-taste.md
Add changeset documenting fixes for persisted user/conversation IDs and resume input fallback behavior.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Registry
  participant Storage
  participant Events

  Client->>Registry: executeWorkflow(options { userId, conversationId, input })
  Registry->>Storage: createWorkflowState({ ..., userId, conversationId, input })
  Storage-->>Registry: stateCreated

  Registry->>Storage: suspend / persist events
  Storage-->>Events: store events

  Client->>Registry: resumeWorkflow(executionId, resumeOptions?)
  Registry->>Storage: loadWorkflowState(executionId)
  Storage-->>Registry: workflowState (may lack input)
  Registry->>Events: find "workflow-start" event for executionId
  Events-->>Registry: workflow-start event (with input) OR none
  Registry->>Registry: determine resumeOptions.userId/conversationId (state -> metadata fallback -> resumeOptions)
  Registry->>Registry: choose input (workflowState.input || workflow-start.input || fail)
  Registry->>Storage: update/resume with resolved input and user/context
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • omeraplak

Poem

🐰
I hopped through state and planted IDs,
Held conversation threads and memory seeds,
When waked, I peek at the start event's clue,
So resumes remember who and what they do,
A little rabbit keeps the workflow true.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: persisting user context (userId/conversationId) and hardening resume state handling.
Description check ✅ Passed The description comprehensively covers all changes, includes test commands, references the closed issue, and aligns well with the template structure and requirements.
Linked Issues check ✅ Passed All requirements from issue #1047 are met: userId/conversationId persisted in workflow state [core.ts], resume logic updated with fallbacks [registry.ts], regression test added [core.spec.ts], and related resume tests [suspend-resume.spec.ts].
Out of Scope Changes check ✅ Passed All changes are directly scoped to the stated objectives: workflow state persistence, resume logic updates, and comprehensive regression testing with no extraneous modifications.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
packages/core/src/workflow/suspend-resume.spec.ts (1)

899-999: Consider splitting the two independent scenarios into separate it blocks.

This test contains two independent scenarios (precedence test A and metadata fallback test B). If scenario A fails, scenario B is silently skipped, masking potential issues. Separating them would improve test isolation and diagnostic clarity.


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.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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/suspend-resume.spec.ts`:
- Around line 1001-1055: The test accesses resumed?.error?.message but
WorkflowExecutionResult.error is typed unknown; add an explicit type guard
before reading message: assert that resumed?.status === "error" and that
resumed?.error is an instance of Error (e.g.,
expect(resumed?.error).toBeInstanceOf(Error) or use if (resumed?.error
instanceof Error)) and only then check resumed.error.message equals "Missing
resume input" so the assertion is type-safe (update the assertions around the
resumed variable returned by registry.resumeSuspendedWorkflow and any direct
access to .error.message).
🧹 Nitpick comments (1)
packages/core/src/workflow/suspend-resume.spec.ts (1)

899-999: Consider splitting the two precedence scenarios into separate it blocks.

This single test contains two independent sub-scenarios (workflowA for top-level precedence, workflowB for metadata fallback). If one fails, the other won't run, and the test name won't clearly indicate which scenario broke. Splitting would improve debuggability.

Copy link
Member

@omeraplak omeraplak left a comment

Choose a reason for hiding this comment

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

thank you so much

@omeraplak omeraplak merged commit bdb2113 into VoltAgent:main Feb 11, 2026
22 checks passed
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.

bug(workflows): userId/conversationId from execute options not persisted to workflow state (Postgres)

2 participants