refactor(config): consolidate model aliases into ModelRegistry

Replaces three scattered model lists (ListSettingsModalViewModel,
DetailsIslandViewModel, GeneralSettingsTabViewModel) and the hardcoded
planning model with a single source. Planning launcher now uses the
opus alias instead of pinning claude-opus-4-7.
This commit is contained in:
mika kuns
2026-05-19 08:58:43 +02:00
parent 623ebf147b
commit a62ef240d1
6 changed files with 31 additions and 21 deletions

View File

@@ -0,0 +1,12 @@
namespace ClaudeDo.Data.Models;
public static class ModelRegistry
{
public static readonly IReadOnlyList<string> Aliases = new[] { "sonnet", "opus", "haiku" };
public const string DefaultAlias = "sonnet";
public const string PlanningAlias = "opus";
public const string ListDefaultSentinel = "(default)";
public const string TaskInheritSentinel = "(inherit)";
}

View File

@@ -95,7 +95,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
[ObservableProperty] private string? _model; [ObservableProperty] private string? _model;
// Agent settings overrides // Agent settings overrides
[ObservableProperty] private string _taskModelSelection = "(inherit)"; [ObservableProperty] private string _taskModelSelection = ModelRegistry.TaskInheritSentinel;
[ObservableProperty] private string _taskSystemPrompt = ""; [ObservableProperty] private string _taskSystemPrompt = "";
[ObservableProperty] private AgentInfo? _taskSelectedAgent; [ObservableProperty] private AgentInfo? _taskSelectedAgent;
@@ -103,10 +103,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
[ObservableProperty] private string _effectiveSystemPromptHint = ""; [ObservableProperty] private string _effectiveSystemPromptHint = "";
[ObservableProperty] private string _effectiveAgentHint = ""; [ObservableProperty] private string _effectiveAgentHint = "";
public System.Collections.ObjectModel.ObservableCollection<string> TaskModelOptions { get; } = new() public System.Collections.ObjectModel.ObservableCollection<string> TaskModelOptions { get; } = new(
{ new[] { ModelRegistry.TaskInheritSentinel }.Concat(ModelRegistry.Aliases));
"(inherit)", "sonnet", "opus", "haiku",
};
public System.Collections.ObjectModel.ObservableCollection<AgentInfo> TaskAgentOptions { get; } = new(); public System.Collections.ObjectModel.ObservableCollection<AgentInfo> TaskAgentOptions { get; } = new();
@@ -365,7 +363,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
await System.Threading.Tasks.Task.Delay(300, ct); await System.Threading.Tasks.Task.Delay(300, ct);
if (Task is null) return; if (Task is null) return;
var model = TaskModelSelection == "(inherit)" ? null : TaskModelSelection; var model = TaskModelSelection == ModelRegistry.TaskInheritSentinel ? null : TaskModelSelection;
var sp = string.IsNullOrWhiteSpace(TaskSystemPrompt) ? null : TaskSystemPrompt; var sp = string.IsNullOrWhiteSpace(TaskSystemPrompt) ? null : TaskSystemPrompt;
var ap = TaskSelectedAgent is null || string.IsNullOrWhiteSpace(TaskSelectedAgent.Path) var ap = TaskSelectedAgent is null || string.IsNullOrWhiteSpace(TaskSelectedAgent.Path)
? null : TaskSelectedAgent.Path; ? null : TaskSelectedAgent.Path;
@@ -384,11 +382,11 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
try try
{ {
TaskAgentOptions.Clear(); TaskAgentOptions.Clear();
TaskAgentOptions.Add(new AgentInfo("(inherit)", "", "")); TaskAgentOptions.Add(new AgentInfo(ModelRegistry.TaskInheritSentinel, "", ""));
var agents = await _worker.GetAgentsAsync(); var agents = await _worker.GetAgentsAsync();
foreach (var a in agents) TaskAgentOptions.Add(a); foreach (var a in agents) TaskAgentOptions.Add(a);
TaskModelSelection = string.IsNullOrWhiteSpace(entity.Model) ? "(inherit)" : entity.Model!; TaskModelSelection = string.IsNullOrWhiteSpace(entity.Model) ? ModelRegistry.TaskInheritSentinel : entity.Model!;
TaskSystemPrompt = entity.SystemPrompt ?? ""; TaskSystemPrompt = entity.SystemPrompt ?? "";
TaskSelectedAgent = string.IsNullOrWhiteSpace(entity.AgentPath) TaskSelectedAgent = string.IsNullOrWhiteSpace(entity.AgentPath)
? TaskAgentOptions[0] ? TaskAgentOptions[0]
@@ -439,7 +437,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
_suppressAgentSave = true; _suppressAgentSave = true;
try try
{ {
TaskModelSelection = "(inherit)"; TaskModelSelection = ModelRegistry.TaskInheritSentinel;
TaskSystemPrompt = ""; TaskSystemPrompt = "";
TaskSelectedAgent = null; TaskSelectedAgent = null;
} }

View File

@@ -16,14 +16,12 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
[ObservableProperty] private string _workingDir = ""; [ObservableProperty] private string _workingDir = "";
[ObservableProperty] private string _defaultCommitType = "chore"; [ObservableProperty] private string _defaultCommitType = "chore";
[ObservableProperty] private string _selectedModel = "(default)"; [ObservableProperty] private string _selectedModel = ModelRegistry.ListDefaultSentinel;
[ObservableProperty] private string _systemPrompt = ""; [ObservableProperty] private string _systemPrompt = "";
[ObservableProperty] private AgentInfo? _selectedAgent; [ObservableProperty] private AgentInfo? _selectedAgent;
public ObservableCollection<string> ModelOptions { get; } = new() public ObservableCollection<string> ModelOptions { get; } = new(
{ new[] { ModelRegistry.ListDefaultSentinel }.Concat(ModelRegistry.Aliases));
"(default)", "sonnet", "opus", "haiku",
};
public ObservableCollection<string> CommitTypeOptions { get; } = new() public ObservableCollection<string> CommitTypeOptions { get; } = new()
{ {
@@ -57,7 +55,7 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
foreach (var a in agents) Agents.Add(a); foreach (var a in agents) Agents.Add(a);
var config = await _worker.GetListConfigAsync(listId); var config = await _worker.GetListConfigAsync(listId);
SelectedModel = string.IsNullOrWhiteSpace(config?.Model) ? "(default)" : config!.Model!; SelectedModel = string.IsNullOrWhiteSpace(config?.Model) ? ModelRegistry.ListDefaultSentinel : config!.Model!;
SystemPrompt = config?.SystemPrompt ?? ""; SystemPrompt = config?.SystemPrompt ?? "";
SelectedAgent = string.IsNullOrWhiteSpace(config?.AgentPath) SelectedAgent = string.IsNullOrWhiteSpace(config?.AgentPath)
? Agents[0] ? Agents[0]
@@ -67,7 +65,7 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
[RelayCommand] [RelayCommand]
private async Task SaveAsync() private async Task SaveAsync()
{ {
var model = SelectedModel == "(default)" ? null : SelectedModel; var model = SelectedModel == ModelRegistry.ListDefaultSentinel ? null : SelectedModel;
var sp = string.IsNullOrWhiteSpace(SystemPrompt) ? null : SystemPrompt; var sp = string.IsNullOrWhiteSpace(SystemPrompt) ? null : SystemPrompt;
var ap = SelectedAgent is null || string.IsNullOrWhiteSpace(SelectedAgent.Path) ? null : SelectedAgent.Path; var ap = SelectedAgent is null || string.IsNullOrWhiteSpace(SelectedAgent.Path) ? null : SelectedAgent.Path;
@@ -89,7 +87,7 @@ public sealed partial class ListSettingsModalViewModel : ViewModelBase
[RelayCommand] [RelayCommand]
private void ResetAgentSettings() private void ResetAgentSettings()
{ {
SelectedModel = "(default)"; SelectedModel = ModelRegistry.ListDefaultSentinel;
SystemPrompt = ""; SystemPrompt = "";
SelectedAgent = Agents.Count > 0 ? Agents[0] : null; SelectedAgent = Agents.Count > 0 ? Agents[0] : null;
} }

View File

@@ -1,3 +1,4 @@
using ClaudeDo.Data.Models;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
namespace ClaudeDo.Ui.ViewModels.Modals.Settings; namespace ClaudeDo.Ui.ViewModels.Modals.Settings;
@@ -5,11 +6,11 @@ namespace ClaudeDo.Ui.ViewModels.Modals.Settings;
public sealed partial class GeneralSettingsTabViewModel : ViewModelBase public sealed partial class GeneralSettingsTabViewModel : ViewModelBase
{ {
[ObservableProperty] private string _defaultClaudeInstructions = ""; [ObservableProperty] private string _defaultClaudeInstructions = "";
[ObservableProperty] private string _defaultModel = "sonnet"; [ObservableProperty] private string _defaultModel = ModelRegistry.DefaultAlias;
[ObservableProperty] private int _defaultMaxTurns = 100; [ObservableProperty] private int _defaultMaxTurns = 100;
[ObservableProperty] private string _defaultPermissionMode = "auto"; [ObservableProperty] private string _defaultPermissionMode = "auto";
public IReadOnlyList<string> Models { get; } = new[] { "opus", "sonnet", "haiku" }; public IReadOnlyList<string> Models { get; } = ModelRegistry.Aliases;
public IReadOnlyList<string> PermissionModes { get; } = new[] public IReadOnlyList<string> PermissionModes { get; } = new[]
{ "auto", "bypassPermissions", "acceptEdits", "plan", "default" }; { "auto", "bypassPermissions", "acceptEdits", "plan", "default" };

View File

@@ -210,7 +210,7 @@ public sealed class WorkerHub : Microsoft.AspNetCore.SignalR.Hub
{ {
Id = AppSettingsEntity.SingletonId, Id = AppSettingsEntity.SingletonId,
DefaultClaudeInstructions = dto.DefaultClaudeInstructions ?? "", DefaultClaudeInstructions = dto.DefaultClaudeInstructions ?? "",
DefaultModel = dto.DefaultModel ?? "sonnet", DefaultModel = dto.DefaultModel ?? ModelRegistry.DefaultAlias,
DefaultMaxTurns = dto.DefaultMaxTurns, DefaultMaxTurns = dto.DefaultMaxTurns,
DefaultPermissionMode = dto.DefaultPermissionMode ?? "bypassPermissions", DefaultPermissionMode = dto.DefaultPermissionMode ?? "bypassPermissions",
WorktreeStrategy = dto.WorktreeStrategy ?? "sibling", WorktreeStrategy = dto.WorktreeStrategy ?? "sibling",

View File

@@ -7,13 +7,14 @@
// No cmd /k shim — arbitrary initial-prompt content would be re-parsed by cmd.exe otherwise. // No cmd /k shim — arbitrary initial-prompt content would be re-parsed by cmd.exe otherwise.
using System.Diagnostics; using System.Diagnostics;
using ClaudeDo.Data.Models;
namespace ClaudeDo.Worker.Planning; namespace ClaudeDo.Worker.Planning;
public sealed class WindowsTerminalPlanningLauncher : IPlanningTerminalLauncher public sealed class WindowsTerminalPlanningLauncher : IPlanningTerminalLauncher
{ {
private const string AllowedTools = "mcp__claudedo__*,Read,Grep,Glob,WebFetch,WebSearch,Skill"; private const string AllowedTools = "mcp__claudedo__*,Read,Grep,Glob,WebFetch,WebSearch,Skill";
private const string Model = "claude-opus-4-7"; private const string Model = ModelRegistry.PlanningAlias;
private readonly string _wtPath; private readonly string _wtPath;
private readonly string _claudePath; private readonly string _claudePath;