Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add regex-based JSON string recognition and add more tests.
  • Loading branch information
eiriktsarpalis committed Jul 3, 2025
commit 77d324af616a4d7d2f20e0ead63af7082426d91e
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#pragma warning disable S2333 // Redundant modifiers should not be used
#pragma warning disable S3011 // Reflection should not be used to increase accessibility of classes, methods, or fields
#pragma warning disable SA1202 // Public members should come before private members
#pragma warning disable SA1203 // Constants should appear before fields

namespace Microsoft.Extensions.AI;

Expand Down Expand Up @@ -825,7 +826,7 @@ static bool IsAsyncMethod(MethodInfo method)
{
try
{
if (value is string potentiallyJsonString)
if (value is string text && IsPotentiallyJson(text))
{
Debug.Assert(typeInfo.Type != typeof(string), "string parameters should not enter this branch.");

Expand All @@ -834,7 +835,7 @@ static bool IsAsyncMethod(MethodInfo method)
// If it's not, we'll fall through to the default path that makes it valid JSON and then tries to deserialize.
try
{
return JsonSerializer.Deserialize(potentiallyJsonString, typeInfo);
return JsonSerializer.Deserialize(text, typeInfo);
}
catch (JsonException)
{
Expand Down Expand Up @@ -1038,6 +1039,35 @@ private record struct DescriptorKey(
AIJsonSchemaCreateOptions SchemaOptions);
}

/// <summary>
/// Quickly checks if the specified string is potentially JSON
/// by checking if the first non-whitespace characters are valid JSON start tokens.
/// </summary>
/// <param name="value">The string to check.</param>
/// <returns>If <see langword="false"/> then the string is definitely not valid JSON.</returns>
private static bool IsPotentiallyJson(string value) => PotentiallyJsonRegex().IsMatch(value);
#if NET
[GeneratedRegex(PotentiallyJsonRegexString, RegexOptions.IgnorePatternWhitespace)]
private static partial Regex PotentiallyJsonRegex();
#else
private static Regex PotentiallyJsonRegex() => _potentiallyJsonRegex;
private static readonly Regex _potentiallyJsonRegex = new(PotentiallyJsonRegexString, RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
#endif
private const string PotentiallyJsonRegexString = """
^\s* # Optional whitespace at the start of the string
( null # null literal
| false # false literal
| true # true literal
| \d # positive number
| -\d # negative number
| " # string
| \[ # start array
| { # start object
| // # Start of single-line comment
| /\* # Start of multi-line comment
)
""";

/// <summary>
/// Removes characters from a .NET member name that shouldn't be used in an AI function name.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,49 @@ public async Task Parameters_ToleratesJsonEncodedParameters()
AssertExtensions.EqualFunctionCallResults(15, result);
}

[Theory]
[InlineData(" null")]
[InlineData(" false ")]
[InlineData("true ")]
[InlineData("42")]
[InlineData("0.0")]
[InlineData("-1e15")]
[InlineData(" \"I am a string!\" ")]
[InlineData(" {}")]
[InlineData("[]")]
public async Task Parameters_ToleratesJsonStringParameters(string jsonStringParam)
{
AIFunction func = AIFunctionFactory.Create((JsonElement param) => param);
JsonElement expectedResult = JsonDocument.Parse(jsonStringParam).RootElement;

var result = await func.InvokeAsync(new()
{
["param"] = jsonStringParam
});

AssertExtensions.EqualFunctionCallResults(expectedResult, result);
}

[Theory]
[InlineData("")]
[InlineData(" \r\n")]
[InlineData("I am a string!")]
[InlineData("/* Code snippet */ int main(void) { return 0; }")]
[InlineData("let rec Y F x = F (Y F) x")]
[InlineData("+3")]
public async Task Parameters_ToleratesInvalidJsonStringParameters(string invalidJsonParam)
{
AIFunction func = AIFunctionFactory.Create((JsonElement param) => param);
JsonElement expectedResult = JsonDocument.Parse(JsonSerializer.Serialize(invalidJsonParam, JsonContext.Default.String)).RootElement;

var result = await func.InvokeAsync(new()
{
["param"] = invalidJsonParam
});

AssertExtensions.EqualFunctionCallResults(expectedResult, result);
}

[Fact]
public async Task Parameters_MappedByType_Async()
{
Expand Down
Loading