Skip to content

Add durable chat history ownership and session persistence - #95

Draft
Tamir Dresher (tamirdresher) wants to merge 11 commits into
tamirdresher-microsoft-harden-durable-delivery-ttlfrom
tamirdresher-microsoft-stack-3-history-provider
Draft

Add durable chat history ownership and session persistence#95
Tamir Dresher (tamirdresher) wants to merge 11 commits into
tamirdresher-microsoft-harden-durable-delivery-ttlfrom
tamirdresher-microsoft-stack-3-history-provider

Conversation

@tamirdresher

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

Copy link
Copy Markdown
Contributor

Summary

Add the C# durable history-provider and opaque-session integration on top of the schema 2 mailbox and workflow-output trust-boundary foundation.

What changed

  • Apply a C#-specific fixed logical history-owner profile while keeping the shared schema 2 historyBinding optional and provisional.
  • Mark only C#-sealed bindings for runtime enforcement; shared/Python-produced descriptors do not impose effective-owner pinning at DTO level.
  • Use an operation-scoped durable history adapter for entity-owned in-memory history.
  • Preserve custom provider, model-service, and opaque agent-session ownership with no new transcript mirrors.
  • Restore and serialize Agent Framework sessions across cold operations.
  • Validate stable non-secret provider keys, owner identity, and required continuation evidence.
  • Keep service ownership provisional until a successful response supplies a conversation ID, then seal before commit.
  • Preserve layer-2 result mailbox payloads, completion receipts, structured values, continuation tokens, result expiry, TTL, rollback, and workflow bookkeeping.
  • Filter legacy errors, the current correlation, metadata-only envelopes, and provider-specific reasoning from entity replay.
  • Reject unsafe local per-service-call persistence and directly discoverable stateful compaction.

C# fixed-owner profile

The shared historyBinding shape from #92 is configuration metadata, not a cross-runtime effective-owner contract. The C# runtime adds an extension marker when it seals a binding after the first successful turn. Only marked C# bindings are treated as immutable runtime ownership.

The logical provider key must remain stable across recreated provider/agent instances and must not be derived from CLR type names, credentials, process instances, or guessed StateBag keys.

Legacy non-entity adoption requires owner-specific public evidence:

  • normal service ownership requires a restored service conversation ID;
  • external provider ownership requires one of the provider's declared StateKeys;
  • opaque CurrentRequestOnly and legacy per-service-call state cannot prove prior ownership and require a new durable session.

No external transcript mirror

External-provider, service, and opaque agent-session owners append no new request or response messages to conversationHistory. They still retain:

  • schema 2 terminal result payloads and permanent completion receipts;
  • request/correlation identity and orchestration bookkeeping;
  • structured/lossless retained values and continuation tokens;
  • result-expiry evidence;
  • whole-entity TTL;
  • opaque session/provider continuation, including conversation IDs and pending approvals.

Mailbox results are never reconstructed into provider history or replayed to the model.

Trust and failure boundaries

  • The layer-2 executor-output trust boundary remains authoritative: agent/model text is data and cannot become workflow state updates, events, routed messages, or halt controls.
  • Provider/model/session/cancellation failures do not commit the working entity state.
  • Unexpected post-response service-owner transitions fail before durable commit and explicitly warn that the remote service may already have observed the call.
  • Local per-service-call provider callbacks remain unsupported because the public callback contract does not expose final outer-response finality.

Compaction boundary

Directly discoverable CompactionProvider configurations and in-memory reducers are rejected before execution.

The pinned Agent Framework public API cannot universally inspect builder-installed or privately nested decorators. Hidden stateful-compaction pipelines are unsupported but cannot be reliably rejected before side effects without an upstream public capability hook. This implementation does not use private reflection, type-name scanning, guessed session keys, factory double invocation, or blanket state stripping.

Tests

  • 258 targeted ownership, mailbox, versioned-envelope, and malicious-output trust-boundary tests.
  • 774 full Microsoft.Agents.AI.DurableTask.UnitTests tests in Release.
  • 223 Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests tests in Release.
  • Full Release solution build and DurableTask package creation.
  • Formatting/analyzers and git diff --check.
  • Independent OpenAI gpt-5.6-sol formal review: ACCEPTED.

Stack dependency

This is product stack layer 3 of 4.

  • Base branch: tamirdresher-microsoft-harden-durable-delivery-ttl
  • Base commit: 6f515fd70cc9372804245669d89735e8beaf6c37
  • Head commit: d3872e1e122b1462628793e193eb7409761b4728
  • Parent layer 1: 1a84c82b
  • Shared schema feedback: Propose durable agent state schema 2.0 contract #92

Not in this PR

  • Retention defaults, algorithms, metrics, or samples
  • FollowCompaction
  • Per-run history-store switching
  • Universal provider snapshots
  • Exactly-once external provider adapters
  • Samples 08, 09, or 10

