Skip to content

Add .NET support for durable agent state schema 2.0 - #93

Draft
Tamir Dresher (tamirdresher) wants to merge 6 commits into
mainfrom
tamirdresher-microsoft-stack-1-dotnet-schema-2
Draft

Add .NET support for durable agent state schema 2.0#93
Tamir Dresher (tamirdresher) wants to merge 6 commits into
mainfrom
tamirdresher-microsoft-stack-1-dotnet-schema-2

Conversation

@tamirdresher

@tamirdresher Tamir Dresher (tamirdresher) commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Draft stacked PR

Base branch: tamirdresher-microsoft-durable-state-schema-2-contract
Depends on schema contract PR #92 at eff12f41d3923d0123310a178b9dd6a0df61fb56.

This PR must not merge or activate schema 2.0 before #92 and its cross-runtime reader/consumer rollout gates are accepted.

Summary

Add passive .NET DTO, source-generation, conversion, and fail-closed validation support for the durable agent state schema 2.0 contract defined by #92.

What changed

  • Preserve existing .NET legacy state support for exact schema snapshots 1.0.0, 1.1.0, and 1.2.0.
  • Add typed terminal result, completion receipt, terminal error/response, truncation, and optional provisional history-binding DTOs.
  • Preserve mailbox identity and consistency with exact ordinal correlation comparisons and linear cross-map validation.
  • Support the accepted lossless shared message shapes: developer role, object or verbatim string function arguments, URI content with omitted media type, and explicit opaque JSON values.
  • Preserve optional terminal value absence separately from explicit null, false, zero, empty string, array, and object.
  • Preserve declared extensionData separately from undeclared future JSON fields at their original object locations.
  • Use an explicitly marked .NET unknown-content envelope so producer JSON that merely resembles internal metadata remains opaque and lossless.
  • Keep opaque session JSON object-only, cloned away from caller-owned document lifetime, and inert with no runtime type activation.
  • Validate RFC 3339 timestamps with mandatory seconds and explicit offsets, exact schema versions, typed known fields, receipt/result invariants, and diagnostic truncation evidence.
  • Link the four shared fixtures from Propose durable agent state schema 2.0 contract #92 into the .NET test output for interoperability tests.

Activation boundary

The production durable-state converter still rejects reading and writing schema 2.0 with a mailbox-aware activation error. New state continues to default to 1.2.0.

This layer exposes only an explicit internal passive contract path for serializer/fixture tests and later deliberate activation. Layer 2 must implement mailbox-aware entity execution and polling before production 2.0 reads/writes are enabled.

History binding

historyBinding remains an optional, opaque, separately versioned runtime profile using the #92 spelling. The shared .NET DTO preserves any JSON value without interpreting nested owner fields, inferring defaults, or restricting transitions. A relying C# profile may be validated and enforced by layer 3.

Atomic boundary

When a later layer activates schema 2.0, one successful durable entity operation must atomically commit its terminal result and matching receipt with the entity-local session continuation, ingestion bookkeeping, transcript, TTL, optional binding, and local control state. External provider writes and tool side effects are outside that entity-local transaction.

Not in this PR

  • Schema contract ownership or edits from Propose durable agent state schema 2.0 contract #92
  • Schema 2.0 production activation
  • Delivery lookup, polling, result expiry behavior, or mailbox mutation
  • Effective history-owner resolution or fixed-owner enforcement
  • Transcript retention
  • FollowCompaction
  • Per-run store switching
  • Reflection or private provider discovery

Validation

  • 401 Microsoft.Agents.AI.DurableTask.UnitTests tests passed in Release
  • Release package build passed
  • Repository analyzers and formatting passed through build/test
  • All 96 language-neutral Propose durable agent state schema 2.0 contract #92 schema validation cases passed, including versioned full envelopes
  • All four Propose durable agent state schema 2.0 contract #92 fixtures passed Draft 2020-12 validation with date-time checking
  • Incremental diff against 664db2d contains no schemas/ changes
  • git diff --check passed
  • Independent OpenAI gpt-5.6-sol formal review: ACCEPT

Stack

This is the .NET implementation layer directly above #92. Every descendant durable-history layer must rebase onto this PR's new head.

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.

Copilot review overview

🟡 Changes recommended

Unresolved moderate and critical correctness findings remain in validation and JSON round-trip behavior.

Get a fresh assessment by requesting another Copilot review.

Review tier: Lite
Findings: 1 High severity · 1 Medium severity

Open findings (2)
What changed in this PR

