Files
eoindoherty1 b19860b8a8 .NET: Implement Purview middleware in dotnet (#1949)
* Move Purview integration logic into middleware

* Improve error handling and user id management

* Rename purview package

* Handle 402s more explicitly; add Middleware generation methods; don't ignore exceptions

* Use DI container; pass scope id to PC

* Add protection scope caching

* Wrap more exceptions in PurviewClient

* Remove block check dedup; add tests

* Refactor PurviewWrapper intialization; Add unit tests

* Use different .Use method and add IDisposable stub

* Add background job processing for Purview

* Misc comment cleanup

* Apply copilot comments

* Fix formatting

* Formatting other files to fix pipeline

* Small updates to settings and exceptions

* Add README

* Move Purview sample

* Address review comments and update XML comments

* Newline after namespace

* Move public Purview classes to single namespace; Clean up csproj and slnx

* Commit the renames

* Remove unused openAI dependency

---------

Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com>
2025-11-14 00:50:08 +00:00

63 lines
2.3 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Purview;
/// <summary>
/// A middleware chat client that connects to Microsoft Purview.
/// </summary>
internal class PurviewChatClient : IChatClient
{
private readonly IChatClient _innerChatClient;
private readonly PurviewWrapper _purviewWrapper;
/// <summary>
/// Initializes a new instance of the <see cref="PurviewChatClient"/> class.
/// </summary>
/// <param name="innerChatClient">The inner chat client to wrap.</param>
/// <param name="purviewWrapper">The purview wrapper used to interact with the Purview service.</param>
public PurviewChatClient(IChatClient innerChatClient, PurviewWrapper purviewWrapper)
{
this._innerChatClient = innerChatClient;
this._purviewWrapper = purviewWrapper;
}
/// <inheritdoc/>
public void Dispose()
{
this._purviewWrapper.Dispose();
this._innerChatClient.Dispose();
}
/// <inheritdoc/>
public Task<ChatResponse> GetResponseAsync(IEnumerable<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
{
return this._purviewWrapper.ProcessChatContentAsync(messages, options, this._innerChatClient, cancellationToken);
}
/// <inheritdoc/>
public object? GetService(Type serviceType, object? serviceKey = null)
{
return this._innerChatClient.GetService(serviceType, serviceKey);
}
/// <inheritdoc/>
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
Task<ChatResponse> responseTask = this._purviewWrapper.ProcessChatContentAsync(messages, options, this._innerChatClient, cancellationToken);
foreach (var update in (await responseTask.ConfigureAwait(false)).ToChatResponseUpdates())
{
yield return update;
}
}
}