Skip to content

.NET: valkey streaming support dotnet#5576

Open
MatthiasHowellYopp wants to merge 1 commit into
microsoft:mainfrom
MatthiasHowellYopp:issue-5544
Open

.NET: valkey streaming support dotnet#5576
MatthiasHowellYopp wants to merge 1 commit into
microsoft:mainfrom
MatthiasHowellYopp:issue-5544

Conversation

@MatthiasHowellYopp

Copy link
Copy Markdown
Contributor

Motivation and Context

The Microsoft.Agents.AI.Valkey package provides ValkeyChatHistoryProvider and ValkeyContextProvider for persistent conversation history and memory context. However, the framework currently has no storage-backed resumable streaming component — if a client disconnects during a streamed agent response (RunStreamingAsync), partial output is lost and must be regenerated. This is the final piece of the Valkey integration story, delivering parity with the Python agent-framework-valkey package.

Valkey Streams (XADD/XRANGE) are a natural fit: each entry gets an auto-generated ID that serves as a continuation token, entries are append-only and durable, and XRANGE with an exclusive start ID gives exact resume-from-here semantics — all with core commands, no modules required.

Fixes issue #5544

Description

Adds ValkeyStreamBuffer to the Microsoft.Agents.AI.Valkey package — a resumable streaming buffer backed by Valkey Streams.

The component writes serialized AgentResponseUpdate chunks to a Valkey Stream via XADD and replays missed entries via XRANGE from a caller-provided entry ID. The stream entry ID returned by each AppendAsync call serves as the continuation token for resumption.

Public API:

  • AppendAsync(responseId, update) — writes a chunk, returns the entry ID
  • ReadAsync(responseId, afterEntryId) — replays entries after a given ID as IAsyncEnumerable
  • GetEntryCountAsync(responseId) — returns stream length
  • DeleteStreamAsync(responseId) — removes a stream
  • MaxLength property — caps stream size via approximate XTRIM after each XADD

Follows the same patterns as the existing Valkey providers: dual constructors (connection string + IConnectionMultiplexer for DI), IAsyncDisposable with disposed-state guard, CancellationToken forwarding, malformed JSON resilience, trimming/AOT attributes, and ILogger integration at appropriate levels (Debug for per-request, Warning for skipped entries).

Includes a self-contained sample (AgentWithMemory_Step06_ResumableStreamingWithValkey) that demonstrates the full workflow — stream, disconnect, resume, full replay — against a live Valkey instance with no LLM or cloud credentials required.

64 unit tests passing, covering constructor validation, append/read round-trips, entry ID incrementing, MaxLength pass-through, malformed entry handling, cancellation, disposal guards, and empty stream edge cases.

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.

Copilot AI review requested due to automatic review settings April 29, 2026 19:13
@moonbox3 moonbox3 added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net labels Apr 29, 2026
@github-actions github-actions Bot changed the title valkey streaming support dotnet .NET: valkey streaming support dotnet Apr 29, 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 5 times, most recently from ee7312c to 9701441 Compare May 5, 2026 20:43
@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 3 times, most recently from bd5b982 to 99bcf8f Compare May 14, 2026 14:29
@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 3 times, most recently from c394fda to 8751b4a Compare May 20, 2026 15:16
@MatthiasHowellYopp

Copy link
Copy Markdown
Contributor Author

@westey-m Hoping I can get a review on this this week, tks

@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 4 times, most recently from 1253dd2 to 3fbdfa9 Compare May 26, 2026 13:36
@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 3 times, most recently from aad29ac to ff0f1fa Compare June 4, 2026 16:43
@MatthiasHowellYopp MatthiasHowellYopp force-pushed the issue-5544 branch 4 times, most recently from bbe3fea to a2ce36d Compare June 11, 2026 13:52
@MatthiasHowellYopp

Copy link
Copy Markdown
Contributor Author

@westey-m Hoping I can get a review on this this week, tks

/// </list>
/// </para>
/// </remarks>
public sealed class ValkeyStreamBuffer

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.

@MatthiasHowellYopp, thanks for the PR. While I think the problem space you are describing is definitely interesting, just the buffer component on it's own is not that useful in the AF context. If you replaced AgentResponseUpdate with a generic type, this component could equally live in the Valkey .net lib.

I think most users would actually be looking for the integration into Agent Framework via some middleware that automatically deals with failures. However, that has some challenges. E.g. the service itself would need to have built in support for resumption. There is some support in Microsoft.Extensions.AI for this already, via ChatClient.AllowBackgroundResponses, which if the service supports this will use continuation tokens to allow the caller to resume reading. I'm not entirely sure how this would fit in with that though and would like to hear more about what you were thinking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@westey-m After reviewing the PR and the initial issue I see that this PR is not complete. I'd like to update this PR with a more complete solution to the issue, which should basically match what you describe. Let me know if it is ok to proceed.

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.

I think this is quite a challenging feature in many ways, and I'm actually not super clear on how it would integrate with agent framework, but happy to see what you have in mind. To save you time, effort and tokens, it may makes sense to create a small design doc of what you have in mind first. Or join our office hours and come discuss. See https://github.com/microsoft/agent-framework/blob/main/COMMUNITY.md for the office hours details.

Adds ValkeyStreamBuffer — a resumable streaming buffer backed by Valkey
Streams (XADD/XRANGE). Enables clients to disconnect and reconnect
mid-stream without data loss using entry ID-based continuation tokens.

- ValkeyStreamBuffer with AppendAsync, ReadAsync, GetEntryCountAsync, DeleteStreamAsync
- ValkeyStreamBufferOptions (KeyPrefix, MaxLength, JsonSerializerOptions)
- Uses Valkey.Glide with type-safe JSON serialization
- Unit tests with mocked client
- Sample demonstrating append, disconnect, and resume workflow

Signed-off-by: Matthias Howell <matthias.howell@improving.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants