Skip to content

.NET: fix(dotnet): refresh reused workflow executor state - #9394

Merged
Vincent Biret (baywet) merged 6 commits into
mainfrom
fix/reset-reused-workflow-executor-state
Oct 15, 2026
Merged

Vincent Biret (baywet) merged 6 commits into
mainfrom
fix/reset-reused-workflow-executor-state

Conversation

@baywet

@baywet Vincent Biret (baywet) commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Motivation & Context

Read executor state from the current workflow context when a hosted workflow reuses an executor instance. Each run should load its persisted workflow state rather than retain an earlier run's cached value.

Description & Review Guide

  • What are the major changes? Remove executor-local state caching and delegate reads and updates to the existing workflow-context state helpers. Preserve explicit full-executor reset opt-in and existing built-in reset declarations. Initialize state only when needed and queue the same value returned to the caller so nested and repeated reads stay consistent. Document the state and reset contracts, retain skipCache for API compatibility, and add hosted-session, interrupted-output, value-state, nested-read, repeated-initialization, and mixed-workflow reuse regressions. Make the test runner context's read-or-initialize implementation use its existing state manager rather than always returning new initial state.
  • What is the impact of these changes? Reused executors read current scoped state, including pending updates and restored checkpoints, without opting subclasses' other instance fields into reset support. Nested initialization reads observe the same state object as the surrounding invocation. ChatProtocolExecutor uses the same context-scoped state for interrupted turns. Reset does not clear persisted workflow state. The executor-local cache optimization is removed.
  • What do you want reviewers to focus on? Scoped state and checkpoint restoration, pending updates within a run, unchanged full-reset opt-in, and existing agent-host and handoff behavior.

Commands executed from dotnet:

  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --filter-class '*WorkflowExecutorStateTests' --no-progress: six original regression cases failed for the intended behavior before the fix; all fourteen final cases passed after the fix.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net472 --no-restore --filter-class '*WorkflowExecutorStateTests' --no-progress: passed, all fourteen cases. CI previously found two unsupported ValueTask factory calls in test helpers; these now wrap compatible canceled and faulted tasks without changing the assertions.
  • dotnet build tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj --no-restore --tl:off -v:quiet: passed across all target frameworks, zero warnings and errors.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --filter-method '*OutputExecutor_ResetClearsMessagesAfterInterruptedTurnAsync' --no-progress: two additional regression cases failed before the output executor reset repair; both passed afterward.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --filter-method '*MixedWorkflow_RequiresExplicitResetSupportForReuseAsync' --no-progress: failed before preserving explicit reset opt-in; passed after the revision.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --filter-method '*StatefulExecutor_PreservesNestedReadUpdatesDuringInitializationAsync' --no-progress: failed before the initialization repair because the nested update was lost; passed afterward.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --filter-method '*StatefulExecutor_InitializesOnlyWhenStateIsMissingAsync' --no-progress: both pending and committed state cases failed before deferring factory execution until initialization; both passed afterward.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.UnitTests -f net10.0 --no-restore --no-progress: passed, 858 tests. Seven existing tests initially failed after cache removal because the test runner context reinitialized state on every read; all passed after aligning that fixture with the state manager, with assertions unchanged.
  • dotnet test --project tests\Microsoft.Agents.AI.Workflows.Declarative.UnitTests -f net10.0 --no-restore --no-progress: passed, 1,028 tests.
  • dotnet build src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj --no-restore --tl:off -v:quiet: passed across all target frameworks, zero warnings and errors.
  • dotnet format src\Microsoft.Agents.AI.Workflows\Microsoft.Agents.AI.Workflows.csproj --no-restore: passed.
  • dotnet format tests\Microsoft.Agents.AI.Workflows.UnitTests\Microsoft.Agents.AI.Workflows.UnitTests.csproj --no-restore: passed.
  • dotnet build agent-framework-dotnet.slnx --tl:off -v:quiet: blocked by unrelated package restore errors (NU1102); the configured feed does not contain A2A or A2A.AspNetCore version 1.0.0-preview3. The full-solution unit suite was not run.

Related Issue

