Repository: envoyproxy/ai-gateway
Pull request #514 (2025-03-20 22:45:21)

extproc: do not list non model header values on /models
**Commit Message**

Previously, /v1/models endpoint returned all header matching values, not limited to the special "x-ai-eg-model" header. This fixes it, and only lists the values from the matching rules using that header.

**Related Issues/PRs (if applicable)**

Follow up on #325 


mathetake: ah

Patch:
diff --git a/go.mod b/go.mod
index 987acc3..c9c07f3 100644
--- a/go.mod
+++ b/go.mod
@@ -192,7 +192,7 @@ require (
 	github.com/goccy/go-yaml v1.15.13 // indirect
 	github.com/gofrs/flock v0.12.1 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
diff --git a/go.sum b/go.sum
index 0ef3715..e19a80e 100644
--- a/go.sum
+++ b/go.sum
@@ -530,8 +530,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
-github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
diff --git a/internal/extproc/server.go b/internal/extproc/server.go
index 56bcc5d..9754690 100644
--- a/internal/extproc/server.go
+++ b/internal/extproc/server.go
@@ -78,7 +78,9 @@ func (s *Server) LoadConfig(ctx context.Context, config *filterapi.Config) error
 		for _, h := range r.Headers {
 			// If explicitly set to something that is not an exact match, skip.
 			// If not set, we assume it's an exact match.
-			if h.Type != nil && *h.Type != gwapiv1.HeaderMatchExact {
+			//
+			// Also, we only care about the AIModel header to declare models.
+			if (h.Type != nil && *h.Type != gwapiv1.HeaderMatchExact) || string(h.Name) != config.ModelNameHeaderKey {
 				continue
 			}
 			declaredModels = append(declaredModels, h.Value)


Test patch:
diff --git a/internal/extproc/server_test.go b/internal/extproc/server_test.go
index ea5f407..fc5159a 100644
--- a/internal/extproc/server_test.go
+++ b/internal/extproc/server_test.go
@@ -69,6 +69,10 @@ func TestServer_LoadConfig(t *testing.T) {
 							Name:  "x-model-name",
 							Value: "gpt4.4444",
 						},
+						{
+							Name:  "some-random-header",
+							Value: "some-random-value",
+						},
 					},
 				},
 			},
@@ -94,6 +98,7 @@ func TestServer_LoadConfig(t *testing.T) {
 		val, err := llmcostcel.EvaluateProgram(prog, "", "", 1, 1, 1)
 		require.NoError(t, err)
 		require.Equal(t, uint64(2), val)
+		require.Equal(t, []string{"llama3.3333", "gpt4.4444"}, s.config.declaredModels)
 	})
 }
 
diff --git a/tests/extproc/testupstream_test.go b/tests/extproc/testupstream_test.go
index 3bdb5ff..bcfe14d 100644
--- a/tests/extproc/testupstream_test.go
+++ b/tests/extproc/testupstream_test.go
@@ -60,15 +60,23 @@ func TestWithTestUpstream(t *testing.T) {
 				Backends: []filterapi.Backend{{Name: "testupstream", Schema: azureOpenAISchema}},
 				Headers:  []filterapi.HeaderMatch{{Name: "x-test-backend", Value: "azure-openai"}},
 			},
+			{
+				Backends: []filterapi.Backend{{Name: "testupstream", Schema: azureOpenAISchema}},
+				Headers: []filterapi.HeaderMatch{
+					{Name: "x-model-name", Value: "some-model1"},
+					{Name: "x-model-name", Value: "some-model2"},
+					{Name: "x-model-name", Value: "some-model3"},
+				},
+			},
 		},
 	})
 
 	expectedModels := openai.ModelList{
 		Object: "list",
 		Data: []openai.Model{
-			{ID: "openai", Object: "model", OwnedBy: "Envoy AI Gateway"},
-			{ID: "aws-bedrock", Object: "model", OwnedBy: "Envoy AI Gateway"},
-			{ID: "azure-openai", Object: "model", OwnedBy: "Envoy AI Gateway"},
+			{ID: "some-model1", Object: "model", OwnedBy: "Envoy AI Gateway"},
+			{ID: "some-model2", Object: "model", OwnedBy: "Envoy AI Gateway"},
+			{ID: "some-model3", Object: "model", OwnedBy: "Envoy AI Gateway"},
 		},
 	}