Skip to content

Commit a4ee537

Browse files
Yuriy TeodorovychYuriy Teodorovych
authored andcommitted
Merge branch 'main' into yt-add-go-coverage-tests
2 parents 6160077 + 1245a8d commit a4ee537

File tree

26 files changed

+5024
-65
lines changed

26 files changed

+5024
-65
lines changed

maas-controller/go.mod

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,30 @@ require (
1414
)
1515

1616
require (
17-
cel.dev/expr v0.19.2 // indirect
17+
cel.dev/expr v0.25.1 // indirect
1818
cloud.google.com/go v0.118.3 // indirect
1919
cloud.google.com/go/auth v0.15.0 // indirect
2020
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
21-
cloud.google.com/go/compute/metadata v0.6.0 // indirect
21+
cloud.google.com/go/compute/metadata v0.9.0 // indirect
2222
cloud.google.com/go/iam v1.4.1 // indirect
2323
cloud.google.com/go/monitoring v1.24.1 // indirect
2424
cloud.google.com/go/storage v1.51.0 // indirect
25-
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
25+
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
2626
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
2727
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
2828
github.com/aws/aws-sdk-go v1.55.6 // indirect
2929
github.com/beorn7/perks v1.0.1 // indirect
3030
github.com/cespare/xxhash/v2 v2.3.0 // indirect
31-
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
31+
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
3232
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3333
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
34-
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
35-
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
34+
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
35+
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
3636
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
3737
github.com/felixge/httpsnoop v1.0.4 // indirect
3838
github.com/fsnotify/fsnotify v1.9.0 // indirect
3939
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
40+
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
4041
github.com/go-logr/stdr v1.2.2 // indirect
4142
github.com/go-logr/zapr v1.3.0 // indirect
4243
github.com/go-openapi/jsonpointer v0.21.1 // indirect
@@ -68,9 +69,10 @@ require (
6869
github.com/prometheus/common v0.64.0 // indirect
6970
github.com/prometheus/procfs v0.16.1 // indirect
7071
github.com/spf13/pflag v1.0.6 // indirect
72+
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
7173
github.com/x448/float16 v0.8.4 // indirect
7274
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
73-
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
75+
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
7476
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
7577
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
7678
go.opentelemetry.io/otel v1.40.0 // indirect
@@ -80,21 +82,21 @@ require (
8082
go.opentelemetry.io/otel/trace v1.40.0 // indirect
8183
go.uber.org/multierr v1.11.0 // indirect
8284
go.uber.org/zap v1.27.0 // indirect
83-
golang.org/x/crypto v0.45.0 // indirect
84-
golang.org/x/net v0.47.0 // indirect
85-
golang.org/x/oauth2 v0.30.0 // indirect
86-
golang.org/x/sync v0.18.0 // indirect
85+
golang.org/x/crypto v0.46.0 // indirect
86+
golang.org/x/net v0.48.0 // indirect
87+
golang.org/x/oauth2 v0.34.0 // indirect
88+
golang.org/x/sync v0.19.0 // indirect
8789
golang.org/x/sys v0.40.0 // indirect
88-
golang.org/x/term v0.37.0 // indirect
89-
golang.org/x/text v0.31.0 // indirect
90+
golang.org/x/term v0.38.0 // indirect
91+
golang.org/x/text v0.32.0 // indirect
9092
golang.org/x/time v0.12.0 // indirect
9193
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
9294
google.golang.org/api v0.228.0 // indirect
9395
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
94-
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
95-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
96-
google.golang.org/grpc v1.71.1 // indirect
97-
google.golang.org/protobuf v1.36.6 // indirect
96+
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
97+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
98+
google.golang.org/grpc v1.79.3 // indirect
99+
google.golang.org/protobuf v1.36.10 // indirect
98100
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
99101
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
100102
gopkg.in/inf.v0 v0.9.1 // indirect

maas-controller/go.sum

Lines changed: 46 additions & 40 deletions
Large diffs are not rendered by default.

payload-processing/cmd/main.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2025.
2+
Copyright 2026.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -27,6 +27,11 @@ import (
2727

2828
ctrl "sigs.k8s.io/controller-runtime"
2929
"sigs.k8s.io/gateway-api-inference-extension/cmd/bbr/runner"
30+
"sigs.k8s.io/gateway-api-inference-extension/pkg/bbr/framework"
31+
32+
api_translation "github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/api-translation"
33+
apikey_injection "github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/apikey-injection"
34+
provider_resolver "github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/model-provider-resolver"
3035
)
3136

3237
func main() {
@@ -41,8 +46,7 @@ func main() {
4146
}
4247

4348
func registerPlugins() {
44-
// TODO uncomment after all code moves
45-
// framework.Register(provider_resolver.ModelProviderResolverPluginType, provider_resolver.ModelProviderResolverFactory)
46-
// framework.Register(api_translation.APITranslationPluginType, api_translation.APITranslationFactory)
47-
// framework.Register(apikey_injection.APIKeyInjectionPluginType, apikey_injection.APIKeyInjectionFactory)
49+
framework.Register(provider_resolver.ModelProviderResolverPluginType, provider_resolver.ModelProviderResolverFactory)
50+
framework.Register(api_translation.APITranslationPluginType, api_translation.APITranslationFactory)
51+
framework.Register(apikey_injection.APIKeyInjectionPluginType, apikey_injection.APIKeyInjectionFactory)
4852
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
Copyright 2026.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package api_translation
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"fmt"
23+
24+
"sigs.k8s.io/gateway-api-inference-extension/pkg/bbr/framework"
25+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/framework/interface/plugin"
26+
27+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/api-translation/translator"
28+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/api-translation/translator/anthropic"
29+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/api-translation/translator/azureopenai"
30+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/api-translation/translator/vertex"
31+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/common/provider"
32+
"github.com/opendatahub-io/ai-gateway-payload-processing/pkg/plugins/common/state"
33+
)
34+
35+
const (
36+
APITranslationPluginType = "api-translation"
37+
)
38+
39+
// compile-time type validation
40+
var _ framework.RequestProcessor = &APITranslationPlugin{}
41+
var _ framework.ResponseProcessor = &APITranslationPlugin{}
42+
43+
// APITranslationFactory defines the factory function for APITranslationPlugin.
44+
func APITranslationFactory(name string, _ json.RawMessage, _ framework.Handle) (framework.BBRPlugin, error) {
45+
return NewAPITranslationPlugin().WithName(name), nil
46+
}
47+
48+
// NewAPITranslationPlugin creates a new plugin instance with all registered providers.
49+
func NewAPITranslationPlugin() *APITranslationPlugin {
50+
return &APITranslationPlugin{
51+
typedName: plugin.TypedName{
52+
Type: APITranslationPluginType,
53+
Name: APITranslationPluginType,
54+
},
55+
providers: map[string]translator.Translator{
56+
provider.Anthropic: anthropic.NewAnthropicTranslator(),
57+
provider.AzureOpenAI: azureopenai.NewAzureOpenAITranslator(),
58+
provider.Vertex: vertex.NewVertexTranslator(),
59+
},
60+
}
61+
}
62+
63+
// APITranslationPlugin translates inference API requests and responses between
64+
// OpenAI Chat Completions format and provider-native formats (e.g., Anthropic Messages API).
65+
type APITranslationPlugin struct {
66+
typedName plugin.TypedName
67+
providers map[string]translator.Translator // map from provider name to translator interface
68+
}
69+
70+
// TypedName returns the type and name tuple of this plugin instance.
71+
func (p *APITranslationPlugin) TypedName() plugin.TypedName {
72+
return p.typedName
73+
}
74+
75+
// WithName sets the name of the plugin instance.
76+
func (p *APITranslationPlugin) WithName(name string) *APITranslationPlugin {
77+
p.typedName.Name = name
78+
return p
79+
}
80+
81+
// ProcessRequest reads the provider from CycleState (set by an upstream plugin) and translates
82+
// the request body from OpenAI format to the provider's native format if needed.
83+
func (p *APITranslationPlugin) ProcessRequest(ctx context.Context, cycleState *framework.CycleState, request *framework.InferenceRequest) error {
84+
if request == nil || request.Headers == nil || request.Body == nil {
85+
return fmt.Errorf("invalid inference request: request/headers/body must be non-nil")
86+
}
87+
88+
providerName, err := framework.ReadCycleStateKey[string](cycleState, state.ProviderKey) // err if not found
89+
if err != nil || providerName == "" || providerName == "openai" { // empty provider means no translation needed
90+
return nil
91+
}
92+
93+
translator, ok := p.providers[providerName]
94+
if !ok {
95+
return fmt.Errorf("unsupported provider - '%s'", providerName)
96+
}
97+
98+
translatedBody, headersToMutate, headersToRemove, err := translator.TranslateRequest(request.Body)
99+
if err != nil {
100+
return fmt.Errorf("request translation failed for provider '%s' - %w", providerName, err)
101+
}
102+
103+
if translatedBody != nil {
104+
request.SetBody(translatedBody)
105+
}
106+
107+
for key, value := range headersToMutate {
108+
request.SetHeader(key, value)
109+
}
110+
for _, key := range headersToRemove {
111+
request.RemoveHeader(key)
112+
}
113+
114+
// authorization is a special header removed by the plugin, no matter which provider is used.
115+
// The api-key is expected to be set by the the api-key injection plugin.
116+
request.RemoveHeader("authorization")
117+
118+
// content-length is another special header that will be set automatically by the pluggable framework when the body is mutated.
119+
120+
return nil
121+
}
122+
123+
// ProcessResponse reads the provider from CycleState and translates the response
124+
// back to OpenAI Chat Completions format if needed.
125+
func (p *APITranslationPlugin) ProcessResponse(ctx context.Context, cycleState *framework.CycleState, response *framework.InferenceResponse) error {
126+
if response == nil || response.Headers == nil || response.Body == nil {
127+
return fmt.Errorf("invalid inference response: response/headers/body must be non-nil")
128+
}
129+
130+
providerName, err := framework.ReadCycleStateKey[string](cycleState, state.ProviderKey) // err if not found
131+
if err != nil || providerName == "" || providerName == "openai" { // empty provider means no translation needed
132+
return nil
133+
}
134+
135+
translator, ok := p.providers[providerName]
136+
if !ok {
137+
return fmt.Errorf("unsupported provider - '%s'", providerName)
138+
}
139+
140+
model, _ := framework.ReadCycleStateKey[string](cycleState, state.ModelKey)
141+
142+
translatedBody, err := translator.TranslateResponse(response.Body, model)
143+
if err != nil {
144+
return fmt.Errorf("response translation failed for provider '%s' - %w", providerName, err)
145+
}
146+
147+
if translatedBody != nil {
148+
response.SetBody(translatedBody)
149+
}
150+
151+
return nil
152+
}

0 commit comments

Comments
 (0)