N/A - maintainer-requested bugfix tracked internally; no public issue was opened. No matching open PR was found.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: GitHub Copilot assisted with implementation, regression tests, XML documentation, and this PR description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405
Copilot AI balanced review requested due to automatic review settings October 14, 2026 17:56
@agent-framework-automation agent-framework-automation Bot added .NET Usage: [Issues, PRs], Target: .Net workflows Usage: [Issues, PRs], Target: Workflows labels Oct 14, 2026
@github-actions github-actions Bot changed the title fix(dotnet): refresh reused workflow executor state .NET: fix(dotnet): refresh reused workflow executor state Oct 14, 2026

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

OutputMessagesExecutor bypasses the new base reset, allowing interrupted-run messages to leak across sessions.

1 open finding
What changed in this PR

Refreshes cached .NET workflow executor state between hosted runs so reused executors restore session-specific persisted state.

Changes:

  • Adds cache initialization tracking and reset lifecycle support.
  • Adds regression coverage for value-state, session reuse, streaming, and interrupted turns.
File Description
StatefulExecutor.cs Invalidates cached state during executor reset.
WorkflowExecutorStateTests.cs Tests state restoration across reset and hosted sessions.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

@github-actions github-actions 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.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 58e47cc33322
Model: gpt-5.6-sol

Overview

The change correctly invalidates the base state cache at workflow release, explicitly tracks value-type cache initialization, and adds focused checkpoint, hosted-session, and interrupted-turn coverage. The cache bypass for concurrent runs and virtual reset dispatch are strong guardrails. However, making the public base class implement IResettableExecutor also marks every existing derived executor as fully resettable even though the base reset cannot clear derived per-run fields, allowing mixed workflows that previously rejected reuse to carry those fields into another session.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: dotnet/src/Microsoft.Agents.AI.Workflows/StatefulExecutor.cs

@github-code-quality

github-code-quality Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: C#

C# / code-coverage/dotnet

main 95511ff fix/reset-reused-wor... 9af8f0b +/-
86% 85% -1%
View coverage of the 4 most impacted files.
File main 95511ff fix/reset-reused-wor... 9af8f0b +/-
/home/runner/wo...SessionStore.cs 100% 53% -47%
/home/runner/wo...unnerContext.cs 94% 92% -2%
/home/runner/wo...efulExecutor.cs 72% 75% +3%
/home/runner/wo...ows/Workflow.cs 61% 67% +6%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated October 14, 2026 19:33 UTC

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405

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

Delayed cache initialization can cause nested state reads to observe different state and lose mutations.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405

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

Cache removal exposes an initialization mismatch that can make consecutive reads return different state without an update.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405
Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405

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.

🟢 Approval recommended

The scoped-state changes and focused regression coverage address stale-state reuse with no unresolved blocking issues identified.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 892f90aa-ef94-4e11-87a3-88a8cb755405

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.

🟢 Approval recommended

The scoped-state changes preserve reset contracts, address prior feedback, and include focused regression coverage with no unresolved findings.

0 open findings

🧠 Review effort: Balanced

@github-actions github-actions 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.

MAF Automated Review — Iteration 2

Result: No findings
Scope: 5 net-new commit(s): 690672937893, 4c6f0cb5b38c, 2af20ad1050e, ecdea14801e0, 9af8f0b55948
Model: gpt-5.6-sol

Overview

This increment removes executor-local workflow-state caching and delegates reads and updates to the current runner-local context while preserving explicit reset opt-in for other executor instance fields. Initialization now occurs only when state is absent and queues the same value returned to callers, with regressions covering repeated and nested reads, hosted reuse, and interrupted output. The workflow ownership guards, context read-your-writes contract, and publish-before-checkpoint lifecycle prevent a publishable cross-session, persistence, compatibility, or security concern.

Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

@baywet
Vincent Biret (baywet) added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit cae4955 Oct 15, 2026
39 checks passed
@baywet
Vincent Biret (baywet) deleted the fix/reset-reused-workflow-executor-state branch October 15, 2026 13:03

This branch was previously deployed

2 inactive deployments
github-app-auth — 9af8f0b5 Deployed Oct 14, 2026 by baywet via team_check #6830
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET Usage: [Issues, PRs], Target: .Net workflows Usage: [Issues, PRs], Target: Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants