skip to Main Content

I’m receiving data from a client that represents a function in a ChaptGPT api request, viewable here: https://platform.openai.com/docs/api-reference/chat/create.

I would expect the received JSON to be parsed by Newtonsoft.Json and then for the JSchema parsing to happen during the JSON parsing, but it seems that perhaps JSchema parsing is happening before the normal JSON parsing, and that my [JsonIgnore] attribute is, ironically, being ignored by the JSchema parsing.

Here are my primary questions:

  • Why does handling json1 in the below for loop cause an error?
  • Why does the JSchema parser expect an object or a boolean when the type of ParametersJson is string?
  • Is there not a practical way to encode the JSON like I have it in json1 and have it all deserialized how I expect it to be, without error? I’d like to keep the JSON schema represented as a string on the clientside.

Here is the error: Unhandled exception. Newtonsoft.Json.Schema.JSchemaReaderException: Unexpected token encountered when reading schema. Expected StartObject, Boolean, got String. Path 'parameters', line 7, position 9. at Newtonsoft.Json.Schema.Infrastructure.JSchemaReader.EnsureToken(JsonReader reader, String name, List`1 tokenTypes, String errorMessage)

Here is the .NET Fiddle: https://dotnetfiddle.net/GE8OMP

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Schema;

public class Program
{
    public static void Main()
    {
        string json0 = @"
{
    'Name': 'TestFunction',
    'Description': 'This is a test function.',
    'parameters': 
    {
        'type': 'object', 
        'properties': 
        {
            'prop1': 
            {
                'type': 'string'
            }
        }
    }
}".Replace("'", """);
        string json1 = @"
{
    'Name': 'TestFunction',
    'Description': 'This is a test function.',
    'parameters': 
    '{
        'type': 'object', 
        'properties': 
        {
            'prop1': 
            {
                'type': 'string'
            }
        }
    }'
}".Replace("'", """);
        var arr = new[]{json0, json1};
        foreach (var json in arr)
        {
            Function deserializedFunction = JsonConvert.DeserializeObject<Function>(json);
            Console.WriteLine($"Name: {deserializedFunction.Name}");
            Console.WriteLine($"Description: {deserializedFunction.Description}");
            Console.WriteLine($"Parameters: {deserializedFunction.Parameters}");
            Console.WriteLine("-------------");
        }
    }
}

#nullable enable
public class Function
{
    /// <summary>
    /// The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// A description of what the function does, used by the model to choose when and how to call the function.
    /// </summary>
    public string? Description { get; set; }

    /// <summary>
    /// The parameters the functions accepts, described as a JSON Schema object.
    /// <br></br>
    /// <br></br>
    /// To describe a function that accepts no parameters, provide the value {"type": "object", "properties": { } }.
    /// </summary>
     // Need to convert from string coming from client to the JSchema object.
    [JsonIgnore]
    public JSchema Parameters { get; set; }

    [JsonProperty("parameters")]
    public string ParametersJson { get => Parameters.ToString(); set => Parameters = JSchema.Parse(value); }

    public Function(string name, string? description, JSchema parameters)
    {
        Name = name;
        Description = description;
        Parameters = parameters;
    }
}

2

Answers


  1. IMHO you need to fix json1

        string json1 = @"
    {
        'Name': 'TestFunction',
        'Description': 'This is a test function.',
        'parameters': 
        '{
            'type': 'object', 
            'properties': 
            {
                'prop1': 
                {
                    'type': 'string'
                }
            }
        }'
    }".Replace("'{", "{").Replace("}'", "}").Replace("'", """);
    
    Login or Signup to reply.
  2. The first thing is your second JSON is invalid:

    1. The quotes in the value for the parameters are needed to be escaped (").

    2. The string value cannot be with multiple lines in the JSON.

    The correct JSON should be:

    {
        "Name": "TestFunction",
        "Description": "This is a test function.",
        "parameters": "{"type": "object", "properties": {"prop1": {"type": "string"}}}"
    }
    

    Assume that you have fixed the JSON issues, for the constructor you should handle the parameters with multiple types:

    1. Change the parameters type to JToken in the constructor to allow the value in multiple types.

    2. Handle the parameters.Type for different JTokenType (String, Object).

    public Function(string name, string? description, JToken parameters)
    {
        Name = name;
        Description = description;
            
        if (parameters.Type == JTokenType.String)
        {
            Parameters = JSchema.Parse(parameters.ToString());
        }
        else if (parameters.Type == JTokenType.Object)
        {
            Parameters = parameters.ToObject<JSchema>();
        }
    }
    

    Note the if-else statement for handling different JTokenType can also simplified to:

    Parameters = JSchema.Parse(parameters.ToString());
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search