UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4

Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem
Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag.

Oberflaeche
- Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als
  mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml
  (eigene ControlThemes statt Fluent umzufaerben).
- Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer
  Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite
  statt eigenem Fenster, Texteditor-Fenster.
- ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter
  entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt.

Rocket.Chat
- Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der
  Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird
  nur, wenn wirklich etwas anliegt.
- send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum
  ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist.
- Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei
  Annahmen waren falsch und sind korrigiert.

Deploymentcenter
- DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json)
  erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke.
- AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst
  ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-23 12:16:05 +02:00
co-authored by Claude Opus 5
parent b5bf97ae74
commit 33d95a6c3f
88 changed files with 11665 additions and 1029 deletions
+248 -118
View File
@@ -3,153 +3,283 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ClawdDotNet.Desktop.ViewModels"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="700"
Padding="16"
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>
<!-- Statusbar am unteren Rand -->
<Border Classes="statusbar" DockPanel.Dock="Bottom">
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center" />
</Border>
<TextBlock DockPanel.Dock="Bottom" Classes="caption" Margin="0,10,0,0"
Text="{Binding StatusText}" TextWrapping="Wrap" />
<!-- Master-Detail Split -->
<Grid ColumnDefinitions="260,*">
<Grid x:Name="OuterGrid" RowDefinitions="*,Auto,*">
<!-- Linke Spalte: Agenten-Liste -->
<DockPanel Grid.Column="0" Margin="0,0,12,0">
<!-- Toolbar -->
<StackPanel Classes="toolbar" DockPanel.Dock="Top">
<Button Content="Neu" Command="{Binding AddAgentCommand}" Classes="accent" />
<Button Content="Entfernen" Command="{Binding RemoveAgentCommand}" IsEnabled="{Binding SelectedAgent, Converter={x:Static ObjectConverters.IsNotNull}}" />
<Button Content="Speichern" Command="{Binding SaveAgentsCommand}" />
</StackPanel>
<!-- ══════════════════ Oben: Agenten ══════════════════ -->
<Grid x:Name="TopGrid" Grid.Row="0" ColumnDefinitions="0.44*,Auto,0.56*">
<!-- Liste -->
<ListBox ItemsSource="{Binding Agents}" SelectedItem="{Binding SelectedAgent}">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:AgentItemViewModel">
<StackPanel Margin="4">
<TextBlock Text="{Binding DisplayName}" FontWeight="Bold" />
<TextBlock Text="{Binding Model}" Classes="caption" />
<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="Agent" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Button>
</DockPanel>
<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="Agent" />
</StackPanel>
</Button>
<!-- Rechte Spalte: Agenten-Details -->
<ContentControl Grid.Column="1" Content="{Binding SelectedAgent}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="vm:AgentItemViewModel">
<TabControl>
<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="Jetzt ausf." />
</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="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="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="Ordner" />
</StackPanel>
</Button>
<Button Classes="toolbar" Command="{Binding SaveAgentsCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<ctrl:StrokeIcon Data="{StaticResource IconSave}" Width="14" Height="14" />
<TextBlock Text="Speichern" />
</StackPanel>
</Button>
</WrapPanel>
<Border DockPanel.Dock="Top" Classes="thead">
<Grid ColumnDefinitions="1.4*,1.6*,2*">
<TextBlock Grid.Column="0" Classes="th" Text="ANZEIGENAME" />
<TextBlock Grid.Column="1" Classes="th" Text="MODELL" />
<TextBlock Grid.Column="2" Classes="th" Text="KURZINFO" />
</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">
<!-- TAB 1: Allgemein & Modell -->
<TabItem Header="Allgemein &amp; Modell">
<ScrollViewer Padding="8">
<StackPanel Spacing="12">
<TextBlock Classes="kicker" Text="ALLGEMEIN &amp; MODELL" />
<TextBlock Classes="h2" Text="{Binding DisplayName}" />
<Grid ColumnDefinitions="140,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto">
<TextBlock Grid.Row="0" Grid.Column="0" Text="Agent ID:" FontWeight="Bold" VerticalAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding AgentId}" IsReadOnly="True" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Anzeigename:" FontWeight="Bold" VerticalAlignment="Center" Margin="0,8,0,0" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DisplayName}" Margin="0,8,0,0" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Modell:" FontWeight="Bold" VerticalAlignment="Center" Margin="0,8,0,0" />
<ComboBox Grid.Row="2" Grid.Column="1" ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).KnownModels}" SelectedItem="{Binding Model}" HorizontalAlignment="Stretch" Margin="0,8,0,0" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Rolle / Beschreibung:" FontWeight="Bold" VerticalAlignment="Center" Margin="0,8,0,0" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Description}" AcceptsReturn="True" Height="60" Margin="0,8,0,0" />
<TextBlock Grid.Row="4" Grid.Column="0" Text="Prompt Caching:" FontWeight="Bold" VerticalAlignment="Center" Margin="0,8,0,0" />
<ComboBox Grid.Row="4" Grid.Column="1" ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).CachingOptions}" SelectedItem="{Binding PromptCaching}" Width="150" HorizontalAlignment="Left" Margin="0,8,0,0" />
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="Agent-ID" />
<TextBox Text="{Binding AgentId}" IsReadOnly="True" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="Anzeigename" />
<TextBox Text="{Binding DisplayName}" />
</StackPanel>
</Grid>
<!-- Limits Card -->
<Border Classes="card" Margin="0,8,0,0">
<StackPanel Spacing="8">
<TextBlock Text="Schutzgrenzen (LoopGuard &amp; Budget)" Classes="heading" />
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,Auto,Auto">
<StackPanel Grid.Row="0" Grid.Column="0" Spacing="4">
<TextBlock Text="Max. Schritte pro Run:" />
<NumericUpDown Value="{Binding MaxSteps}" Minimum="1" Maximum="100" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" Spacing="4" Margin="8,0,0,0">
<TextBlock Text="Timeout (Sekunden):" />
<NumericUpDown Value="{Binding TimeoutSeconds}" Minimum="10" Maximum="3600" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Spacing="4" Margin="0,8,0,0">
<TextBlock Text="Max. Kontext-Tokens:" />
<NumericUpDown Value="{Binding MaxContextTokens}" Minimum="1000" Maximum="2000000" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" Spacing="4" Margin="8,8,0,0">
<TextBlock Text="Max. Tool-Ergebnis (Zeichen):" />
<NumericUpDown Value="{Binding MaxToolResultChars}" Minimum="1000" Maximum="500000" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="Modell" />
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).KnownModels}"
SelectedItem="{Binding Model}" />
</StackPanel>
</Border>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="Prompt Caching" />
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).CachingOptions}"
SelectedItem="{Binding PromptCaching}" />
</StackPanel>
</Grid>
<StackPanel>
<TextBlock Classes="label" Text="Rolle / Beschreibung" />
<TextBox Text="{Binding Description}" AcceptsReturn="True" Height="54"
TextWrapping="Wrap" />
</StackPanel>
<StackPanel>
<TextBlock Classes="label" Text="System-Prompt (zusätzliche Anweisungen)" />
<TextBox Text="{Binding SystemPrompt}" AcceptsReturn="True" Height="70"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- TAB 2: System Prompt & Seele -->
<TabItem Header="System-Prompt &amp; Soul">
<ScrollViewer Padding="8">
<Border Classes="hr" />
<StackPanel Spacing="12">
<StackPanel Spacing="4">
<TextBlock Text="System-Prompt (Zusätzliche Anweisungen):" FontWeight="Bold" />
<TextBox Text="{Binding SystemPrompt}" AcceptsReturn="True" Height="120" TextWrapping="Wrap" />
</StackPanel>
<TextBlock Classes="kicker" Text="GRENZEN" />
<TextBlock Classes="h2" Text="Schutzgrenzen (LoopGuard &amp; Budget)" />
<StackPanel Spacing="4">
<TextBlock Text="Identität (Identity):" FontWeight="Bold" />
<TextBox Text="{Binding Identity}" AcceptsReturn="True" Height="100" TextWrapping="Wrap" />
</StackPanel>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="Max. Schritte pro Run" />
<TextBox Text="{Binding MaxSteps}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="Timeout (Sekunden)" />
<TextBox Text="{Binding TimeoutSeconds}" />
</StackPanel>
</Grid>
<StackPanel Spacing="4">
<TextBlock Text="Seele &amp; Werte (Soul):" FontWeight="Bold" />
<TextBox Text="{Binding Soul}" AcceptsReturn="True" Height="100" TextWrapping="Wrap" />
</StackPanel>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="Max. Kontext-Tokens" />
<TextBox Text="{Binding MaxContextTokens}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="Max. Tool-Ergebnis (Zeichen)" />
<TextBox Text="{Binding MaxToolResultChars}" />
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0">
<TextBlock Classes="label" Text="Tagesbudget ($ USD)" />
<TextBox Text="{Binding DailyCostUsd}" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock Classes="label" Text="Tagesbudget (Tokens)" />
<TextBox Text="{Binding DailyTokens}" />
</StackPanel>
</Grid>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- TAB 3: Werkzeuge (Tools) -->
<TabItem Header="Werkzeuge (Tools)">
<ScrollViewer Padding="8">
<StackPanel Spacing="8">
<TextBlock Text="Zugelassene Werkzeuge für diesen Agenten:" Classes="heading" />
<ItemsControl ItemsSource="{Binding AvailableTools}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:ToolItemViewModel">
<Grid ColumnDefinitions="200,Auto" Margin="0,4">
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsEnabled}" Grid.Column="0" VerticalAlignment="Center" />
<Button Content="⚙ Konfigurieren" Command="{Binding $parent[UserControl].((vm:AgentsPageViewModel)DataContext).ConfigureToolCommand}" CommandParameter="{Binding}" IsEnabled="{Binding IsEnabled}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</TabItem>
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</ScrollViewer>
</Grid>
</TabControl>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
<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 SelectedAgent.DisplayName,
StringFormat='ZUGELASSENE WERKZEUGE FÜR {0}'}" />
<Border DockPanel.Dock="Top" Classes="thead">
<Grid ColumnDefinitions="36,1.4*,2.4*">
<TextBlock Grid.Column="1" Classes="th" Text="WERKZEUG" />
<TextBlock Grid.Column="2" Classes="th" Text="BESCHREIBUNG" />
</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="WERKZEUG-EINSTELLUNGEN" />
<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="Übernehmen" />
</StackPanel>
</Button>
</DockPanel>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ContentControl Content="{Binding ToolSettings}" />
</ScrollViewer>
</DockPanel>
</Grid>
</Grid>
</DockPanel>
</UserControl>