Adds passive .NET DTO, conversion, source-generation, and fail-closed validation support for durable agent state schema 2.0 while keeping production activation disabled.

Changes:

  • Adds schema 2.0 terminal, receipt, mailbox, truncation, and history-binding models.
  • Preserves legacy snapshots and lossless JSON/message conversions.
  • Adds validation, fixtures, tests, documentation, logging, and changelog coverage.
File Reviewed change Final review finding
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateTests.cs Legacy versions, cloning, extensions, and opaque session tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateResponseTests.cs Response conversion tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateMessageTests.cs Versioned message conversion tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateMailboxTests.cs Schema 2.0 mailbox interoperability tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateFunctionCallContentTests.cs Function argument tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​State/​DurableAgentStateContentTests.cs Content preservation tests
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​Microsoft.Agents.AI.DurableTask.UnitTests.csproj Shared fixture linking
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​README.md Schema and activation documentation
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateUsage.cs State usage support
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateUriContent.cs URI content model
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateUnknownContent.cs Opaque JSON content preservation Critical (1 vote): Avoid envelope-shape collisions that lose arbitrary payload data.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateTruncation.cs Truncation metadata
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateTerminalResult.cs Terminal result DTO
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateTerminalResponse.cs JSON-safe terminal response projection Moderate (1 vote): Reject undefined JsonElement values at the conversion boundary.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateTerminalError.cs Terminal error validation Moderate (3 votes): Reject control characters in diagnostic messages.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateSchemaVersion.cs Strict schema version parsing
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateResponse.cs State response model
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateRequest.cs State request model
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateMessageIdentity.cs Message identity and correlation
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateMessage.cs Versioned message model and conversion
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateJsonConverter.cs Serialization, version gating, and validation Moderate (1 vote): Handle valid RFC 3339 timestamps with more than seven fractional digits or explicitly constrain the contract.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateJsonContext.cs Source-generation registrations
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateFunctionResultContent.cs Function result conversion
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateFunctionCallContent.cs Function call and argument conversion
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateErrorResponse.cs Error response model
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateErrorContent.cs Error content conversion Moderate (1 vote): Preserve details: null as an explicit null rather than "null".
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateEntry.cs State entry model
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateData.cs Mailbox and cross-map validation Moderate (1 vote): Validate legacy entries and contents before serialization.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateContract.cs Shared validation limits
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateContent.cs Content model and conversion
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateCompletionReceipt.cs Completion receipt invariants
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateCompaction.cs Compaction metadata
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentState.cs Top-level state defaults and cloning
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​Logs.cs Unknown-content fallback logging
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​CHANGELOG.md Unreleased changelog entry Nit (1 vote): Move the entry above the existing #84 bullet.

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

Copilot AI review requested due to automatic review settings September 12, 2026 04:25

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.

Copilot review overview

🔵 Needs a closer look

Unresolved moderate validation and legacy-compatibility issues remain across serialization, null handling, numeric bounds, roles, and URI conversion.

Review tier: Lite
Findings: None

Resolved findings (2)
Previously missed findings (2)

In code that hasn't changed since last review

Medium severity Write path does not enforce version-specific message shapes

dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateJsonConverter.cs:145

This revised-schema write guard only checks activation; after it passes, WriteValue calls Data.Validate, whose legacy branch checks revised top-level fields but never runs the transcript/content shape validation used by ReadElement. Consequently, a 1.2.0 state containing a developer role (or a legacy function-call string argument) can be serialized, and a 2.0.0 state with missing required content fields can likewise emit JSON that the shared schema rejects. Please apply the same version-aware structural validation to the serialized data before writing (or add equivalent model validation) so the writer remains fail-closed.

Low severity Link the changelog entry to this pull request

dotnet/​src/​Microsoft.Agents.AI.DurableTask/​CHANGELOG.md:6

This entry links to tamirdresher/agent-framework-durable-extension#1, which is the earlier schema 1.2 foundation PR, not this schema 2.0 pull request (#93). The package changelog should link the new entry to the PR that introduces this change.

Base automatically changed from tamirdresher-microsoft-durable-state-schema-2-contract to main September 12, 2026 12:17
Tamir Dresher added 6 commits September 12, 2026 15:17
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
@tamirdresher
Tamir Dresher (tamirdresher) force-pushed the tamirdresher-microsoft-stack-1-dotnet-schema-2 branch from 6b5410e to 86bf671 Compare September 12, 2026 12:17
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.

2 participants