mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-27 17:19:08 +02:00
Merge remote-tracking branch 'origin/main' into feat/kimi-3-agent-networks
This commit is contained in:
@@ -247,6 +247,9 @@ func (c *Client) DebugBundle(platformFiles PlatformFiles, anonymize bool) (strin
|
|||||||
deps.SyncResponse = resp
|
deps.SyncResponse = resp
|
||||||
|
|
||||||
if e := cc.Engine(); e != nil {
|
if e := cc.Engine(); e != nil {
|
||||||
|
deps.RefreshStatus = func() {
|
||||||
|
e.RunHealthProbes(context.Background(), true)
|
||||||
|
}
|
||||||
if cm := e.GetClientMetrics(); cm != nil {
|
if cm := e.GetClientMetrics(); cm != nil {
|
||||||
deps.ClientMetrics = cm
|
deps.ClientMetrics = cm
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,6 +233,9 @@ func (c *Client) DebugBundle(anonymize bool) (string, error) {
|
|||||||
deps.SyncResponse = resp
|
deps.SyncResponse = resp
|
||||||
|
|
||||||
if e := cc.Engine(); e != nil {
|
if e := cc.Engine(); e != nil {
|
||||||
|
deps.RefreshStatus = func() {
|
||||||
|
e.RunHealthProbes(context.Background(), true)
|
||||||
|
}
|
||||||
if cm := e.GetClientMetrics(); cm != nil {
|
if cm := e.GetClientMetrics(); cm != nil {
|
||||||
deps.ClientMetrics = cm
|
deps.ClientMetrics = cm
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package llm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// bedrockRegionPrefixes are the cross-region inference-profile prefixes that
|
||||||
|
// front a Bedrock model id (e.g. "eu.anthropic.claude-...").
|
||||||
|
var bedrockRegionPrefixes = []string{"us.", "eu.", "apac.", "global."}
|
||||||
|
|
||||||
|
// bedrockVersionSuffix matches the trailing "-vN[:N]" or "-YYYYMMDD-vN[:N]"
|
||||||
|
// version/throughput suffix of a Bedrock model id.
|
||||||
|
var bedrockVersionSuffix = regexp.MustCompile(`-(\d{8}-)?v\d+(:\d+)?$`)
|
||||||
|
|
||||||
|
// NormalizeBedrockModel strips an ARN wrapper, a cross-region inference-profile
|
||||||
|
// prefix, and the version/throughput suffix from a Bedrock model id so it
|
||||||
|
// matches the catalog/pricing key, e.g.
|
||||||
|
// "eu.anthropic.claude-sonnet-4-5-20250929-v1:0" -> "anthropic.claude-sonnet-4-5"
|
||||||
|
// and the inference-profile ARN's last segment likewise. It is the single
|
||||||
|
// source of truth shared by the request parser (which normalizes the request
|
||||||
|
// model from the URL path) and the router (which normalizes the operator's
|
||||||
|
// registered Bedrock model ids so both sides compare equal).
|
||||||
|
func NormalizeBedrockModel(modelID string) string {
|
||||||
|
m := modelID
|
||||||
|
if strings.HasPrefix(m, "arn:") {
|
||||||
|
if i := strings.LastIndex(m, "/"); i >= 0 {
|
||||||
|
m = m[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, p := range bedrockRegionPrefixes {
|
||||||
|
if strings.HasPrefix(m, p) {
|
||||||
|
m = m[len(p):]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bedrockVersionSuffix.ReplaceAllString(m, "")
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package llm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNormalizeBedrockModel(t *testing.T) {
|
||||||
|
cases := map[string]string{
|
||||||
|
"eu.anthropic.claude-sonnet-4-5-20250929-v1:0": "anthropic.claude-sonnet-4-5",
|
||||||
|
"us.anthropic.claude-haiku-4-5": "anthropic.claude-haiku-4-5",
|
||||||
|
"us.anthropic.claude-opus-4-8-20250101-v1:0": "anthropic.claude-opus-4-8",
|
||||||
|
"anthropic.claude-sonnet-4-5-20250929-v1:0": "anthropic.claude-sonnet-4-5",
|
||||||
|
"meta.llama3-3-70b-instruct-v1:0": "meta.llama3-3-70b-instruct",
|
||||||
|
"amazon.nova-pro-v1:0": "amazon.nova-pro",
|
||||||
|
// Inference-profile ARN — model id lives in the last path segment.
|
||||||
|
"arn:aws:bedrock:eu-central-1:123456789012:inference-profile/eu.anthropic.claude-sonnet-4-5-20250929-v1:0": "anthropic.claude-sonnet-4-5",
|
||||||
|
}
|
||||||
|
for in, want := range cases {
|
||||||
|
require.Equal(t, want, NormalizeBedrockModel(in), "normalize %q", in)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package llm_router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestRouteClaimsModel_BedrockNormalizesCandidate guards the fix for the native
|
||||||
|
// Bedrock routing gap: the request model reaches the router already normalized
|
||||||
|
// (the parser strips the region/inference-profile prefix and version suffix),
|
||||||
|
// so a provider registered with the raw inference-profile id must still match.
|
||||||
|
func TestRouteClaimsModel_BedrockNormalizesCandidate(t *testing.T) {
|
||||||
|
route := ProviderRoute{Bedrock: true, Models: []string{"us.anthropic.claude-haiku-4-5"}}
|
||||||
|
assert.True(t, routeClaimsModel(route, "anthropic.claude-haiku-4-5"),
|
||||||
|
"raw region-prefixed Bedrock model must match the normalized request model")
|
||||||
|
assert.False(t, routeClaimsModel(route, "anthropic.claude-opus-4-8"),
|
||||||
|
"a model outside the provider's list must not match")
|
||||||
|
|
||||||
|
// A provider registered with the already-normalized id also matches.
|
||||||
|
normalized := ProviderRoute{Bedrock: true, Models: []string{"anthropic.claude-haiku-4-5"}}
|
||||||
|
assert.True(t, routeClaimsModel(normalized, "anthropic.claude-haiku-4-5"),
|
||||||
|
"normalized Bedrock model must match")
|
||||||
|
|
||||||
|
// Non-Bedrock routes keep exact matching (no prefix stripping).
|
||||||
|
openai := ProviderRoute{Models: []string{"gpt-4o"}}
|
||||||
|
assert.True(t, routeClaimsModel(openai, "gpt-4o"), "exact model must match")
|
||||||
|
assert.False(t, routeClaimsModel(openai, "us.gpt-4o"),
|
||||||
|
"non-Bedrock routes must not strip a us. prefix")
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/oauth2/google"
|
"golang.org/x/oauth2/google"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/proxy/internal/llm"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/middleware"
|
"github.com/netbirdio/netbird/proxy/internal/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -555,6 +556,14 @@ func routeClaimsModel(route ProviderRoute, model string) bool {
|
|||||||
if candidate == model {
|
if candidate == model {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// Bedrock request models reach the router already normalized (the parser
|
||||||
|
// strips the region / inference-profile prefix and version suffix), but
|
||||||
|
// the operator may register the raw inference-profile id (e.g.
|
||||||
|
// "us.anthropic.claude-haiku-4-5"). Normalize the candidate so both sides
|
||||||
|
// compare equal; otherwise a native Bedrock request denies as not-routable.
|
||||||
|
if route.Bedrock && llm.NormalizeBedrockModel(candidate) == model {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user