Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
226
backend/internal/thinking/apply_configured_api_key_test.go
Normal file
226
backend/internal/thinking/apply_configured_api_key_test.go
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
package thinking_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/registry"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/thinking"
|
||||
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/thinking/provider/claude"
|
||||
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/thinking/provider/codex"
|
||||
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/thinking/provider/openai"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func TestApplyThinkingWithModelInfoMapsCrossFamilyHighIntent(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
source string
|
||||
supported []string
|
||||
want string
|
||||
}{
|
||||
{name: "xhigh stays xhigh", source: "xhigh", supported: []string{"high", "max", "xhigh"}, want: "xhigh"},
|
||||
{name: "xhigh prefers max", source: "xhigh", supported: []string{"high", "max"}, want: "max"},
|
||||
{name: "xhigh falls back to high", source: "xhigh", supported: []string{"high"}, want: "high"},
|
||||
{name: "max stays max", source: "max", supported: []string{"high", "xhigh", "max"}, want: "max"},
|
||||
{name: "max prefers xhigh", source: "max", supported: []string{"high", "xhigh"}, want: "xhigh"},
|
||||
{name: "max falls back to high", source: "max", supported: []string{"high"}, want: "high"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "claude-upstream",
|
||||
Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: tc.supported},
|
||||
}
|
||||
body := []byte(`{"thinking":{"type":"adaptive"},"output_config":{"effort":"low"}}`)
|
||||
source := []byte(`{"reasoning_effort":"` + tc.source + `"}`)
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(body, source, "claude-upstream", "openai", "claude", "claude", modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "output_config.effort").String(); got != tc.want {
|
||||
t.Fatalf("output effort = %q, want %q; body=%s", got, tc.want, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoMapsOpenAICompatibilityHighIntent(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "compat-upstream",
|
||||
Type: "openai-compatibility",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high", "max"}},
|
||||
}
|
||||
body := []byte(`{"reasoning_effort":"high"}`)
|
||||
source := []byte(`{"reasoning_effort":"xhigh"}`)
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(body, source, "compat-upstream", "openai", "openai", "compat-provider", modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "reasoning_effort").String(); got != "max" {
|
||||
t.Fatalf("reasoning_effort = %q, want max; body=%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoMapsResponsesToCodexHighIntent(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "codex-upstream",
|
||||
Type: "codex",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high", "xhigh"}},
|
||||
}
|
||||
body := []byte(`{"reasoning":{"effort":"high"}}`)
|
||||
source := []byte(`{"reasoning":{"effort":"max"}}`)
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(body, source, "codex-upstream", "openai-response", "codex", "codex", modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "reasoning.effort").String(); got != "xhigh" {
|
||||
t.Fatalf("reasoning.effort = %q, want xhigh; body=%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoKeepsSameFamilyValidationStrict(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "openai-upstream",
|
||||
Type: "openai",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"low", "medium", "high"}},
|
||||
}
|
||||
body := []byte(`{"reasoning_effort":"xhigh"}`)
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(body, body, "openai-upstream", "openai", "openai", "openai", modelInfo)
|
||||
if err == nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = nil, want unsupported xhigh error; body=%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoAppliesEnabledSummaryOnlyClaudeVisibility(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "private-claude",
|
||||
Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high"}},
|
||||
}
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(
|
||||
[]byte(`{"model":"private-claude","max_tokens":32000}`),
|
||||
[]byte(`{"reasoning":{"summary":"auto"}}`),
|
||||
"private-claude", "openai-response", "claude", "claude", modelInfo,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "thinking.type").String(); got != "adaptive" {
|
||||
t.Fatalf("thinking.type = %q, want adaptive; body=%s", got, out)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "thinking.display").String(); got != "summarized" {
|
||||
t.Fatalf("thinking.display = %q, want summarized; body=%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoAndSummaryDropsInferredClaudeModeWhenSummaryRemoved(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "private-manual-claude",
|
||||
Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Min: 1024, Max: 16000},
|
||||
}
|
||||
out, err := thinking.ApplyThinkingWithModelInfoAndSummary(
|
||||
[]byte(`{"model":"private-manual-claude","max_tokens":32000,"thinking":{"type":"adaptive"}}`),
|
||||
[]byte(`{"reasoning":{"summary":"auto"}}`),
|
||||
"private-manual-claude", "openai-response", "claude", "claude", modelInfo,
|
||||
thinking.SummaryConfig{},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfoAndSummary() error = %v", err)
|
||||
}
|
||||
if gjson.GetBytes(out, "thinking").Exists() {
|
||||
t.Fatalf("removed summary retained globally inferred adaptive thinking: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoDoesNotActivateClaudeForDisabledSummary(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "private-claude",
|
||||
Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high"}},
|
||||
}
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(
|
||||
[]byte(`{"model":"private-claude","max_tokens":32000}`),
|
||||
[]byte(`{"reasoning":{"summary":null}}`),
|
||||
"private-claude", "openai-response", "claude", "claude", modelInfo,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if gjson.GetBytes(out, "thinking").Exists() {
|
||||
t.Fatalf("disabled summary activated Claude thinking: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoSummaryOnlyDoesNotInventOpenAIEffort(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "private-openai",
|
||||
Type: "openai",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high", "max"}},
|
||||
}
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(
|
||||
[]byte(`{"model":"private-openai","messages":[{"role":"user","content":"hi"}]}`),
|
||||
[]byte(`{"model":"private-openai","reasoning":{"summary":"auto"},"input":"hi"}`),
|
||||
"private-openai", "openai-response", "openai", "openai", modelInfo,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v; body=%s", err, out)
|
||||
}
|
||||
if gjson.GetBytes(out, "reasoning_effort").Exists() {
|
||||
t.Fatalf("summary-only request invented reasoning_effort: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithSummaryKeepsOpenAIChatSuffixNone(t *testing.T) {
|
||||
out, err := thinking.ApplyThinkingWithSummary(
|
||||
[]byte(`{"model":"private-openai","messages":[{"role":"user","content":"hi"}]}`),
|
||||
"private-openai(none)", "openai-response", "openai", "openai",
|
||||
thinking.SummaryConfig{Mode: thinking.SummaryEnabled, Detail: "auto"},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithSummary() error = %v; body=%s", err, out)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "reasoning_effort").String(); got != "none" {
|
||||
t.Fatalf("reasoning_effort = %q, want none; body=%s", got, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoUsesOpenRouterVisibility(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "openrouter-model",
|
||||
Type: "openai-compatibility",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high", "max"}},
|
||||
}
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(
|
||||
[]byte(`{"model":"openrouter-model","messages":[{"role":"user","content":"hi"}]}`),
|
||||
[]byte(`{"model":"openrouter-model","reasoning":{"summary":"auto"},"input":"hi"}`),
|
||||
"openrouter-model", "openai-response", "openai", "openrouter", modelInfo,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v; body=%s", err, out)
|
||||
}
|
||||
if exclude := gjson.GetBytes(out, "reasoning.exclude"); !exclude.Exists() || exclude.Bool() {
|
||||
t.Fatalf("OpenRouter summary visibility not enabled: %s", out)
|
||||
}
|
||||
if gjson.GetBytes(out, "reasoning_effort").Exists() {
|
||||
t.Fatalf("OpenRouter summary visibility invented reasoning_effort: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyThinkingWithModelInfoUsesOriginalResponsesEffort(t *testing.T) {
|
||||
modelInfo := ®istry.ModelInfo{
|
||||
ID: "claude-upstream",
|
||||
Type: "claude",
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"high", "max"}},
|
||||
}
|
||||
body := []byte(`{"thinking":{"type":"adaptive"},"output_config":{"effort":"low"}}`)
|
||||
source := []byte(`{"reasoning":{"effort":"xhigh"}}`)
|
||||
out, err := thinking.ApplyThinkingWithModelInfo(body, source, "claude-upstream", "openai-response", "claude", "claude", modelInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("ApplyThinkingWithModelInfo() error = %v", err)
|
||||
}
|
||||
if got := gjson.GetBytes(out, "output_config.effort").String(); got != "max" {
|
||||
t.Fatalf("output effort = %q, want max; body=%s", got, out)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue