Skip to content

.Net: Find Associated Tool(s) Called #10654

Closed
@aherrick

Description

@aherrick

I'm trying to figure out the cleanest way to figure out what tools were invoked in a call. Here is what I've come up with but there has to be a better way?

using System.ComponentModel;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;

var kernel = Kernel
    .CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        deploymentName: "gpt-4o",
        endpoint: "",
        apiKey: ""
    )
    .Build();

kernel.Plugins.AddFromType<WeatherPlugin>();

var chatHistory = new ChatHistory();

chatHistory.AddUserMessage("whats the weather");

var promptExecutionSettings = new PromptExecutionSettings
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
};

var chatService = kernel.GetRequiredService<IChatCompletionService>();
var result = await chatService.GetChatMessageContentAsync(
    chatHistory,
    promptExecutionSettings,
    kernel
);

Console.WriteLine(result.Content);

var plugins = GetPluginsUsed(chatHistory);
foreach (var plugin in plugins)
{
    Console.WriteLine(plugin);
}

Console.ReadLine();

static List<string> GetPluginsUsed(ChatHistory chatHistory)
{
    // Find the index of the most recent user message
    int lastUserMessageIndex = -1;
    for (int i = chatHistory.Count - 1; i >= 0; i--)
    {
        if (chatHistory[i].Role == AuthorRole.User)
        {
            lastUserMessageIndex = i;
            break;
        }
    }

    // Extract only tool messages that appear AFTER the last user message
    var toolMessages = chatHistory
        .Skip(lastUserMessageIndex + 1) // Start from the message after the user's last input
        .Where(msg => msg.Role == AuthorRole.Tool)
        .SelectMany(toolMsg =>
            toolMsg
                .Items.OfType<FunctionResultContent>()
                .Select(x => $"({x.PluginName}: {x.FunctionName})")
        )
        .ToList();

    return toolMessages;
}

public class WeatherPlugin
{
    // Hard coded weather data
    private readonly string[] weatherData =
    [
        "Sunny, 15°C",
        "Cloudy, 12°C",
        "Rainy, 10°C",
        "Snowy, -2°C",
    ];

    private readonly Random random = new();

    [KernelFunction, Description("Get weather information")]
    public string GetWeather()
    {
        // Get random weather data
        int index = random.Next(weatherData.Length);
        return weatherData[index];
    }
}

Metadata

Metadata

Labels

.NETIssue or Pull requests regarding .NET code

Type

No type

Projects

Status

Sprint: Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions