mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-10-18 05:29:00 +08:00
108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
package executor
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v8/internal/config"
|
|
"github.com/router-for-me/CLIProxyAPI/v8/internal/runtime/executor/helps"
|
|
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v8/sdk/cliproxy/auth"
|
|
coreusage "github.com/router-for-me/CLIProxyAPI/v8/sdk/cliproxy/usage"
|
|
)
|
|
|
|
const codexResponseModelTestStream = `event: response.created
|
|
data: {"type":"response.created","response":{"id":"resp_1","model":"gpt-5.6-luna"}}
|
|
|
|
data: {"type":"response.output_text.delta","delta":"he"}
|
|
|
|
data: {"type":"response.output_text.delta","delta":"llo"}
|
|
|
|
data: {"type":"response.completed","response":{"id":"resp_1","model":"gpt-5.6-luna","usage":{"input_tokens":5,"output_tokens":7,"total_tokens":12}}}
|
|
|
|
data: [DONE]`
|
|
|
|
// TestObserveCodexTokenEventRecordsResponseModel guards the wiring between the codex
|
|
// stream loops and the usage reporter: every transport funnels through observeCodexTokenEvent.
|
|
func TestObserveCodexTokenEventRecordsResponseModel(t *testing.T) {
|
|
reporter := helps.NewExecutorUsageReporter(context.Background(), NewCodexExecutor(&config.Config{}), "gpt-6-astra", nil)
|
|
|
|
for _, line := range bytes.Split([]byte(codexResponseModelTestStream), []byte("\n")) {
|
|
line = bytes.TrimSpace(line)
|
|
if !bytes.HasPrefix(line, dataTag) {
|
|
continue
|
|
}
|
|
observeCodexTokenEvent(reporter, bytes.TrimSpace(line[len(dataTag):]))
|
|
}
|
|
|
|
if got := reporter.ResponseModel(); got != "gpt-5.6-luna" {
|
|
t.Fatalf("reporter response model = %q, want %q", got, "gpt-5.6-luna")
|
|
}
|
|
}
|
|
|
|
type codexResponseModelUsageCapture struct {
|
|
alias string
|
|
records chan coreusage.Record
|
|
}
|
|
|
|
func (c *codexResponseModelUsageCapture) HandleUsage(_ context.Context, record coreusage.Record) {
|
|
if record.Alias != c.alias {
|
|
return
|
|
}
|
|
select {
|
|
case c.records <- record:
|
|
default:
|
|
}
|
|
}
|
|
|
|
type codexResponseModelNoopUsagePlugin struct{}
|
|
|
|
func (codexResponseModelNoopUsagePlugin) HandleUsage(context.Context, coreusage.Record) {}
|
|
|
|
func (c *codexResponseModelUsageCapture) await(t *testing.T) coreusage.Record {
|
|
t.Helper()
|
|
select {
|
|
case record := <-c.records:
|
|
return record
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("timed out waiting for the usage record")
|
|
return coreusage.Record{}
|
|
}
|
|
}
|
|
|
|
// TestCodexUsageRecordsCarryResponseModelPerModel checks that the attempt record reports
|
|
// the served model while the image generation tool record must not claim it.
|
|
func TestCodexUsageRecordsCarryResponseModelPerModel(t *testing.T) {
|
|
const alias = "codex-response-model-wiring-test"
|
|
capture := &codexResponseModelUsageCapture{alias: alias, records: make(chan coreusage.Record, 4)}
|
|
coreusage.RegisterNamedPlugin(t.Name(), capture)
|
|
t.Cleanup(func() {
|
|
coreusage.RegisterNamedPlugin(t.Name(), codexResponseModelNoopUsagePlugin{})
|
|
})
|
|
|
|
ctx := coreusage.WithRequestedModelAlias(context.Background(), alias)
|
|
auth := &cliproxyauth.Auth{ID: "codex-auth-1", Index: "auth-index-7", Provider: "codex"}
|
|
reporter := helps.NewExecutorUsageReporter(ctx, NewCodexExecutor(&config.Config{}), "gpt-5.4-mini", auth)
|
|
|
|
observeCodexTokenEvent(reporter, []byte(`{"type":"response.completed","response":{"model":"gpt-5.4-mini","usage":{"total_tokens":12}}}`))
|
|
reporter.EnsurePublished(ctx)
|
|
reporter.PublishAdditionalModel(ctx, "gpt-image-1.5", coreusage.Detail{TotalTokens: 5})
|
|
|
|
attemptRecord := capture.await(t)
|
|
if attemptRecord.Model != "gpt-5.4-mini" {
|
|
t.Fatalf("attempt record model = %q, want %q", attemptRecord.Model, "gpt-5.4-mini")
|
|
}
|
|
if attemptRecord.ResponseModel != "gpt-5.4-mini" {
|
|
t.Fatalf("attempt record response model = %q, want %q", attemptRecord.ResponseModel, "gpt-5.4-mini")
|
|
}
|
|
|
|
imageRecord := capture.await(t)
|
|
if imageRecord.Model != "gpt-image-1.5" {
|
|
t.Fatalf("image record model = %q, want %q", imageRecord.Model, "gpt-image-1.5")
|
|
}
|
|
if imageRecord.ResponseModel != "" {
|
|
t.Fatalf("image record response model = %q, want empty", imageRecord.ResponseModel)
|
|
}
|
|
}
|