proxy: add versionless API endpoint (#733)

Add versionless endpoints under v/ to support upstream peers that 
do not use the v1/ prefix.

Fixes #728.
This commit is contained in:
Wim Vander Schelden
2026-05-03 22:47:38 +02:00
committed by GitHub
parent 11b7913287
commit e261745c66
3 changed files with 146 additions and 20 deletions
+100
View File
@@ -1779,3 +1779,103 @@ models:
assert.Nil(t, capture.ReqBody)
assert.NotNil(t, capture.RespBody)
}
func TestProxyManager_VersionlessEndpoints_LocalModel(t *testing.T) {
cfg := testConfigFromYAML(t, `
healthCheckTimeout: 15
logLevel: error
models:
model1:
cmd: {{RESPONDER}} --port ${PORT} --silent --respond model1
`)
proxy := New(cfg)
defer proxy.StopProcesses(StopWaitForInflightRequest)
injectTestHandlers(proxy, nil)
endpoints := []string{
"/v/chat/completions",
"/v/responses",
"/v/completions",
"/v/embeddings",
"/v/rerank",
"/v/reranking",
}
for _, endpoint := range endpoints {
t.Run(endpoint, func(t *testing.T) {
reqBody := `{"model":"model1"}`
req := httptest.NewRequest("POST", endpoint, bytes.NewBufferString(reqBody))
w := CreateTestResponseRecorder()
proxy.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "model1")
})
}
t.Run("/v/messages", func(t *testing.T) {
reqBody := `{"model":"model1","messages":[{"role":"user","content":"hi"}]}`
req := httptest.NewRequest("POST", "/v/messages", bytes.NewBufferString(reqBody))
w := CreateTestResponseRecorder()
proxy.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "model1")
})
}
func TestProxyManager_VersionlessEndpoints_PeerModel(t *testing.T) {
peerServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `{"endpoint":"%s","model":"peer-model"}`, r.URL.Path)
}))
defer peerServer.Close()
cfg := testConfigFromYAML(t, fmt.Sprintf(`
healthCheckTimeout: 15
logLevel: error
peers:
test-peer:
proxy: %s
models:
- peer-model
models:
local-model:
cmd: {{RESPONDER}} --port ${PORT} --silent --respond local-model
`, peerServer.URL))
proxy := New(cfg)
defer proxy.StopProcesses(StopImmediately)
endpoints := []struct {
path string
wantSuffix string
}{
{"/v/chat/completions", "/chat/completions"},
{"/v/responses", "/responses"},
{"/v/completions", "/completions"},
{"/v/embeddings", "/embeddings"},
{"/v/rerank", "/rerank"},
{"/v/reranking", "/reranking"},
}
for _, ep := range endpoints {
t.Run(ep.path, func(t *testing.T) {
reqBody := `{"model":"peer-model"}`
req := httptest.NewRequest("POST", ep.path, bytes.NewBufferString(reqBody))
w := CreateTestResponseRecorder()
proxy.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), ep.wantSuffix)
})
}
t.Run("/v/messages", func(t *testing.T) {
reqBody := `{"model":"peer-model","messages":[{"role":"user","content":"hi"}]}`
req := httptest.NewRequest("POST", "/v/messages", bytes.NewBufferString(reqBody))
w := CreateTestResponseRecorder()
proxy.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Contains(t, w.Body.String(), "/messages")
})
}