Kernel chat history serialization sample -> issue with deserialization (fields/properties not deserializing to proper types) #6582
-
We are trying to serialize and de-serialize our chat history. I used the sample (https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/ChatCompletion/ChatHistorySerialization.cs) to serialize and deserialize Kernel ChatHistory. When deserialized, the metadata "ChatResponseMessage.FunctionToolCalls" key never gets deserialized to List. This is just one example, there are many fields/properties(nested as well) that dont get deserialized to proper types as the orginal chat history before serialization/deserialization. Its gets deserialized to ValueKind = Array : "[ Can anyone confirm, that the deserialization mechanism provided in the sample is considered complete and ok just the way it is? We want contextual prompts to be working and dont know if the contextual prompts will work based on chat history if the deserialization is incomplete? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
@EVENFLOW212 Since type of Metadata is Here is a code example how to handle public class MyMetadataConverter : JsonConverter<IReadOnlyDictionary<string, object?>>
{
public override IReadOnlyDictionary<string, object?>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dictionary = new Dictionary<string, object?>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}
string key = reader.GetString()!;
reader.Read();
object? value;
if (key.Equals("ChatResponseMessage.FunctionToolCalls", StringComparison.OrdinalIgnoreCase))
{
var array = JsonSerializer.Deserialize<JsonElement>(ref reader, options);
int length = array.GetArrayLength();
var ftcs = new List<ChatCompletionsToolCall>(length);
for (int i = 0; i < length; i++)
{
JsonElement e = array[i];
if (e.TryGetProperty("Id", out JsonElement id) &&
e.TryGetProperty("Name", out JsonElement name) &&
e.TryGetProperty("Arguments", out JsonElement arguments) &&
id.ValueKind == JsonValueKind.String &&
name.ValueKind == JsonValueKind.String &&
arguments.ValueKind == JsonValueKind.String)
{
ftcs.Add(new ChatCompletionsFunctionToolCall(id.GetString()!, name.GetString()!, arguments.GetString()!));
}
}
value = ftcs;
}
else
{
value = JsonSerializer.Deserialize<object?>(ref reader, options);
}
dictionary[key] = value;
}
throw new JsonException("Expected EndObject token");
}
public override void Write(Utf8JsonWriter writer, IReadOnlyDictionary<string, object?> value, JsonSerializerOptions options)
{ }
} And usage: var options = new JsonSerializerOptions();
options.Converters.Add(new MyMetadataConverter());
var deserialized = JsonSerializer.Deserialize<ChatMessageContent>(serialized, options); |
Beta Was this translation helpful? Give feedback.
-
Thanks @dmytrostruk for your quick response. We will take a look and come back. |
Beta Was this translation helpful? Give feedback.
@EVENFLOW212 Since type of Metadata is
IReadOnlyDictionary<string, object?>?
, I'm not sure it will be possible to handle all deserialization cases, because it can hold any type. ButChatResponseMessage.FunctionToolCalls
is our predefined metadata key, so maybe we can provide some default deserialization logic. Meanwhile, you can implement your ownJsonConverter<IReadOnlyDictionary<string, object?>>
and handle deserialization on your side in a way you need.Here is a code example how to handle
ChatResponseMessage.FunctionToolCalls
deserialization: