Go: add stats (#17061)

### Summary

Add LLM token stats framework

---------

Signed-off-by: Jin Hai <haijin.chn@gmail.com>
This commit is contained in:
Jin Hai
2026-07-18 21:02:07 +08:00
committed by GitHub
parent cafbbd467d
commit b8d06d02e6
144 changed files with 1578 additions and 1280 deletions

View File

@@ -123,7 +123,7 @@ func TestModelScopeChatHappyPathNormalizesBaseURLAndOmitsEmptyAuth(t *testing.T)
resp, err := m.ChatWithMessages("Qwen/Qwen2.5-7B-Instruct",
[]Message{{Role: "user", Content: "ping"}},
&APIConfig{},
&ChatConfig{MaxTokens: &maxTokens, Temperature: &temp})
&ChatConfig{MaxTokens: &maxTokens, Temperature: &temp}, nil)
if err != nil {
t.Fatalf("ChatWithMessages: %v", err)
}
@@ -157,7 +157,7 @@ func TestModelScopeChatSendsAuthHeaderWhenKeyProvided(t *testing.T) {
key := "ms-test"
_, err := m.ChatWithMessages("Qwen/Qwen2.5-7B-Instruct",
[]Message{{Role: "user", Content: "x"}},
&APIConfig{ApiKey: &key}, nil)
&APIConfig{ApiKey: &key}, nil, nil)
if err != nil {
t.Fatalf("ChatWithMessages: %v", err)
}
@@ -175,7 +175,7 @@ func TestModelScopeChatExtractsReasoningFields(t *testing.T) {
m := newModelScopeForTest(srv.URL)
resp, err := m.ChatWithMessages("Qwen/Qwen3-8B",
[]Message{{Role: "user", Content: "15% of 80?"}},
&APIConfig{}, nil)
&APIConfig{}, nil, nil)
if err != nil {
t.Fatalf("ChatWithMessages: %v", err)
}
@@ -220,7 +220,7 @@ func TestModelScopeStreamHappyPath(t *testing.T) {
var sawDone bool
err := m.ChatStreamlyWithSender("Qwen/Qwen2.5-7B-Instruct",
[]Message{{Role: "user", Content: "hi"}},
&APIConfig{}, nil,
&APIConfig{}, nil, nil,
func(c *string, r *string) error {
if r != nil && *r != "" {
reasoning = append(reasoning, *r)
@@ -254,6 +254,7 @@ func TestModelScopeStreamRejectsFalseStreamConfig(t *testing.T) {
[]Message{{Role: "user", Content: "x"}},
&APIConfig{},
&ChatConfig{Stream: &stream},
nil,
func(*string, *string) error { return nil })
if err == nil || !strings.Contains(err.Error(), "stream must be true") {
t.Errorf("expected stream-must-be-true error, got %v", err)
@@ -282,7 +283,7 @@ func TestModelScopeStreamCancelsOnIdle(t *testing.T) {
m := newModelScopeForTest(srv.URL)
err := m.ChatStreamlyWithSender("Qwen/Qwen2.5-7B-Instruct",
[]Message{{Role: "user", Content: "x"}},
&APIConfig{}, nil,
&APIConfig{}, nil, nil,
func(*string, *string) error { return nil })
if err == nil || !strings.Contains(err.Error(), "stream idle") {
t.Errorf("expected stream-idle error, got %v", err)
@@ -320,7 +321,7 @@ func TestModelScopeMissingBaseURLFailsClearly(t *testing.T) {
m := NewModelScopeModel(map[string]string{}, URLSuffix{Chat: "v1/chat/completions"})
_, err := m.ChatWithMessages("Qwen/Qwen2.5-7B-Instruct",
[]Message{{Role: "user", Content: "x"}},
&APIConfig{}, nil)
&APIConfig{}, nil, nil)
if err == nil || !strings.Contains(err.Error(), "base URL") {
t.Errorf("expected missing-base-URL error, got %v", err)
}
@@ -330,28 +331,28 @@ func TestModelScopeUnsupportedMethodsReturnNoSuchMethod(t *testing.T) {
m := newModelScopeForTest("http://unused")
model := "Qwen/Qwen2.5-7B-Instruct"
if _, err := m.Embed(&model, []string{"x"}, &APIConfig{}, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if _, err := m.Embed(&model, []string{"x"}, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("Embed: expected no such method, got %v", err)
}
if _, err := m.Rerank(&model, "q", []string{"d"}, &APIConfig{}, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if _, err := m.Rerank(&model, "q", []string{"d"}, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("Rerank: expected no such method, got %v", err)
}
if _, err := m.Balance(&APIConfig{}); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("Balance: expected no such method, got %v", err)
}
if _, err := m.TranscribeAudio(&model, nil, &APIConfig{}, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if _, err := m.TranscribeAudio(&model, nil, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("TranscribeAudio: expected no such method, got %v", err)
}
if err := m.TranscribeAudioWithSender(&model, nil, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if err := m.TranscribeAudioWithSender(&model, nil, &APIConfig{}, nil, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("TranscribeAudioWithSender: expected no such method, got %v", err)
}
if _, err := m.AudioSpeech(&model, nil, &APIConfig{}, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if _, err := m.AudioSpeech(&model, nil, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("AudioSpeech: expected no such method, got %v", err)
}
if err := m.AudioSpeechWithSender(&model, nil, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if err := m.AudioSpeechWithSender(&model, nil, &APIConfig{}, nil, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("AudioSpeechWithSender: expected no such method, got %v", err)
}
if _, err := m.OCRFile(&model, nil, nil, &APIConfig{}, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
if _, err := m.OCRFile(&model, nil, nil, &APIConfig{}, nil, nil); err == nil || !strings.Contains(err.Error(), "no such method") {
t.Errorf("OCRFile: expected no such method, got %v", err)
}
}