Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
|
|
@ -0,0 +1,233 @@
|
|||
package helps_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
internalconfig "github.com/router-for-me/CLIProxyAPI/v7/internal/config"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/registry"
|
||||
helps "github.com/router-for-me/CLIProxyAPI/v7/internal/runtime/executor/helps"
|
||||
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/thinking/provider/claude"
|
||||
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/translator"
|
||||
cliproxyauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
|
||||
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/executor"
|
||||
sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type configuredThinkingExecutor struct {
|
||||
seenModel string
|
||||
resolved bool
|
||||
translateRequest bool
|
||||
translatedBody []byte
|
||||
}
|
||||
|
||||
func (*configuredThinkingExecutor) Identifier() string { return "claude" }
|
||||
|
||||
func (e *configuredThinkingExecutor) Execute(_ context.Context, _ *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
||||
e.seenModel = req.Model
|
||||
modelInfo, resolved := cliproxyauth.ResolvedAPIKeyModelInfo(req)
|
||||
e.resolved = resolved && modelInfo != nil
|
||||
body := []byte(`{"thinking":{"type":"adaptive"},"output_config":{"effort":"low"}}`)
|
||||
if e.translateRequest {
|
||||
body = sdktranslator.TranslateRequest(opts.SourceFormat, sdktranslator.FormatClaude, req.Model, req.Payload, opts.Stream)
|
||||
e.translatedBody = append(e.translatedBody[:0], body...)
|
||||
}
|
||||
out, err := helps.ApplyRequestThinking(body, req, opts, opts.SourceFormat.String(), "claude", "claude")
|
||||
return cliproxyexecutor.Response{Payload: out}, err
|
||||
}
|
||||
|
||||
func (e *configuredThinkingExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (*cliproxyexecutor.StreamResult, error) {
|
||||
response, err := e.Execute(ctx, auth, req, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
chunks := make(chan cliproxyexecutor.StreamChunk, 1)
|
||||
chunks <- cliproxyexecutor.StreamChunk{Payload: response.Payload}
|
||||
close(chunks)
|
||||
return &cliproxyexecutor.StreamResult{Chunks: chunks}, nil
|
||||
}
|
||||
|
||||
func (*configuredThinkingExecutor) Refresh(_ context.Context, auth *cliproxyauth.Auth) (*cliproxyauth.Auth, error) {
|
||||
return auth, nil
|
||||
}
|
||||
|
||||
func (e *configuredThinkingExecutor) CountTokens(ctx context.Context, auth *cliproxyauth.Auth, req cliproxyexecutor.Request, opts cliproxyexecutor.Options) (cliproxyexecutor.Response, error) {
|
||||
return e.Execute(ctx, auth, req, opts)
|
||||
}
|
||||
|
||||
func (*configuredThinkingExecutor) HttpRequest(context.Context, *cliproxyauth.Auth, *http.Request) (*http.Response, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestApplyRequestThinkingUsesExactClaudeModeForSummaryOnlyRequest(t *testing.T) {
|
||||
manager := cliproxyauth.NewManager(nil, nil, nil)
|
||||
manager.SetConfig(&internalconfig.Config{
|
||||
SDKConfig: internalconfig.SDKConfig{ForceModelPrefix: true},
|
||||
ClaudeKey: []internalconfig.ClaudeKey{{
|
||||
APIKey: "summary-selected-key",
|
||||
Prefix: "summary-tenant",
|
||||
Models: []internalconfig.ClaudeModel{{
|
||||
Name: "summary-shared-upstream",
|
||||
Alias: "summary-public-model",
|
||||
Thinking: ®istry.ThinkingSupport{
|
||||
Min: 1024,
|
||||
Max: 16000,
|
||||
},
|
||||
}},
|
||||
}},
|
||||
})
|
||||
executor := &configuredThinkingExecutor{translateRequest: true}
|
||||
manager.RegisterExecutor(executor)
|
||||
auth := &cliproxyauth.Auth{
|
||||
ID: "summary-selected-auth",
|
||||
Provider: "claude",
|
||||
Prefix: "summary-tenant",
|
||||
Attributes: map[string]string{
|
||||
cliproxyauth.AttributeAuthKind: cliproxyauth.AuthKindAPIKey,
|
||||
cliproxyauth.AttributeAPIKey: "summary-selected-key",
|
||||
cliproxyauth.AttributeSource: "config:claude[0]",
|
||||
},
|
||||
}
|
||||
|
||||
modelRegistry := registry.GetGlobalRegistry()
|
||||
modelRegistry.RegisterClient(auth.ID, auth.Provider, []*registry.ModelInfo{{
|
||||
ID: "summary-tenant/summary-public-model", Type: "claude",
|
||||
}})
|
||||
modelRegistry.RegisterClient("summary-unrelated-auth", auth.Provider, []*registry.ModelInfo{{
|
||||
ID: "summary-shared-upstream", Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high"}},
|
||||
}})
|
||||
t.Cleanup(func() {
|
||||
modelRegistry.UnregisterClient(auth.ID)
|
||||
modelRegistry.UnregisterClient("summary-unrelated-auth")
|
||||
})
|
||||
if registered, errRegister := manager.Register(t.Context(), auth); errRegister != nil {
|
||||
t.Fatalf("Register() error = %v", errRegister)
|
||||
} else if registered == nil {
|
||||
t.Fatal("Register() returned nil auth")
|
||||
}
|
||||
|
||||
original := []byte(`{"model":"summary-tenant/summary-public-model","reasoning":{"summary":"auto"},"input":"hi"}`)
|
||||
response, errExecute := manager.Execute(t.Context(), []string{"claude"}, cliproxyexecutor.Request{
|
||||
Model: "summary-tenant/summary-public-model",
|
||||
Payload: original,
|
||||
Format: sdktranslator.FormatOpenAIResponse,
|
||||
}, cliproxyexecutor.Options{
|
||||
SourceFormat: sdktranslator.FormatOpenAIResponse,
|
||||
OriginalRequest: original,
|
||||
})
|
||||
if errExecute != nil {
|
||||
t.Fatalf("Execute() error = %v", errExecute)
|
||||
}
|
||||
if got := gjson.GetBytes(executor.translatedBody, "thinking.type").String(); got != "adaptive" {
|
||||
t.Fatalf("pre-executor thinking.type = %q, want global adaptive trigger; body=%s", got, executor.translatedBody)
|
||||
}
|
||||
if got := gjson.GetBytes(response.Payload, "thinking.type").String(); got != "enabled" {
|
||||
t.Fatalf("thinking.type = %q, want exact manual mode; body=%s", got, response.Payload)
|
||||
}
|
||||
if got := gjson.GetBytes(response.Payload, "thinking.budget_tokens").Int(); got != 1024 {
|
||||
t.Fatalf("thinking.budget_tokens = %d, want exact minimum 1024; body=%s", got, response.Payload)
|
||||
}
|
||||
if got := gjson.GetBytes(response.Payload, "thinking.display").String(); got != "summarized" {
|
||||
t.Fatalf("thinking.display = %q, want summarized; body=%s", got, response.Payload)
|
||||
}
|
||||
if gjson.GetBytes(response.Payload, "output_config.effort").Exists() {
|
||||
t.Fatalf("manual thinking retained adaptive effort: %s", response.Payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRequestThinkingUsesSelectedPrefixedAPIKeyModel(t *testing.T) {
|
||||
manager := cliproxyauth.NewManager(nil, nil, nil)
|
||||
manager.SetConfig(&internalconfig.Config{
|
||||
SDKConfig: internalconfig.SDKConfig{ForceModelPrefix: true},
|
||||
ClaudeKey: []internalconfig.ClaudeKey{{
|
||||
APIKey: "selected-key",
|
||||
Prefix: "tenant",
|
||||
Models: []internalconfig.ClaudeModel{{
|
||||
Name: "shared-upstream", Alias: "public-model",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high"}},
|
||||
}},
|
||||
}},
|
||||
})
|
||||
executor := &configuredThinkingExecutor{}
|
||||
manager.RegisterExecutor(executor)
|
||||
auth := &cliproxyauth.Auth{
|
||||
ID: "selected-auth",
|
||||
Provider: "claude",
|
||||
Prefix: "tenant",
|
||||
Attributes: map[string]string{
|
||||
cliproxyauth.AttributeAuthKind: cliproxyauth.AuthKindAPIKey,
|
||||
cliproxyauth.AttributeAPIKey: "selected-key",
|
||||
cliproxyauth.AttributeSource: "config:claude[0]",
|
||||
},
|
||||
}
|
||||
|
||||
modelRegistry := registry.GetGlobalRegistry()
|
||||
modelRegistry.RegisterClient(auth.ID, auth.Provider, []*registry.ModelInfo{{ID: "tenant/public-model", Type: "claude"}})
|
||||
modelRegistry.RegisterClient("unrelated-auth", auth.Provider, []*registry.ModelInfo{{
|
||||
ID: "shared-upstream", Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"max"}},
|
||||
}})
|
||||
t.Cleanup(func() {
|
||||
modelRegistry.UnregisterClient(auth.ID)
|
||||
modelRegistry.UnregisterClient("unrelated-auth")
|
||||
})
|
||||
ctx := t.Context()
|
||||
registered, errRegister := manager.Register(ctx, auth)
|
||||
if errRegister != nil {
|
||||
t.Fatalf("Register() error = %v", errRegister)
|
||||
}
|
||||
if registered == nil {
|
||||
t.Fatal("Register() returned nil auth")
|
||||
}
|
||||
|
||||
original := []byte(`{"model":"tenant/public-model","reasoning_effort":"max","messages":[{"role":"user","content":"hello"}]}`)
|
||||
req := cliproxyexecutor.Request{
|
||||
Model: "tenant/public-model",
|
||||
Payload: original,
|
||||
Format: sdktranslator.FormatOpenAI,
|
||||
}
|
||||
opts := cliproxyexecutor.Options{
|
||||
SourceFormat: sdktranslator.FormatOpenAI,
|
||||
OriginalRequest: original,
|
||||
}
|
||||
assertResponse := func(path string, payload []byte) {
|
||||
t.Helper()
|
||||
if executor.seenModel != "shared-upstream" {
|
||||
t.Fatalf("%s executor model = %q, want shared-upstream", path, executor.seenModel)
|
||||
}
|
||||
if !executor.resolved {
|
||||
t.Fatalf("%s request did not receive selected model capabilities", path)
|
||||
}
|
||||
if got := gjson.GetBytes(payload, "output_config.effort").String(); got != "high" {
|
||||
t.Fatalf("%s output effort = %q, want selected credential capability high; body=%s", path, got, payload)
|
||||
}
|
||||
}
|
||||
|
||||
response, errExecute := manager.Execute(ctx, []string{"claude"}, req, opts)
|
||||
if errExecute != nil {
|
||||
t.Fatalf("Execute() error = %v", errExecute)
|
||||
}
|
||||
assertResponse("execute", response.Payload)
|
||||
|
||||
countResponse, errCount := manager.ExecuteCount(ctx, []string{"claude"}, req, opts)
|
||||
if errCount != nil {
|
||||
t.Fatalf("ExecuteCount() error = %v", errCount)
|
||||
}
|
||||
assertResponse("count", countResponse.Payload)
|
||||
|
||||
streamResult, errStream := manager.ExecuteStream(ctx, []string{"claude"}, req, opts)
|
||||
if errStream != nil {
|
||||
t.Fatalf("ExecuteStream() error = %v", errStream)
|
||||
}
|
||||
var streamPayload []byte
|
||||
for chunk := range streamResult.Chunks {
|
||||
if chunk.Err != nil {
|
||||
t.Fatalf("ExecuteStream() chunk error = %v", chunk.Err)
|
||||
}
|
||||
streamPayload = append(streamPayload, chunk.Payload...)
|
||||
}
|
||||
assertResponse("stream", streamPayload)
|
||||
}
|
||||
Loading…
Reference in a new issue