mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-20 08:57:57 +00:00
feat(auto): AUTO-only priority chain with tiered slots + live source probing; CSV export w/ key names; audit persistence; fix prompt token accounting & deepseek thinking
This commit is contained in:
@ -57,9 +57,14 @@ type Provider struct {
|
||||
adapter string
|
||||
client *http.Client
|
||||
|
||||
mu sync.Mutex
|
||||
sem chan struct{}
|
||||
health health
|
||||
mu sync.Mutex
|
||||
sem chan struct{}
|
||||
health health
|
||||
lastProbe struct {
|
||||
ok bool
|
||||
err string
|
||||
at int64
|
||||
}
|
||||
}
|
||||
|
||||
func New(cfg config.Source, vm *lua.VM) *Provider {
|
||||
@ -175,6 +180,48 @@ func (p *Provider) Available() bool {
|
||||
return p.health.available()
|
||||
}
|
||||
|
||||
// Probe performs a lightweight reachability + auth check against the source
|
||||
// using its best chat model (1-token). It records the result for Status().
|
||||
func (p *Provider) Probe(ctx context.Context) (bool, string) {
|
||||
ok := false
|
||||
msg := ""
|
||||
model := p.bestChatModel()
|
||||
if pm := p.ModelByID(model); pm != nil && pm.Kind == "image" {
|
||||
model = ""
|
||||
}
|
||||
if model == "" {
|
||||
if ms := p.Models(); len(ms) > 0 {
|
||||
model = ms[0]
|
||||
}
|
||||
}
|
||||
if model != "" {
|
||||
_, err := p.Chat(ctx, &types.ChatRequest{
|
||||
Model: model,
|
||||
Messages: []types.ChatMessage{{Role: "user", Content: types.StringContent("hi")}},
|
||||
MaxTokens: 1,
|
||||
})
|
||||
if err == nil {
|
||||
ok = true
|
||||
} else {
|
||||
msg = err.Error()
|
||||
}
|
||||
} else {
|
||||
msg = "no chat model configured"
|
||||
}
|
||||
p.mu.Lock()
|
||||
p.lastProbe.ok = ok
|
||||
p.lastProbe.err = msg
|
||||
p.lastProbe.at = time.Now().Unix()
|
||||
p.mu.Unlock()
|
||||
return ok, msg
|
||||
}
|
||||
|
||||
func (p *Provider) LastProbe() (bool, string, int64) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
return p.lastProbe.ok, p.lastProbe.err, p.lastProbe.at
|
||||
}
|
||||
|
||||
// ReportStatus records an upstream HTTP status for backoff decisions.
|
||||
func (p *Provider) ReportStatus(code int) {
|
||||
p.mu.Lock()
|
||||
@ -331,21 +378,23 @@ func (p *Provider) ChatStream(ctx context.Context, req *types.ChatRequest) (<-ch
|
||||
}()
|
||||
|
||||
ch := make(chan types.UnifiedChunk, 64)
|
||||
sel := <-rc
|
||||
if sel.err != nil {
|
||||
p.reportError()
|
||||
p.Release()
|
||||
return nil, sel.err
|
||||
}
|
||||
if sel.resp.StatusCode != 200 {
|
||||
raw, _ := io.ReadAll(sel.resp.Body)
|
||||
sel.resp.Body.Close()
|
||||
p.ReportStatus(sel.resp.StatusCode)
|
||||
p.Release()
|
||||
return nil, fmt.Errorf("api error %d: %s", sel.resp.StatusCode, truncate(string(raw), 500))
|
||||
}
|
||||
go func() {
|
||||
defer p.Release()
|
||||
defer close(ch)
|
||||
sel := <-rc
|
||||
if sel.err != nil {
|
||||
p.reportError()
|
||||
return
|
||||
}
|
||||
defer sel.resp.Body.Close()
|
||||
if sel.resp.StatusCode != 200 {
|
||||
raw, _ := io.ReadAll(sel.resp.Body)
|
||||
p.ReportStatus(sel.resp.StatusCode)
|
||||
_ = raw
|
||||
return
|
||||
}
|
||||
scanner := bufio.NewScanner(sel.resp.Body)
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
|
||||
for scanner.Scan() {
|
||||
|
||||
Reference in New Issue
Block a user