From fa3f2cd0b6d7c0be5e0f2b2c7257c2120a41a76e Mon Sep 17 00:00:00 2001 From: Vitali sharp8n Date: Thu, 1 Oct 2026 17:11:34 +0300 Subject: [PATCH] safe JsonContent --- .../Utilities/StringExtensions.cs | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs index 8e2fd9bb..764fb1c9 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Utilities/StringExtensions.cs @@ -69,7 +69,19 @@ public static class StringExtensions AllowTrailingCommas = true }; - return JsonSerializer.Deserialize(text, options); + // The payload usually comes from an LLM (tool-call arguments or a model's JSON answer) and is + // occasionally not valid JSON — e.g. an unquoted first key (`{skill: "x"}`) or two objects + // concatenated. A malformed payload must not throw out of a utility used across the whole + // turn loop: it is treated as absent, so the caller keeps going instead of the whole + // generation failing with a JsonException. + try + { + return JsonSerializer.Deserialize(text, options); + } + catch (JsonException) + { + return default; + } } public static string JsonArrayContent(this string text) @@ -90,7 +102,16 @@ public static class StringExtensions AllowTrailingCommas = true }; - return JsonSerializer.Deserialize(text, options); + // Same tolerance as JsonContent: model-produced JSON is best-effort input, not a + // contract, so invalid content yields no result rather than an unhandled exception. + try + { + return JsonSerializer.Deserialize(text, options); + } + catch (JsonException) + { + return default; + } } public static bool IsPrimitiveValue(this string value)