diff --git a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs
index fb38cc4f..22d79441 100644
--- a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs
+++ b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs
@@ -21,7 +21,7 @@ public sealed class ProviderAlibabaCloud(ILogger logger) : BaseProvider("https:/
public override string InstanceName { get; set; } = "AlibabaCloud";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
index 7ff631fd..a09564df 100644
--- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
+++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
@@ -18,7 +18,7 @@ public sealed class ProviderAnthropic(ILogger logger) : BaseProvider("https://ap
public override string InstanceName { get; set; } = "Anthropic";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Anthropic/ResponseStreamLine.cs b/app/MindWork AI Studio/Provider/Anthropic/ResponseStreamLine.cs
index c42e131c..c74e13ea 100644
--- a/app/MindWork AI Studio/Provider/Anthropic/ResponseStreamLine.cs
+++ b/app/MindWork AI Studio/Provider/Anthropic/ResponseStreamLine.cs
@@ -13,7 +13,7 @@ public readonly record struct ResponseStreamLine(string Type, int Index, Delta D
public bool ContainsContent() => this != default && !string.IsNullOrWhiteSpace(this.Delta.Text);
///
- public string GetContent() => this.Delta.Text;
+ public ContentStreamChunk GetContent() => new(this.Delta.Text, []);
}
///
diff --git a/app/MindWork AI Studio/Provider/BaseProvider.cs b/app/MindWork AI Studio/Provider/BaseProvider.cs
index 32c0e621..cc81ab3c 100644
--- a/app/MindWork AI Studio/Provider/BaseProvider.cs
+++ b/app/MindWork AI Studio/Provider/BaseProvider.cs
@@ -63,7 +63,7 @@ public abstract class BaseProvider : IProvider, ISecretId
public abstract string InstanceName { get; set; }
///
- public abstract IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, CancellationToken token = default);
+ public abstract IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, CancellationToken token = default);
///
public abstract IAsyncEnumerable StreamImageCompletion(Model imageModel, string promptPositive, string promptNegative = FilterOperator.String.Empty, ImageURL referenceImageURL = default, CancellationToken token = default);
@@ -96,7 +96,7 @@ public abstract class BaseProvider : IProvider, ISecretId
/// A function that builds the request.
/// The cancellation token.
/// The status object of the request.
- protected async Task SendRequest(Func> requestBuilder, CancellationToken token = default)
+ private async Task SendRequest(Func> requestBuilder, CancellationToken token = default)
{
const int MAX_RETRIES = 6;
const double RETRY_DELAY_SECONDS = 4;
@@ -189,7 +189,7 @@ public abstract class BaseProvider : IProvider, ISecretId
return new HttpRateLimitedStreamResult(true, false, string.Empty, response);
}
- protected async IAsyncEnumerable StreamChatCompletionInternal(string providerName, Func> requestBuilder, [EnumeratorCancellation] CancellationToken token = default) where T : struct, IResponseStreamLine
+ protected async IAsyncEnumerable StreamChatCompletionInternal(string providerName, Func> requestBuilder, [EnumeratorCancellation] CancellationToken token = default) where T : struct, IResponseStreamLine
{
StreamReader? streamReader = null;
try
diff --git a/app/MindWork AI Studio/Provider/ContentStreamChunk.cs b/app/MindWork AI Studio/Provider/ContentStreamChunk.cs
new file mode 100644
index 00000000..c6b2e205
--- /dev/null
+++ b/app/MindWork AI Studio/Provider/ContentStreamChunk.cs
@@ -0,0 +1,16 @@
+namespace AIStudio.Provider;
+
+///
+/// A chunk of content from a content stream, along with its associated sources.
+///
+/// The text content of the chunk.
+/// The list of sources associated with the chunk.
+public sealed record ContentStreamChunk(string Content, IList Sources)
+{
+ ///
+ /// Implicit conversion to string.
+ ///
+ /// The content stream chunk.
+ /// The text content of the chunk.
+ public static implicit operator string(ContentStreamChunk chunk) => chunk.Content;
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs
index 57f74f4c..c7ab556f 100644
--- a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs
+++ b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs
@@ -20,7 +20,7 @@ public sealed class ProviderDeepSeek(ILogger logger) : BaseProvider("https://api
public override string InstanceName { get; set; } = "DeepSeek";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
index 22164e18..880804e0 100644
--- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
+++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
@@ -19,7 +19,7 @@ public class ProviderFireworks(ILogger logger) : BaseProvider("https://api.firew
public override string InstanceName { get; set; } = "Fireworks.ai";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Fireworks/ResponseStreamLine.cs b/app/MindWork AI Studio/Provider/Fireworks/ResponseStreamLine.cs
index b3832f51..e9da7a53 100644
--- a/app/MindWork AI Studio/Provider/Fireworks/ResponseStreamLine.cs
+++ b/app/MindWork AI Studio/Provider/Fireworks/ResponseStreamLine.cs
@@ -14,7 +14,7 @@ public readonly record struct ResponseStreamLine(string Id, string Object, uint
public bool ContainsContent() => this != default && this.Choices.Count > 0;
///
- public string GetContent() => this.Choices[0].Delta.Content;
+ public ContentStreamChunk GetContent() => new(this.Choices[0].Delta.Content, []);
}
///
diff --git a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs
index ad41804d..b9a997d6 100644
--- a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs
+++ b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs
@@ -20,7 +20,7 @@ public sealed class ProviderGWDG(ILogger logger) : BaseProvider("https://chat-ai
public override string InstanceName { get; set; } = "GWDG SAIA";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
index de1df964..7819614f 100644
--- a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
+++ b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs
@@ -20,7 +20,7 @@ public class ProviderGoogle(ILogger logger) : BaseProvider("https://generativela
public override string InstanceName { get; set; } = "Google Gemini";
///
- public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs
index 30d81ed0..8729b1d5 100644
--- a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs
+++ b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs
@@ -20,7 +20,7 @@ public class ProviderGroq(ILogger logger) : BaseProvider("https://api.groq.com/o
public override string InstanceName { get; set; } = "Groq";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs
index 09a95387..bc8a3832 100644
--- a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs
+++ b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs
@@ -20,7 +20,7 @@ public sealed class ProviderHelmholtz(ILogger logger) : BaseProvider("https://ap
public override string InstanceName { get; set; } = "Helmholtz Blablador";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs
index 659a8ca9..f0b312b9 100644
--- a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs
+++ b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs
@@ -25,7 +25,7 @@ public sealed class ProviderHuggingFace : BaseProvider
public override string InstanceName { get; set; } = "HuggingFace";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/IProvider.cs b/app/MindWork AI Studio/Provider/IProvider.cs
index 86a60913..cede6ca4 100644
--- a/app/MindWork AI Studio/Provider/IProvider.cs
+++ b/app/MindWork AI Studio/Provider/IProvider.cs
@@ -27,7 +27,7 @@ public interface IProvider
/// The settings manager instance to use.
/// The cancellation token.
/// The chat completion stream.
- public IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, CancellationToken token = default);
+ public IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, CancellationToken token = default);
///
/// Starts an image completion stream.
diff --git a/app/MindWork AI Studio/Provider/IResponseStreamLine.cs b/app/MindWork AI Studio/Provider/IResponseStreamLine.cs
index b3e7c284..366b9884 100644
--- a/app/MindWork AI Studio/Provider/IResponseStreamLine.cs
+++ b/app/MindWork AI Studio/Provider/IResponseStreamLine.cs
@@ -12,5 +12,17 @@ public interface IResponseStreamLine
/// Gets the content of the response line.
///
/// The content of the response line.
- public string GetContent();
+ public ContentStreamChunk GetContent();
+
+ ///
+ /// Checks if the response line contains any sources.
+ ///
+ /// True when the response line contains sources, false otherwise.
+ public bool ContainsSources() => false;
+
+ ///
+ /// Gets the sources of the response line.
+ ///
+ /// The sources of the response line.
+ public IList GetSources() => [];
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Provider/ISource.cs b/app/MindWork AI Studio/Provider/ISource.cs
new file mode 100644
index 00000000..38f3505d
--- /dev/null
+++ b/app/MindWork AI Studio/Provider/ISource.cs
@@ -0,0 +1,17 @@
+namespace AIStudio.Provider;
+
+///
+/// Data model for a source used in the response.
+///
+public interface ISource
+{
+ ///
+ /// The title of the source.
+ ///
+ public string Title { get; }
+
+ ///
+ /// The URL of the source.
+ ///
+ public string URL { get; }
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
index ed87d12f..db094210 100644
--- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
+++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
@@ -18,7 +18,7 @@ public sealed class ProviderMistral(ILogger logger) : BaseProvider("https://api.
public override string InstanceName { get; set; } = "Mistral";
///
- public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/NoProvider.cs b/app/MindWork AI Studio/Provider/NoProvider.cs
index 983ab875..b06ce2e0 100644
--- a/app/MindWork AI Studio/Provider/NoProvider.cs
+++ b/app/MindWork AI Studio/Provider/NoProvider.cs
@@ -19,7 +19,7 @@ public class NoProvider : IProvider
public Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) => Task.FromResult>([]);
- public async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatChatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatChatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
await Task.FromResult(0);
yield break;
diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
index b5f8f818..cc89d1b2 100644
--- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
+++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
@@ -22,7 +22,7 @@ public sealed class ProviderOpenAI(ILogger logger) : BaseProvider("https://api.o
public override string InstanceName { get; set; } = "OpenAI";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/OpenAI/ResponseStreamLine.cs b/app/MindWork AI Studio/Provider/OpenAI/ResponseStreamLine.cs
index 98b2b2d9..96f6fc46 100644
--- a/app/MindWork AI Studio/Provider/OpenAI/ResponseStreamLine.cs
+++ b/app/MindWork AI Studio/Provider/OpenAI/ResponseStreamLine.cs
@@ -15,7 +15,7 @@ public readonly record struct ResponseStreamLine(string Id, string Object, uint
public bool ContainsContent() => this != default && this.Choices.Count > 0;
///
- public string GetContent() => this.Choices[0].Delta.Content;
+ public ContentStreamChunk GetContent() => new(this.Choices[0].Delta.Content, []);
}
///
diff --git a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs
index e578b7f0..8193f237 100644
--- a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs
+++ b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs
@@ -29,7 +29,7 @@ public sealed class ProviderPerplexity(ILogger logger) : BaseProvider("https://a
public override string InstanceName { get; set; } = "Perplexity";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
index 3655fd15..db6766ac 100644
--- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
+++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
@@ -18,7 +18,7 @@ public sealed class ProviderSelfHosted(ILogger logger, Host host, string hostnam
public override string InstanceName { get; set; } = "Self-hosted";
///
- public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, isTrying: true);
diff --git a/app/MindWork AI Studio/Provider/Source.cs b/app/MindWork AI Studio/Provider/Source.cs
new file mode 100644
index 00000000..d666e375
--- /dev/null
+++ b/app/MindWork AI Studio/Provider/Source.cs
@@ -0,0 +1,8 @@
+namespace AIStudio.Provider;
+
+///
+/// Data model for a source used in the response.
+///
+/// The title of the source.
+/// The URL of the source.
+public record Source(string Title, string URL) : ISource;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Provider/SourceExtensions.cs b/app/MindWork AI Studio/Provider/SourceExtensions.cs
new file mode 100644
index 00000000..a99f213e
--- /dev/null
+++ b/app/MindWork AI Studio/Provider/SourceExtensions.cs
@@ -0,0 +1,35 @@
+using System.Text;
+
+using AIStudio.Tools.PluginSystem;
+
+namespace AIStudio.Provider;
+
+public static class SourceExtensions
+{
+ private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(SourceExtensions).Namespace, nameof(SourceExtensions));
+
+ ///
+ /// Converts a list of sources to a markdown-formatted string.
+ ///
+ /// The list of sources to convert.
+ /// A markdown-formatted string representing the sources.
+ public static string ToMarkdown(this IList sources)
+ {
+ var sb = new StringBuilder();
+ sb.Append("## ");
+ sb.AppendLine(TB("Sources"));
+
+ var sourceNum = 0;
+ foreach (var source in sources)
+ {
+ sb.Append($"- [{++sourceNum}] ");
+ sb.Append('[');
+ sb.Append(source.Title);
+ sb.Append("](");
+ sb.Append(source.URL);
+ sb.AppendLine(")");
+ }
+
+ return sb.ToString();
+ }
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Provider/X/ProviderX.cs b/app/MindWork AI Studio/Provider/X/ProviderX.cs
index 884c1007..9fc5ec90 100644
--- a/app/MindWork AI Studio/Provider/X/ProviderX.cs
+++ b/app/MindWork AI Studio/Provider/X/ProviderX.cs
@@ -20,7 +20,7 @@ public sealed class ProviderX(ILogger logger) : BaseProvider("https://api.x.ai/v
public override string InstanceName { get; set; } = "xAI";
///
- public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
+ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
{
// Get the API key:
var requestedSecret = await RUST_SERVICE.GetAPIKey(this);
diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.51.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.51.md
index d4936af5..f810950e 100644
--- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.51.md
+++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.51.md
@@ -2,6 +2,7 @@
- Added support for predefined chat templates in configuration plugins to help enterprises roll out consistent templates across the organization.
- Added the ability to choose between automatic and manual update installation to the app settings (default is manual).
- Added the ability to control the update installation behavior by configuration plugins.
+- Added the option for LLM providers to return citations.
- Improved memory usage in several areas of the app.
- Improved plugin management for configuration plugins so that hot reload detects when a provider or chat template has been removed.
- Improved the dialog for naming chats and workspaces to ensure valid inputs are entered.