Skip to content

Commit d6bf13f

Browse files
committed
anthropic vertex ai support
Signed-off-by: omar <[email protected]>
1 parent e837e48 commit d6bf13f

File tree

4 files changed

+76
-8
lines changed

4 files changed

+76
-8
lines changed

api/v1alpha1/ai_backend.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,13 @@ type GeminiConfig struct {
254254
ApiVersion string `json:"apiVersion"`
255255
}
256256

257-
// Publisher configures the type of publisher model to use for VertexAI. Currently, only Google is supported.
257+
// Publisher configures the type of publisher model to use for VertexAI. Google and Anthropic are supported.
258258
type Publisher string
259259

260-
const GOOGLE Publisher = "GOOGLE"
260+
const (
261+
GOOGLE Publisher = "GOOGLE"
262+
ANTHROPIC Publisher = "ANTHROPIC"
263+
)
261264

262265
// VertexAIConfig settings for the [Vertex AI](https://cloud.google.com/vertex-ai/docs) LLM provider.
263266
// To find the values for the project ID, project location, and publisher, you can check the fields of an API request, such as
@@ -293,8 +296,8 @@ type VertexAIConfig struct {
293296
// Optional: The model path to route to. Defaults to the Gemini model path, `generateContent`.
294297
ModelPath *string `json:"modelPath,omitempty"`
295298

296-
// The type of publisher model to use. Currently, only Google is supported.
297-
// +kubebuilder:validation:Enum=GOOGLE
299+
// The type of publisher model to use. Google and Anthropic are supported.
300+
// +kubebuilder:validation:Enum=GOOGLE;ANTHROPIC
298301
Publisher Publisher `json:"publisher"`
299302
}
300303

install/helm/kgateway-crds/templates/gateway.kgateway.dev_backends.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,11 @@ spec:
542542
minLength: 1
543543
type: string
544544
publisher:
545-
description: The type of publisher model to use. Currently,
546-
only Google is supported.
545+
description: The type of publisher model to use. Google
546+
and Anthropic are supported.
547547
enum:
548548
- GOOGLE
549+
- ANTHROPIC
549550
type: string
550551
required:
551552
- apiVersion
@@ -1088,9 +1089,10 @@ spec:
10881089
type: string
10891090
publisher:
10901091
description: The type of publisher model to use.
1091-
Currently, only Google is supported.
1092+
Google and Anthropic are supported.
10921093
enum:
10931094
- GOOGLE
1095+
- ANTHROPIC
10941096
type: string
10951097
required:
10961098
- apiVersion

