Skip to content

.NET: fix: Make State Persistence APIs work better with PortableValue#1367

Merged
crickman merged 2 commits intomainfrom
dev/dotnet_workflow/state_and_portablevalue_fixes
Oct 9, 2025
Merged

.NET: fix: Make State Persistence APIs work better with PortableValue#1367
crickman merged 2 commits intomainfrom
dev/dotnet_workflow/state_and_portablevalue_fixes

Conversation

@lokitoth
Copy link
Copy Markdown
Member

@lokitoth lokitoth commented Oct 9, 2025

Motivation and Context

With the changes to make our type system work a better with transparent serialization round-tripping during checkpointing, we replaced the object-based catch-all in MessageRouter and RouteBuilder with one taking PortableValue, since object as a target-type can result in truncation or leaking JsonElement objects when interacting with JSON serialization.

We did not make a similar change to state persistence, which means that it is unclear how to get a "supertype" of everything to operate on when a specific type is not known. Users could get into trouble writing arbitrary types and trying to read back object. They could use PortableValue but this caues

It also exposed a pair of bugs:

  • in cases like the abstraction leak detailed above, the deserialization process caches the bad leaked value and makes it impossible to cleanly deserialize as the correct value afterwards.
  • in cases where the user asks for the wrong type backed by JSON via IDelayedDeserialization (and would leak if requested to convert to object), PortableValue throws out of Is<T>/As<T>.

Description

  • QOL improvement for developer: Now loading a state as PortableValue will correctly wrap non-PV objects in it, but also avoid double-wrapping if it was stored as a PV in the first place.
  • Fix the two bugs in PortableValue

Closes #1361

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@lokitoth lokitoth requested review from Copilot and crickman October 9, 2025 19:29
@markwallace-microsoft markwallace-microsoft added .NET workflows Related to Workflows in agent-framework labels Oct 9, 2025
@github-actions github-actions Bot changed the title fix: Make State Persistence APIs work better with PortableValue .NET: fix: Make State Persistence APIs work better with PortableValue Oct 9, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR improves state persistence APIs to work better with PortableValue by fixing serialization round-trip issues and preventing object type abstractions that can leak JsonElement objects. The changes ensure PortableValue can serve as a supertype for all stored values without double-wrapping or deserialization cache corruption.

Key changes:

  • Enhanced StateManager and StateScope to properly handle PortableValue as a wrapper type
  • Fixed PortableValue deserialization caching bugs that caused corruption and exceptions
  • Added comprehensive test coverage for PortableValue round-trip scenarios

Reviewed Changes

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

Show a summary per file
File Description
StateManagerTests.cs Added comprehensive tests for PortableValue state persistence scenarios
PortableValueTests.cs New test file covering PortableValue serialization round-trips and delayed deserialization
JsonSerializationTests.cs Made helper methods internal for reuse in new tests
PortableValue.cs Fixed deserialization caching logic and added robust cache management
StateScope.cs Added special handling for PortableValue wrapper behavior
StateManager.cs Enhanced to prevent object type reads and handle PortableValue wrapping

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread dotnet/src/Microsoft.Agents.AI.Workflows/Execution/StateScope.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Workflows/PortableValue.cs Outdated
@lokitoth lokitoth force-pushed the dev/dotnet_workflow/state_and_portablevalue_fixes branch from 6770b01 to a965764 Compare October 9, 2025 19:34
@lokitoth lokitoth force-pushed the dev/dotnet_workflow/state_and_portablevalue_fixes branch from a965764 to 98453e3 Compare October 9, 2025 19:37
@crickman crickman moved this to In Review in Agent Framework Oct 9, 2025
@lokitoth lokitoth enabled auto-merge October 9, 2025 19:45
@crickman crickman requested a review from alliscode October 9, 2025 19:50
@lokitoth lokitoth added this pull request to the merge queue Oct 9, 2025
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 9, 2025
@lokitoth
Copy link
Copy Markdown
Member Author

lokitoth commented Oct 9, 2025

PR failed to merge because IT fails due to breaking change on .ReadStateAsync<object>(). Will remove the check and re-add later.

@crickman crickman added this pull request to the merge queue Oct 9, 2025
Merged via the queue into main with commit 4cd81fe Oct 9, 2025
14 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in Agent Framework Oct 9, 2025
@crickman crickman deleted the dev/dotnet_workflow/state_and_portablevalue_fixes branch October 10, 2025 19:14
ReubenBond pushed a commit to ReubenBond/agent-framework that referenced this pull request Oct 28, 2025
…microsoft#1367)

* fix: Make State Persistence APIs work better with PortableValue

* test: Temporarily disable checking for T=object in ReadStateAsync
arisng pushed a commit to arisng/agent-framework that referenced this pull request Feb 2, 2026
…microsoft#1367)

* fix: Make State Persistence APIs work better with PortableValue

* test: Temporarily disable checking for T=object in ReadStateAsync
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET workflows Related to Workflows in agent-framework

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

.NET: PortableValue type-cast cache does not do the right then when first cast is to object

5 participants