Skip to content

.Net: Bug: Kernel.Invoke Function is not calling other functions specified in the prompt template #12016

@vamsidogiparthi

Description

@vamsidogiparthi

Describe the bug
Currently, I have been trying to invoke some functions from registered plugins (registered using DI) in the Handlebar yaml prompt template. But the kernel is not invoking the function and returning a message saying cannot find the current user time.

Program.cs

using IAUI.Agent.Plugins.FunctionPlugin;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddUserSecrets<Program>(optional: true)
    .AddEnvironmentVariables()
    .Build();

builder.Services.AddOpenApi();
builder.Services.AddLogging(loggingBuilder =>
    loggingBuilder.AddConsole().AddConfiguration(configuration.GetSection("Logging"))
);
builder.Services.AddOptions();
builder.Services.Configure<OpenAIConfiguration>(
    configuration.GetSection(OpenAIConfiguration.SectionName)
);
builder.Services.Configure<IAUIStoreDatabaseConfiguration>(
    configuration.GetSection(IAUIStoreDatabaseConfiguration.SectionName)
);

builder.Services.Configure<GoogleAIConfiguration>(
    configuration.GetSection(GoogleAIConfiguration.SectionName)
);

builder.Services.Configure<ProfileScoringAlgorithmConfiguration>(
    configuration.GetSection(ProfileScoringAlgorithmConfiguration.SectionName)
);

builder.Services.AddSingleton<IIAUIDatabaseService, IAUIDatabaseService>();
builder.Services.AddSingleton<IDataSeeder, DataSeeder>();
builder.Services.AddSingleton<IProfileScoringService, ProfileScoringService>();

builder.Services.AddSingleton<IChatCompletionService>(sp =>
{
    var openAIConfiguration =
        configuration.GetSection(OpenAIConfiguration.SectionName).Get<OpenAIConfiguration>()
        ?? throw new Exception("OpenAI configuration is missing");

    var googleAIConfiguration =
        configuration.GetSection(GoogleAIConfiguration.SectionName).Get<GoogleAIConfiguration>()
        ?? throw new Exception("Google AI configuration is missing");

#pragma warning disable SKEXP0070 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
    // return new GoogleAIGeminiChatCompletionService(
    //     googleAIConfiguration.Model,
    //     googleAIConfiguration.ApiKey
    // );
#pragma warning restore SKEXP0070 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

    return new OpenAIChatCompletionService(openAIConfiguration.Model, openAIConfiguration.ApiKey);
});

builder.Services.AddTransient<TimePlugin>();

//builder.Services.AddSingleton<ProfileDataFetchPlugin>();
builder.Services.AddKeyedTransient<ProfileScoringPlugin>(nameof(ProfileScoringPlugin));

builder.Services.AddTransient<UIComponentLibraryPlugin>();
builder.Services.AddKeyedTransient(
    "IAUIKKernel",
    (sp, key) =>
    {
        KernelPluginCollection kernelFunctions = [];
        kernelFunctions.AddFromObject(sp.GetRequiredService<TimePlugin>());
        //kernelFunctions.AddFromObject(sp.GetRequiredService<ProfileDataFetchPlugin>());
        kernelFunctions.AddFromObject(
            sp.GetRequiredKeyedService<ProfileScoringPlugin>(nameof(ProfileScoringPlugin))
        );
        kernelFunctions.AddFromObject(sp.GetRequiredService<UIComponentLibraryPlugin>());

        return new Kernel(sp, kernelFunctions);
    }
);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

//await app.Services.GetRequiredService<IDataSeeder>().SeedData();
await app.Services.GetRequiredService<IProfileScoringService>().GetUIComponentLibrariesAsync();

Yaml Prompt Template:

name: PromptTemplateTest
template: |
  <message role="system">
  The current time is {{TimePlugin.get_time}}
  </message>
template_format: handlebars
description: This is a test template to check the functionality of the PromptTemplate.
input_variables:
  - name: user
    description: user profile information.
    is_required: true
    allow_dangerously_set_content: false
output_variable:
  description: The output will be in json format. It will contain the userId, profileScore, uiComponents, theme, languageCode and localizationLanguageCode.

TimePlugin:

namespace IAUI.Agent.Plugins.FunctionPlugin;

