Made the JSON types of the providers settable instead of init-only

This commit is contained in:
Thorsten Sommer committed 2026-11-02 19:00:16 +01:00
1 parent 5d80d3894b
commit df09c1c753
44 files changed
+240 -81

No files matched your search

@@ -10,4 +10,12 @@ namespace AIStudio.Provider.Anthropic;
/// thinking blocks, and the thinking blocks have to return exactly as they arrived — reading and
/// rebuilding them would risk changing them.
/// </remarks>
public sealed record AnthropicMessage(IList<JsonElement> Content, string Role = "assistant") : IMessage<IList<JsonElement>>;
public sealed record AnthropicMessage(IList<JsonElement> Content, string Role = "assistant") : IMessage<IList<JsonElement>>
{
//
// The properties of the parameters, declared again to be settable, as the messages demand it. Keep them in
// the order of the parameters, which is the order they get written in:
//
public IList<JsonElement> Content { get; set; } = Content;
public string Role { get; set; } = Role;
}
@@ -14,5 +14,5 @@ public sealed record AnthropicStreamMessage
/// <summary>
/// What the request carried, where the stream states it.
/// </summary>
public AnthropicUsage? Usage { get; init; }
public AnthropicUsage? Usage { get; set; }
}
@@ -11,11 +11,11 @@ namespace AIStudio.Provider.Anthropic;
/// </remarks>
public sealed record AnthropicTool
{
public string Name { get; init; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; init; } = string.Empty;
public string Description { get; set; } = string.Empty;
public bool Strict { get; init; }
public bool Strict { get; set; }
public JsonElement InputSchema { get; init; }
public JsonElement InputSchema { get; set; }
}
@@ -4,11 +4,11 @@ namespace AIStudio.Provider.Anthropic;
public sealed record AnthropicToolResultContent
{
public string Type { get; init; } = "tool_result";
public string Type { get; set; } = "tool_result";
public string ToolUseId { get; init; } = string.Empty;
public string ToolUseId { get; set; } = string.Empty;
public string Content { get; init; } = string.Empty;
public string Content { get; set; } = string.Empty;
/// <summary>
/// Whether the tool failed rather than returning a result.
@@ -18,5 +18,5 @@ public sealed record AnthropicToolResultContent
/// result stays byte-identical to what earlier versions sent.
/// </remarks>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public bool IsError { get; init; }
public bool IsError { get; set; }
}
@@ -7,4 +7,12 @@ namespace AIStudio.Provider.Anthropic;
/// All results of one turn belong in a single message. Splitting them across several messages
/// teaches the model to stop asking for more than one tool at a time.
/// </remarks>
public sealed record AnthropicToolResultMessage(IList<AnthropicToolResultContent> Content, string Role = "user") : IMessage<IList<AnthropicToolResultContent>>;
public sealed record AnthropicToolResultMessage(IList<AnthropicToolResultContent> Content, string Role = "user") : IMessage<IList<AnthropicToolResultContent>>
{
//
// The properties of the parameters, declared again to be settable, as the messages demand it. Keep them in
// the order of the parameters, which is the order they get written in:
//
public IList<AnthropicToolResultContent> Content { get; set; } = Content;
public string Role { get; set; } = Role;
}
@@ -23,17 +23,17 @@ public sealed record AnthropicUsage
/// <summary>
/// What the request carried after its last cache breakpoint, which is all of it without caching.
/// </summary>
public int? InputTokens { get; init; }
public int? InputTokens { get; set; }
/// <summary>
/// What the request wrote to the cache.
/// </summary>
public int? CacheCreationInputTokens { get; init; }
public int? CacheCreationInputTokens { get; set; }
/// <summary>
/// What the request read from the cache.
/// </summary>
public int? CacheReadInputTokens { get; init; }
public int? CacheReadInputTokens { get; set; }
/// <summary>
/// States what this block reports, as far as it can be believed.
@@ -10,7 +10,11 @@ namespace AIStudio.Provider.Anthropic;
/// <param name="MaxTokens">The maximum number of tokens to generate.</param>
/// <param name="Stream">Whether to stream the chat completion.</param>
/// <param name="System">The system prompt for the chat completion.</param>
public readonly record struct ChatRequest(
/// <remarks>
/// Not readonly, so that its properties can be settable: the source generation of System.Text.Json refuses to
/// write extension data which is init-only.
/// </remarks>
public record struct ChatRequest(
string Model,
IList<IMessageBase> Messages,
int MaxTokens,
@@ -26,9 +30,12 @@ public readonly record struct ChatRequest(
/// tools at all, and the final round of a tool conversation has to offer none.
/// </remarks>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IList<AnthropicTool>? Tools { get; init; }
public IList<AnthropicTool>? Tools { get; set; }
// Attention: The "required" modifier is not supported for [JsonExtensionData].
//
// Attention: The "required" modifier is not supported for [JsonExtensionData], and neither is init: the source
// generation of System.Text.Json refuses to write the request at all then.
//
[JsonExtensionData]
public IDictionary<string, object> AdditionalApiParameters { get; init; } = new Dictionary<string, object>();
public IDictionary<string, object> AdditionalApiParameters { get; set; } = new Dictionary<string, object>();
}
@@ -4,7 +4,7 @@ public record SubContentBase64Image : ISubContentImageSource
{
public SubContentImageType Type => SubContentImageType.BASE64;
public string MediaType { get; init; } = string.Empty;
public string MediaType { get; set; } = string.Empty;
public string Data { get; init; } = string.Empty;
public string Data { get; set; } = string.Empty;
}
@@ -4,6 +4,15 @@ namespace AIStudio.Provider.Anthropic;
public record SubContentImage(SubContentType Type, ISubContentImageSource Source) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public ISubContentImageSource Source { get; set; } = Source;
public SubContentImage() : this(SubContentType.IMAGE, new SubContentImageUrl())
{
}
@@ -4,5 +4,5 @@ public record SubContentImageUrl : ISubContentImageSource
{
public SubContentImageType Type => SubContentImageType.URL;
public string Url { get; init; } = string.Empty;
public string Url { get; set; } = string.Empty;
}
@@ -2,13 +2,13 @@
public sealed record EmbeddingResponse
{
public string? Id { get; init; }
public string? Id { get; set; }
public string? Object { get; init; }
public string? Object { get; set; }
public List<EmbeddingData>? Data { get; init; }
public List<EmbeddingData>? Data { get; set; }
public string? Model { get; init; }
public string? Model { get; set; }
public EmbeddingUsage? Usage { get; init; }
public EmbeddingUsage? Usage { get; set; }
}
@@ -2,5 +2,5 @@
public sealed record GoogleEmbedding
{
public List<float>? Values { get; init; }
public List<float>? Values { get; set; }
}
@@ -6,9 +6,13 @@ namespace AIStudio.Provider.Google;
public sealed record GoogleEmbeddingResponse
{
[JsonConverter(typeof(GoogleEmbeddingListConverter))]
public List<GoogleEmbedding>? Embedding { get; init; }
public List<GoogleEmbedding>? Embedding { get; set; }
private sealed class GoogleEmbeddingListConverter : JsonConverter<List<GoogleEmbedding>>
/// <remarks>
/// Internal rather than private: the JSON context of the providers has to reach the converter, else it reads
/// the embeddings without it.
/// </remarks>
internal sealed class GoogleEmbeddingListConverter : JsonConverter<List<GoogleEmbedding>>
{
public override List<GoogleEmbedding> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
+1 -1
View File
@@ -11,5 +11,5 @@ public interface IMessage<T> : IMessageBase
/// The content encapsulates the core information or data being transmitted,
/// and its type can vary based on the specific implementation or use case.
/// </summary>
public T Content { get; init; }
public T Content { get; set; }
}
@@ -10,5 +10,5 @@ public interface IMessageBase
/// This property typically identifies whether the entity is acting
/// as a user, assistant, or system in the context of the interaction.
/// </summary>
public string Role { get; init; }
public string Role { get; set; }
}
@@ -5,12 +5,12 @@ namespace AIStudio.Provider.OpenAI;
public sealed record AssistantToolCallMessage : IMessageBase
{
public string Role { get; init; } = "assistant";
public string Role { get; set; } = "assistant";
public JsonElement? Content { get; init; }
public JsonElement? Content { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ReasoningContent { get; init; }
public string? ReasoningContent { get; set; }
public IList<ChatCompletionToolCall> ToolCalls { get; init; } = [];
public IList<ChatCompletionToolCall> ToolCalls { get; set; } = [];
}
@@ -14,15 +14,25 @@ public record ChatCompletionAPIRequest(
bool Stream
)
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public string Model { get; set; } = Model;
public IList<IMessageBase> Messages { get; set; } = Messages;
public bool Stream { get; set; } = Stream;
public ChatCompletionAPIRequest() : this(string.Empty, [], true)
{
}
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IList<object>? Tools { get; init; }
public IList<object>? Tools { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public bool? ParallelToolCalls { get; init; }
public bool? ParallelToolCalls { get; set; }
/// <summary>
/// Asks a streamed request to end with what it cost.
@@ -35,7 +45,10 @@ public record ChatCompletionAPIRequest(
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public ChatCompletionStreamOptions? StreamOptions => this.Stream ? ChatCompletionStreamOptions.INCLUDE_USAGE : null;
// Attention: The "required" modifier is not supported for [JsonExtensionData].
//
// Attention: The "required" modifier is not supported for [JsonExtensionData], and neither is init: the source
// generation of System.Text.Json refuses to write the request at all then.
//
[JsonExtensionData]
public IDictionary<string, object> AdditionalApiParameters { get; init; } = new Dictionary<string, object>();
public IDictionary<string, object> AdditionalApiParameters { get; set; } = new Dictionary<string, object>();
}
@@ -7,6 +7,14 @@ namespace AIStudio.Provider.OpenAI;
/// <param name="Delta">The delta text of the choice.</param>
public record ChatCompletionChoice(int Index, ChatCompletionDelta Delta)
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters:
//
public int Index { get; set; } = Index;
public ChatCompletionDelta Delta { get; set; } = Delta;
public ChatCompletionChoice() : this(0, new())
{
}
@@ -9,7 +9,7 @@ namespace AIStudio.Provider.OpenAI;
public sealed record ChatCompletionDelta
{
[JsonPropertyName("content")]
public JsonElement? RawContent { get; init; }
public JsonElement? RawContent { get; set; }
[JsonIgnore]
public string Content => ChatCompletionContent.GetText(this.RawContent) ?? string.Empty;
@@ -11,6 +11,19 @@ namespace AIStudio.Provider.OpenAI;
/// <param name="Choices">The choices made by the AI.</param>
public record ChatCompletionDeltaStreamLine(string Id, string Object, uint Created, string Model, string SystemFingerprint, IList<ChatCompletionChoice> Choices) : IResponseStreamLine
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost, e.g., the empty list of choices of the line which carries the
// usage. Keep them first and in the order of the parameters:
//
public string Id { get; set; } = Id;
public string Object { get; set; } = Object;
public uint Created { get; set; } = Created;
public string Model { get; set; } = Model;
public string SystemFingerprint { get; set; } = SystemFingerprint;
public IList<ChatCompletionChoice> Choices { get; set; } = Choices;
public ChatCompletionDeltaStreamLine() : this(string.Empty, string.Empty, 0, string.Empty, string.Empty, [])
{
}
@@ -25,7 +38,7 @@ public record ChatCompletionDeltaStreamLine(string Id, string Object, uint Creat
/// line of its own which carries no choices -- which is why the usage is read apart from the
/// content rather than next to it.
/// </remarks>
public ChatCompletionUsage? Usage { get; init; }
public ChatCompletionUsage? Usage { get; set; }
/// <inheritdoc />
public bool ContainsContent() => this.Choices.Count > 0;
@@ -7,11 +7,11 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public sealed record ChatCompletionFunctionDeclaration
{
public string Name { get; init; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; init; } = string.Empty;
public string Description { get; set; } = string.Empty;
public JsonElement Parameters { get; init; }
public JsonElement Parameters { get; set; }
public bool Strict { get; init; }
public bool Strict { get; set; }
}
@@ -5,7 +5,7 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public sealed record ChatCompletionFunctionTool
{
public string Type { get; init; } = "function";
public string Type { get; set; } = "function";
public ChatCompletionFunctionDeclaration Function { get; init; } = new();
public ChatCompletionFunctionDeclaration Function { get; set; } = new();
}
@@ -16,7 +16,7 @@ public sealed record ChatCompletionStreamDelta
/// The content as it arrived: a string for most providers, a list of parts for some.
/// </summary>
[JsonPropertyName("content")]
public JsonElement? RawContent { get; init; }
public JsonElement? RawContent { get; set; }
/// <summary>
/// The text of this fragment, whichever shape it arrived in.
@@ -27,10 +27,10 @@ public sealed record ChatCompletionStreamDelta
/// <summary>
/// The reasoning text some providers stream next to the answer.
/// </summary>
public string? ReasoningContent { get; init; }
public string? ReasoningContent { get; set; }
/// <summary>
/// The fragments of the tool calls the model is asking for.
/// </summary>
public IList<ChatCompletionToolCallDelta?>? ToolCalls { get; init; }
public IList<ChatCompletionToolCallDelta?>? ToolCalls { get; set; }
}
@@ -5,12 +5,12 @@ namespace AIStudio.Provider.OpenAI;
public sealed record ChatCompletionToolCall
{
public string? Id { get; init; }
public string? Id { get; set; }
public string? Type { get; init; } = "function";
public string? Type { get; set; } = "function";
public ChatCompletionToolFunction? Function { get; init; }
public ChatCompletionToolFunction? Function { get; set; }
[JsonExtensionData]
public IDictionary<string, JsonElement> AdditionalMetadata { get; init; } = new Dictionary<string, JsonElement>();
public IDictionary<string, JsonElement> AdditionalMetadata { get; set; } = new Dictionary<string, JsonElement>();
}
@@ -2,7 +2,7 @@ namespace AIStudio.Provider.OpenAI;
public sealed record ChatCompletionToolFunction
{
public string? Name { get; init; }
public string? Name { get; set; }
public string? Arguments { get; init; }
public string? Arguments { get; set; }
}
@@ -21,5 +21,5 @@ public sealed record ChatCompletionToolStreamLine(string? Id, IList<ChatCompleti
/// ChatCompletionAPIRequest asks for it, the requests of the tool rounds included. Not a
/// positional parameter, because nobody but the serializer ever builds this line.
/// </remarks>
public ChatCompletionUsage? Usage { get; init; }
public ChatCompletionUsage? Usage { get; set; }
}
@@ -17,7 +17,7 @@ public sealed record ChatCompletionUsage
/// <summary>
/// What everything sent to the model cost.
/// </summary>
public int? PromptTokens { get; init; }
public int? PromptTokens { get; set; }
/// <summary>
/// States what this block reports, as far as it can be believed.
@@ -8,5 +8,5 @@ public interface ISubContent
/// <summary>
/// The type of the sub-content.
/// </summary>
public SubContentType Type { get; init; }
public SubContentType Type { get; set; }
}
@@ -15,5 +15,5 @@ public interface ISubContentImageUrl
/// <summary>
/// The URL or base64-encoded data URI of the image.
/// </summary>
public string Url { get; init; }
public string Url { get; set; }
}
@@ -7,6 +7,15 @@ namespace AIStudio.Provider.OpenAI;
/// <param name="Role">The role of the message.</param>
public record MultimodalMessage(List<ISubContent> Content, string Role) : IMessage<List<ISubContent>>
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public List<ISubContent> Content { get; set; } = Content;
public string Role { get; set; } = Role;
public MultimodalMessage() : this([], string.Empty)
{
}
@@ -17,11 +17,26 @@ public record ResponsesAPIRequest(
bool Store,
IList<object> Tools)
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public string Model { get; set; } = Model;
public IList<object> Input { get; set; } = Input;
public bool Stream { get; set; } = Stream;
public bool Store { get; set; } = Store;
public IList<object> Tools { get; set; } = Tools;
public ResponsesAPIRequest() : this(string.Empty, [], true, false, [])
{
}
// Attention: The "required" modifier is not supported for [JsonExtensionData].
//
// Attention: The "required" modifier is not supported for [JsonExtensionData], and neither is init: the source
// generation of System.Text.Json refuses to write the request at all then.
//
[JsonExtensionData]
public IDictionary<string, object> AdditionalApiParameters { get; init; } = new Dictionary<string, object>();
public IDictionary<string, object> AdditionalApiParameters { get; set; } = new Dictionary<string, object>();
}
@@ -5,9 +5,9 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public sealed record ResponsesFunctionCallOutputItem
{
public string Type { get; init; } = "function_call_output";
public string Type { get; set; } = "function_call_output";
public string CallId { get; init; } = string.Empty;
public string CallId { get; set; } = string.Empty;
public string Output { get; init; } = string.Empty;
public string Output { get; set; } = string.Empty;
}
@@ -7,13 +7,13 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public sealed record ResponsesFunctionTool
{
public string Type { get; init; } = "function";
public string Type { get; set; } = "function";
public string Name { get; init; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; init; } = string.Empty;
public string Description { get; set; } = string.Empty;
public JsonElement Parameters { get; init; }
public JsonElement Parameters { get; set; }
public bool Strict { get; init; }
public bool Strict { get; set; }
}
@@ -17,18 +17,18 @@ public sealed record ResponsesResponse
/// </remarks>
private static readonly HashSet<string> OUTPUT_ITEMS_LEAVING_THE_INPUT_ALONE = ["message", "reasoning", "function_call"];
public string Id { get; init; } = string.Empty;
public string Id { get; set; } = string.Empty;
public string Model { get; init; } = string.Empty;
public string Model { get; set; } = string.Empty;
public string? OutputText { get; init; }
public string? OutputText { get; set; }
public IList<JsonElement> Output { get; init; } = [];
public IList<JsonElement> Output { get; set; } = [];
/// <summary>
/// What OpenAI says the response cost. Only the completed response carries it.
/// </summary>
public ResponsesUsage? Usage { get; init; }
public ResponsesUsage? Usage { get; set; }
/// <summary>
/// States what the request of this response carried, as far as it can be believed.
@@ -17,7 +17,7 @@ public sealed record ResponsesUsage
/// <summary>
/// What everything sent to the model cost, the cached part included.
/// </summary>
public int? InputTokens { get; init; }
public int? InputTokens { get; set; }
/// <summary>
/// States what this block reports, as far as it can be believed.
@@ -5,6 +5,15 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public record SubContentImageUrl(SubContentType Type, string ImageUrl) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public string ImageUrl { get; set; } = ImageUrl;
public SubContentImageUrl() : this(SubContentType.IMAGE_URL, string.Empty)
{
}
@@ -13,5 +13,5 @@ namespace AIStudio.Provider.OpenAI;
public record SubContentImageUrlData : ISubContentImageUrl
{
/// <inheritdoc />
public string Url { get; init; } = string.Empty;
public string Url { get; set; } = string.Empty;
}
@@ -12,6 +12,15 @@ namespace AIStudio.Provider.OpenAI;
/// </remarks>
public record SubContentImageUrlNested(SubContentType Type, ISubContentImageUrl ImageUrl) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public ISubContentImageUrl ImageUrl { get; set; } = ImageUrl;
public SubContentImageUrlNested() : this(SubContentType.IMAGE_URL, new SubContentImageUrlData())
{
}
@@ -8,6 +8,15 @@ namespace AIStudio.Provider.OpenAI;
/// </remarks>
public record SubContentInputImage(SubContentType Type, string ImageUrl) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public string ImageUrl { get; set; } = ImageUrl;
public SubContentInputImage() : this(SubContentType.INPUT_IMAGE, string.Empty)
{
}
@@ -8,6 +8,15 @@ namespace AIStudio.Provider.OpenAI;
/// </remarks>
public record SubContentInputText(SubContentType Type, string Text) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public string Text { get; set; } = Text;
public SubContentInputText() : this(SubContentType.INPUT_TEXT, string.Empty)
{
}
@@ -5,6 +5,15 @@ namespace AIStudio.Provider.OpenAI;
/// </summary>
public record SubContentText(SubContentType Type, string Text) : ISubContent
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public SubContentType Type { get; set; } = Type;
public string Text { get; set; } = Text;
public SubContentText() : this(SubContentType.TEXT, string.Empty)
{
}
@@ -7,6 +7,15 @@ namespace AIStudio.Provider.OpenAI;
/// <param name="Role">The role of the message.</param>
public record TextMessage(string Content, string Role) : IMessage<string>
{
//
// The properties of the parameters, declared again to be settable. The source generation of System.Text.Json
// sets every init-only property while it creates the object, also one missing in the JSON, so its value from
// the parameterless constructor would get lost. Keep them first and in the order of the parameters, which is
// the order they get written in:
//
public string Content { get; set; } = Content;
public string Role { get; set; } = Role;
public TextMessage() : this(string.Empty, string.Empty)
{
}
@@ -2,9 +2,9 @@ namespace AIStudio.Provider.OpenAI;
public sealed record ToolResultMessage : IMessage<string>
{
public string Role { get; init; } = "tool";
public string Role { get; set; } = "tool";
public string Content { get; init; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string ToolCallId { get; init; } = string.Empty;
public string ToolCallId { get; set; } = string.Empty;
}
+12 -1
View File
@@ -5,4 +5,15 @@ namespace AIStudio.Tools;
/// </summary>
/// <param name="Title">The title of the source.</param>
/// <param name="URL">The URL of the source.</param>
public record Source(string Title, string URL, SourceOrigin Origin) : ISource;
public record Source(string Title, string URL, SourceOrigin Origin) : ISource
{
//
// The properties of the parameters, declared again to be settable. A derived record which passes a value of
// its own to one of them, as the search results of Perplexity do with the origin, would otherwise lose it:
// the source generation of System.Text.Json sets every init-only property while it creates the object, also
// one missing in the JSON. Keep them in the order of the parameters, which is the order they get stored in:
//
public string Title { get; set; } = Title;
public string URL { get; set; } = URL;
public SourceOrigin Origin { get; set; } = Origin;
}