Given a record like public record Movie(string Title, int Year, ...);, when invoking the client with var movies = await client.CompleteAsync<Movie[]>(...) we get an exception:
Unhandled exception. System.ClientModel.ClientResultException: HTTP 400 (invalid_request_error: invalid_value)
Parameter: response_format.json_schema.name
Invalid 'response_format.json_schema.name': string does not match pattern. Expected a string that matches the pattern '^[a-zA-Z0-9_-]+$'.
at OpenAI.ClientPipelineExtensions.ProcessMessageAsync(ClientPipeline pipeline, PipelineMessage message, RequestOptions options)
at OpenAI.Chat.ChatClient.CompleteChatAsync(BinaryContent content, RequestOptions options)
at OpenAI.Chat.ChatClient.CompleteChatAsync(IEnumerable`1 messages, ChatCompletionOptions options, CancellationToken cancellationToken)
at Microsoft.Extensions.AI.OpenAIChatClient.CompleteAsync(IList`1 chatMessages, ChatOptions options, CancellationToken cancellationToken)
at Microsoft.Extensions.AI.OpenTelemetryChatClient.CompleteAsync(IList`1 chatMessages, ChatOptions options, CancellationToken cancellationToken)
at Microsoft.Extensions.AI.LoggingChatClient.CompleteAsync(IList`1 chatMessages, ChatOptions options, CancellationToken cancellationToken)
at Microsoft.Extensions.AI.ChatClientStructuredOutputExtensions.CompleteAsync[T](IChatClient chatClient, IList`1 chatMessages, JsonSerializerOptions serializerOptions, ChatOptions options, Nullable`1 useNativeJsonSchema, CancellationToken cancellationToken)
at Program.<Main>$(String[] args) in C:\Code\script\TypedChat.cs:line 39
at Program.<Main>(String[] args)
Reproduction Steps
var services = new ServiceCollection()
.AddChatClient(builder => builder
.Use(new OpenAI.OpenAIClient(configuration["OpenAI:Key"]!).AsChatClient("gpt-4o-mini")))
.BuildServiceProvider();
var movies = await client.CompleteAsync<Movie[]>("Top 5 movies from Christopher Nolan", useNativeJsonSchema: true);
Console.WriteLine(movies.Length);
public record Movie(string Title, int Year);
If you switch the type to be a wrapper type, things work, such as: public record MoviesResult(Movie[] Movies);.
Note that switching to a non-generic type such as public class Movies : List<Movie> { } also fails, but this time with:
Unhandled exception. System.ClientModel.ClientResultException: HTTP 400 (invalid_request_error: )
Parameter: response_format
Invalid schema for response_format 'Movies': schema must be a JSON Schema of 'type: "object"', got 'type: "array"'.
at OpenAI.ClientPipelineExtensions.ProcessMessageAsync(ClientPipeline pipeline, PipelineMessage message, RequestOptions options)
at OpenAI.Chat.ChatClient.CompleteChatAsync(BinaryContent content, RequestOptions options)
at OpenAI.Chat.ChatClient.CompleteChatAsync(IEnumerable`1 messages, ChatCompletionOptions options, CancellationToken cancellationToken)
In this case, it's due to the fact that OpenAI expects the root schema element to be an object, and the JSON exporter infers it to be an array instead. This can be solved by detecting this situation automatically and using a wrapper type automatically and unwrapping before returning, such as
public class Values<T>
{
public required T Data { get; set; }
}
Expected behavior
Typed chats work regardless of which T you are using: arrays, lists, dictionaries,etc. should all be supported and work as-is.
Actual behavior
Multiple failure modes depending on what types you are specifying for the result, with many "gotchas" to learn as a consequence. User doesn't fall in the proverbial pit of success :)
Regression?
No response
Known Workarounds
Use "Response" wrapper types always. Very annoying.
Description
Given a record like
public record Movie(string Title, int Year, ...);
, when invoking the client withvar movies = await client.CompleteAsync<Movie[]>(...)
we get an exception:Reproduction Steps
If you switch the type to be a wrapper type, things work, such as:
public record MoviesResult(Movie[] Movies);
.Note that switching to a non-generic type such as
public class Movies : List<Movie> { }
also fails, but this time with:In this case, it's due to the fact that OpenAI expects the root schema element to be an object, and the JSON exporter infers it to be an array instead. This can be solved by detecting this situation automatically and using a wrapper type automatically and unwrapping before returning, such as
Expected behavior
Typed chats work regardless of which T you are using: arrays, lists, dictionaries,etc. should all be supported and work as-is.
Actual behavior
Multiple failure modes depending on what types you are specifying for the result, with many "gotchas" to learn as a consequence. User doesn't fall in the proverbial pit of success :)
Regression?
No response
Known Workarounds
Use "Response" wrapper types always. Very annoying.
Configuration
SDK: 9.0.100-rc.1.24452.12
Other information
No response