microsoft / semantic-kernel

Integrate cutting-edge LLM technology quickly and easily into your apps
https://aka.ms/semantic-kernel
MIT License
21.31k stars 3.13k forks source link

.Net: HandlebarsPlanner JsonException #6013

Open rborosak opened 4 months ago

rborosak commented 4 months ago

Describe the bug When invoking CreatePlanAsync of the HandlebarsPlanner I get an exception

System.Text.Json.JsonException: 'The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1.'
InvalidOperationException: Cannot get the value of a token type 'StartArray' as a string.

To Reproduce Create an empty console app. Add Microsoft.SemanticKernel v1.9.0 nuget package Add Microsoft.SemanticKernel .Planners.OpenAI v 1.9.0-preview nugetpackage

var _kernel = Kernel.CreateBuilder().AddOpenAIChatCompletion("gpt-3.5-turbo", openAiApiKey, openAiOrg).Build();
_kernel.Plugins.AddFromType<CinemaPlugin>();

var planner = new HandlebarsPlanner(new HandlebarsPlannerOptions() { AllowLoops = false });
var plan = await planner.CreatePlanAsync(_kernel, "How to make a movie reservation");

CinemaPlugin

 public class CinemaPlugin
 {
     [KernelFunction]
     public async Task<string> MakeAMoviewReservation(DateTime? date)
     {
         return "Done";
     }
}

Expected behavior The plan should be created

Screenshots If applicable, add screenshots to help explain your problem.

Platform

Additional context

It works If I leave out the plugin registration. (If I comment this line _kernel.Plugins.AddFromType();)

teresaqhoang commented 4 months ago

Hi @rborosak , can you provide a sample plan and the prompt the Planner used?

You can get both from the HandlebarsPlan object:

rborosak commented 4 months ago

@teresaqhoang No, beacuse planner.CreatePlanAsync throws an exception.

teresaqhoang commented 4 months ago

@rborosak ah I see. The Planner should throw a PlanCreationException, so you should be able to wrap the Planner call in a try catch block and get the details that way.

try
{
     await planner.CreatePlanAsync(kernel, "goal")
}
catch (PlanCreationException e)
{
     Console.WriteLine(e.Message);
     Console.WriteLine(e.InnerException?.Message);

     // Invalid Plan object
     Console.WriteLine(exception?.ModelResults?.Content);

     // Prompt
     Console.WriteLine(exception?.CreatePlanPrompt);
}
NickDrouin commented 4 months ago

Same for me, after update to latest:
Cannot get the value of a token type 'StartArray' as a string.

The exception from a wrap of CreatePlanAsync is {System.Text.Json.JsonException}

NickDrouin commented 4 months ago

Found it, @rborosak , @teresaqhoang

In here:


    public static KernelParameterMetadata ParseJsonSchema(this KernelParameterMetadata parameter)
    {
        var schema = parameter.Schema!;

        var type = "object";
        if (schema.RootElement.TryGetProperty("type", out var typeNode))
        {
            type = typeNode.Deserialize<string>()!;
        }

        if (IsPrimitiveOrStringType(type) || type == "null")
        {
            return new(parameter)
            {
                ParameterType = GetTypeFromSchema(type),
                Schema = null,
            };
        }

        return parameter;
    }

Throws on type = typeNode.Deserialize<string>()!; because typeNode has a ValueKind: array:

My Schema is:

{
  "type": [
    "integer",
    "null"
  ],
  "description": "The number of the frame"
}

For this plugin definition:

    [KernelFunction("ConvertFrameToUri")]
    [Description("Provide the Uri when given a frame number")]
    public string ConvertFrameToUri([Description("The number of the frame")] long? number1)
    {
    ...
    }

As you can see, I am using the nullable long? .

The above is while debugging with local sources detached at the commit for 1.10.

This is a regression for me, I will attempt to work-around without the nullable types in my plugins.

Edit: Removing nullable types worked around this successfully.

github-actions[bot] commented 1 month ago

This issue is stale because it has been open for 90 days with no activity.