mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
c70e594e6c
* rename AgentRunResponse and AgentRunResponseUpdate classes - part1 * rename varialbles, parameters, methods and tests * rollback unnecessary changes
83 lines
3.9 KiB
C#
83 lines
3.9 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.AI;
|
|
|
|
namespace Microsoft.Agents.AI;
|
|
|
|
/// <summary>
|
|
/// Internal agent decorator that adds function invocation middleware logic.
|
|
/// </summary>
|
|
internal sealed class FunctionInvocationDelegatingAgent : DelegatingAIAgent
|
|
{
|
|
private readonly Func<AIAgent, FunctionInvocationContext, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>>, CancellationToken, ValueTask<object?>> _delegateFunc;
|
|
|
|
internal FunctionInvocationDelegatingAgent(AIAgent innerAgent, Func<AIAgent, FunctionInvocationContext, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>>, CancellationToken, ValueTask<object?>> delegateFunc) : base(innerAgent)
|
|
{
|
|
this._delegateFunc = delegateFunc;
|
|
}
|
|
|
|
protected override Task<AgentResponse> RunCoreAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
|
|
=> this.InnerAgent.RunAsync(messages, thread, this.AgentRunOptionsWithFunctionMiddleware(options), cancellationToken);
|
|
|
|
protected override IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingAsync(IEnumerable<ChatMessage> messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
|
|
=> this.InnerAgent.RunStreamingAsync(messages, thread, this.AgentRunOptionsWithFunctionMiddleware(options), cancellationToken);
|
|
|
|
// Decorate options to add the middleware function
|
|
private AgentRunOptions? AgentRunOptionsWithFunctionMiddleware(AgentRunOptions? options)
|
|
{
|
|
if (options is null || options.GetType() == typeof(AgentRunOptions))
|
|
{
|
|
options = new ChatClientAgentRunOptions();
|
|
}
|
|
|
|
if (options is not ChatClientAgentRunOptions aco)
|
|
{
|
|
throw new NotSupportedException($"Function Invocation Middleware is only supported without options or with {nameof(ChatClientAgentRunOptions)}.");
|
|
}
|
|
|
|
var originalFactory = aco.ChatClientFactory;
|
|
aco.ChatClientFactory = chatClient =>
|
|
{
|
|
var builder = chatClient.AsBuilder();
|
|
|
|
if (originalFactory is not null)
|
|
{
|
|
builder.Use(originalFactory);
|
|
}
|
|
|
|
return builder.ConfigureOptions(co
|
|
=> co.Tools = co.Tools?.Select(tool => tool is AIFunction aiFunction
|
|
? new MiddlewareEnabledFunction(this.InnerAgent, aiFunction, this._delegateFunc)
|
|
: tool)
|
|
.ToList())
|
|
.Build();
|
|
};
|
|
|
|
return options;
|
|
}
|
|
|
|
private sealed class MiddlewareEnabledFunction(AIAgent innerAgent, AIFunction innerFunction, Func<AIAgent, FunctionInvocationContext, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>>, CancellationToken, ValueTask<object?>> next) : DelegatingAIFunction(innerFunction)
|
|
{
|
|
protected override async ValueTask<object?> InvokeCoreAsync(AIFunctionArguments arguments, CancellationToken cancellationToken)
|
|
{
|
|
var context = FunctionInvokingChatClient.CurrentContext
|
|
?? new FunctionInvocationContext() // When there is no ambient context, create a new one to hold the arguments
|
|
{
|
|
Arguments = arguments,
|
|
Function = this.InnerFunction,
|
|
CallContent = new(string.Empty, this.InnerFunction.Name, new Dictionary<string, object?>(arguments)),
|
|
};
|
|
|
|
return await next(innerAgent, context, CoreLogicAsync, cancellationToken).ConfigureAwait(false);
|
|
|
|
ValueTask<object?> CoreLogicAsync(FunctionInvocationContext ctx, CancellationToken cancellationToken)
|
|
=> base.InvokeCoreAsync(ctx.Arguments, cancellationToken);
|
|
}
|
|
}
|
|
}
|