using System.ComponentModel;

public class TimePlugin()
{
    [KernelFunction("get_time")]
    [Description("Get the current time.")]
    public string GetTime()
    {
        return DateTime.Now.ToString("HH:mm:ss");
    }

    [KernelFunction("get_date")]
    [Description("Get the current date.")]
    public string GetDate()
    {
        return DateTime.Now.ToString("yyyy-MM-dd");
    }

    [KernelFunction("get_date_with_format")]
    [Description("Get the current date with requested fornmat")]
    public string GetDate(
        [Description(
            "contains the desired date time format in which the output date time should be"
        )]
            string format
    )
    {
        return DateTime.Now.ToString(format);
    }

    [KernelFunction("get_time_and_date")]
    [Description("Get the current time and date.")]
    public string GetTimeAndDate()
    {
        return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }

    [KernelFunction("get_time_and_date_with_format")]
    [Description("Get the current time and date with requested format.")]
    public string GetTimeAndDate(
        [Description("Desired format in which the current datetime has to be converted to")]
            string format
    )
    {
        return DateTime.Now.ToString(format);
    }

    [KernelFunction("get_local_time_zone")]
    [Description("Get the local time zone.")]
    public string GetLocalTimeZone()
    {
        return TimeZoneInfo.Local.DisplayName;
    }

    [KernelFunction("get_local_time_zone_iana")]
    [Description("Get the local time zone in IANA format.")]
    public string GetLocalTimeZoneIana()
    {
        return TimeZoneInfo.Local.Id;
    }

    [KernelFunction("convert_to_desired_time_zone")]
    [Description("Convert the given time to the desired time zone.")]
    public string ConvertToDesiredTimeZone(
        [Description("date time to be converted")] string time,
        [Description("source datetime time zone")] string sourceTimeZone,
        [Description("desired datetime time zone to which the conversion should happen")]
            string destinationTimeZone
    )
    {
        DateTime dateTime = DateTime.Parse(time);
        TimeZoneInfo sourceTZ = TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone);
        TimeZoneInfo destinationTZ = TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZone);

        dateTime = TimeZoneInfo.ConvertTime(dateTime, sourceTZ, destinationTZ);
        return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
    }

    [KernelFunction("get_time_in_time_zone")]
    [Description("Get the current time in the given time zone.")]
    public string GetCurrentTimeInTimeZone(
        [Description("Desired timezone in which we want the current time to be")] string timeZone
    )
    {
        DateTime dateTime = DateTime.UtcNow;
        TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
        dateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime, timeZoneInfo);
        return dateTime.ToString("HH:mm:ss");
    }

    [KernelFunction("get_current_date_time_in_time_zone")]
    [Description("Get the current time in the given time zone.")]
    public string GetCurrentDateTimeInTimeZone(
        [Description("Desired timezone in which we want the current datetime to be")]
            string timeZone
    )
    {
        DateTime dateTime = DateTime.UtcNow;
        TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
        dateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime, timeZoneInfo);
        return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
    }

    [KernelFunction("Get_Date_Time_In_Date_Time_Offset")]
    [Description("Get the Date time offset for the given Date Time.")]
    public DateTimeOffset GetDateTimeInDateTimeOffset(
        [Description("date time to be converted to date time offset")] string dateTime
    )
    {
        return DateTimeOffset.Parse(dateTime);
    }
}

Expected behavior:

The LLM should call the function as instructed to get the current use time during the kernel invocation

Platform

  • Language: [C#]
  • Source:
     <PackageReference Include="Microsoft.SemanticKernel" Version="1.48.0" />
     <PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.49.0-alpha" />
     <PackageReference Include="Microsoft.SemanticKernel.PromptTemplates.Handlebars" Version="1.48.0" />
     <PackageReference Include="Microsoft.SemanticKernel.Yaml" Version="1.48.0" />
  • AI model: [gpt-4o, gpt-4.1-mini, gpt-4.1, gpt-4o-mini]
  • IDE: [ VS Code]
  • OS: Mac]

Additional context:

my github repo

Metadata

Metadata

Labels

.NETIssue or Pull requests regarding .NET codeBuildFeatures planned for next Build conferencebugSomething isn't working

Type

Projects

Status

Bug

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions