diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicMessage.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicMessage.cs index 489958d43..a55840454 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicMessage.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicMessage.cs @@ -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. /// -public sealed record AnthropicMessage(IList Content, string Role = "assistant") : IMessage>; \ No newline at end of file +public sealed record AnthropicMessage(IList Content, string Role = "assistant") : IMessage> +{ + // + // 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 Content { get; set; } = Content; + public string Role { get; set; } = Role; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicStreamMessage.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicStreamMessage.cs index 660400f3e..fcf017e8b 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicStreamMessage.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicStreamMessage.cs @@ -14,5 +14,5 @@ public sealed record AnthropicStreamMessage /// /// What the request carried, where the stream states it. /// - public AnthropicUsage? Usage { get; init; } + public AnthropicUsage? Usage { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicTool.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicTool.cs index aca8c9012..7509412d7 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicTool.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicTool.cs @@ -11,11 +11,11 @@ namespace AIStudio.Provider.Anthropic; /// 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; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultContent.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultContent.cs index 304aa5870..523eafdc0 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultContent.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultContent.cs @@ -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; /// /// 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. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool IsError { get; init; } + public bool IsError { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultMessage.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultMessage.cs index b634efb0b..0d44b2765 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultMessage.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolResultMessage.cs @@ -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. /// -public sealed record AnthropicToolResultMessage(IList Content, string Role = "user") : IMessage>; \ No newline at end of file +public sealed record AnthropicToolResultMessage(IList Content, string Role = "user") : IMessage> +{ + // + // 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 Content { get; set; } = Content; + public string Role { get; set; } = Role; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicUsage.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicUsage.cs index 70a9f7a87..5a9866d13 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/AnthropicUsage.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicUsage.cs @@ -23,17 +23,17 @@ public sealed record AnthropicUsage /// /// What the request carried after its last cache breakpoint, which is all of it without caching. /// - public int? InputTokens { get; init; } + public int? InputTokens { get; set; } /// /// What the request wrote to the cache. /// - public int? CacheCreationInputTokens { get; init; } + public int? CacheCreationInputTokens { get; set; } /// /// What the request read from the cache. /// - public int? CacheReadInputTokens { get; init; } + public int? CacheReadInputTokens { get; set; } /// /// States what this block reports, as far as it can be believed. diff --git a/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs b/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs index 99632e477..708b22bdb 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs @@ -10,7 +10,11 @@ namespace AIStudio.Provider.Anthropic; /// The maximum number of tokens to generate. /// Whether to stream the chat completion. /// The system prompt for the chat completion. -public readonly record struct ChatRequest( +/// +/// 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. +/// +public record struct ChatRequest( string Model, IList 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. /// [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IList? Tools { get; init; } + public IList? 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 AdditionalApiParameters { get; init; } = new Dictionary(); + public IDictionary AdditionalApiParameters { get; set; } = new Dictionary(); } diff --git a/app/MindWork AI Studio/Provider/Anthropic/SubContentBase64Image.cs b/app/MindWork AI Studio/Provider/Anthropic/SubContentBase64Image.cs index 8123c8146..beb0ae6c2 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/SubContentBase64Image.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/SubContentBase64Image.cs @@ -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; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Anthropic/SubContentImage.cs b/app/MindWork AI Studio/Provider/Anthropic/SubContentImage.cs index 074f5db0e..11321fd9c 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/SubContentImage.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/SubContentImage.cs @@ -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()) { } diff --git a/app/MindWork AI Studio/Provider/Anthropic/SubContentImageUrl.cs b/app/MindWork AI Studio/Provider/Anthropic/SubContentImageUrl.cs index 0247a40c0..21e10fa5a 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/SubContentImageUrl.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/SubContentImageUrl.cs @@ -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; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/EmbeddingResponse.cs b/app/MindWork AI Studio/Provider/EmbeddingResponse.cs index 6a6c6a86f..7e848f6fe 100644 --- a/app/MindWork AI Studio/Provider/EmbeddingResponse.cs +++ b/app/MindWork AI Studio/Provider/EmbeddingResponse.cs @@ -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? Data { get; init; } + public List? Data { get; set; } - public string? Model { get; init; } + public string? Model { get; set; } - public EmbeddingUsage? Usage { get; init; } + public EmbeddingUsage? Usage { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Google/GoogleEmbedding.cs b/app/MindWork AI Studio/Provider/Google/GoogleEmbedding.cs index 9a7d9b380..d57f491f2 100644 --- a/app/MindWork AI Studio/Provider/Google/GoogleEmbedding.cs +++ b/app/MindWork AI Studio/Provider/Google/GoogleEmbedding.cs @@ -2,5 +2,5 @@ public sealed record GoogleEmbedding { - public List? Values { get; init; } + public List? Values { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/Google/GoogleEmbeddingResponse.cs b/app/MindWork AI Studio/Provider/Google/GoogleEmbeddingResponse.cs index 24d9c175c..d45914a4e 100644 --- a/app/MindWork AI Studio/Provider/Google/GoogleEmbeddingResponse.cs +++ b/app/MindWork AI Studio/Provider/Google/GoogleEmbeddingResponse.cs @@ -6,9 +6,13 @@ namespace AIStudio.Provider.Google; public sealed record GoogleEmbeddingResponse { [JsonConverter(typeof(GoogleEmbeddingListConverter))] - public List? Embedding { get; init; } + public List? Embedding { get; set; } - private sealed class GoogleEmbeddingListConverter : JsonConverter> + /// + /// Internal rather than private: the JSON context of the providers has to reach the converter, else it reads + /// the embeddings without it. + /// + internal sealed class GoogleEmbeddingListConverter : JsonConverter> { public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/app/MindWork AI Studio/Provider/IMessage.cs b/app/MindWork AI Studio/Provider/IMessage.cs index 2a8c9e2f4..485f4413c 100644 --- a/app/MindWork AI Studio/Provider/IMessage.cs +++ b/app/MindWork AI Studio/Provider/IMessage.cs @@ -11,5 +11,5 @@ public interface IMessage : IMessageBase /// The content encapsulates the core information or data being transmitted, /// and its type can vary based on the specific implementation or use case. /// - public T Content { get; init; } + public T Content { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/IMessageBase.cs b/app/MindWork AI Studio/Provider/IMessageBase.cs index 8f67cc8b3..9da827275 100644 --- a/app/MindWork AI Studio/Provider/IMessageBase.cs +++ b/app/MindWork AI Studio/Provider/IMessageBase.cs @@ -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. /// - public string Role { get; init; } + public string Role { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/AssistantToolCallMessage.cs b/app/MindWork AI Studio/Provider/OpenAI/AssistantToolCallMessage.cs index cd4048789..a3cebb0b1 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/AssistantToolCallMessage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/AssistantToolCallMessage.cs @@ -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 ToolCalls { get; init; } = []; + public IList ToolCalls { get; set; } = []; } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionAPIRequest.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionAPIRequest.cs index 5c64ce441..60cc07473 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionAPIRequest.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionAPIRequest.cs @@ -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 Messages { get; set; } = Messages; + public bool Stream { get; set; } = Stream; + public ChatCompletionAPIRequest() : this(string.Empty, [], true) { } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IList? Tools { get; init; } + public IList? Tools { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public bool? ParallelToolCalls { get; init; } + public bool? ParallelToolCalls { get; set; } /// /// 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 AdditionalApiParameters { get; init; } = new Dictionary(); + public IDictionary AdditionalApiParameters { get; set; } = new Dictionary(); } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionChoice.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionChoice.cs index 22788bbeb..ae4a8e2b6 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionChoice.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionChoice.cs @@ -7,6 +7,14 @@ namespace AIStudio.Provider.OpenAI; /// The delta text of the choice. 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()) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDelta.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDelta.cs index 9f6f6cfcc..7981f0375 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDelta.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDelta.cs @@ -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; diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDeltaStreamLine.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDeltaStreamLine.cs index cdd1dfef7..663381561 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDeltaStreamLine.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionDeltaStreamLine.cs @@ -11,6 +11,19 @@ namespace AIStudio.Provider.OpenAI; /// The choices made by the AI. public record ChatCompletionDeltaStreamLine(string Id, string Object, uint Created, string Model, string SystemFingerprint, IList 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 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. /// - public ChatCompletionUsage? Usage { get; init; } + public ChatCompletionUsage? Usage { get; set; } /// public bool ContainsContent() => this.Choices.Count > 0; diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionDeclaration.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionDeclaration.cs index f00a4744c..cf3ab37ba 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionDeclaration.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionDeclaration.cs @@ -7,11 +7,11 @@ namespace AIStudio.Provider.OpenAI; /// 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; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionTool.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionTool.cs index 8441c296c..e4865dd21 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionTool.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionFunctionTool.cs @@ -5,7 +5,7 @@ namespace AIStudio.Provider.OpenAI; /// 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(); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionStreamDelta.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionStreamDelta.cs index 2949f9f75..6b7d6ab18 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionStreamDelta.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionStreamDelta.cs @@ -16,7 +16,7 @@ public sealed record ChatCompletionStreamDelta /// The content as it arrived: a string for most providers, a list of parts for some. /// [JsonPropertyName("content")] - public JsonElement? RawContent { get; init; } + public JsonElement? RawContent { get; set; } /// /// The text of this fragment, whichever shape it arrived in. @@ -27,10 +27,10 @@ public sealed record ChatCompletionStreamDelta /// /// The reasoning text some providers stream next to the answer. /// - public string? ReasoningContent { get; init; } + public string? ReasoningContent { get; set; } /// /// The fragments of the tool calls the model is asking for. /// - public IList? ToolCalls { get; init; } + public IList? ToolCalls { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolCall.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolCall.cs index 9c0a38c0d..651d6f37a 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolCall.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolCall.cs @@ -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 AdditionalMetadata { get; init; } = new Dictionary(); + public IDictionary AdditionalMetadata { get; set; } = new Dictionary(); } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolFunction.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolFunction.cs index 2d24971f5..5292876ff 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolFunction.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolFunction.cs @@ -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; } } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolStreamLine.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolStreamLine.cs index a0f0bbf82..d9404419e 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolStreamLine.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionToolStreamLine.cs @@ -21,5 +21,5 @@ public sealed record ChatCompletionToolStreamLine(string? Id, IList - public ChatCompletionUsage? Usage { get; init; } + public ChatCompletionUsage? Usage { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionUsage.cs b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionUsage.cs index 186cee76c..4b4b2f671 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionUsage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ChatCompletionUsage.cs @@ -17,7 +17,7 @@ public sealed record ChatCompletionUsage /// /// What everything sent to the model cost. /// - public int? PromptTokens { get; init; } + public int? PromptTokens { get; set; } /// /// States what this block reports, as far as it can be believed. diff --git a/app/MindWork AI Studio/Provider/OpenAI/ISubContent.cs b/app/MindWork AI Studio/Provider/OpenAI/ISubContent.cs index 165d07b1c..8472738db 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ISubContent.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ISubContent.cs @@ -8,5 +8,5 @@ public interface ISubContent /// /// The type of the sub-content. /// - public SubContentType Type { get; init; } + public SubContentType Type { get; set; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Provider/OpenAI/ISubContentImageUrl.cs b/app/MindWork AI Studio/Provider/OpenAI/ISubContentImageUrl.cs index b2f9b51df..3be1d5f53 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ISubContentImageUrl.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ISubContentImageUrl.cs @@ -15,5 +15,5 @@ public interface ISubContentImageUrl /// /// The URL or base64-encoded data URI of the image. /// - public string Url { get; init; } + public string Url { get; set; } } diff --git a/app/MindWork AI Studio/Provider/OpenAI/MultimodalMessage.cs b/app/MindWork AI Studio/Provider/OpenAI/MultimodalMessage.cs index 8b7ff8e0e..7b84f5283 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/MultimodalMessage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/MultimodalMessage.cs @@ -7,6 +7,15 @@ namespace AIStudio.Provider.OpenAI; /// The role of the message. public record MultimodalMessage(List Content, string Role) : IMessage> { + // + // 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 Content { get; set; } = Content; + public string Role { get; set; } = Role; + public MultimodalMessage() : this([], string.Empty) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponsesAPIRequest.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponsesAPIRequest.cs index 155400aef..8df508e2d 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ResponsesAPIRequest.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ResponsesAPIRequest.cs @@ -17,11 +17,26 @@ public record ResponsesAPIRequest( bool Store, IList 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 Input { get; set; } = Input; + public bool Stream { get; set; } = Stream; + public bool Store { get; set; } = Store; + public IList 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 AdditionalApiParameters { get; init; } = new Dictionary(); + public IDictionary AdditionalApiParameters { get; set; } = new Dictionary(); } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionCallOutputItem.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionCallOutputItem.cs index 19e9bedb4..a7c6b3701 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionCallOutputItem.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionCallOutputItem.cs @@ -5,9 +5,9 @@ namespace AIStudio.Provider.OpenAI; /// 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; } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionTool.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionTool.cs index fe9f5dc0a..c4c73bc01 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionTool.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ResponsesFunctionTool.cs @@ -7,13 +7,13 @@ namespace AIStudio.Provider.OpenAI; /// 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; } } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponsesResponse.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponsesResponse.cs index 91f106286..8f9eb16e8 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ResponsesResponse.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ResponsesResponse.cs @@ -17,18 +17,18 @@ public sealed record ResponsesResponse /// private static readonly HashSet 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 Output { get; init; } = []; + public IList Output { get; set; } = []; /// /// What OpenAI says the response cost. Only the completed response carries it. /// - public ResponsesUsage? Usage { get; init; } + public ResponsesUsage? Usage { get; set; } /// /// States what the request of this response carried, as far as it can be believed. diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponsesUsage.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponsesUsage.cs index 1a161ecb5..e9b24fd6a 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ResponsesUsage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ResponsesUsage.cs @@ -17,7 +17,7 @@ public sealed record ResponsesUsage /// /// What everything sent to the model cost, the cached part included. /// - public int? InputTokens { get; init; } + public int? InputTokens { get; set; } /// /// States what this block reports, as far as it can be believed. diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrl.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrl.cs index fe190fb8f..149d4878f 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrl.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrl.cs @@ -5,6 +5,15 @@ namespace AIStudio.Provider.OpenAI; /// 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) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlData.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlData.cs index af0ffc9ee..3e16eed81 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlData.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlData.cs @@ -13,5 +13,5 @@ namespace AIStudio.Provider.OpenAI; public record SubContentImageUrlData : ISubContentImageUrl { /// - public string Url { get; init; } = string.Empty; + public string Url { get; set; } = string.Empty; } diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlNested.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlNested.cs index 297a73fe4..80e87bd1f 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlNested.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentImageUrlNested.cs @@ -12,6 +12,15 @@ namespace AIStudio.Provider.OpenAI; /// 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()) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentInputImage.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentInputImage.cs index 211449524..44246525e 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentInputImage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentInputImage.cs @@ -8,6 +8,15 @@ namespace AIStudio.Provider.OpenAI; /// 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) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentInputText.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentInputText.cs index 30fb51d82..4e27b9e4a 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentInputText.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentInputText.cs @@ -8,6 +8,15 @@ namespace AIStudio.Provider.OpenAI; /// 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) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/SubContentText.cs b/app/MindWork AI Studio/Provider/OpenAI/SubContentText.cs index f94dd710e..f6bfb686c 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/SubContentText.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/SubContentText.cs @@ -5,6 +5,15 @@ namespace AIStudio.Provider.OpenAI; /// 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) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/TextMessage.cs b/app/MindWork AI Studio/Provider/OpenAI/TextMessage.cs index 0e75f87f5..36689a5a6 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/TextMessage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/TextMessage.cs @@ -7,6 +7,15 @@ namespace AIStudio.Provider.OpenAI; /// The role of the message. public record TextMessage(string Content, string Role) : IMessage { + // + // 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) { } diff --git a/app/MindWork AI Studio/Provider/OpenAI/ToolResultMessage.cs b/app/MindWork AI Studio/Provider/OpenAI/ToolResultMessage.cs index 3972ac09e..809a2de64 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ToolResultMessage.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ToolResultMessage.cs @@ -2,9 +2,9 @@ namespace AIStudio.Provider.OpenAI; public sealed record ToolResultMessage : IMessage { - 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; } diff --git a/app/MindWork AI Studio/Tools/Source.cs b/app/MindWork AI Studio/Tools/Source.cs index 0c75371e7..78bda4c21 100644 --- a/app/MindWork AI Studio/Tools/Source.cs +++ b/app/MindWork AI Studio/Tools/Source.cs @@ -5,4 +5,15 @@ namespace AIStudio.Tools; /// /// The title of the source. /// The URL of the source. -public record Source(string Title, string URL, SourceOrigin Origin) : ISource; \ No newline at end of file +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; +} \ No newline at end of file