mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-22 22:59:09 +02:00
[proxy] Keep slash-bearing model ids in the discovery filter
The filter treated a slash in a listing entry's id as a gateway provider prefix and matched only the tail. Self-hosted backends serve ids that carry a slash of their own, so every "Qwen/Qwen2.5-0.5B-Instruct" style model was dropped from the picker even when the policy named it exactly. Try the id as written first and fall back to the tail, so both a prefixed id and a self-hosted one resolve.
This commit is contained in:
@@ -109,7 +109,7 @@ func filterListingBody(body []byte, permitted map[string]struct{}) ([]byte, bool
|
|||||||
|
|
||||||
kept := make([]map[string]json.RawMessage, 0, len(entries))
|
kept := make([]map[string]json.RawMessage, 0, len(entries))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if _, ok := permitted[entryModelID(entry)]; ok {
|
if entryPermitted(entry, permitted) {
|
||||||
kept = append(kept, entry)
|
kept = append(kept, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,23 +126,40 @@ func filterListingBody(body []byte, permitted map[string]struct{}) ([]byte, bool
|
|||||||
return out, true
|
return out, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// entryModelID returns the entry's model id in the form the policy stores
|
// entryPermitted reports whether a listing entry names a model the policy
|
||||||
// it, or "" when the entry carries no usable id. A provider-prefixed id
|
// authorises, trying every form the same model is written in.
|
||||||
// ("bedrock/anthropic.claude-sonnet-5") keeps only its last segment, which
|
func entryPermitted(entry map[string]json.RawMessage, permitted map[string]struct{}) bool {
|
||||||
// is what the operator registers.
|
|
||||||
func entryModelID(entry map[string]json.RawMessage) string {
|
|
||||||
raw, ok := entry["id"]
|
raw, ok := entry["id"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return false
|
||||||
}
|
}
|
||||||
var id string
|
var id string
|
||||||
if err := json.Unmarshal(raw, &id); err != nil {
|
if err := json.Unmarshal(raw, &id); err != nil {
|
||||||
return ""
|
return false
|
||||||
}
|
}
|
||||||
|
for _, candidate := range modelIDForms(id) {
|
||||||
|
if _, ok := permitted[candidate]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// modelIDForms returns the forms a single model id may be written in: the id
|
||||||
|
// itself, its undated form, and the same two with a gateway's provider
|
||||||
|
// prefix removed ("vertex_ai/claude-sonnet-5"). The bare id is tried first,
|
||||||
|
// because a self-hosted id can legitimately contain a slash of its own
|
||||||
|
// ("Qwen/Qwen2.5-0.5B-Instruct") and must not be cut down to its tail.
|
||||||
|
func modelIDForms(id string) []string {
|
||||||
|
if id == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
forms := []string{id, sharedllm.NormalizeAnthropicModel(id)}
|
||||||
if slash := strings.LastIndex(id, "/"); slash >= 0 {
|
if slash := strings.LastIndex(id, "/"); slash >= 0 {
|
||||||
id = id[slash+1:]
|
tail := id[slash+1:]
|
||||||
|
forms = append(forms, tail, sharedllm.NormalizeAnthropicModel(tail))
|
||||||
}
|
}
|
||||||
return sharedllm.NormalizeAnthropicModel(id)
|
return forms
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreBody puts body back on the response and fixes the length headers
|
// restoreBody puts body back on the response and fixes the length headers
|
||||||
|
|||||||
@@ -153,3 +153,20 @@ func TestModelDiscoveryFilter_RunsNextHook(t *testing.T) {
|
|||||||
require.NoError(t, modelDiscoveryFilter([]string{"claude-sonnet-5"}, next)(resp)) //nolint:bodyclose // in-memory body, replaced by the filter
|
require.NoError(t, modelDiscoveryFilter([]string{"claude-sonnet-5"}, next)(resp)) //nolint:bodyclose // in-memory body, replaced by the filter
|
||||||
assert.True(t, called, "the chained hook must still run")
|
assert.True(t, called, "the chained hook must still run")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestModelDiscoveryFilter_KeepsSlashBearingIDs covers self-hosted backends
|
||||||
|
// whose model ids carry a slash of their own. Treating the slash as a
|
||||||
|
// gateway prefix and keeping only the tail dropped every such model from
|
||||||
|
// the picker even though the policy named it exactly.
|
||||||
|
func TestModelDiscoveryFilter_KeepsSlashBearingIDs(t *testing.T) {
|
||||||
|
ids := listedIDs(t, []string{"Qwen/Qwen2.5-0.5B-Instruct"}, `{
|
||||||
|
"object": "list",
|
||||||
|
"data": [
|
||||||
|
{"id": "Qwen/Qwen2.5-0.5B-Instruct"},
|
||||||
|
{"id": "Qwen/Qwen2.5-7B-Instruct"}
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"Qwen/Qwen2.5-0.5B-Instruct"}, ids,
|
||||||
|
"a slash inside the model id is part of the id, not a provider prefix")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user