diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingArtifactService.Assembly.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingArtifactService.Assembly.cs
index 73821e83..17ad23de 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingArtifactService.Assembly.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingArtifactService.Assembly.cs
@@ -328,9 +328,7 @@ public sealed partial class VisualBriefingArtifactService
.GroupBy(contribution => contribution.Model, StringComparer.Ordinal)
.Select(group =>
{
- var roles = group.Select(contribution => contribution.Role)
- .Distinct()
- .Select(role => role is VisualBriefingModelRole.DESIGN ? "presentation" : "content");
+ var roles = group.Select(contribution => contribution.Role is VisualBriefingModelRole.DESIGN ? "presentation" : "content").Distinct(StringComparer.Ordinal);
return $"{group.Key} ({string.Join(", ", roles)})";
}));
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingBuildOrchestrator.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingBuildOrchestrator.cs
index 5adf277f..3a02cc20 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingBuildOrchestrator.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingBuildOrchestrator.cs
@@ -382,7 +382,7 @@ internal sealed partial class VisualBriefingBuildOrchestrator
};
var revision = await this.store.AddRevisionAsync(new(manifest.BriefingId, parentRevisionId, mode, manifest.Settings.Instruction,
- compiled.Data, compiled.TemplateHtml, compiled.Css, VisualBriefingModelNames.ExportLabel(provider.Model), "MindWork AI Studio",
+ compiled.Data, compiled.TemplateHtml, compiled.Css, VisualBriefingModelNames.ExportLabel(provider), "MindWork AI Studio",
content.ArtifactId, presentation.ArtifactId, build.BuildId, build.OperationId, contributions, revisionId, revisionCreatedAt, embeddedAssets,
content.AssetPlan, evidence.ArtifactId, plan.ArtifactId), token);
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingContentStage.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingContentStage.cs
index 6ef25782..1bb157a5 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingContentStage.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingContentStage.cs
@@ -51,7 +51,7 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
artifact.CreatedAtUtc = DateTimeOffset.UtcNow;
artifact.SourceCoverage = evidence.SourceCoverage;
artifact.StructuralSignature = plan.StructuralSignature;
- artifact.Model = VisualBriefingModelNames.ExportLabel(provider.Model);
+ artifact.Model = VisualBriefingModelNames.ExportLabel(provider);
artifact.Data = JsonSerializer.SerializeToElement(new
{
slots = artifact.Slots.ToDictionary(slot => slot.SlotId, slot => slot.Value, StringComparer.Ordinal),
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingEvidenceStage.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingEvidenceStage.cs
index 6a452c41..bdcd4574 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingEvidenceStage.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingEvidenceStage.cs
@@ -63,7 +63,7 @@ internal sealed class VisualBriefingEvidenceStage(StructuredLlmStageRunner stage
Tables = response.Tables,
SourceCoverage = response.SourceCoverage,
AssetPlan = response.AssetPlan,
- Model = VisualBriefingModelNames.ExportLabel(provider.Model),
+ Model = VisualBriefingModelNames.ExportLabel(provider),
};
await store.WriteEvidenceArtifactAsync(manifest.BriefingId, artifact, token);
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingModelNames.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingModelNames.cs
index 08029d33..8e620cfb 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingModelNames.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingModelNames.cs
@@ -1,17 +1,46 @@
using AIStudio.Provider;
+using ProviderSettings = AIStudio.Settings.Provider;
+
namespace AIStudio.Assistants.VisualBriefing;
///
-/// Produces export-safe model labels without exposing provider model identifiers.
+/// Produces export-safe provider and model labels.
///
internal static class VisualBriefingModelNames
{
///
- /// Returns the configured display name or a neutral fallback.
+ /// Returns the public provider family and configured model name.
///
- /// The selected provider model.
- /// An export-safe model label.
- internal static string ExportLabel(Model model) =>
- string.IsNullOrWhiteSpace(model.DisplayName) ? "Model" : model.DisplayName.Trim();
+ /// The selected provider and model.
+ /// An export-safe provider and model label.
+ internal static string ExportLabel(ProviderSettings provider) => $"{provider.UsedLLMProvider.ToName(translate: false)} — {ExportModelName(provider.Model)}";
+
+ ///
+ /// Reconstructs an export label from persisted build provenance.
+ ///
+ /// The persisted provider family.
+ /// The persisted model name.
+ /// An export-safe provider and model label.
+ internal static string ExportLabel(string providerFamily, string model)
+ {
+ var providerName = Enum.TryParse(providerFamily, out var parsedProvider) ? parsedProvider.ToName(translate: false) : string.IsNullOrWhiteSpace(providerFamily) ? "Unknown provider" : providerFamily.Trim();
+ var modelName = string.IsNullOrWhiteSpace(model) ? "model not reported" : model.Trim();
+
+ return $"{providerName} — {modelName}";
+ }
+
+ ///
+ /// Returns the configured display name, model ID, or provider-managed fallback.
+ ///
+ private static string ExportModelName(Model model)
+ {
+ if (!string.IsNullOrWhiteSpace(model.DisplayName))
+ return model.DisplayName.Trim();
+
+ if (model.IsSystemModel)
+ return "provider-configured model";
+
+ return string.IsNullOrWhiteSpace(model.Id) ? "model not reported" : model.Id.Trim();
+ }
}
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPlanStage.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPlanStage.cs
index 34e61f54..465c04ce 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPlanStage.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPlanStage.cs
@@ -64,7 +64,7 @@ internal sealed class VisualBriefingPlanStage(StructuredLlmStageRunner stageRunn
PayloadHash = VisualBriefingHashing.ComputeSections(payload, structuralSignature),
Sections = sections,
StructuralSignature = structuralSignature,
- Model = VisualBriefingModelNames.ExportLabel(provider.Model),
+ Model = VisualBriefingModelNames.ExportLabel(provider),
};
await store.WritePlanArtifactAsync(manifest.BriefingId, artifact, token);
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPresentationStage.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPresentationStage.cs
index 11bd49bb..e4646eb7 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPresentationStage.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingPresentationStage.cs
@@ -97,7 +97,7 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
Css = compiled.Css,
TemplateHash = compiled.TemplateHash,
CssHash = compiled.CssHash,
- Model = VisualBriefingModelNames.ExportLabel(provider.Model),
+ Model = VisualBriefingModelNames.ExportLabel(provider),
};
await store.WritePresentationArtifactAsync(manifest.BriefingId, artifact, token);
diff --git a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingStore.Recovery.cs b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingStore.Recovery.cs
index 760c4635..006bc43b 100644
--- a/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingStore.Recovery.cs
+++ b/app/MindWork AI Studio/Assistants/VisualBriefing/VisualBriefingStore.Recovery.cs
@@ -194,18 +194,19 @@ public sealed partial class VisualBriefingStore
if (build is null || string.IsNullOrWhiteSpace(build.Model))
return [];
+ var model = VisualBriefingModelNames.ExportLabel(build.ProviderFamily, build.Model);
List contributions = [];
if (build.EvidenceArtifactId is not null)
- contributions.Add(new(VisualBriefingModelRole.EVIDENCE, build.Model));
+ contributions.Add(new(VisualBriefingModelRole.EVIDENCE, model));
if (build.PlanArtifactId is not null)
- contributions.Add(new(VisualBriefingModelRole.PLAN, build.Model));
+ contributions.Add(new(VisualBriefingModelRole.PLAN, model));
if (build.ContentArtifactId is not null)
- contributions.Add(new(VisualBriefingModelRole.CONTENT, build.Model));
+ contributions.Add(new(VisualBriefingModelRole.CONTENT, model));
if (build.PresentationArtifactId is not null)
- contributions.Add(new(VisualBriefingModelRole.DESIGN, build.Model));
+ contributions.Add(new(VisualBriefingModelRole.DESIGN, model));
return contributions;
}
diff --git a/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs
index f4e34844..92a7860d 100644
--- a/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs
+++ b/app/MindWork AI Studio/Provider/LLMProvidersExtensions.cs
@@ -35,9 +35,17 @@ public static class LLMProvidersExtensions
///
/// The provider.
/// The human-readable name of the provider.
- public static string ToName(this LLMProviders llmProvider) => llmProvider switch
+ public static string ToName(this LLMProviders llmProvider) => llmProvider.ToName(translate: true);
+
+ ///
+ /// Returns the human-readable name of the provider.
+ ///
+ /// The provider.
+ /// Whether generic provider names should be translated.
+ /// The human-readable name of the provider.
+ public static string ToName(this LLMProviders llmProvider, bool translate) => llmProvider switch
{
- LLMProviders.NONE => TB("No provider selected"),
+ LLMProviders.NONE => translate ? TB("No provider selected") : "No provider selected",
LLMProviders.OPEN_AI => "OpenAI",
LLMProviders.ANTHROPIC => "Anthropic",
@@ -53,12 +61,12 @@ public static class LLMProvidersExtensions
LLMProviders.FIREWORKS => "Fireworks.ai",
LLMProviders.HUGGINGFACE => "Hugging Face",
- LLMProviders.SELF_HOSTED => TB("Self-hosted"),
+ LLMProviders.SELF_HOSTED => translate ? TB("Self-hosted") : "Self-hosted",
LLMProviders.HELMHOLTZ => "Helmholtz Blablador",
LLMProviders.GWDG => "GWDG SAIA",
- _ => TB("Unknown"),
+ _ => translate ? TB("Unknown") : "Unknown",
};
///