Something went wrong. Try again.
sloproxy
Something went wrong. Try again.
11 kB · 288 lines
Go
at commit 42eef103
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289package executor
import ( "context" "io" "net/http" "net/http/httptest" "testing"
"github.com/router-for-me/CLIProxyAPI/v7/internal/config" 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")
func TestCodexExecutorExecuteResponsesLiteHeaderDoesNotInjectImageGenerationTool(t *testing.T) { var gotBody []byte server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, errRead := io.ReadAll(r.Body) if errRead != nil { t.Fatalf("read request body: %v", errRead) } gotBody = body w.Header().Set("Content-Type", "text/event-stream") _, _ = w.Write([]byte("data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_1\",\"object\":\"response\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"total_tokens\":0}}}\n\n")) })) defer server.Close()
executor := NewCodexExecutor(&config.Config{}) auth := &cliproxyauth.Auth{ Provider: "codex", Attributes: map[string]string{ "api_key": "test", "base_url": server.URL, "plan_type": "pro", }, } headers := make(http.Header) headers.Set("X-OpenAI-Internal-Codex-Responses-Lite", "true")
_, err := executor.Execute(context.Background(), auth, cliproxyexecutor.Request{ Model: "gpt-5.6-sol", Payload: []byte(`{"model":"gpt-5.6-sol","input":"hello"}`), }, cliproxyexecutor.Options{ SourceFormat: sdktranslator.FromString("openai-response"), Headers: headers, }) if err != nil { t.Fatalf("Execute() error = %v", err) } if tools := gjson.GetBytes(gotBody, "tools"); tools.Exists() { t.Fatalf("unexpected tools in responses-lite upstream payload: %s", tools.Raw) } parallelToolCalls := gjson.GetBytes(gotBody, "parallel_tool_calls") if !parallelToolCalls.Exists() || parallelToolCalls.Bool() { t.Fatalf("responses-lite parallel_tool_calls should be false: %s", gotBody) }}
func TestCodexExecutorExecuteStreamResponsesLiteHeaderForcesParallelToolCallsFalse(t *testing.T) { var gotBody []byte server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, errRead := io.ReadAll(r.Body) if errRead != nil { t.Fatalf("read request body: %v", errRead) } gotBody = body w.Header().Set("Content-Type", "text/event-stream") _, _ = w.Write([]byte("data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_1\",\"object\":\"response\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":0,\"output_tokens\":0,\"total_tokens\":0}}}\n\n")) })) defer server.Close()
executor := NewCodexExecutor(&config.Config{}) auth := &cliproxyauth.Auth{ Provider: "codex", Attributes: map[string]string{ "api_key": "test", "base_url": server.URL, "plan_type": "pro", }, } headers := make(http.Header) headers.Set(codexResponsesLiteHeader, "true")
result, errExecute := executor.ExecuteStream(context.Background(), auth, cliproxyexecutor.Request{ Model: "gpt-5.6-luna", Payload: []byte(`{"model":"gpt-5.6-luna","input":"hello"}`), }, cliproxyexecutor.Options{ SourceFormat: sdktranslator.FromString("openai-response"), Headers: headers, }) if errExecute != nil { t.Fatalf("ExecuteStream() error = %v", errExecute) } for chunk := range result.Chunks { if chunk.Err != nil { t.Fatalf("stream chunk error = %v", chunk.Err) } }
parallelToolCalls := gjson.GetBytes(gotBody, "parallel_tool_calls") if !parallelToolCalls.Exists() || parallelToolCalls.Bool() { t.Fatalf("responses-lite parallel_tool_calls should be false: %s", gotBody) }}
func TestEnsureImageGenerationTool_ResponsesLiteMetadataDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.6-sol","client_metadata":{"ws_request_header_x_openai_internal_codex_responses_lite":"true"},"input":[{"role":"user","content":"hello"}]}`) result := ensureImageGenerationTool(body, "gpt-5.6-sol", nil, nil)
if string(result) != string(body) { t.Fatalf("expected responses-lite body to be unchanged, got %s", string(result)) } if gjson.GetBytes(result, "tools").Exists() { t.Fatalf("expected no injected tools for responses-lite request, got %s", gjson.GetBytes(result, "tools").Raw) }}
func TestEnsureImageGenerationTool_ResponsesLiteBooleanMetadataDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.6-sol","client_metadata":{"ws_request_header_x_openai_internal_codex_responses_lite":true},"input":"hello"}`) result := ensureImageGenerationTool(body, "gpt-5.6-sol", nil, nil)
if string(result) != string(body) { t.Fatalf("expected responses-lite body to be unchanged, got %s", string(result)) }}
func TestEnsureImageGenerationTool_ResponsesLiteHeaderDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.6-sol","input":"hello"}`) headers := make(http.Header) headers.Set("X-OpenAI-Internal-Codex-Responses-Lite", "true") result := ensureImageGenerationTool(body, "gpt-5.6-sol", nil, headers)
if string(result) != string(body) { t.Fatalf("expected responses-lite body to be unchanged, got %s", string(result)) }}
func TestEnsureImageGenerationTool_ResponsesLiteFalseMetadataStillInjectsTool(t *testing.T) { body := []byte(`{"model":"gpt-5.6-sol","client_metadata":{"ws_request_header_x_openai_internal_codex_responses_lite":"false"},"input":"hello"}`) result := ensureImageGenerationTool(body, "gpt-5.6-sol", nil, nil)
if got := gjson.GetBytes(result, "tools.0.type").String(); got != "image_generation" { t.Fatalf("tools.0.type = %q, want image_generation; body=%s", got, result) }}
func TestEnsureImageGenerationTool_NoTools(t *testing.T) { body := []byte(`{"model":"gpt-5.4","input":"draw a cat"}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools") if !tools.IsArray() { t.Fatalf("expected tools array, got %v", tools.Type) } arr := tools.Array() if len(arr) != 1 { t.Fatalf("expected 1 tool, got %d", len(arr)) } if arr[0].Get("type").String() != "image_generation" { t.Fatalf("expected type=image_generation, got %s", arr[0].Get("type").String()) } if arr[0].Get("output_format").String() != "png" { t.Fatalf("expected output_format=png, got %s", arr[0].Get("output_format").String()) }}
func TestEnsureImageGenerationTool_ExistingToolsWithoutImageGen(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"function","name":"get_weather","parameters":{}}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools") arr := tools.Array() if len(arr) != 2 { t.Fatalf("expected 2 tools, got %d", len(arr)) } if arr[0].Get("type").String() != "function" { t.Fatalf("expected first tool type=function, got %s", arr[0].Get("type").String()) } if arr[1].Get("type").String() != "image_generation" { t.Fatalf("expected second tool type=image_generation, got %s", arr[1].Get("type").String()) }}
func TestEnsureImageGenerationTool_AlreadyPresent(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"image_generation","output_format":"webp"},{"type":"function","name":"f1"}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools") arr := tools.Array() if len(arr) != 2 { t.Fatalf("expected 2 tools (no duplicate), got %d", len(arr)) } if arr[0].Get("output_format").String() != "webp" { t.Fatalf("expected original output_format=webp preserved, got %s", arr[0].Get("output_format").String()) }}
func TestEnsureImageGenerationTool_ImageGenNamespaceDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"namespace","name":"image_gen","tools":[{"type":"function","name":"imagegen","parameters":{}}]}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
if string(result) != string(body) { t.Fatalf("expected body to be unchanged, got %s", string(result)) }}
func TestEnsureImageGenerationTool_FlattenedImageGenFunctionDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"function","name":"image_gen.imagegen","parameters":{}}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
if string(result) != string(body) { t.Fatalf("expected body to be unchanged, got %s", string(result)) }}
func TestEnsureImageGenerationTool_SimilarNamespaceStillInjectsTool(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"namespace","name":"image_tools","tools":[{"type":"function","name":"imagegen","parameters":{}}]}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools").Array() if len(tools) != 2 { t.Fatalf("expected 2 tools, got %d", len(tools)) } if tools[1].Get("type").String() != "image_generation" { t.Fatalf("expected second tool type=image_generation, got %s", tools[1].Get("type").String()) }}
func TestEnsureImageGenerationTool_EmptyToolsArray(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools") arr := tools.Array() if len(arr) != 1 { t.Fatalf("expected 1 tool, got %d", len(arr)) } if arr[0].Get("type").String() != "image_generation" { t.Fatalf("expected type=image_generation, got %s", arr[0].Get("type").String()) }}
func TestEnsureImageGenerationTool_WebSearchAndImageGen(t *testing.T) { body := []byte(`{"model":"gpt-5.4","tools":[{"type":"web_search"}]}`) result := ensureImageGenerationTool(body, "gpt-5.4", nil, nil)
tools := gjson.GetBytes(result, "tools") arr := tools.Array() if len(arr) != 2 { t.Fatalf("expected 2 tools, got %d", len(arr)) } if arr[0].Get("type").String() != "web_search" { t.Fatalf("expected first tool type=web_search, got %s", arr[0].Get("type").String()) } if arr[1].Get("type").String() != "image_generation" { t.Fatalf("expected second tool type=image_generation, got %s", arr[1].Get("type").String()) }}
func TestEnsureImageGenerationTool_GPT53CodexSparkDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.3-codex-spark","input":"draw a cat"}`) result := ensureImageGenerationTool(body, "gpt-5.3-codex-spark", nil, nil)
if string(result) != string(body) { t.Fatalf("expected body to be unchanged, got %s", string(result)) } if gjson.GetBytes(result, "tools").Exists() { t.Fatalf("expected no tools for gpt-5.3-codex-spark, got %s", gjson.GetBytes(result, "tools").Raw) }}
func TestEnsureImageGenerationTool_FreeCodexAuthDoesNotInjectTool(t *testing.T) { body := []byte(`{"model":"gpt-5.4","input":"draw a cat"}`) freeAuth := &cliproxyauth.Auth{ Provider: "codex", Attributes: map[string]string{"plan_type": "free"}, } result := ensureImageGenerationTool(body, "gpt-5.4", freeAuth, nil)
if string(result) != string(body) { t.Fatalf("expected body to be unchanged, got %s", string(result)) } if gjson.GetBytes(result, "tools").Exists() { t.Fatalf("expected no tools for free codex auth, got %s", gjson.GetBytes(result, "tools").Raw) }}