fix: audit round-3 — proxy safety, intervals persistence, SMTP timeout, sort fix

- Skip websearch provider when ProxyID is set but proxy not found (prevent
  silent direct connection bypass)
- Fix sortByStableRandomWeight: pair factors with items so sort.Slice swap
  keeps weights aligned
- Allow empty platform in account_stats_pricing_rules (wildcard matching),
  only force anthropic default for main model_pricing
- Add channel_account_stats_pricing_intervals table and repo layer support
  for interval-based pricing in account stats rules
- calculateTokenStatsCost now uses interval pricing when available
- Replace smtp.SendMail/tls.Dial with net.Dialer timeout (10s dial, 20s IO)
  to prevent goroutine leak on SMTP hang
- Fix gofmt formatting issues
- Web Search label: black text with red warning hint
This commit is contained in:
erio
2026-04-14 01:10:46 +08:00
parent 9c09bd19b4
commit 0a4ece5f5b
11 changed files with 199 additions and 27 deletions

View File

@@ -200,13 +200,20 @@ func sortByStableRandomWeight(items []weighted) {
if len(items) <= 1 {
return
}
factors := make([]float64, len(items))
for i, item := range items {
factors[i] = float64(item.weight) * (0.5 + rand.Float64())
type entry struct {
item weighted
factor float64
}
sort.Slice(items, func(i, j int) bool {
return factors[i] > factors[j]
entries := make([]entry, len(items))
for i, item := range items {
entries[i] = entry{item: item, factor: float64(item.weight) * (0.5 + rand.Float64())}
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].factor > entries[j].factor
})
for i, e := range entries {
items[i] = e.item
}
}
func mergeWeightedResults(withQuota, withoutQuota []weighted, capacity int) []ProviderConfig {