package helps import ( "bytes" "context" "fmt" "net/http" "strings" "testing" "github.com/router-for-me/CLIProxyAPI/v7/internal/config" _ "github.com/router-for-me/CLIProxyAPI/v7/internal/translator" sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator" "github.com/tidwall/gjson" "github.com/tidwall/sjson") type pairRequestPluginHooks struct { calls int64} func (h *pairRequestPluginHooks) NormalizeRequest(_ context.Context, _, _ sdktranslator.Format, _ string, body []byte, _ bool) []byte { h.calls++ updated, _ := sjson.SetBytes(body, "plugin_call", h.calls) return updated} func (*pairRequestPluginHooks) TranslateRequest(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, bool) ([]byte, bool) { return nil, false} func (*pairRequestPluginHooks) NormalizeResponseBefore(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) []byte { return nil} func (*pairRequestPluginHooks) TranslateResponse(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) ([]byte, bool) { return nil, false} func (*pairRequestPluginHooks) NormalizeResponseAfter(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) []byte { return nil} func geminiToolHistoryPayload(turns int) []byte { contents := []string{`{"role":"user","parts":[{"text":"start"}]}`} for i := 0; i < turns; i++ { contents = append(contents, fmt.Sprintf(`{"role":"user","parts":[{"text":"ask %d"}]}`, i), fmt.Sprintf(`{"role":"model","parts":[{"text":"think %d"},{"thoughtSignature":"sig-%d","functionCall":{"id":"c%d","name":"read_file","args":{"path":"a%d.go"}}}]}`, i, i, i, i), fmt.Sprintf(`{"role":"user","parts":[{"functionResponse":{"id":"c%d","name":"read_file","response":{"content":"data %d"}}}]}`, i, i), fmt.Sprintf(`{"role":"model","parts":[{"text":"answer %d"}]}`, i)) } return []byte(fmt.Sprintf( `{"contents":[%s],"tools":[{"functionDeclarations":[{"name":"read_file","description":"read a file","parameters":{"type":"object","properties":{"path":{"type":"string"}},"required":["path"]}}]}],"generationConfig":{"temperature":1}}`, strings.Join(contents, ",")))} // TestTranslateRequestPairMatchesSeparateTranslations pins the reuse fast path to// the behavior of translating both payloads independently.func TestTranslateRequestPairMatchesSeparateTranslations(t *testing.T) { from := sdktranslator.FormatGemini to := sdktranslator.FromString("antigravity") cfg := &config.Config{} const model = "gemini-3.6-flash-high" for _, turns := range []int{0, 1, 5, 20} { payload := geminiToolHistoryPayload(turns) // Same bytes in a different backing array forces the translate-twice branch. detached := append([]byte(nil), payload...) want := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, payload, true) reuseBase, reuseWork := TranslateRequestPairWithCodexMultiAgentV2( context.Background(), http.Header{}, cfg, from, to, model, payload, payload, true) twiceBase, twiceWork := TranslateRequestPairWithCodexMultiAgentV2( context.Background(), http.Header{}, cfg, from, to, model, payload, detached, true) for name, got := range map[string][]byte{ "reuse baseline": reuseBase, "reuse working": reuseWork, "twice baseline": twiceBase, "twice working": twiceWork, } { if !bytes.Equal(want, got) { t.Fatalf("turns=%d: %s translation differs from a standalone translation", turns, name) } } if len(reuseBase) > 0 && &reuseBase[0] == &reuseWork[0] { t.Fatalf("turns=%d: working copy aliases the baseline; later in-place edits would corrupt it", turns) } // The caller mutates the working copy, so the baseline must stay intact. baselineBefore := append([]byte(nil), reuseBase...) reuseWork[0] = 'X' if !bytes.Equal(baselineBefore, reuseBase) { t.Fatalf("turns=%d: mutating the working copy changed the baseline", turns) } }} // TestTranslateRequestPairTranslatesDistinctPayloads guards the case where the// executor really does hand over two different requests.func TestTranslateRequestPairTranslatesDistinctPayloads(t *testing.T) { from := sdktranslator.FormatGemini to := sdktranslator.FromString("antigravity") cfg := &config.Config{} const model = "gemini-3.6-flash-high" original := geminiToolHistoryPayload(2) request := geminiToolHistoryPayload(4) base, work := TranslateRequestPairWithCodexMultiAgentV2( context.Background(), http.Header{}, cfg, from, to, model, original, request, true) wantBase := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, original, true) wantWork := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, request, true) if !bytes.Equal(wantBase, base) { t.Fatal("baseline translation differs for distinct payloads") } if !bytes.Equal(wantWork, work) { t.Fatal("working translation differs for distinct payloads") } if bytes.Equal(base, work) { t.Fatal("distinct payloads produced identical translations; the reuse path was taken by mistake") }} func TestTranslateRequestPairPreservesPluginHookInvocations(t *testing.T) { hooks := &pairRequestPluginHooks{} sdktranslator.SetPluginHooks(hooks) t.Cleanup(func() { sdktranslator.SetPluginHooks(nil) }) payload := geminiToolHistoryPayload(1) base, work := TranslateRequestPairWithCodexMultiAgentV2( context.Background(), http.Header{}, &config.Config{}, sdktranslator.FormatGemini, sdktranslator.FromString("antigravity"), "gemini-3.6-flash-high", payload, payload, true, ) if hooks.calls != 2 { t.Fatalf("plugin hook calls = %d, want 2", hooks.calls) } if got := gjson.GetBytes(base, "plugin_call").Int(); got != 1 { t.Fatalf("baseline plugin_call = %d, want 1", got) } if got := gjson.GetBytes(work, "plugin_call").Int(); got != 2 { t.Fatalf("working plugin_call = %d, want 2", got) }} func TestSameByteSlice(t *testing.T) { buf := []byte("payload") cases := []struct { name string a, b []byte want bool }{ {"identical slice", buf, buf, true}, {"same array same length", buf[:3], buf[:3], true}, {"equal bytes different array", buf, append([]byte(nil), buf...), false}, {"different length", buf, buf[:3], false}, {"both nil", nil, nil, true}, {"nil and empty", nil, []byte{}, true}, {"nil and non-empty", nil, buf, false}, {"offset alias", buf, buf[1:], false}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := sameByteSlice(tc.a, tc.b); got != tc.want { t.Fatalf("sameByteSlice() = %v, want %v", got, tc.want) } }) }}
package helps
import (
"bytes"
"context"
"fmt"
"net/http"
"strings"
"testing"
"github.com/router-for-me/CLIProxyAPI/v7/internal/config"
_ "github.com/router-for-me/CLIProxyAPI/v7/internal/translator"
sdktranslator "github.com/router-for-me/CLIProxyAPI/v7/sdk/translator"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)
type pairRequestPluginHooks struct {
calls int64
}
func (h *pairRequestPluginHooks) NormalizeRequest(_ context.Context, _, _ sdktranslator.Format, _ string, body []byte, _ bool) []byte {
h.calls++
updated, _ := sjson.SetBytes(body, "plugin_call", h.calls)
return updated
}
func (*pairRequestPluginHooks) TranslateRequest(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, bool) ([]byte, bool) {
return nil, false
}
func (*pairRequestPluginHooks) NormalizeResponseBefore(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) []byte {
return nil
}
func (*pairRequestPluginHooks) TranslateResponse(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) ([]byte, bool) {
return nil, false
}
func (*pairRequestPluginHooks) NormalizeResponseAfter(context.Context, sdktranslator.Format, sdktranslator.Format, string, []byte, []byte, []byte, bool) []byte {
return nil
}
func geminiToolHistoryPayload(turns int) []byte {
contents := []string{`{"role":"user","parts":[{"text":"start"}]}`}
for i := 0; i < turns; i++ {
contents = append(contents,
fmt.Sprintf(`{"role":"user","parts":[{"text":"ask %d"}]}`, i),
fmt.Sprintf(`{"role":"model","parts":[{"text":"think %d"},{"thoughtSignature":"sig-%d","functionCall":{"id":"c%d","name":"read_file","args":{"path":"a%d.go"}}}]}`, i, i, i, i),
fmt.Sprintf(`{"role":"user","parts":[{"functionResponse":{"id":"c%d","name":"read_file","response":{"content":"data %d"}}}]}`, i, i),
fmt.Sprintf(`{"role":"model","parts":[{"text":"answer %d"}]}`, i))
}
return []byte(fmt.Sprintf(
`{"contents":[%s],"tools":[{"functionDeclarations":[{"name":"read_file","description":"read a file","parameters":{"type":"object","properties":{"path":{"type":"string"}},"required":["path"]}}]}],"generationConfig":{"temperature":1}}`,
strings.Join(contents, ",")))
}
// TestTranslateRequestPairMatchesSeparateTranslations pins the reuse fast path to
// the behavior of translating both payloads independently.
func TestTranslateRequestPairMatchesSeparateTranslations(t *testing.T) {
from := sdktranslator.FormatGemini
to := sdktranslator.FromString("antigravity")
cfg := &config.Config{}
const model = "gemini-3.6-flash-high"
for _, turns := range []int{0, 1, 5, 20} {
payload := geminiToolHistoryPayload(turns)
// Same bytes in a different backing array forces the translate-twice branch.
detached := append([]byte(nil), payload...)
want := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, payload, true)
reuseBase, reuseWork := TranslateRequestPairWithCodexMultiAgentV2(
context.Background(), http.Header{}, cfg, from, to, model, payload, payload, true)
twiceBase, twiceWork := TranslateRequestPairWithCodexMultiAgentV2(
context.Background(), http.Header{}, cfg, from, to, model, payload, detached, true)
for name, got := range map[string][]byte{
"reuse baseline": reuseBase,
"reuse working": reuseWork,
"twice baseline": twiceBase,
"twice working": twiceWork,
} {
if !bytes.Equal(want, got) {
t.Fatalf("turns=%d: %s translation differs from a standalone translation", turns, name)
}
}
if len(reuseBase) > 0 && &reuseBase[0] == &reuseWork[0] {
t.Fatalf("turns=%d: working copy aliases the baseline; later in-place edits would corrupt it", turns)
}
// The caller mutates the working copy, so the baseline must stay intact.
baselineBefore := append([]byte(nil), reuseBase...)
reuseWork[0] = 'X'
if !bytes.Equal(baselineBefore, reuseBase) {
t.Fatalf("turns=%d: mutating the working copy changed the baseline", turns)
}
}
}
// TestTranslateRequestPairTranslatesDistinctPayloads guards the case where the
// executor really does hand over two different requests.
func TestTranslateRequestPairTranslatesDistinctPayloads(t *testing.T) {
from := sdktranslator.FormatGemini
to := sdktranslator.FromString("antigravity")
cfg := &config.Config{}
const model = "gemini-3.6-flash-high"
original := geminiToolHistoryPayload(2)
request := geminiToolHistoryPayload(4)
base, work := TranslateRequestPairWithCodexMultiAgentV2(
context.Background(), http.Header{}, cfg, from, to, model, original, request, true)
wantBase := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, original, true)
wantWork := TranslateRequestWithCodexMultiAgentV2(context.Background(), http.Header{}, cfg, from, to, model, request, true)
if !bytes.Equal(wantBase, base) {
t.Fatal("baseline translation differs for distinct payloads")
}
if !bytes.Equal(wantWork, work) {
t.Fatal("working translation differs for distinct payloads")
}
if bytes.Equal(base, work) {
t.Fatal("distinct payloads produced identical translations; the reuse path was taken by mistake")
}
}
func TestTranslateRequestPairPreservesPluginHookInvocations(t *testing.T) {
hooks := &pairRequestPluginHooks{}
sdktranslator.SetPluginHooks(hooks)
t.Cleanup(func() { sdktranslator.SetPluginHooks(nil) })
payload := geminiToolHistoryPayload(1)
base, work := TranslateRequestPairWithCodexMultiAgentV2(
context.Background(),
http.Header{},
&config.Config{},
sdktranslator.FormatGemini,
sdktranslator.FromString("antigravity"),
"gemini-3.6-flash-high",
payload,
payload,
true,
)
if hooks.calls != 2 {
t.Fatalf("plugin hook calls = %d, want 2", hooks.calls)
}
if got := gjson.GetBytes(base, "plugin_call").Int(); got != 1 {
t.Fatalf("baseline plugin_call = %d, want 1", got)
}
if got := gjson.GetBytes(work, "plugin_call").Int(); got != 2 {
t.Fatalf("working plugin_call = %d, want 2", got)
}
}
func TestSameByteSlice(t *testing.T) {
buf := []byte("payload")
cases := []struct {
name string
a, b []byte
want bool
}{
{"identical slice", buf, buf, true},
{"same array same length", buf[:3], buf[:3], true},
{"equal bytes different array", buf, append([]byte(nil), buf...), false},
{"different length", buf, buf[:3], false},
{"both nil", nil, nil, true},
{"nil and empty", nil, []byte{}, true},
{"nil and non-empty", nil, buf, false},
{"offset alias", buf, buf[1:], false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := sameByteSlice(tc.a, tc.b); got != tc.want {
t.Fatalf("sameByteSlice() = %v, want %v", got, tc.want)
}
})
}
}