Skip to content

Commit 91894b2

Browse files
committed
Persist backend profiles with capabilities
Add per-backend profile storage (model + capability flags) and use it in settings UI. SettingsService: introduce BackendProfile record and SaveProfileForBackendAsync/GetProfileForBackendAsync using a new storage key. Settings.razor: load profile on backend select, restore manual vision/reasoning/imagegen flags only for unregistered models, fallback to legacy model-history when no profile exists, and save the full profile instead of just the model. This enables preserving capability information per backend while remaining compatible with older model-only entries.
1 parent da63125 commit 91894b2

4 files changed

Lines changed: 44 additions & 5 deletions

File tree

src/MaIN.InferPage/Components/Pages/Settings.razor

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,27 @@
278278
if (_selectedBackend == null) return;
279279

280280
var backendKey = GetBackendStorageKey();
281-
var lastModel = await SettingsStorage.GetLastModelForBackendAsync(backendKey);
282-
if (!string.IsNullOrEmpty(lastModel))
281+
var profile = await SettingsStorage.GetProfileForBackendAsync(backendKey);
282+
if (profile != null)
283283
{
284-
_modelName = lastModel;
285-
OnModelNameChanged();
284+
_modelName = profile.Model;
285+
OnModelNameChanged(); // sets _isRegisteredModel + auto-detects caps
286+
if (!_isRegisteredModel) // only restore manual caps for unregistered models
287+
{
288+
_manualVision = profile.Vision;
289+
_manualReasoning = profile.Reasoning;
290+
_manualImageGen = profile.ImageGen;
291+
}
292+
}
293+
else
294+
{
295+
// Fallback: old model-history entry (no capability info)
296+
var lastModel = await SettingsStorage.GetLastModelForBackendAsync(backendKey);
297+
if (!string.IsNullOrEmpty(lastModel))
298+
{
299+
_modelName = lastModel;
300+
OnModelNameChanged();
301+
}
286302
}
287303

288304
await LoadApiKeyPreview();
@@ -370,7 +386,8 @@
370386
};
371387
await SettingsStorage.SaveSettingsAsync(settings);
372388

373-
await SettingsStorage.SaveModelForBackendAsync(backendKey, _modelName);
389+
await SettingsStorage.SaveProfileForBackendAsync(
390+
backendKey, _modelName, hasVision, hasReasoning, hasImageGen);
374391

375392
// Resolve API key: use new input, or fall back to saved key
376393
string? apiKey = null;

src/MaIN.InferPage/Services/SettingsService.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ public async Task<bool> HasSettingsAsync()
2323
public Task SaveModelForBackendAsync(string backend, string model) => SetInDictAsync(ModelHistoryKey, backend, model);
2424
public Task<string?> GetLastModelForBackendAsync(string backend) => GetFromDictAsync(ModelHistoryKey, backend);
2525

26+
private const string BackendProfilesKey = "inferpage-backend-profiles";
27+
28+
public async Task SaveProfileForBackendAsync(string backend, string model,
29+
bool vision, bool reasoning, bool imageGen)
30+
{
31+
var profiles = await js.InvokeAsync<Dictionary<string, BackendProfile>?>(
32+
"settingsManager.load", BackendProfilesKey) ?? new();
33+
profiles[backend] = new BackendProfile(model, vision, reasoning, imageGen);
34+
await js.InvokeVoidAsync("settingsManager.save", BackendProfilesKey, profiles);
35+
}
36+
37+
public async Task<BackendProfile?> GetProfileForBackendAsync(string backend)
38+
{
39+
var profiles = await js.InvokeAsync<Dictionary<string, BackendProfile>?>(
40+
"settingsManager.load", BackendProfilesKey);
41+
return profiles?.GetValueOrDefault(backend);
42+
}
43+
2644
private async Task SetInDictAsync(string storageKey, string key, string value)
2745
{
2846
var dict = await LoadDictAsync(storageKey);
@@ -36,3 +54,5 @@ private async Task SetInDictAsync(string storageKey, string key, string value)
3654
private async Task<Dictionary<string, string>> LoadDictAsync(string storageKey)
3755
=> await js.InvokeAsync<Dictionary<string, string>?>("settingsManager.load", storageKey) ?? new();
3856
}
57+
58+
public record BackendProfile(string Model, bool Vision, bool Reasoning, bool ImageGen);

src/MaIN.Services/Services/LLMService/DeepSeekService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ protected override void ValidateApiKey()
6767

6868
chat.Messages.Last().Content = message.Content;
6969
chat.Messages.Last().Files = [];
70+
chat.Messages.Last().Images = null;
7071
var result = await Send(chat, requestOptions, cancellationToken);
7172
chat.Messages.Last().Content = lastMsg.Content;
7273
return result;

src/MaIN.Services/Services/LLMService/OllamaService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ protected override void ValidateApiKey()
5858

5959
chat.Messages.Last().Content = message.Content;
6060
chat.Messages.Last().Files = [];
61+
chat.Messages.Last().Images = null;
6162
var result = await Send(chat, requestOptions, cancellationToken);
6263
chat.Messages.Last().Content = lastMsg.Content;
6364
return result;

0 commit comments

Comments
 (0)