internal/kgateway/extensions2/plugins/backend/ai/ai_model_cluster.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,8 @@ func buildVertexAIEndpoint(data *v1alpha1.VertexAIConfig, host *string, port *gw
285285
switch data.Publisher {
286286
case v1alpha1.GOOGLE:
287287
publisher = "google"
288+
case v1alpha1.ANTHROPIC:
289+
publisher = "anthropic"
288290
default:
289291
// TODO(npolshak): add support for other publishers
290292
slog.Warn("unsupported Vertex AI publisher, defaulting to Google", "publisher", string(data.Publisher))
@@ -401,6 +403,8 @@ func getTransformation(provider *v1alpha1.LLMProvider) (string, string, string,
401403
switch provider.VertexAI.Publisher {
402404
case v1alpha1.GOOGLE:
403405
modelPath = getVertexAIGeminiModelPath()
406+
case v1alpha1.ANTHROPIC:
407+
modelPath = getVertexAIAnthropicModelPath()
404408
default:
405409
// TODO(npolshak): add support for other publishers
406410
slog.Warn("unsupported Vertex AI publisher, defaulting to Google", "publisher", string(provider.VertexAI.Publisher))
@@ -439,6 +443,11 @@ func getVertexAIGeminiModelPath() string {
439443
return `models/{{host_metadata("model")}}:{% if dynamic_metadata("route_type") == "CHAT_STREAMING" %}streamGenerateContent?alt=sse{% else %}generateContent{% endif %}`
440444
}
441445

446+
func getVertexAIAnthropicModelPath() string {
447+
return `models/{{host_metadata("model")}}:{% if dynamic_metadata("route_type") == "CHAT_STREAMING" %}streamGenerateContent{% else %}generateContent{% endif %}`
448+
// return `models/{{host_metadata("model")}}:{% if dynamic_metadata("route_type") == "CHAT_STREAMING" %}streamRawPredict?alt=sse{% else %}rawPredict{% endif %}`
449+
}
450+
442451
func defaultBodyTransformation() *envoytransformation.TransformationTemplate_MergeJsonKeys {
443452
return &envoytransformation.TransformationTemplate_MergeJsonKeys{
444453
MergeJsonKeys: &envoytransformation.MergeJsonKeys{

internal/kgateway/extensions2/plugins/backend/ai/ai_model_cluster_test.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ func TestProcessAIBackend_Gemini(t *testing.T) {
236236
assert.Equal(t, "v1", filterMeta.Fields["api_version"].GetStringValue())
237237
}
238238

239-
func TestProcessAIBackend_VertexAI(t *testing.T) {
239+
func TestProcessAIBackend_VertexAIGoogle(t *testing.T) {
240240
cluster := &envoyclusterv3.Cluster{
241241
Name: "vertex-ai-cluster",
242242
}
@@ -290,6 +290,60 @@ func TestProcessAIBackend_VertexAI(t *testing.T) {
290290
assert.Equal(t, "google", filterMeta.Fields["publisher"].GetStringValue())
291291
}
292292

293+
func TestProcessAIBackend_VertexAIAnthropic(t *testing.T) {
294+
cluster := &envoyclusterv3.Cluster{
295+
Name: "vertex-ai-cluster",
296+
}
297+
298+
aiBackend := &v1alpha1.AIBackend{
299+
LLM: &v1alpha1.LLMProvider{
300+
VertexAI: &v1alpha1.VertexAIConfig{
301+
Model: "claude-3-opus-20240229",
302+
ApiVersion: "v1",
303+
Location: "us-central1",
304+
ProjectId: "my-project",
305+
Publisher: v1alpha1.ANTHROPIC,
306+
AuthToken: v1alpha1.SingleAuthToken{
307+
Kind: v1alpha1.Inline,
308+
Inline: ptr.To("vertex-token"),
309+
},
310+
},
311+
},
312+
}
313+
314+
secrets := &ir.Secret{}
315+
multiSecrets := map[string]*ir.Secret{}
316+
317+
err := ProcessAIBackend(aiBackend, secrets, multiSecrets, cluster)
318+
319+
require.NoError(t, err)
320+
321+
// Verify endpoint
322+
endpoints := cluster.LoadAssignment.Endpoints[0].LbEndpoints
323+
require.Len(t, endpoints, 1)
324+
325+
endpoint := endpoints[0]
326+
hostEndpoint := endpoint.GetEndpoint()
327+
require.NotNil(t, hostEndpoint)
328+
329+
// Verify socket address
330+
address := hostEndpoint.Address.GetSocketAddress()
331+
require.NotNil(t, address)
332+
assert.Equal(t, "us-central1-aiplatform.googleapis.com", address.Address)
333+
assert.Equal(t, uint32(443), address.GetPortValue())
334+
335+
// Verify metadata
336+
require.NotNil(t, endpoint.Metadata)
337+
filterMeta := endpoint.Metadata.FilterMetadata["io.solo.transformation"]
338+
require.NotNil(t, filterMeta)
339+
assert.Equal(t, "vertex-token", filterMeta.Fields["auth_token"].GetStringValue())
340+
assert.Equal(t, "claude-3-opus-20240229", filterMeta.Fields["model"].GetStringValue())
341+
assert.Equal(t, "v1", filterMeta.Fields["api_version"].GetStringValue())
342+
assert.Equal(t, "us-central1", filterMeta.Fields["location"].GetStringValue())
343+
assert.Equal(t, "my-project", filterMeta.Fields["project"].GetStringValue())
344+
assert.Equal(t, "anthropic", filterMeta.Fields["publisher"].GetStringValue())
345+
}
346+
293347
func TestProcessAIBackend_CustomURL(t *testing.T) {
294348
cluster := &envoyclusterv3.Cluster{
295349
Name: "custom-host-cluster",

0 commit comments

Comments
 (0)