feat(ui): show inherited markers and max-turns override in task flyout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-06-04 12:37:45 +02:00
parent d0ab382973
commit cd683ba227
2 changed files with 106 additions and 37 deletions

View File

@@ -138,28 +138,60 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
OnPropertyChanged(nameof(ShowContinue));
OnPropertyChanged(nameof(ShowResetAndRetry));
OnPropertyChanged(nameof(IsAgentSectionEnabled));
OnPropertyChanged(nameof(EffectiveModelLabel));
OnPropertyChanged(nameof(EffectiveAgentLabel));
}
[ObservableProperty] private string? _model;
// Agent settings overrides
[ObservableProperty] private string _taskModelSelection = ModelRegistry.TaskInheritSentinel;
[ObservableProperty] private string? _taskModelSelection; // null = inherit
[ObservableProperty] private string _taskSystemPrompt = "";
[ObservableProperty] private AgentInfo? _taskSelectedAgent;
[ObservableProperty] private string _effectiveModelHint = "";
[ObservableProperty] private decimal? _taskMaxTurns; // null = inherit
[ObservableProperty] private string _modelBadge = "";
[ObservableProperty] private string _modelInheritedHint = "";
[ObservableProperty] private string _turnsBadge = "";
[ObservableProperty] private string _turnsInheritedHint = "";
[ObservableProperty] private string _agentBadge = "";
[ObservableProperty] private string _effectiveSystemPromptHint = "";
[ObservableProperty] private string _effectiveAgentHint = "";
public string EffectiveModelLabel => Loc.T("vm.details.effectiveIfInherited", EffectiveModelHint);
public string EffectiveAgentLabel => Loc.T("vm.details.effectiveIfInherited", EffectiveAgentHint);
private string _globalModel = ModelRegistry.DefaultAlias;
private int _globalMaxTurns = 100;
private string? _listModel;
private int? _listMaxTurns;
private string? _listAgentName;
partial void OnEffectiveModelHintChanged(string value) => OnPropertyChanged(nameof(EffectiveModelLabel));
partial void OnEffectiveAgentHintChanged(string value) => OnPropertyChanged(nameof(EffectiveAgentLabel));
partial void OnTaskModelSelectionChanged(string? value) { RecomputeModelBadge(); QueueAgentSave(); }
partial void OnTaskMaxTurnsChanged(decimal? value) { RecomputeTurnsBadge(); QueueAgentSave(); }
public System.Collections.ObjectModel.ObservableCollection<string> TaskModelOptions { get; } = new(
new[] { ModelRegistry.TaskInheritSentinel }.Concat(ModelRegistry.Aliases));
private void RecomputeModelBadge()
{
var (value, source) = InheritanceResolver.Resolve(TaskModelSelection, _listModel, _globalModel);
ModelInheritedHint = value;
ModelBadge = BadgeFor(source, !string.IsNullOrWhiteSpace(TaskModelSelection));
}
private void RecomputeTurnsBadge()
{
var (value, source) = InheritanceResolver.Resolve(
TaskMaxTurns?.ToString(), _listMaxTurns?.ToString(), _globalMaxTurns.ToString());
TurnsInheritedHint = value;
TurnsBadge = BadgeFor(source, TaskMaxTurns is not null);
}
private void RecomputeAgentBadge()
{
var taskSet = TaskSelectedAgent is not null && !string.IsNullOrWhiteSpace(TaskSelectedAgent.Path);
var (_, source) = InheritanceResolver.Resolve(
taskSet ? TaskSelectedAgent!.Path : null, _listAgentName, null);
AgentBadge = BadgeFor(source, taskSet);
}
private static string BadgeFor(InheritSource source, bool taskSet) => taskSet
? Loc.T("settings.inherit.overrideBadge")
: source == InheritSource.List
? Loc.T("settings.inherit.inheritedFromList")
: Loc.T("settings.inherit.inheritedFromGlobal");
public System.Collections.ObjectModel.ObservableCollection<string> TaskModelOptions { get; } = new(ModelRegistry.Aliases);
public System.Collections.ObjectModel.ObservableCollection<AgentInfo> TaskAgentOptions { get; } = new();
@@ -288,8 +320,9 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
Loc.LanguageChanged += (_, _) =>
{
OnPropertyChanged(nameof(AgentStatusLabel));
OnPropertyChanged(nameof(EffectiveModelLabel));
OnPropertyChanged(nameof(EffectiveAgentLabel));
RecomputeModelBadge();
RecomputeTurnsBadge();
RecomputeAgentBadge();
};
// Subscribe once; filter by current task id inside the handler
@@ -433,9 +466,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
Log.Add(new LogLineViewModel { Kind = LogKind.Claude, Text = piece });
}
partial void OnTaskModelSelectionChanged(string value) => QueueAgentSave();
partial void OnTaskSystemPromptChanged(string value) => QueueAgentSave();
partial void OnTaskSelectedAgentChanged(AgentInfo? value) => QueueAgentSave();
partial void OnTaskSelectedAgentChanged(AgentInfo? value) { RecomputeAgentBadge(); QueueAgentSave(); }
partial void OnEditableDescriptionChanged(string value)
{
@@ -478,13 +510,14 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
await System.Threading.Tasks.Task.Delay(300, ct);
if (Task is null) return;
var model = TaskModelSelection == ModelRegistry.TaskInheritSentinel ? null : TaskModelSelection;
var model = string.IsNullOrWhiteSpace(TaskModelSelection) ? null : TaskModelSelection;
var sp = string.IsNullOrWhiteSpace(TaskSystemPrompt) ? null : TaskSystemPrompt;
var ap = TaskSelectedAgent is null || string.IsNullOrWhiteSpace(TaskSelectedAgent.Path)
? null : TaskSelectedAgent.Path;
var turns = TaskMaxTurns is decimal d ? (int?)d : null;
await _worker.UpdateTaskAgentSettingsAsync(
new ClaudeDo.Ui.Services.UpdateTaskAgentSettingsDto(Task.Id, model, sp, ap));
new ClaudeDo.Ui.Services.UpdateTaskAgentSettingsDto(Task.Id, model, sp, ap, turns));
}
catch (OperationCanceledException) { }
catch { }
@@ -497,21 +530,31 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
try
{
TaskAgentOptions.Clear();
TaskAgentOptions.Add(new AgentInfo(ModelRegistry.TaskInheritSentinel, "", ""));
TaskAgentOptions.Add(new AgentInfo("(inherited)", "", ""));
var agents = await _worker.GetAgentsAsync();
foreach (var a in agents) TaskAgentOptions.Add(a);
TaskModelSelection = string.IsNullOrWhiteSpace(entity.Model) ? ModelRegistry.TaskInheritSentinel : entity.Model!;
TaskModelSelection = string.IsNullOrWhiteSpace(entity.Model) ? null : entity.Model!;
TaskMaxTurns = entity.MaxTurns is int tmt ? tmt : (decimal?)null;
TaskSystemPrompt = entity.SystemPrompt ?? "";
TaskSelectedAgent = string.IsNullOrWhiteSpace(entity.AgentPath)
? TaskAgentOptions[0]
: (TaskAgentOptions.FirstOrDefault(a => a.Path == entity.AgentPath) ?? TaskAgentOptions[0]);
var listCfg = await _worker.GetListConfigAsync(entity.ListId);
EffectiveModelHint = string.IsNullOrWhiteSpace(listCfg?.Model) ? "(global default)" : listCfg!.Model!;
EffectiveSystemPromptHint = string.IsNullOrWhiteSpace(listCfg?.SystemPrompt) ? "(none)" : listCfg!.SystemPrompt!;
EffectiveAgentHint = string.IsNullOrWhiteSpace(listCfg?.AgentPath)
? "(none)" : System.IO.Path.GetFileName(listCfg!.AgentPath!);
var app = await _worker.GetAppSettingsAsync();
_globalModel = app?.DefaultModel ?? ModelRegistry.DefaultAlias;
_globalMaxTurns = app?.DefaultMaxTurns ?? 100;
_listModel = listCfg?.Model;
_listMaxTurns = listCfg?.MaxTurns;
_listAgentName = string.IsNullOrWhiteSpace(listCfg?.AgentPath)
? null : System.IO.Path.GetFileName(listCfg!.AgentPath!);
EffectiveSystemPromptHint = string.IsNullOrWhiteSpace(listCfg?.SystemPrompt) ? "" : listCfg!.SystemPrompt!;
RecomputeModelBadge();
RecomputeTurnsBadge();
RecomputeAgentBadge();
}
finally
{
@@ -583,7 +626,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
_suppressAgentSave = true;
try
{
TaskModelSelection = ModelRegistry.TaskInheritSentinel;
TaskModelSelection = null;
TaskMaxTurns = null;
TaskSystemPrompt = "";
TaskSelectedAgent = null;
}
@@ -591,9 +635,7 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
{
_suppressAgentSave = false;
}
EffectiveModelHint = "";
EffectiveSystemPromptHint = "";
EffectiveAgentHint = "";
return;
}
@@ -1085,6 +1127,10 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase
private bool CanResetAndRetry() =>
Task != null && _worker.IsConnected && ShowResetAndRetry;
[RelayCommand] private void ResetTaskModel() => TaskModelSelection = null;
[RelayCommand] private void ResetTaskTurns() => TaskMaxTurns = null;
[RelayCommand] private void ResetTaskAgent() => TaskSelectedAgent = TaskAgentOptions.Count > 0 ? TaskAgentOptions[0] : null;
}
public sealed partial class SubtaskRowViewModel : ViewModelBase