diff --git a/app/MindWork AI Studio/Chat/ContentText.cs b/app/MindWork AI Studio/Chat/ContentText.cs
index 93d0fcb2..9daeec49 100644
--- a/app/MindWork AI Studio/Chat/ContentText.cs
+++ b/app/MindWork AI Studio/Chat/ContentText.cs
@@ -229,11 +229,15 @@ public sealed class ContentText : IContent
if(this.FileAttachments.Count > 0)
{
+ var normalizedAttachments = this.FileAttachments
+ .Select(attachment => attachment.Normalize())
+ .ToList();
+
// Get the list of existing documents:
- var existingDocuments = this.FileAttachments.Where(x => x.Type is FileAttachmentType.DOCUMENT && x.Exists).ToList();
+ var existingDocuments = normalizedAttachments.Where(x => x.Type is FileAttachmentType.DOCUMENT && x.Exists).ToList();
// Log warning for missing files:
- var missingDocuments = this.FileAttachments.Except(existingDocuments).Where(x => x.Type is FileAttachmentType.DOCUMENT).ToList();
+ var missingDocuments = normalizedAttachments.Except(existingDocuments).Where(x => x.Type is FileAttachmentType.DOCUMENT).ToList();
if (missingDocuments.Count > 0)
foreach (var missingDocument in missingDocuments)
LOGGER.LogWarning("File attachment no longer exists and will be skipped: '{MissingDocument}'.", missingDocument.FilePath);
@@ -269,7 +273,7 @@ public sealed class ContentText : IContent
sb.AppendLine("````");
}
- var numImages = this.FileAttachments.Count(x => x is { IsImage: true, Exists: true });
+ var numImages = normalizedAttachments.Count(x => x is { IsImage: true, Exists: true });
if (numImages > 0)
{
sb.AppendLine();
diff --git a/app/MindWork AI Studio/Chat/FileAttachment.cs b/app/MindWork AI Studio/Chat/FileAttachment.cs
index 10e506d8..bdc9651d 100644
--- a/app/MindWork AI Studio/Chat/FileAttachment.cs
+++ b/app/MindWork AI Studio/Chat/FileAttachment.cs
@@ -53,6 +53,11 @@ public record FileAttachment(FileAttachmentType Type, string FileName, string Fi
///
public bool Exists => File.Exists(this.FilePath);
+ ///
+ /// Rebuilds the attachment from its current file path so file type detection uses the latest rules.
+ ///
+ public FileAttachment Normalize() => FromPath(this.FilePath);
+
///
/// Creates a FileAttachment from a file path by automatically determining the type,
/// extracting the filename, and reading the file size.
diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor.cs b/app/MindWork AI Studio/Components/ChatComponent.razor.cs
index f734d620..c4b30a2f 100644
--- a/app/MindWork AI Studio/Components/ChatComponent.razor.cs
+++ b/app/MindWork AI Studio/Components/ChatComponent.razor.cs
@@ -94,7 +94,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
// Apply template's file attachments, if any:
foreach (var attachment in this.currentChatTemplate.FileAttachments)
- this.chatDocumentPaths.Add(attachment);
+ this.chatDocumentPaths.Add(attachment.Normalize());
//
// Check for deferred messages of the kind 'SEND_TO_CHAT',
@@ -392,7 +392,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
// Apply template's file attachments (replaces existing):
this.chatDocumentPaths.Clear();
foreach (var attachment in this.currentChatTemplate.FileAttachments)
- this.chatDocumentPaths.Add(attachment);
+ this.chatDocumentPaths.Add(attachment.Normalize());
if(this.ChatThread is null)
return;
@@ -538,10 +538,15 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
IContent? lastUserPrompt;
if (!reuseLastUserPrompt)
{
+ var normalizedAttachments = this.chatDocumentPaths
+ .Select(attachment => attachment.Normalize())
+ .Where(attachment => attachment.IsValid)
+ .ToList();
+
lastUserPrompt = new ContentText
{
Text = this.userInput,
- FileAttachments = [..this.chatDocumentPaths.Where(x => x.IsValid)],
+ FileAttachments = normalizedAttachments,
};
//
@@ -764,7 +769,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
// Apply template's file attachments:
this.chatDocumentPaths.Clear();
foreach (var attachment in this.currentChatTemplate.FileAttachments)
- this.chatDocumentPaths.Add(attachment);
+ this.chatDocumentPaths.Add(attachment.Normalize());
// Now, we have to reset the data source options as well:
this.ApplyStandardDataSourceOptions();
diff --git a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs
index 0aa16ddf..cbc438cf 100644
--- a/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/ChatTemplateDialog.razor.cs
@@ -133,7 +133,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
SystemPrompt = this.DataSystemPrompt,
PredefinedUserPrompt = this.PredefinedUserPrompt,
ExampleConversation = this.dataExampleConversation,
- FileAttachments = [..this.fileAttachments],
+ FileAttachments = this.fileAttachments.Select(attachment => attachment.Normalize()).ToList(),
AllowProfileUsage = this.AllowProfileUsage,
EnterpriseConfigurationPluginId = Guid.Empty,
diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md b/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md
index bc67a032..115c3edd 100644
--- a/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md
+++ b/app/MindWork AI Studio/wwwroot/changelog/v26.3.1.md
@@ -25,6 +25,7 @@
- Improved the app startup resilience by allowing AI Studio to continue without Qdrant if it fails to initialize.
- Improved the translation assistant by updating the system and user prompts.
- Fixed an issue where assistants hidden via configuration plugins still appear in "Send to ..." menus. Thanks, Gunnar, for reporting this issue.
+- Fixed an issue with chat templates that could stop working because the stored validation result for attached files was reused. AI Studio now checks attached files again when you use a chat template.
- Fixed an issue with voice recording where AI Studio could log errors and keep the feature available even though required parts failed to initialize. Voice recording is now disabled automatically for the current session in that case.
- Fixed an issue where the app could turn white or appear invisible in certain chats after HTML-like content was shown. Thanks, Inga, for reporting this issue and providing some context on how to reproduce it.
- Fixed security issues in the native app runtime by strengthening how AI Studio creates and protects the secret values used for its internal secure connection.