feat(worker): clamp max-turns to a configurable ceiling

Runaway sessions were the single biggest cost driver: model_presets was
never persisted (stayed code-only), default_max_turns shipped at 100, and
ResolveMaxTurns had no upper bound, so a task/list override could run
hundreds of turns unchecked.

- TaskRunner.ResolveMaxTurns now clamps the resolved value to
  AppSettings.MaxTurnsCeiling (new column, default 80) and logs a warning
  with task id / requested / effective value when it clamps.
- default_max_turns default lowered from 100 to 40 (entity, EF config,
  and the seeded row via the new AddMaxTurnsCeiling migration).
- AppSettingsRepository.GetAsync backfills model_presets with the
  shipping defaults on first read instead of leaving the column null.
- Settings > General's per-model preset table and the task/list agent
  editor now show a hint when a set max-turns value exceeds the ceiling.
This commit is contained in:
mika kuns
2026-08-05 15:40:02 +02:00
parent 83ea429b8a
commit 08ac8bf7b1
22 changed files with 1093 additions and 50 deletions
@@ -129,14 +129,19 @@
<ItemsControl ItemsSource="{Binding General.ModelPresets}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="settings:ModelPresetRowViewModel">
<Grid ColumnDefinitions="90,12,*,12,110" Margin="0,0,0,6">
<TextBlock Grid.Column="0" Text="{Binding Model}" VerticalAlignment="Center"/>
<ComboBox Grid.Column="2" ItemsSource="{Binding EffortLevels}"
SelectedItem="{Binding Effort, Mode=TwoWay}"
HorizontalAlignment="Stretch"/>
<NumericUpDown Grid.Column="4" Value="{Binding MaxTurns, Mode=TwoWay}"
Minimum="1" Maximum="200" Increment="1" FormatString="0"/>
</Grid>
<StackPanel Spacing="2" Margin="0,0,0,6">
<Grid ColumnDefinitions="90,12,*,12,110">
<TextBlock Grid.Column="0" Text="{Binding Model}" VerticalAlignment="Center"/>
<ComboBox Grid.Column="2" ItemsSource="{Binding EffortLevels}"
SelectedItem="{Binding Effort, Mode=TwoWay}"
HorizontalAlignment="Stretch"/>
<NumericUpDown Grid.Column="4" Value="{Binding MaxTurns, Mode=TwoWay}"
Minimum="1" Maximum="200" Increment="1" FormatString="0"/>
</Grid>
<TextBlock Classes="meta" Opacity="0.6" TextWrapping="Wrap"
Text="{Binding ClampHint}"
IsVisible="{Binding ClampHint, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>