Review reading order

  1. DurableAgentHistoryBinding.cs
  2. DurableAgentHistoryOwnership.cs
  3. State/DurableAgentStateReplay.cs and DurableChatHistoryProvider.cs
  4. DurableAgentSessionState.cs
  5. EntityAgentWrapper.cs
  6. DurableAgentsOptions.cs
  7. AgentEntity.cs
  8. Binding/ownership/provider/session/wrapper tests, then entity integration tests

Relationship to prior drafts

This supersedes the obsolete layer-3 drafts based on f4ce89e and 2d5aa78. It preserves the accepted C# fixed-owner subset while integrating the final opaque optional history profile and the final layer-2 mailbox, consumer, TTL, rollback, versioned-envelope, and executor-output trust semantics.

Tamir Dresher and others added 3 commits September 10, 2026 18:15
Define a draft language-neutral execution/completion contract, synthetic review fixtures, and explicit cross-runtime rollout prerequisites without activating runtime writes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Record independent gpt-5.6-sol ACCEPT of the unchanged schema-only tree 9051274. Keep the proposal commit unchanged and record both required trailers together in an append-only review record.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
Constrain v2 correlations, preserve supported JSON message and structured result shapes, make the provisional binding optional, and clarify legacy ingestion and entity-local commit semantics. Add language-neutral validation cases without runtime activation. Binding representation and expired lookup outcome remain pending agreement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 532fe4f5-939b-4962-989d-a1883dccd283
@tamirdresher
Tamir Dresher (tamirdresher) added this pull request to stack #96 September 11, 2026 19:24
Tamir Dresher and others added 7 commits September 12, 2026 02:29
Restore historical message and content validation, isolate expanded v2 transcript and terminal response definitions, and add full-envelope version boundary cases. Treat historyBinding as an opaque runtime profile and clarify authoritative expired outcomes without inventing legacy outcomes. No runtime activation.

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
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 12, 2026 03:09
@tamirdresher
Tamir Dresher (tamirdresher) force-pushed the tamirdresher-microsoft-stack-3-history-provider branch from 4a0f438 to d3872e1 Compare September 12, 2026 03:09

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 findings affect history replay and provider-key validation; required changelog entries are also missing.

Get a fresh assessment by requesting another Copilot review.

Review tier: Lite
Findings: 2 Medium severity

Open findings (2)
What changed in this PR

Adds C# durable history ownership, session persistence, replay filtering, and schema 2 mailbox integration.

Changes:

  • Adds ownership bindings, provider-key handling, and compaction checks.
  • Persists opaque sessions and stages durable history per operation.
  • Integrates filtered replay, mailbox state, and related tests.
File Reviewed changes and notes
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​EntityAgentWrapperTests.cs Tests wrapper identity and provider overrides.
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​DurableChatHistoryProviderTests.cs Tests durable history staging and replay.
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​DurableAgentSessionStateTests.cs Tests session persistence and restoration.
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​DurableAgentHistoryOwnershipTests.cs Tests ownership resolution and validation.
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​AgentEntityHistoryTests.cs Tests entity history integration.
dotnet/​tests/​Microsoft.Agents.AI.DurableTask.UnitTests/​AgentEntityDeliveryTests.cs Tests mailbox and binding behavior.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateResponse.cs Adds lossless response conversion.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateRequest.cs Supports staged request conversion.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateReplay.cs Provides filtered replay projection.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​State/​DurableAgentStateMessage.cs Supports replayable message conversion.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​README.md Documents ownership and mailbox behavior.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​Logs.cs Updates durable execution logging.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​EntityAgentWrapper.cs Applies operation-scoped provider integration.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableChatHistoryProvider.cs Stages entity-owned history. Moderate: merged context messages can duplicate prior transcript entries.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentsOptions.cs Adds ownership configuration. Nit: required changelog entry is missing.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentSessionState.cs Serializes and restores sessions.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentHistoryReplayMode.cs Defines replay policies.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentHistoryOwnershipNotSupportedException.cs Reports unsupported ownership.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentHistoryOwnership.cs Resolves ownership and compaction support.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentHistoryBindingMismatchException.cs Reports binding mismatches.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentHistoryBinding.cs Parses and seals bindings. Moderate: malformed provider keys can be adopted without validation.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​DurableAgentCompactionNotSupportedException.cs Reports unsupported compaction.
dotnet/​src/​Microsoft.Agents.AI.DurableTask/​AgentEntity.cs Integrates replay, sessions, ownership, and commits. Moderate: legacy promotion can duplicate and replay the transcript. Nit: required changelog entry is missing.

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

Comment on lines +605 to +611
if (isLegacyState)
{
return workingState.Data.ConversationHistory
.SelectMany(entry => entry.Messages)
.Select(message => message.ToChatMessage());
}

Comment on lines +62 to +66
this._history.Add(DurableAgentStateRequest.FromRunRequest(
this._request,
context.RequestMessages,
allowLosslessV2,
this._logger));
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