mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
1055 lines
34 KiB
Go
1055 lines
34 KiB
Go
package test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/translator"
|
|
|
|
// Import provider packages to trigger init() registration of ProviderAppliers
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/antigravity"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/claude"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/codex"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/gemini"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/geminicli"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/iflow"
|
|
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/thinking/provider/openai"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
|
sdktranslator "github.com/router-for-me/CLIProxyAPI/v6/sdk/translator"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
// TestThinkingE2EMatrix tests the thinking configuration transformation using the real data flow path.
|
|
// Data flow: Input JSON → TranslateRequest → ApplyThinking → Validate Output
|
|
// No helper functions are used; all test data is inline.
|
|
func TestThinkingE2EMatrix(t *testing.T) {
|
|
// Register test models directly
|
|
reg := registry.GetGlobalRegistry()
|
|
uid := fmt.Sprintf("thinking-e2e-%d", time.Now().UnixNano())
|
|
|
|
testModels := []*registry.ModelInfo{
|
|
{
|
|
ID: "level-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "openai",
|
|
DisplayName: "Level Model",
|
|
Thinking: ®istry.ThinkingSupport{
|
|
Levels: []string{"minimal", "low", "medium", "high"},
|
|
ZeroAllowed: false,
|
|
DynamicAllowed: false,
|
|
},
|
|
},
|
|
{
|
|
ID: "gemini-budget-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "gemini",
|
|
DisplayName: "Gemini Budget Model",
|
|
Thinking: ®istry.ThinkingSupport{
|
|
Min: 128,
|
|
Max: 20000,
|
|
ZeroAllowed: false,
|
|
DynamicAllowed: true,
|
|
},
|
|
},
|
|
{
|
|
ID: "gemini-mixed-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "gemini",
|
|
DisplayName: "Gemini Mixed Model",
|
|
Thinking: ®istry.ThinkingSupport{
|
|
Min: 128,
|
|
Max: 32768,
|
|
Levels: []string{"low", "high"},
|
|
ZeroAllowed: false,
|
|
DynamicAllowed: true,
|
|
},
|
|
},
|
|
{
|
|
ID: "claude-budget-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "claude",
|
|
DisplayName: "Claude Budget Model",
|
|
Thinking: ®istry.ThinkingSupport{
|
|
Min: 1024,
|
|
Max: 128000,
|
|
ZeroAllowed: true,
|
|
DynamicAllowed: false,
|
|
},
|
|
},
|
|
{
|
|
ID: "antigravity-budget-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "gemini-cli",
|
|
DisplayName: "Antigravity Budget Model",
|
|
Thinking: ®istry.ThinkingSupport{
|
|
Min: 128,
|
|
Max: 20000,
|
|
ZeroAllowed: true,
|
|
DynamicAllowed: true,
|
|
},
|
|
},
|
|
{
|
|
ID: "no-thinking-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "openai",
|
|
DisplayName: "No Thinking Model",
|
|
Thinking: nil,
|
|
},
|
|
{
|
|
ID: "user-defined-model",
|
|
Object: "model",
|
|
Created: 1700000000,
|
|
OwnedBy: "test",
|
|
Type: "openai",
|
|
DisplayName: "User Defined Model",
|
|
UserDefined: true,
|
|
Thinking: nil,
|
|
},
|
|
}
|
|
|
|
reg.RegisterClient(uid, "test", testModels)
|
|
defer reg.UnregisterClient(uid)
|
|
|
|
type testCase struct {
|
|
name string
|
|
from string
|
|
to string
|
|
modelSuffix string
|
|
inputJSON string
|
|
expectField string
|
|
expectValue string
|
|
includeThoughts string
|
|
expectErr bool
|
|
}
|
|
|
|
cases := []testCase{
|
|
// level-model (Levels=minimal/low/medium/high, ZeroAllowed=false, DynamicAllowed=false)
|
|
// Case 1: No suffix, translator adds default medium for codex
|
|
{
|
|
name: "1",
|
|
from: "openai",
|
|
to: "codex",
|
|
modelSuffix: "level-model",
|
|
inputJSON: `{"model":"level-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 2: Explicit medium level
|
|
{
|
|
name: "2",
|
|
from: "openai",
|
|
to: "codex",
|
|
modelSuffix: "level-model(medium)",
|
|
inputJSON: `{"model":"level-model(medium)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 3: xhigh not in Levels=[minimal,low,medium,high] → ValidateConfig returns error
|
|
{
|
|
name: "3",
|
|
from: "openai",
|
|
to: "codex",
|
|
modelSuffix: "level-model(xhigh)",
|
|
inputJSON: `{"model":"level-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: true,
|
|
},
|
|
// Case 4: none → ModeNone, ZeroAllowed=false → clamp to min level (minimal)
|
|
{
|
|
name: "4",
|
|
from: "openai",
|
|
to: "codex",
|
|
modelSuffix: "level-model(none)",
|
|
inputJSON: `{"model":"level-model(none)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "minimal",
|
|
expectErr: false,
|
|
},
|
|
// Case 5: auto → ModeAuto, DynamicAllowed=false → convert to mid-range (medium)
|
|
{
|
|
name: "5",
|
|
from: "openai",
|
|
to: "codex",
|
|
modelSuffix: "level-model(auto)",
|
|
inputJSON: `{"model":"level-model(auto)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 6: No suffix from gemini → translator injects default reasoning.effort: medium
|
|
{
|
|
name: "6",
|
|
from: "gemini",
|
|
to: "codex",
|
|
modelSuffix: "level-model",
|
|
inputJSON: `{"model":"level-model","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 7: 8192 → medium (1025-8192)
|
|
{
|
|
name: "7",
|
|
from: "gemini",
|
|
to: "codex",
|
|
modelSuffix: "level-model(8192)",
|
|
inputJSON: `{"model":"level-model(8192)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 8: 64000 → xhigh → not supported → error
|
|
{
|
|
name: "8",
|
|
from: "gemini",
|
|
to: "codex",
|
|
modelSuffix: "level-model(64000)",
|
|
inputJSON: `{"model":"level-model(64000)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: true,
|
|
},
|
|
// Case 9: 0 → ModeNone, ZeroAllowed=false → clamp to min level (minimal)
|
|
{
|
|
name: "9",
|
|
from: "gemini",
|
|
to: "codex",
|
|
modelSuffix: "level-model(0)",
|
|
inputJSON: `{"model":"level-model(0)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "minimal",
|
|
expectErr: false,
|
|
},
|
|
// Case 10: -1 → ModeAuto, DynamicAllowed=false → convert to mid-range (medium)
|
|
{
|
|
name: "10",
|
|
from: "gemini",
|
|
to: "codex",
|
|
modelSuffix: "level-model(-1)",
|
|
inputJSON: `{"model":"level-model(-1)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 11: No suffix from claude → no thinking config
|
|
{
|
|
name: "11",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "level-model",
|
|
inputJSON: `{"model":"level-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// Case 12: 8192 → medium
|
|
{
|
|
name: "12",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "level-model(8192)",
|
|
inputJSON: `{"model":"level-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// Case 13: 64000 → xhigh → not supported → error
|
|
{
|
|
name: "13",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "level-model(64000)",
|
|
inputJSON: `{"model":"level-model(64000)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: true,
|
|
},
|
|
// Case 14: 0 → ModeNone, ZeroAllowed=false → clamp to min level (minimal)
|
|
{
|
|
name: "14",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "level-model(0)",
|
|
inputJSON: `{"model":"level-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "minimal",
|
|
expectErr: false,
|
|
},
|
|
// Case 15: -1 → ModeAuto, DynamicAllowed=false → convert to mid-range (medium)
|
|
{
|
|
name: "15",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "level-model(-1)",
|
|
inputJSON: `{"model":"level-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
|
|
// gemini-budget-model (Min=128, Max=20000, ZeroAllowed=false, DynamicAllowed=true)
|
|
{
|
|
name: "16",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model",
|
|
inputJSON: `{"model":"gemini-budget-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// medium → 8192
|
|
{
|
|
name: "17",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(medium)",
|
|
inputJSON: `{"model":"gemini-budget-model(medium)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
// xhigh → 32768 → clamp to 20000
|
|
{
|
|
name: "18",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(xhigh)",
|
|
inputJSON: `{"model":"gemini-budget-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "20000",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
// none → 0 → ZeroAllowed=false → clamp to 128, includeThoughts=false
|
|
{
|
|
name: "19",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(none)",
|
|
inputJSON: `{"model":"gemini-budget-model(none)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "128",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
// auto → -1 dynamic allowed
|
|
{
|
|
name: "20",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(auto)",
|
|
inputJSON: `{"model":"gemini-budget-model(auto)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "21",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model",
|
|
inputJSON: `{"model":"gemini-budget-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "22",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(8192)",
|
|
inputJSON: `{"model":"gemini-budget-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "23",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(64000)",
|
|
inputJSON: `{"model":"gemini-budget-model(64000)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "20000",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "24",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(0)",
|
|
inputJSON: `{"model":"gemini-budget-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "128",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "25",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-budget-model(-1)",
|
|
inputJSON: `{"model":"gemini-budget-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
|
|
// gemini-mixed-model (Min=128, Max=32768, Levels=low/high, ZeroAllowed=false, DynamicAllowed=true)
|
|
{
|
|
name: "26",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model",
|
|
inputJSON: `{"model":"gemini-mixed-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// high → use thinkingLevel
|
|
{
|
|
name: "27",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(high)",
|
|
inputJSON: `{"model":"gemini-mixed-model(high)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingLevel",
|
|
expectValue: "high",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
// xhigh → not in Levels=[low,high] → error
|
|
{
|
|
name: "28",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(xhigh)",
|
|
inputJSON: `{"model":"gemini-mixed-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: true,
|
|
},
|
|
// none → ModeNone, ZeroAllowed=false → set Level to lowest (low), includeThoughts=false
|
|
{
|
|
name: "29",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(none)",
|
|
inputJSON: `{"model":"gemini-mixed-model(none)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingLevel",
|
|
expectValue: "low",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
// auto → dynamic allowed, use thinkingBudget=-1
|
|
{
|
|
name: "30",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(auto)",
|
|
inputJSON: `{"model":"gemini-mixed-model(auto)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "31",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model",
|
|
inputJSON: `{"model":"gemini-mixed-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// 8192 → ModeBudget → clamp (in range) → thinkingBudget: 8192
|
|
{
|
|
name: "32",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(8192)",
|
|
inputJSON: `{"model":"gemini-mixed-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
// 64000 → ModeBudget → clamp to 32768 → thinkingBudget: 32768
|
|
{
|
|
name: "33",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(64000)",
|
|
inputJSON: `{"model":"gemini-mixed-model(64000)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "32768",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
// 0 → ModeNone, ZeroAllowed=false → set Level to lowest (low), includeThoughts=false
|
|
{
|
|
name: "34",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(0)",
|
|
inputJSON: `{"model":"gemini-mixed-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingLevel",
|
|
expectValue: "low",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
// -1 → auto, dynamic allowed
|
|
{
|
|
name: "35",
|
|
from: "claude",
|
|
to: "gemini",
|
|
modelSuffix: "gemini-mixed-model(-1)",
|
|
inputJSON: `{"model":"gemini-mixed-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
|
|
// claude-budget-model (Min=1024, Max=128000, ZeroAllowed=true, DynamicAllowed=false)
|
|
{
|
|
name: "36",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model",
|
|
inputJSON: `{"model":"claude-budget-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// medium → 8192
|
|
{
|
|
name: "37",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(medium)",
|
|
inputJSON: `{"model":"claude-budget-model(medium)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "8192",
|
|
expectErr: false,
|
|
},
|
|
// xhigh → 32768
|
|
{
|
|
name: "38",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(xhigh)",
|
|
inputJSON: `{"model":"claude-budget-model(xhigh)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "32768",
|
|
expectErr: false,
|
|
},
|
|
// none → ZeroAllowed=true → disabled
|
|
{
|
|
name: "39",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(none)",
|
|
inputJSON: `{"model":"claude-budget-model(none)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.type",
|
|
expectValue: "disabled",
|
|
expectErr: false,
|
|
},
|
|
// auto → ModeAuto, DynamicAllowed=false → convert to mid-range
|
|
{
|
|
name: "40",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(auto)",
|
|
inputJSON: `{"model":"claude-budget-model(auto)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "64512",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "41",
|
|
from: "gemini",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model",
|
|
inputJSON: `{"model":"claude-budget-model","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "42",
|
|
from: "gemini",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(8192)",
|
|
inputJSON: `{"model":"claude-budget-model(8192)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "8192",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "43",
|
|
from: "gemini",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(200000)",
|
|
inputJSON: `{"model":"claude-budget-model(200000)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "128000",
|
|
expectErr: false,
|
|
},
|
|
// 0 → ZeroAllowed=true → disabled
|
|
{
|
|
name: "44",
|
|
from: "gemini",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(0)",
|
|
inputJSON: `{"model":"claude-budget-model(0)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "thinking.type",
|
|
expectValue: "disabled",
|
|
expectErr: false,
|
|
},
|
|
// -1 → auto → DynamicAllowed=false → mid-range
|
|
{
|
|
name: "45",
|
|
from: "gemini",
|
|
to: "claude",
|
|
modelSuffix: "claude-budget-model(-1)",
|
|
inputJSON: `{"model":"claude-budget-model(-1)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "64512",
|
|
expectErr: false,
|
|
},
|
|
|
|
// antigravity-budget-model (Min=128, Max=20000, ZeroAllowed=true, DynamicAllowed=true)
|
|
{
|
|
name: "46",
|
|
from: "gemini",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model",
|
|
inputJSON: `{"model":"antigravity-budget-model","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "47",
|
|
from: "gemini",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(medium)",
|
|
inputJSON: `{"model":"antigravity-budget-model(medium)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "48",
|
|
from: "gemini",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(xhigh)",
|
|
inputJSON: `{"model":"antigravity-budget-model(xhigh)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "20000",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "49",
|
|
from: "gemini",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(none)",
|
|
inputJSON: `{"model":"antigravity-budget-model(none)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "0",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "50",
|
|
from: "gemini",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(auto)",
|
|
inputJSON: `{"model":"antigravity-budget-model(auto)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "51",
|
|
from: "claude",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model",
|
|
inputJSON: `{"model":"antigravity-budget-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "52",
|
|
from: "claude",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(8192)",
|
|
inputJSON: `{"model":"antigravity-budget-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "53",
|
|
from: "claude",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(64000)",
|
|
inputJSON: `{"model":"antigravity-budget-model(64000)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "20000",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "54",
|
|
from: "claude",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(0)",
|
|
inputJSON: `{"model":"antigravity-budget-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "0",
|
|
includeThoughts: "false",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "55",
|
|
from: "claude",
|
|
to: "antigravity",
|
|
modelSuffix: "antigravity-budget-model(-1)",
|
|
inputJSON: `{"model":"antigravity-budget-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "request.generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "-1",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
|
|
// no-thinking-model (Thinking=nil)
|
|
{
|
|
name: "46",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model",
|
|
inputJSON: `{"model":"no-thinking-model","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "47",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(8192)",
|
|
inputJSON: `{"model":"no-thinking-model(8192)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "48",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(0)",
|
|
inputJSON: `{"model":"no-thinking-model(0)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "49",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(-1)",
|
|
inputJSON: `{"model":"no-thinking-model(-1)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "50",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model",
|
|
inputJSON: `{"model":"no-thinking-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "51",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(8192)",
|
|
inputJSON: `{"model":"no-thinking-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "52",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(0)",
|
|
inputJSON: `{"model":"no-thinking-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "53",
|
|
from: "claude",
|
|
to: "openai",
|
|
modelSuffix: "no-thinking-model(-1)",
|
|
inputJSON: `{"model":"no-thinking-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
|
|
// user-defined-model (UserDefined=true, Thinking=nil)
|
|
{
|
|
name: "54",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "user-defined-model",
|
|
inputJSON: `{"model":"user-defined-model","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "",
|
|
expectErr: false,
|
|
},
|
|
// 8192 → medium (passthrough for UserDefined)
|
|
{
|
|
name: "55",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// 64000 → xhigh
|
|
{
|
|
name: "56",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "user-defined-model(64000)",
|
|
inputJSON: `{"model":"user-defined-model(64000)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "xhigh",
|
|
expectErr: false,
|
|
},
|
|
// 0 → none
|
|
{
|
|
name: "57",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "user-defined-model(0)",
|
|
inputJSON: `{"model":"user-defined-model(0)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "none",
|
|
expectErr: false,
|
|
},
|
|
// -1 → auto
|
|
{
|
|
name: "58",
|
|
from: "gemini",
|
|
to: "openai",
|
|
modelSuffix: "user-defined-model(-1)",
|
|
inputJSON: `{"model":"user-defined-model(-1)","contents":[{"role":"user","parts":[{"text":"hi"}]}]}`,
|
|
expectField: "reasoning_effort",
|
|
expectValue: "auto",
|
|
expectErr: false,
|
|
},
|
|
// Case 59: No suffix from claude → translator injects default reasoning.effort: medium
|
|
{
|
|
name: "59",
|
|
from: "claude",
|
|
to: "codex",
|
|
modelSuffix: "user-defined-model",
|
|
inputJSON: `{"model":"user-defined-model","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// 8192 → medium
|
|
{
|
|
name: "60",
|
|
from: "claude",
|
|
to: "codex",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "medium",
|
|
expectErr: false,
|
|
},
|
|
// 64000 → xhigh
|
|
{
|
|
name: "61",
|
|
from: "claude",
|
|
to: "codex",
|
|
modelSuffix: "user-defined-model(64000)",
|
|
inputJSON: `{"model":"user-defined-model(64000)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "xhigh",
|
|
expectErr: false,
|
|
},
|
|
// 0 → none
|
|
{
|
|
name: "62",
|
|
from: "claude",
|
|
to: "codex",
|
|
modelSuffix: "user-defined-model(0)",
|
|
inputJSON: `{"model":"user-defined-model(0)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "none",
|
|
expectErr: false,
|
|
},
|
|
// -1 → auto
|
|
{
|
|
name: "63",
|
|
from: "claude",
|
|
to: "codex",
|
|
modelSuffix: "user-defined-model(-1)",
|
|
inputJSON: `{"model":"user-defined-model(-1)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "reasoning.effort",
|
|
expectValue: "auto",
|
|
expectErr: false,
|
|
},
|
|
// openai/codex → gemini/claude for user-defined-model
|
|
{
|
|
name: "64",
|
|
from: "openai",
|
|
to: "gemini",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "65",
|
|
from: "openai",
|
|
to: "claude",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","messages":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "8192",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "66",
|
|
from: "codex",
|
|
to: "gemini",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","input":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "generationConfig.thinkingConfig.thinkingBudget",
|
|
expectValue: "8192",
|
|
includeThoughts: "true",
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "67",
|
|
from: "codex",
|
|
to: "claude",
|
|
modelSuffix: "user-defined-model(8192)",
|
|
inputJSON: `{"model":"user-defined-model(8192)","input":[{"role":"user","content":"hi"}]}`,
|
|
expectField: "thinking.budget_tokens",
|
|
expectValue: "8192",
|
|
expectErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
testName := fmt.Sprintf("Case%s_%s->%s_%s", tc.name, tc.from, tc.to, tc.modelSuffix)
|
|
t.Run(testName, func(t *testing.T) {
|
|
// Real data flow path:
|
|
// 1. Parse suffix to get base model
|
|
suffixResult := thinking.ParseSuffix(tc.modelSuffix)
|
|
baseModel := suffixResult.ModelName
|
|
|
|
// 2. Translate request from source format to target format
|
|
body := sdktranslator.TranslateRequest(
|
|
sdktranslator.FromString(tc.from),
|
|
sdktranslator.FromString(tc.to),
|
|
baseModel,
|
|
[]byte(tc.inputJSON),
|
|
true,
|
|
)
|
|
|
|
// 3. Apply thinking configuration (main entry point)
|
|
body, err := thinking.ApplyThinking(body, tc.modelSuffix, tc.to)
|
|
|
|
// Validate results
|
|
if tc.expectErr {
|
|
if err == nil {
|
|
t.Fatalf("expected error but got none, body=%s", string(body))
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v, body=%s", err, string(body))
|
|
}
|
|
|
|
// Check for expected field absence
|
|
if tc.expectField == "" {
|
|
var hasThinking bool
|
|
switch tc.to {
|
|
case "gemini":
|
|
hasThinking = gjson.GetBytes(body, "generationConfig.thinkingConfig").Exists()
|
|
case "claude":
|
|
hasThinking = gjson.GetBytes(body, "thinking").Exists()
|
|
case "openai":
|
|
hasThinking = gjson.GetBytes(body, "reasoning_effort").Exists()
|
|
case "codex":
|
|
hasThinking = gjson.GetBytes(body, "reasoning.effort").Exists() || gjson.GetBytes(body, "reasoning").Exists()
|
|
}
|
|
if hasThinking {
|
|
t.Fatalf("expected no thinking field but found one, body=%s", string(body))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Check expected field value
|
|
val := gjson.GetBytes(body, tc.expectField)
|
|
if !val.Exists() {
|
|
t.Fatalf("expected field %s not found, body=%s", tc.expectField, string(body))
|
|
}
|
|
|
|
actualValue := val.String()
|
|
if val.Type == gjson.Number {
|
|
actualValue = fmt.Sprintf("%d", val.Int())
|
|
}
|
|
if actualValue != tc.expectValue {
|
|
t.Fatalf("field %s: expected %q, got %q, body=%s", tc.expectField, tc.expectValue, actualValue, string(body))
|
|
}
|
|
|
|
// Check includeThoughts for Gemini/Antigravity
|
|
if tc.includeThoughts != "" && (tc.to == "gemini" || tc.to == "antigravity") {
|
|
path := "generationConfig.thinkingConfig.includeThoughts"
|
|
if tc.to == "antigravity" {
|
|
path = "request.generationConfig.thinkingConfig.includeThoughts"
|
|
}
|
|
itVal := gjson.GetBytes(body, path)
|
|
if !itVal.Exists() {
|
|
t.Fatalf("expected includeThoughts field not found, body=%s", string(body))
|
|
}
|
|
actual := fmt.Sprintf("%v", itVal.Bool())
|
|
if actual != tc.includeThoughts {
|
|
t.Fatalf("includeThoughts: expected %s, got %s, body=%s", tc.includeThoughts, actual, string(body))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|