Files
ClawdDotNet/src/ClawdDotNet.Desktop/Views/AgentsPageView.axaml
T
RichardandClaude Opus 5.5 5f3a85595b Budgetende, Stufe 1: Ausfall vermerken, Regel je Agent, mitnehmen statt anrennen (#716)
Bisher teilte sich eine Budgetablehnung den Ausgang NichtGelaufen mit dem
Herunterfahren. Einmalige Aufgaben wurden den Rest des Tages alle 30 Minuten
erneut abgelehnt (jedes Mal ein Beleg) und liefen nach Mitternacht still zu
Lasten des neuen Tages. Wiederkehrende verfielen still.

- TaskLauf.KeinBudget als eigener Ausgang; der Dispatcher bildet
  BudgetExceeded darauf ab.
- Vier Felder an der Aufgabe: BudgetMissCount, LastBudgetMissAt,
  DeferredUntil, CatchUpPending (Spalten werden fuer bestehende Datenbanken
  nachgeruestet).
- Einmalige Aufgaben werden mitgenommen: Der Termin bleibt erhalten, faellig
  ist die Aufgabe wieder ab der naechsten lokalen Mitternacht, nicht vorher.
- Wiederkehrende Aufgaben folgen der Regel des Agenten
  (budget.whenExhausted): expire vermerkt den Ausfall und laesst den Termin
  verfallen; catchUpOnce fasst alle verpassten Termine zu einem Nachholauf am
  naechsten Tag zusammen. Ein regulaer faelliger Termin deckt das Nachholen
  mit ab, es bleibt bei einem Lauf.
- Der neue Tag hat Vorfahrt: Mitgenommenes und Nachholaeufe kommen nach allem
  regulaer Faelligen, unabhaengig von der Prioritaet.
- Beim ersten Takt eines neuen Tages eine Zusammenfassung je Agent im Log.
- Sichtbar: Die Aufgabenkarte der WebUI zeigt Ausfaelle, Mitnahme und
  Nachholen; die Regel ist im Desktop je Agent einstellbar. Nebenbei sind
  "Next:"/"Last:" auf der Karte ins Sprachpaket gewandert.

Stufen 2 bis 4 (Reservierung, Spielraum statt pauschalem Anteil, Vorbeugen)
folgen.

Tests: BudgetMissTests (9 neu). 1.238 gruen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 12:03:15 +02:00

294 lines
15 KiB
XML

<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ClawdDotNet.Desktop.ViewModels"
xmlns:ctrl="using:ClawdDotNet.Desktop.Controls"
mc:Ignorable="d" d:DesignWidth="1280" d:DesignHeight="820"
x:Class="ClawdDotNet.Desktop.Views.AgentsPageView"
x:DataType="vm:AgentsPageViewModel">
<!--
Vier Felder wie in der WinForms-Vorlage: oben Agentenliste und Agenteneinstellungen,
unten Werkzeugliste und Werkzeugeinstellungen — aber mit ziehbaren Teilern statt
fester SplitterDistance und mit flachen Feldern statt PropertyGrid.
Die Teilerstellungen werden im Code-Behind gelesen und gespeichert: ColumnDefinition
liegt nicht im Sichtbarkeitsbaum und erbt deshalb keinen DataContext — eine Bindung
darauf wuerde stillschweigend nichts tun.
-->
<DockPanel>
<TextBlock DockPanel.Dock="Bottom" Classes="caption" Margin="0,10,0,0"
Text="{Binding StatusText}" TextWrapping="Wrap" />
<Grid x:Name="OuterGrid" RowDefinitions="*,Auto,*">
<!-- ══════════════════ Oben: Agenten ══════════════════ -->
<Grid x:Name="TopGrid" Grid.Row="0" ColumnDefinitions="0.44*,Auto,0.56*">
<!-- Liste -->
<DockPanel Grid.Column="0" Margin="0,0,14,0">
<WrapPanel DockPanel.Dock="Top" Classes="toolbar">
<Button Classes="toolbar" Command="{Binding AddAgentCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconPlus}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.addAgent]}" />
</StackPanel>
</Button>
<Button Classes="toolbar" Command="{Binding RemoveAgentCommand}"
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconMinus}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.removeAgent]}" />
</StackPanel>
</Button>
<Border Classes="sep" />
<Button Classes="toolbar" Command="{Binding RunAgentNowCommand}"
IsEnabled="{Binding !IsRunning}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconPlay}" Width="12" Height="12" IsFilled="True" />
<TextBlock Text="{Binding L[desktop.agents.runNow]}" />
</StackPanel>
</Button>
<Border Classes="sep" />
<Button Classes="toolbar" Command="{Binding EditIdentityCommand}"
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconPencil}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.identity]}" />
</StackPanel>
</Button>
<Button Classes="toolbar" Command="{Binding EditSoulCommand}"
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconPencil}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.soul]}" />
</StackPanel>
</Button>
<Border Classes="sep" />
<Button Classes="toolbar" Command="{Binding OpenAgentFolderCommand}"
IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconFolder}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.folder]}" />
</StackPanel>
</Button>
<Button Classes="toolbar" Command="{Binding SaveAgentsCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.save]}" />
</StackPanel>
</Button>
</WrapPanel>
<Border DockPanel.Dock="Top" Classes="thead">
<Grid ColumnDefinitions="1.4*,1.6*,2*">
<TextBlock Grid.Column="0" Classes="th" Text="{Binding L[desktop.agents.thDisplayName]}" />
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.agents.thModel]}" />
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.agents.thSummary]}" />
</Grid>
</Border>
<ListBox Classes="table" ItemsSource="{Binding Agents}"
SelectedItem="{Binding SelectedAgent}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:AgentItemViewModel">
<Border Classes="tr" Padding="7">
<Grid ColumnDefinitions="1.4*,1.6*,2*">
<TextBlock Grid.Column="0" Classes="td" FontWeight="SemiBold"
Text="{Binding DisplayName}" />
<TextBlock Grid.Column="1" Classes="td dim" Text="{Binding Model}" />
<TextBlock Grid.Column="2" Classes="td dim" Text="{Binding Description}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<GridSplitter x:Name="TopSplitter" Grid.Column="1" Classes="vertical"
ResizeDirection="Columns" />
<!-- Einstellungen des gewählten Agenten -->
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto" Padding="4,0,0,0">
<ContentControl Content="{Binding SelectedAgent}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="vm:AgentItemViewModel">
<StackPanel Spacing="20" MaxWidth="640" HorizontalAlignment="Left">
<StackPanel Spacing="12">
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.kickerGeneralModel]}" />
<TextBlock Classes="h2" Text="{Binding DisplayName}" />
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.agentId]}" />
<TextBox Text="{Binding AgentId}" IsReadOnly="True" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.displayName]}" />
<TextBox Text="{Binding DisplayName}" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.model]}" />
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).KnownModels}"
SelectedItem="{Binding Model}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.promptCaching]}" />
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).CachingOptions}"
SelectedItem="{Binding PromptCaching}" />
</StackPanel>
</Grid>
<StackPanel>
<TextBlock Classes="label" Text="{Binding L[desktop.agents.roleDescription]}" />
<TextBox Text="{Binding Description}" AcceptsReturn="True" Height="54"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel>
<TextBlock Classes="label" Text="{Binding L[desktop.agents.systemPrompt]}" />
<TextBox Text="{Binding SystemPrompt}" AcceptsReturn="True" Height="70"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<Border Classes="hr" />
<StackPanel Spacing="12">
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.kickerLimits]}" />
<TextBlock Classes="h2" Text="{Binding L[desktop.agents.limitsTitle]}" />
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxSteps]}" />
<TextBox Text="{Binding MaxSteps}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.timeoutSeconds]}" />
<TextBox Text="{Binding TimeoutSeconds}" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxContextTokens]}" />
<TextBox Text="{Binding MaxContextTokens}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.maxToolResultChars]}" />
<TextBox Text="{Binding MaxToolResultChars}" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.dailyCost]}" />
<TextBox Text="{Binding DailyCostUsd}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="{Binding L[desktop.agents.dailyTokens]}" />
<TextBox Text="{Binding DailyTokens}" />
</StackPanel>
</Grid>
<StackPanel>
<TextBlock Classes="label" Text="{Binding L[desktop.agents.whenExhausted]}" />
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding WhenExhaustedOptions}"
SelectedItem="{Binding WhenExhausted}" />
<TextBlock Classes="caption" TextWrapping="Wrap"
Text="{Binding L[desktop.agents.whenExhaustedHint]}" />
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</ScrollViewer>
</Grid>
<GridSplitter x:Name="VerticalSplitter" Grid.Row="1" Classes="horizontal"
ResizeDirection="Rows" Margin="0,8" />
<!-- ══════════════════ Unten: Werkzeuge ══════════════════ -->
<Grid x:Name="BottomGrid" Grid.Row="2" ColumnDefinitions="0.44*,Auto,0.56*">
<DockPanel Grid.Column="0" Margin="0,0,14,0">
<TextBlock DockPanel.Dock="Top" Classes="kicker" Margin="0,4,0,8"
Text="{Binding AllowedToolsHeader}" />
<Border DockPanel.Dock="Top" Classes="thead">
<Grid ColumnDefinitions="36,1.4*,2.4*">
<TextBlock Grid.Column="1" Classes="th" Text="{Binding L[desktop.agents.thTool]}" />
<TextBlock Grid.Column="2" Classes="th" Text="{Binding L[desktop.agents.thDescription]}" />
</Grid>
</Border>
<ListBox Classes="table" ItemsSource="{Binding SelectedAgent.AvailableTools}"
SelectedItem="{Binding SelectedTool}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:ToolItemViewModel">
<Border Classes="tr" Padding="7">
<Grid ColumnDefinitions="36,1.4*,2.4*">
<CheckBox Grid.Column="0" IsChecked="{Binding IsEnabled}"
VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Classes="td" FontWeight="SemiBold"
Text="{Binding Name}" />
<TextBlock Grid.Column="2" Classes="td dim" Text="{Binding Description}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<GridSplitter x:Name="BottomSplitter" Grid.Column="1" Classes="vertical"
ResizeDirection="Columns" />
<DockPanel Grid.Column="2" Margin="4,0,0,0">
<StackPanel DockPanel.Dock="Top" Spacing="2" Margin="0,4,0,10">
<TextBlock Classes="kicker" Text="{Binding L[desktop.agents.toolSettingsKicker]}" />
<DockPanel>
<TextBlock Classes="h2" VerticalAlignment="Center"
Text="{Binding SelectedTool.Name}" />
<Button DockPanel.Dock="Right" HorizontalAlignment="Right" Classes="toolbar primary"
Command="{Binding SaveToolSettingsCommand}"
IsEnabled="{Binding ToolSettings, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
<TextBlock Text="{Binding L[desktop.agents.apply]}" />
</StackPanel>
</Button>
</DockPanel>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ContentControl Content="{Binding ToolSettings}" />
</ScrollViewer>
</DockPanel>
</Grid>
</Grid>
</DockPanel>
</UserControl>