fix: anthropic tool-call round-trip, cache zero-hit parity, round-robin load balancing

anthropic.lua v3.0.0:
- Issue 1: tool_result/tool_use round-trip
- Issue 3: thinking default OFF (opt-in via extra_body.thinking)
- Issue 4: tool_choice mapping
- Issue 5: collect_blocks preserves unknown part types
- message_stop no longer emits done=true (was overwriting tool_calls finish_reason)
- cache_read_input_tokens normalized even at 0

gemini.lua:
- transform_response was missing cachedContentTokenCount

openai.lua (Issue 6):
- transform_error handles flat envelopes, nginx HTML, bare text

chat.go mergeUsage:
- Keep PromptTokensDetails even when CachedTokens=0

scheduler.go:
- Remove sort.SliceStable by Pref; round-robin cursor is the only LB mechanism

provider.go ModelAvailable:
- Also check Pref() > prefMin, persistently failing slots exit cands

presets.go:
- 17 built-in source templates

Tests: 6 new test functions, 2 updated for new semantics
This commit is contained in:
JianFeeeee
2026-08-28 12:02:46 +08:00
parent 94cbcb6771
commit 624fd74b45
15 changed files with 1170 additions and 114 deletions

View File

@ -138,6 +138,38 @@ func (s *Store) DeletedAdapters() map[string]bool {
return out
}
// SeedTemplates adds preset templates that the store has never seen before.
// A preset is seeded at most once: its name is recorded in PresetTemplates so
// a user who edits or deletes it never gets it silently restored on restart.
func (s *Store) SeedTemplates(presets []SourceTemplate) error {
s.mu.Lock()
defer s.mu.Unlock()
seen := make(map[string]bool, len(s.data.PresetTemplates))
for _, n := range s.data.PresetTemplates {
seen[n] = true
}
existing := make(map[string]bool, len(s.data.SourceTemplates))
for _, t := range s.data.SourceTemplates {
existing[t.Name] = true
}
added := false
for _, p := range presets {
if p.Name == "" || seen[p.Name] {
continue
}
s.data.PresetTemplates = append(s.data.PresetTemplates, p.Name)
added = true
if existing[p.Name] {
continue // user already has a template by this name: never overwrite
}
s.data.SourceTemplates = append(s.data.SourceTemplates, p)
}
if !added {
return nil
}
return s.persistLocked()
}
// UpsertTemplate adds or replaces a source template and persists.
func (s *Store) UpsertTemplate(t SourceTemplate) error {
s.mu.Lock()