@@ -1991,6 +1991,106 @@ data: [DONE]
19911991 }
19921992}
19931993
1994+ func TestChatCompletionStreaming_FastPathUsesPassthroughForOpenAICompatibleProviders (t * testing.T ) {
1995+ streamData := "data: {\" id\" :\" chatcmpl-123\" ,\" choices\" :[{\" delta\" :{\" content\" :\" Hello\" }}]}\n \n data: [DONE]\n \n "
1996+ reqBody := `{"model":"gpt-4o-mini","stream":true,"messages":[{"role":"user","content":"Hi"}]}`
1997+ mock := & mockProvider {
1998+ supportedModels : []string {"gpt-4o-mini" },
1999+ providerTypes : map [string ]string {
2000+ "gpt-4o-mini" : "openai" ,
2001+ },
2002+ passthroughResponse : & core.PassthroughResponse {
2003+ StatusCode : http .StatusOK ,
2004+ Headers : map [string ][]string {
2005+ "Content-Type" : {"text/event-stream" },
2006+ },
2007+ Body : io .NopCloser (strings .NewReader (streamData )),
2008+ },
2009+ }
2010+
2011+ e := echo .New ()
2012+ handler := NewHandler (mock , nil , nil , nil )
2013+
2014+ req := httptest .NewRequest (http .MethodPost , "/v1/chat/completions" , strings .NewReader (reqBody ))
2015+ req .Header .Set ("Content-Type" , "application/json" )
2016+ rec := httptest .NewRecorder ()
2017+ c := e .NewContext (req , rec )
2018+
2019+ err := handler .ChatCompletion (c )
2020+ if err != nil {
2021+ t .Fatalf ("handler returned error: %v" , err )
2022+ }
2023+
2024+ if rec .Code != http .StatusOK {
2025+ t .Fatalf ("status = %d, want %d" , rec .Code , http .StatusOK )
2026+ }
2027+ if got := rec .Header ().Get ("Content-Type" ); got != "text/event-stream" {
2028+ t .Fatalf ("Content-Type = %q, want text/event-stream" , got )
2029+ }
2030+ if got := rec .Body .String (); got != streamData {
2031+ t .Fatalf ("stream body = %q, want %q" , got , streamData )
2032+ }
2033+ if mock .lastPassthroughProvider != "openai" {
2034+ t .Fatalf ("lastPassthroughProvider = %q, want openai" , mock .lastPassthroughProvider )
2035+ }
2036+ if mock .lastPassthroughReq == nil {
2037+ t .Fatal ("lastPassthroughReq = nil, want passthrough request" )
2038+ }
2039+ if body := readPassthroughRequestBody (t , mock .lastPassthroughReq .Body ); body != reqBody {
2040+ t .Fatalf ("passthrough body = %q, want %q" , body , reqBody )
2041+ }
2042+ }
2043+
2044+ func TestChatCompletionStreaming_FastPathSkipsQualifiedModelRewrite (t * testing.T ) {
2045+ streamData := "data: {\" id\" :\" chatcmpl-123\" ,\" choices\" :[{\" delta\" :{\" content\" :\" Hello\" }}]}\n \n data: [DONE]\n \n "
2046+ provider := & capturingProvider {
2047+ mockProvider : mockProvider {
2048+ supportedModels : []string {"gpt-4o-mini" },
2049+ providerTypes : map [string ]string {
2050+ "gpt-4o-mini" : "openai" ,
2051+ },
2052+ streamData : streamData ,
2053+ passthroughResponse : & core.PassthroughResponse {
2054+ StatusCode : http .StatusOK ,
2055+ Headers : map [string ][]string {
2056+ "Content-Type" : {"text/event-stream" },
2057+ },
2058+ Body : io .NopCloser (strings .NewReader ("data: should-not-be-used\n \n " )),
2059+ },
2060+ },
2061+ }
2062+
2063+ e := echo .New ()
2064+ handler := NewHandler (provider , nil , nil , nil )
2065+
2066+ reqBody := `{"model":"openai/gpt-4o-mini","stream":true,"messages":[{"role":"user","content":"Hi"}]}`
2067+ req := httptest .NewRequest (http .MethodPost , "/v1/chat/completions" , strings .NewReader (reqBody ))
2068+ req .Header .Set ("Content-Type" , "application/json" )
2069+ rec := httptest .NewRecorder ()
2070+ c := e .NewContext (req , rec )
2071+
2072+ err := handler .ChatCompletion (c )
2073+ if err != nil {
2074+ t .Fatalf ("handler returned error: %v" , err )
2075+ }
2076+
2077+ if provider .lastPassthroughReq != nil {
2078+ t .Fatal ("lastPassthroughReq != nil, want rewritten request to use StreamChatCompletion path" )
2079+ }
2080+ if provider .capturedChatReq == nil {
2081+ t .Fatal ("capturedChatReq = nil, want StreamChatCompletion request" )
2082+ }
2083+ if provider .capturedChatReq .Model != "gpt-4o-mini" {
2084+ t .Fatalf ("captured model = %q, want gpt-4o-mini" , provider .capturedChatReq .Model )
2085+ }
2086+ if provider .capturedChatReq .Provider != "openai" {
2087+ t .Fatalf ("captured provider = %q, want openai" , provider .capturedChatReq .Provider )
2088+ }
2089+ if got := rec .Body .String (); got != streamData {
2090+ t .Fatalf ("stream body = %q, want %q" , got , streamData )
2091+ }
2092+ }
2093+
19942094func TestHandleStreamingResponse_FlushesEachChunk (t * testing.T ) {
19952095 e := echo .New ()
19962096 handler := NewHandler (& mockProvider {}, nil , nil , nil )
@@ -4307,7 +4407,10 @@ func TestStreamingChatCompletion_InjectsStreamOptions(t *testing.T) {
43074407 provider := & capturingProvider {
43084408 mockProvider : mockProvider {
43094409 supportedModels : []string {"gpt-4o-mini" },
4310- streamData : streamData ,
4410+ providerTypes : map [string ]string {
4411+ "gpt-4o-mini" : "openai" ,
4412+ },
4413+ streamData : streamData ,
43114414 },
43124415 }
43134416
@@ -4337,6 +4440,10 @@ func TestStreamingChatCompletion_InjectsStreamOptions(t *testing.T) {
43374440 t .Errorf ("expected status 200, got %d" , rec .Code )
43384441 }
43394442
4443+ if provider .lastPassthroughReq != nil {
4444+ t .Fatal ("lastPassthroughReq != nil, want usage-enforced streaming to stay on translated stream path" )
4445+ }
4446+
43404447 if provider .capturedChatReq .StreamOptions == nil {
43414448 t .Fatal ("ChatCompletion streaming should have StreamOptions injected" )
43424449 }
0 commit comments