Files
agent-framework/dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIChatResponseUpdateStreamExtensions.cs
T
Javier Calvarro NelsonandGitHub e859edc2a4 .NET: AG-UI support for .NET: Support for tool calling (#1896)
* Initial implementation

* tmp

* Replace function calling with a FunctionInvokingChatClient

* Cleanups

* Remove custom thread

* Fixing function calling server and client

* Cleanup

* Cleanup serialization

* Run dotnet format

* Pass logger factory

* Populate message properties

* Remove files

* Cleanups

* cleanup

* Cleanups

* More cleanup

* Simplify things

* Cleanup

* Clean up json serialization

* Additional tests

* Add service collection extensions for serialization

* Combine options in AGUIChatClient

* Additional tests

* Include tool calling in the sample, fix mixed server and client tool calls

* Fix tests

* More cleanups

* Fix tests

* Cleanups

* Dojo project and fixes

* Fix build

* Remove dojo

* Cleanup

* Address feedback

* address feedback

* Additional feedback

* Fix build

* Fix build

* Make packages packable
2025-11-07 17:23:21 +00:00

91 lines
3.2 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
internal static class AGUIChatResponseUpdateStreamExtensions
{
public static async IAsyncEnumerable<ChatResponseUpdate> FilterServerToolsFromMixedToolInvocationsAsync(
this IAsyncEnumerable<ChatResponseUpdate> updates,
List<AITool>? clientTools,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
if (clientTools is null || clientTools.Count == 0)
{
await foreach (var update in updates.WithCancellation(cancellationToken))
{
yield return update;
}
yield break;
}
var set = new HashSet<string>(clientTools.Count);
foreach (var tool in clientTools)
{
set.Add(tool.Name);
}
await foreach (var update in updates.WithCancellation(cancellationToken))
{
if (update.FinishReason == ChatFinishReason.ToolCalls)
{
var containsClientTools = false;
var containsServerTools = false;
for (var i = update.Contents.Count - 1; i >= 0; i--)
{
var content = update.Contents[i];
if (content is FunctionCallContent functionCallContent)
{
containsClientTools |= set.Contains(functionCallContent.Name);
containsServerTools |= !set.Contains(functionCallContent.Name);
if (containsClientTools && containsServerTools)
{
break;
}
}
}
if (containsClientTools && containsServerTools)
{
var newContents = new List<AIContent>();
for (var i = update.Contents.Count - 1; i >= 0; i--)
{
var content = update.Contents[i];
if (content is not FunctionCallContent fcc ||
set.Contains(fcc.Name))
{
newContents.Add(content);
}
}
yield return new ChatResponseUpdate(update.Role, newContents)
{
ConversationId = update.ConversationId,
ResponseId = update.ResponseId,
FinishReason = update.FinishReason,
AdditionalProperties = update.AdditionalProperties,
AuthorName = update.AuthorName,
CreatedAt = update.CreatedAt,
MessageId = update.MessageId,
ModelId = update.ModelId
};
}
else
{
yield return update;
}
}
else
{
yield return update;
}
}
}
}