From 69c84fc867f2ac9192c4eceecb9efc384d88fc64 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Thu, 15 Jan 2026 13:49:55 -0500 Subject: [PATCH 1/6] support bedrock Signed-off-by: Jet Chiang --- go/api/v1alpha2/modelconfig_types.go | 15 +++- go/api/v1alpha2/zz_generated.deepcopy.go | 20 +++++ .../crd/bases/kagent.dev_modelconfigs.yaml | 13 ++++ go/internal/adk/types.go | 44 +++++++++++ .../translator/agent/adk_api_translator.go | 78 +++++++++++++++++++ go/internal/httpserver/handlers/models.go | 7 ++ go/internal/httpserver/handlers/providers.go | 4 + .../templates/kagent.dev_modelconfigs.yaml | 22 ++++++ python/packages/kagent-adk/pyproject.toml | 1 + .../kagent-adk/src/kagent/adk/types.py | 10 ++- python/uv.lock | 51 ++++++++++++ 11 files changed, 263 insertions(+), 2 deletions(-) diff --git a/go/api/v1alpha2/modelconfig_types.go b/go/api/v1alpha2/modelconfig_types.go index 4e9315730..1c84d2951 100644 --- a/go/api/v1alpha2/modelconfig_types.go +++ b/go/api/v1alpha2/modelconfig_types.go @@ -25,7 +25,7 @@ const ( ) // ModelProvider represents the model provider type -// +kubebuilder:validation:Enum=Anthropic;OpenAI;AzureOpenAI;Ollama;Gemini;GeminiVertexAI;AnthropicVertexAI +// +kubebuilder:validation:Enum=Anthropic;OpenAI;AzureOpenAI;Ollama;Gemini;GeminiVertexAI;AnthropicVertexAI;Bedrock type ModelProvider string const ( @@ -36,6 +36,7 @@ const ( ModelProviderGemini ModelProvider = "Gemini" ModelProviderGeminiVertexAI ModelProvider = "GeminiVertexAI" ModelProviderAnthropicVertexAI ModelProvider = "AnthropicVertexAI" + ModelProviderBedrock ModelProvider = "Bedrock" ) type BaseVertexAIConfig struct { @@ -210,6 +211,13 @@ type OllamaConfig struct { type GeminiConfig struct{} +// BedrockConfig contains AWS Bedrock-specific configuration options. +type BedrockConfig struct { + // AWS region where the Bedrock model is available (e.g., us-east-1, us-west-2) + // +required + Region string `json:"region"` +} + // TLSConfig contains TLS/SSL configuration options for model provider connections. // This enables agents to connect to internal LiteLLM gateways or other providers // that use self-signed certificates or custom certificate authorities. @@ -255,6 +263,7 @@ type TLSConfig struct { // +kubebuilder:validation:XValidation:message="provider.gemini must be nil if the provider is not Gemini",rule="!(has(self.gemini) && self.provider != 'Gemini')" // +kubebuilder:validation:XValidation:message="provider.geminiVertexAI must be nil if the provider is not GeminiVertexAI",rule="!(has(self.geminiVertexAI) && self.provider != 'GeminiVertexAI')" // +kubebuilder:validation:XValidation:message="provider.anthropicVertexAI must be nil if the provider is not AnthropicVertexAI",rule="!(has(self.anthropicVertexAI) && self.provider != 'AnthropicVertexAI')" +// +kubebuilder:validation:XValidation:message="provider.bedrock must be nil if the provider is not Bedrock",rule="!(has(self.bedrock) && self.provider != 'Bedrock')" // +kubebuilder:validation:XValidation:message="apiKeySecret must be set if apiKeySecretKey is set",rule="!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))" // +kubebuilder:validation:XValidation:message="apiKeySecretKey must be set if apiKeySecret is set",rule="!(has(self.apiKeySecret) && !has(self.apiKeySecretKey))" // +kubebuilder:validation:XValidation:message="caCertSecretKey requires caCertSecretRef",rule="!(has(self.tls) && has(self.tls.caCertSecretKey) && size(self.tls.caCertSecretKey) > 0 && (!has(self.tls.caCertSecretRef) || size(self.tls.caCertSecretRef) == 0))" @@ -306,6 +315,10 @@ type ModelConfigSpec struct { // +optional AnthropicVertexAI *AnthropicVertexAIConfig `json:"anthropicVertexAI,omitempty"` + // AWS Bedrock-specific configuration + // +optional + Bedrock *BedrockConfig `json:"bedrock,omitempty"` + // TLS configuration for provider connections. // Enables agents to connect to internal LiteLLM gateways or other providers // that use self-signed certificates or custom certificate authorities. diff --git a/go/api/v1alpha2/zz_generated.deepcopy.go b/go/api/v1alpha2/zz_generated.deepcopy.go index 31e860071..ff2199c13 100644 --- a/go/api/v1alpha2/zz_generated.deepcopy.go +++ b/go/api/v1alpha2/zz_generated.deepcopy.go @@ -290,6 +290,21 @@ func (in *BaseVertexAIConfig) DeepCopy() *BaseVertexAIConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BedrockConfig) DeepCopyInto(out *BedrockConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BedrockConfig. +func (in *BedrockConfig) DeepCopy() *BedrockConfig { + if in == nil { + return nil + } + out := new(BedrockConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ByoDeploymentSpec) DeepCopyInto(out *ByoDeploymentSpec) { *out = *in @@ -549,6 +564,11 @@ func (in *ModelConfigSpec) DeepCopyInto(out *ModelConfigSpec) { *out = new(AnthropicVertexAIConfig) (*in).DeepCopyInto(*out) } + if in.Bedrock != nil { + in, out := &in.Bedrock, &out.Bedrock + *out = new(BedrockConfig) + **out = **in + } if in.TLS != nil { in, out := &in.TLS, &out.TLS *out = new(TLSConfig) diff --git a/go/config/crd/bases/kagent.dev_modelconfigs.yaml b/go/config/crd/bases/kagent.dev_modelconfigs.yaml index 74153526d..1d705700e 100644 --- a/go/config/crd/bases/kagent.dev_modelconfigs.yaml +++ b/go/config/crd/bases/kagent.dev_modelconfigs.yaml @@ -466,6 +466,16 @@ spec: - apiVersion - azureEndpoint type: object + bedrock: + description: AWS Bedrock-specific configuration + properties: + region: + description: AWS region where the Bedrock model is available (e.g., + us-east-1, us-west-2) + type: string + required: + - region + type: object defaultHeaders: additionalProperties: type: string @@ -576,6 +586,7 @@ spec: - Gemini - GeminiVertexAI - AnthropicVertexAI + - Bedrock type: string tls: description: |- @@ -636,6 +647,8 @@ spec: - message: provider.anthropicVertexAI must be nil if the provider is not AnthropicVertexAI rule: '!(has(self.anthropicVertexAI) && self.provider != ''AnthropicVertexAI'')' + - message: provider.bedrock must be nil if the provider is not Bedrock + rule: '!(has(self.bedrock) && self.provider != ''Bedrock'')' - message: apiKeySecret must be set if apiKeySecretKey is set rule: '!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))' - message: apiKeySecretKey must be set if apiKeySecret is set diff --git a/go/internal/adk/types.go b/go/internal/adk/types.go index b90667f31..348f7125e 100644 --- a/go/internal/adk/types.go +++ b/go/internal/adk/types.go @@ -69,6 +69,7 @@ const ( ModelTypeGeminiAnthropic = "gemini_anthropic" ModelTypeOllama = "ollama" ModelTypeGemini = "gemini" + ModelTypeBedrock = "bedrock" ) func (o *OpenAI) MarshalJSON() ([]byte, error) { @@ -185,6 +186,43 @@ func (g *Gemini) GetType() string { return ModelTypeGemini } +type Bedrock struct { + BaseModel + // Region is the AWS region where the model is available + Region string `json:"region,omitempty"` + // Temperature for sampling + Temperature *float64 `json:"temperature,omitempty"` + // MaxTokens is the maximum number of tokens to generate + MaxTokens *int `json:"max_tokens,omitempty"` + // TopP is the top-p sampling parameter + TopP *float64 `json:"top_p,omitempty"` +} + +func (b *Bedrock) MarshalJSON() ([]byte, error) { + data := map[string]any{ + "type": ModelTypeBedrock, + "model": b.Model, + "headers": b.Headers, + } + if b.Region != "" { + data["region"] = b.Region + } + if b.Temperature != nil { + data["temperature"] = *b.Temperature + } + if b.MaxTokens != nil { + data["max_tokens"] = *b.MaxTokens + } + if b.TopP != nil { + data["top_p"] = *b.TopP + } + return json.Marshal(data) +} + +func (b *Bedrock) GetType() string { + return ModelTypeBedrock +} + func ParseModel(bytes []byte) (Model, error) { var model BaseModel if err := json.Unmarshal(bytes, &model); err != nil { @@ -233,6 +271,12 @@ func ParseModel(bytes []byte) (Model, error) { return nil, err } return &ollama, nil + case ModelTypeBedrock: + var bedrock Bedrock + if err := json.Unmarshal(bytes, &bedrock); err != nil { + return nil, err + } + return &bedrock, nil } return nil, fmt.Errorf("unknown model type: %s", model.Type) } diff --git a/go/internal/controller/translator/agent/adk_api_translator.go b/go/internal/controller/translator/agent/adk_api_translator.go index 75af6f884..624ed8d98 100644 --- a/go/internal/controller/translator/agent/adk_api_translator.go +++ b/go/internal/controller/translator/agent/adk_api_translator.go @@ -932,6 +932,84 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC populateTLSFields(&gemini.BaseModel, model.Spec.TLS) return gemini, modelDeploymentData, secretHashBytes, nil + case v1alpha2.ModelProviderBedrock: + if model.Spec.Bedrock == nil { + return nil, nil, nil, fmt.Errorf("bedrock model config is required") + } + + // Set AWS region (always required) + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_REGION", + Value: model.Spec.Bedrock.Region, + }) + + // 1. Bearer Token: set apiKeySecretKey to "AWS_BEARER_TOKEN_BEDROCK" + // 2. IAM Credentials: set apiKeySecretKey to "AWS_ACCESS_KEY_ID" (will also inject AWS_SECRET_ACCESS_KEY) + if model.Spec.APIKeySecret != "" { + if model.Spec.APIKeySecretKey == "AWS_BEARER_TOKEN_BEDROCK" { + // Bearer token authentication + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_BEARER_TOKEN_BEDROCK", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: model.Spec.APIKeySecret, + }, + Key: "AWS_BEARER_TOKEN_BEDROCK", + }, + }, + }) + } else { + // IAM credentials authentication (default) + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_ACCESS_KEY_ID", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: model.Spec.APIKeySecret, + }, + Key: "AWS_ACCESS_KEY_ID", + }, + }, + }) + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_SECRET_ACCESS_KEY", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: model.Spec.APIKeySecret, + }, + Key: "AWS_SECRET_ACCESS_KEY", + }, + }, + }) + // AWS_SESSION_TOKEN is optional, only needed for temporary/SSO credentials + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_SESSION_TOKEN", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: model.Spec.APIKeySecret, + }, + Key: "AWS_SESSION_TOKEN", + Optional: ptr.To(true), + }, + }, + }) + } + } + bedrock := &adk.Bedrock{ + BaseModel: adk.BaseModel{ + Model: model.Spec.Model, + Headers: model.Spec.DefaultHeaders, + }, + Region: model.Spec.Bedrock.Region, + } + + // Populate TLS fields in BaseModel + populateTLSFields(&bedrock.BaseModel, model.Spec.TLS) + + return bedrock, modelDeploymentData, secretHashBytes, nil } return nil, nil, nil, fmt.Errorf("unknown model provider: %s", model.Spec.Provider) diff --git a/go/internal/httpserver/handlers/models.go b/go/internal/httpserver/handlers/models.go index 106f04913..ffea821d4 100644 --- a/go/internal/httpserver/handlers/models.go +++ b/go/internal/httpserver/handlers/models.go @@ -83,6 +83,13 @@ func (h *ModelHandler) HandleListSupportedModels(w ErrorResponseWriter, r *http. {Name: "claude-sonnet-4@20250514", FunctionCalling: true}, {Name: "claude-3-5-haiku@20241022", FunctionCalling: true}, }, + v1alpha2.ModelProviderBedrock: { + {Name: "anthropic.claude-3-sonnet-20240229-v1:0", FunctionCalling: true}, + {Name: "us.anthropic.claude-3-5-haiku-20241022-v1:0", FunctionCalling: true}, + {Name: "global.anthropic.claude-sonnet-4-5-20250929-v1:0", FunctionCalling: true}, + {Name: "global.anthropic.claude-opus-4-5-20251101-v1:0", FunctionCalling: true}, + {Name: "us.amazon.nova-2-lite-v1:0", FunctionCalling: false}, + }, } log.Info("Successfully listed supported models", "count", len(supportedModels)) diff --git a/go/internal/httpserver/handlers/providers.go b/go/internal/httpserver/handlers/providers.go index 1e2f1fdde..da4b2afa2 100644 --- a/go/internal/httpserver/handlers/providers.go +++ b/go/internal/httpserver/handlers/providers.go @@ -26,6 +26,9 @@ func getRequiredKeysForModelProvider(providerType v1alpha2.ModelProvider) []stri case v1alpha2.ModelProviderAzureOpenAI: // Based on the +required comments in the AzureOpenAIConfig struct definition return []string{"azureEndpoint", "apiVersion"} + case v1alpha2.ModelProviderBedrock: + // Region is required for Bedrock + return []string{"region"} case v1alpha2.ModelProviderOpenAI, v1alpha2.ModelProviderAnthropic, v1alpha2.ModelProviderOllama: // These providers currently have no fields marked as strictly required in the API definition return []string{} @@ -101,6 +104,7 @@ func (h *ProviderHandler) HandleListSupportedModelProviders(w ErrorResponseWrite {v1alpha2.ModelProviderGemini, reflect.TypeFor[v1alpha2.GeminiConfig]()}, {v1alpha2.ModelProviderGeminiVertexAI, reflect.TypeFor[v1alpha2.GeminiVertexAIConfig]()}, {v1alpha2.ModelProviderAnthropicVertexAI, reflect.TypeFor[v1alpha2.AnthropicVertexAIConfig]()}, + {v1alpha2.ModelProviderBedrock, reflect.TypeFor[v1alpha2.BedrockConfig]()}, } providersResponse := []map[string]any{} diff --git a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml index 74153526d..3091807e4 100644 --- a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml +++ b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml @@ -466,6 +466,25 @@ spec: - apiVersion - azureEndpoint type: object + bedrock: + description: AWS Bedrock-specific configuration + properties: + maxTokens: + description: Maximum tokens to generate + type: integer + region: + description: AWS region where the Bedrock model is deployed (e.g., + us-east-1, us-west-2) + type: string + temperature: + description: Temperature for sampling + type: string + topP: + description: Top-p sampling parameter + type: string + required: + - region + type: object defaultHeaders: additionalProperties: type: string @@ -576,6 +595,7 @@ spec: - Gemini - GeminiVertexAI - AnthropicVertexAI + - Bedrock type: string tls: description: |- @@ -636,6 +656,8 @@ spec: - message: provider.anthropicVertexAI must be nil if the provider is not AnthropicVertexAI rule: '!(has(self.anthropicVertexAI) && self.provider != ''AnthropicVertexAI'')' + - message: provider.bedrock must be nil if the provider is not Bedrock + rule: '!(has(self.bedrock) && self.provider != ''Bedrock'')' - message: apiKeySecret must be set if apiKeySecretKey is set rule: '!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))' - message: apiKeySecretKey must be set if apiKeySecret is set diff --git a/python/packages/kagent-adk/pyproject.toml b/python/packages/kagent-adk/pyproject.toml index 362abbb73..3dac82669 100644 --- a/python/packages/kagent-adk/pyproject.toml +++ b/python/packages/kagent-adk/pyproject.toml @@ -31,6 +31,7 @@ dependencies = [ "typing-extensions>=4.8.0", "jsonref>=1.1.0", "a2a-sdk>=0.3.22", + "boto3>=1.28.57", ] [tool.uv.sources] diff --git a/python/packages/kagent-adk/src/kagent/adk/types.py b/python/packages/kagent-adk/src/kagent/adk/types.py index 44378a67f..c50e71eda 100644 --- a/python/packages/kagent-adk/src/kagent/adk/types.py +++ b/python/packages/kagent-adk/src/kagent/adk/types.py @@ -95,8 +95,13 @@ class Gemini(BaseLLM): type: Literal["gemini"] +class Bedrock(BaseLLM): + region: str | None = None + type: Literal["bedrock"] + + class AgentConfig(BaseModel): - model: Union[OpenAI, Anthropic, GeminiVertexAI, GeminiAnthropic, Ollama, AzureOpenAI, Gemini] = Field( + model: Union[OpenAI, Anthropic, GeminiVertexAI, GeminiAnthropic, Ollama, AzureOpenAI, Gemini, Bedrock] = Field( discriminator="type" ) description: str @@ -248,6 +253,9 @@ async def rewrite_url_to_proxy(request: httpx.Request) -> None: ) elif self.model.type == "gemini": model = self.model.model + elif self.model.type == "bedrock": + # LiteLLM handles Bedrock via boto3 internally when model starts with "bedrock/" + model = LiteLlm(model=f"bedrock/{self.model.model}", extra_headers=extra_headers) else: raise ValueError(f"Invalid model type: {self.model.type}") return Agent( diff --git a/python/uv.lock b/python/uv.lock index f938597a7..1d0134dde 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -407,6 +407,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, ] +[[package]] +name = "boto3" +version = "1.42.28" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/aa/a44ea8c8ee8239f3f7c32cce966512c846297df5fe48b56db6882f3b7ca0/boto3-1.42.28.tar.gz", hash = "sha256:7d56c298b8d98f5e9b04cf5d6627f68e7792e25614533aef17f815681b5e1096", size = 112846, upload-time = "2026-01-14T20:37:21.448Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/35/5d95169ed145f0c49ebfeb6a5228ab63d54e95a2c7a43f0f0eb893540660/boto3-1.42.28-py3-none-any.whl", hash = "sha256:7994bc2a094c1894f6a4221a1696c5d18af6c9c888191051866f1d05c4fba431", size = 140575, upload-time = "2026-01-14T20:37:20.098Z" }, +] + +[[package]] +name = "botocore" +version = "1.42.28" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/8d/e0828726aa568e5ab0ec477c7a47a82aa37f00951858d9ad892b6b1d5e32/botocore-1.42.28.tar.gz", hash = "sha256:0c15e78d1accf97df691083331f682e97b1bef73ef12dcdaadcf652abf9c182c", size = 14886029, upload-time = "2026-01-14T20:37:11.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/ff/72470b92ba96868be1936b8b3c7a70f902b60d36268bdeddb732317bef7a/botocore-1.42.28-py3-none-any.whl", hash = "sha256:d26c7a0851489ce1a18279f9802fe434bd736ea861d4888cc2c7d83fb1f6af8f", size = 14559264, upload-time = "2026-01-14T20:37:08.184Z" }, +] + [[package]] name = "build" version = "1.3.0" @@ -1767,6 +1795,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/4a/4175a563579e884192ba6e81725fc0448b042024419be8d83aa8a80a3f44/jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5", size = 354213, upload-time = "2025-05-18T19:04:41.894Z" }, ] +[[package]] +name = "jmespath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, +] + [[package]] name = "json-repair" version = "0.25.2" @@ -1853,6 +1890,7 @@ dependencies = [ { name = "aiofiles" }, { name = "anthropic", extra = ["vertex"] }, { name = "anyio" }, + { name = "boto3" }, { name = "fastapi" }, { name = "google-adk" }, { name = "google-auth" }, @@ -1888,6 +1926,7 @@ requires-dist = [ { name = "aiofiles", specifier = ">=24.1.0" }, { name = "anthropic", extras = ["vertex"], specifier = ">=0.49.0" }, { name = "anyio", specifier = ">=4.9.0" }, + { name = "boto3", specifier = ">=1.28.57" }, { name = "fastapi", specifier = ">=0.115.1" }, { name = "google-adk", specifier = ">=1.21.0" }, { name = "google-auth", specifier = ">=2.40.2" }, @@ -4030,6 +4069,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4c/9b/0b8aa09817b63e78d94b4977f18b1fcaead3165a5ee49251c5d5c245bb2d/ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69", size = 11982083, upload-time = "2025-07-29T22:32:33.881Z" }, ] +[[package]] +name = "s3transfer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, +] + [[package]] name = "shapely" version = "2.1.1" From 9bbf8be6b912a199afeb917e5c4acd027c8cb9a1 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Thu, 15 Jan 2026 13:56:24 -0500 Subject: [PATCH 2/6] remove optional fields Signed-off-by: Jet Chiang --- go/internal/adk/types.go | 15 --------------- .../templates/kagent.dev_modelconfigs.yaml | 11 +---------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/go/internal/adk/types.go b/go/internal/adk/types.go index 348f7125e..c99a657c9 100644 --- a/go/internal/adk/types.go +++ b/go/internal/adk/types.go @@ -190,12 +190,6 @@ type Bedrock struct { BaseModel // Region is the AWS region where the model is available Region string `json:"region,omitempty"` - // Temperature for sampling - Temperature *float64 `json:"temperature,omitempty"` - // MaxTokens is the maximum number of tokens to generate - MaxTokens *int `json:"max_tokens,omitempty"` - // TopP is the top-p sampling parameter - TopP *float64 `json:"top_p,omitempty"` } func (b *Bedrock) MarshalJSON() ([]byte, error) { @@ -207,15 +201,6 @@ func (b *Bedrock) MarshalJSON() ([]byte, error) { if b.Region != "" { data["region"] = b.Region } - if b.Temperature != nil { - data["temperature"] = *b.Temperature - } - if b.MaxTokens != nil { - data["max_tokens"] = *b.MaxTokens - } - if b.TopP != nil { - data["top_p"] = *b.TopP - } return json.Marshal(data) } diff --git a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml index 3091807e4..1d705700e 100644 --- a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml +++ b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml @@ -469,19 +469,10 @@ spec: bedrock: description: AWS Bedrock-specific configuration properties: - maxTokens: - description: Maximum tokens to generate - type: integer region: - description: AWS region where the Bedrock model is deployed (e.g., + description: AWS region where the Bedrock model is available (e.g., us-east-1, us-west-2) type: string - temperature: - description: Temperature for sampling - type: string - topP: - description: Top-p sampling parameter - type: string required: - region type: object From 810f58f459e42c8744829318eabb4f9355da2a26 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Thu, 15 Jan 2026 16:08:49 -0500 Subject: [PATCH 3/6] fix everything mcp server and lock version Signed-off-by: Jet Chiang --- go/test/e2e/invoke_api_test.go | 6 +++--- go/test/e2e/manifests/add-numbers-agent.yaml | 2 +- go/test/e2e/manifests/everything-mcp-server.yaml | 2 +- go/test/e2e/mocks/invoke_mcp_agent.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go/test/e2e/invoke_api_test.go b/go/test/e2e/invoke_api_test.go index ecda7c5ea..ddeda2156 100644 --- a/go/test/e2e/invoke_api_test.go +++ b/go/test/e2e/invoke_api_test.go @@ -367,7 +367,7 @@ func generateMCPServer() *v1alpha1.MCPServer { Deployment: v1alpha1.MCPServerDeployment{ Port: 3000, Cmd: "npx", - Args: []string{"-y", "@modelcontextprotocol/server-everything"}, + Args: []string{"-y", "@modelcontextprotocol/server-everything@2026.1.14"}, }, TransportType: v1alpha1.TransportTypeStdio, }, @@ -518,7 +518,7 @@ func TestE2EInvokeDeclarativeAgentWithMcpServerTool(t *testing.T) { Kind: "MCPServer", Name: mcpServer.Name, }, - ToolNames: []string{"add"}, + ToolNames: []string{"get-sum"}, }, }, } @@ -782,7 +782,7 @@ func TestE2EInvokeSTSIntegration(t *testing.T) { Kind: "MCPServer", Name: mcpServer.Name, }, - ToolNames: []string{"add"}, + ToolNames: []string{"get-sum"}, }, }, } diff --git a/go/test/e2e/manifests/add-numbers-agent.yaml b/go/test/e2e/manifests/add-numbers-agent.yaml index 770a68914..1b4d5e1f4 100644 --- a/go/test/e2e/manifests/add-numbers-agent.yaml +++ b/go/test/e2e/manifests/add-numbers-agent.yaml @@ -14,7 +14,7 @@ spec: kind: MCPServer name: everything-mcp-server toolNames: - - add + - get-sum type: McpServer description: This agent adds numbers. type: Declarative diff --git a/go/test/e2e/manifests/everything-mcp-server.yaml b/go/test/e2e/manifests/everything-mcp-server.yaml index 89302f1b3..0923dfd59 100644 --- a/go/test/e2e/manifests/everything-mcp-server.yaml +++ b/go/test/e2e/manifests/everything-mcp-server.yaml @@ -9,5 +9,5 @@ spec: cmd: npx args: - "-y" - - "@modelcontextprotocol/server-everything" + - "@modelcontextprotocol/server-everything@2026.1.14" transportType: stdio diff --git a/go/test/e2e/mocks/invoke_mcp_agent.json b/go/test/e2e/mocks/invoke_mcp_agent.json index fd3fd5264..dc13d3f2e 100644 --- a/go/test/e2e/mocks/invoke_mcp_agent.json +++ b/go/test/e2e/mocks/invoke_mcp_agent.json @@ -25,7 +25,7 @@ "id": "call_1", "type": "function", "function": { - "name": "add", + "name": "get-sum", "arguments": "{\"a\": 3, \"b\": 5}" } } From 2f01167f26c683f09bfc49957c49461c40865854 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Thu, 15 Jan 2026 16:38:45 -0500 Subject: [PATCH 4/6] test for bedrock translator Signed-off-by: Jet Chiang --- .../translator/agent/adk_api_translator.go | 2 +- .../agent/testdata/inputs/bedrock_agent.yaml | 36 ++ .../agent/testdata/outputs/bedrock_agent.json | 316 ++++++++++++++++++ 3 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml create mode 100644 go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json diff --git a/go/internal/controller/translator/agent/adk_api_translator.go b/go/internal/controller/translator/agent/adk_api_translator.go index 624ed8d98..2b4fd9aa9 100644 --- a/go/internal/controller/translator/agent/adk_api_translator.go +++ b/go/internal/controller/translator/agent/adk_api_translator.go @@ -955,7 +955,7 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC LocalObjectReference: corev1.LocalObjectReference{ Name: model.Spec.APIKeySecret, }, - Key: "AWS_BEARER_TOKEN_BEDROCK", + Key: model.Spec.APIKeySecretKey, }, }, }) diff --git a/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml b/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml new file mode 100644 index 000000000..5d809c44d --- /dev/null +++ b/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml @@ -0,0 +1,36 @@ +operation: translateAgent +targetObject: bedrock-agent +namespace: test +objects: + - apiVersion: v1 + kind: Secret + metadata: + name: bedrock-credentials + namespace: test + data: + AWS_ACCESS_KEY_ID: QUtJQVRFU1RLRVk= # base64 encoded "AKIATESTKEY" + AWS_SECRET_ACCESS_KEY: dGVzdHNlY3JldGtleQ== # base64 encoded "testsecretkey" + - apiVersion: kagent.dev/v1alpha2 + kind: ModelConfig + metadata: + name: bedrock-model + namespace: test + spec: + provider: Bedrock + model: us.anthropic.claude-sonnet-4-20250514-v1:0 + apiKeySecret: bedrock-credentials + apiKeySecretKey: AWS_ACCESS_KEY_ID + bedrock: + region: us-east-1 + - apiVersion: kagent.dev/v1alpha2 + kind: Agent + metadata: + name: bedrock-agent + namespace: test + spec: + type: Declarative + declarative: + description: An agent using AWS Bedrock with Claude + systemMessage: You are a helpful AI assistant running on AWS Bedrock. + modelConfig: bedrock-model + tools: [] diff --git a/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json b/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json new file mode 100644 index 000000000..e57b76b40 --- /dev/null +++ b/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json @@ -0,0 +1,316 @@ +{ + "agentCard": { + "capabilities": { + "pushNotifications": false, + "stateTransitionHistory": true, + "streaming": true + }, + "defaultInputModes": [ + "text" + ], + "defaultOutputModes": [ + "text" + ], + "description": "", + "name": "bedrock_agent", + "skills": null, + "url": "http://bedrock-agent.test:8080", + "version": "" + }, + "config": { + "description": "", + "http_tools": null, + "instruction": "You are a helpful AI assistant running on AWS Bedrock.", + "model": { + "headers": null, + "model": "us.anthropic.claude-sonnet-4-20250514-v1:0", + "region": "us-east-1", + "type": "bedrock" + }, + "remote_agents": null, + "sse_tools": null, + "stream": false + }, + "manifest": [ + { + "apiVersion": "v1", + "kind": "Secret", + "metadata": { + "labels": { + "app": "kagent", + "app.kubernetes.io/managed-by": "kagent", + "app.kubernetes.io/name": "bedrock-agent", + "app.kubernetes.io/part-of": "kagent", + "kagent": "bedrock-agent" + }, + "name": "bedrock-agent", + "namespace": "test", + "ownerReferences": [ + { + "apiVersion": "kagent.dev/v1alpha2", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Agent", + "name": "bedrock-agent", + "uid": "" + } + ] + }, + "stringData": { + "agent-card.json": "{\"name\":\"bedrock_agent\",\"description\":\"\",\"url\":\"http://bedrock-agent.test:8080\",\"version\":\"\",\"capabilities\":{\"streaming\":true,\"pushNotifications\":false,\"stateTransitionHistory\":true},\"defaultInputModes\":[\"text\"],\"defaultOutputModes\":[\"text\"],\"skills\":[]}", + "config.json": "{\"model\":{\"headers\":null,\"model\":\"us.anthropic.claude-sonnet-4-20250514-v1:0\",\"region\":\"us-east-1\",\"type\":\"bedrock\"},\"description\":\"\",\"instruction\":\"You are a helpful AI assistant running on AWS Bedrock.\",\"http_tools\":null,\"sse_tools\":null,\"remote_agents\":null,\"stream\":false}" + } + }, + { + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "labels": { + "app": "kagent", + "app.kubernetes.io/managed-by": "kagent", + "app.kubernetes.io/name": "bedrock-agent", + "app.kubernetes.io/part-of": "kagent", + "kagent": "bedrock-agent" + }, + "name": "bedrock-agent", + "namespace": "test", + "ownerReferences": [ + { + "apiVersion": "kagent.dev/v1alpha2", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Agent", + "name": "bedrock-agent", + "uid": "" + } + ] + } + }, + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "kagent", + "app.kubernetes.io/managed-by": "kagent", + "app.kubernetes.io/name": "bedrock-agent", + "app.kubernetes.io/part-of": "kagent", + "kagent": "bedrock-agent" + }, + "name": "bedrock-agent", + "namespace": "test", + "ownerReferences": [ + { + "apiVersion": "kagent.dev/v1alpha2", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Agent", + "name": "bedrock-agent", + "uid": "" + } + ] + }, + "spec": { + "selector": { + "matchLabels": { + "app": "kagent", + "kagent": "bedrock-agent" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": 1, + "maxUnavailable": 0 + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "annotations": { + "kagent.dev/config-hash": "4534659890849344430" + }, + "labels": { + "app": "kagent", + "app.kubernetes.io/managed-by": "kagent", + "app.kubernetes.io/name": "bedrock-agent", + "app.kubernetes.io/part-of": "kagent", + "kagent": "bedrock-agent" + } + }, + "spec": { + "containers": [ + { + "args": [ + "--host", + "0.0.0.0", + "--port", + "8080", + "--filepath", + "/config" + ], + "env": [ + { + "name": "AWS_REGION", + "value": "us-east-1" + }, + { + "name": "AWS_ACCESS_KEY_ID", + "valueFrom": { + "secretKeyRef": { + "key": "AWS_ACCESS_KEY_ID", + "name": "bedrock-credentials" + } + } + }, + { + "name": "AWS_SECRET_ACCESS_KEY", + "valueFrom": { + "secretKeyRef": { + "key": "AWS_SECRET_ACCESS_KEY", + "name": "bedrock-credentials" + } + } + }, + { + "name": "AWS_SESSION_TOKEN", + "valueFrom": { + "secretKeyRef": { + "key": "AWS_SESSION_TOKEN", + "name": "bedrock-credentials", + "optional": true + } + } + }, + { + "name": "KAGENT_NAMESPACE", + "valueFrom": { + "fieldRef": { + "fieldPath": "metadata.namespace" + } + } + }, + { + "name": "KAGENT_NAME", + "valueFrom": { + "fieldRef": { + "fieldPath": "spec.serviceAccountName" + } + } + }, + { + "name": "KAGENT_URL", + "value": "http://kagent-controller.kagent:8083" + } + ], + "image": "cr.kagent.dev/kagent-dev/kagent/app:dev", + "imagePullPolicy": "IfNotPresent", + "name": "kagent", + "ports": [ + { + "containerPort": 8080, + "name": "http" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/health", + "port": "http" + }, + "initialDelaySeconds": 15, + "periodSeconds": 15, + "timeoutSeconds": 15 + }, + "resources": { + "limits": { + "cpu": "2", + "memory": "1Gi" + }, + "requests": { + "cpu": "100m", + "memory": "384Mi" + } + }, + "volumeMounts": [ + { + "mountPath": "/config", + "name": "config" + }, + { + "mountPath": "/var/run/secrets/tokens", + "name": "kagent-token" + } + ] + } + ], + "serviceAccountName": "bedrock-agent", + "volumes": [ + { + "name": "config", + "secret": { + "secretName": "bedrock-agent" + } + }, + { + "name": "kagent-token", + "projected": { + "sources": [ + { + "serviceAccountToken": { + "audience": "kagent", + "expirationSeconds": 3600, + "path": "kagent-token" + } + } + ] + } + } + ] + } + } + }, + "status": {} + }, + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "labels": { + "app": "kagent", + "app.kubernetes.io/managed-by": "kagent", + "app.kubernetes.io/name": "bedrock-agent", + "app.kubernetes.io/part-of": "kagent", + "kagent": "bedrock-agent" + }, + "name": "bedrock-agent", + "namespace": "test", + "ownerReferences": [ + { + "apiVersion": "kagent.dev/v1alpha2", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Agent", + "name": "bedrock-agent", + "uid": "" + } + ] + }, + "spec": { + "ports": [ + { + "name": "http", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "app": "kagent", + "kagent": "bedrock-agent" + }, + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + } + ] +} \ No newline at end of file From f266ff38d340678c685a3ad6230aa9c772451f44 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Fri, 16 Jan 2026 10:37:16 -0500 Subject: [PATCH 5/6] remove apikey secret key Signed-off-by: Jet Chiang --- .../translator/agent/adk_api_translator.go | 36 ++++++++++--------- .../agent/testdata/inputs/bedrock_agent.yaml | 1 - .../agent/testdata/outputs/bedrock_agent.json | 10 ------ 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/go/internal/controller/translator/agent/adk_api_translator.go b/go/internal/controller/translator/agent/adk_api_translator.go index 2b4fd9aa9..e0625879a 100644 --- a/go/internal/controller/translator/agent/adk_api_translator.go +++ b/go/internal/controller/translator/agent/adk_api_translator.go @@ -943,11 +943,15 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC Value: model.Spec.Bedrock.Region, }) - // 1. Bearer Token: set apiKeySecretKey to "AWS_BEARER_TOKEN_BEDROCK" - // 2. IAM Credentials: set apiKeySecretKey to "AWS_ACCESS_KEY_ID" (will also inject AWS_SECRET_ACCESS_KEY) + // If AWS_BEARER_TOKEN_BEDROCK key exists: use bearer token auth + // Otherwise, use IAM credentials if model.Spec.APIKeySecret != "" { - if model.Spec.APIKeySecretKey == "AWS_BEARER_TOKEN_BEDROCK" { - // Bearer token authentication + secret := &corev1.Secret{} + if err := a.kube.Get(ctx, types.NamespacedName{Namespace: namespace, Name: model.Spec.APIKeySecret}, secret); err != nil { + return nil, nil, nil, fmt.Errorf("failed to get Bedrock credentials secret: %w", err) + } + + if _, hasBearerToken := secret.Data["AWS_BEARER_TOKEN_BEDROCK"]; hasBearerToken { modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ Name: "AWS_BEARER_TOKEN_BEDROCK", ValueFrom: &corev1.EnvVarSource{ @@ -955,12 +959,11 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC LocalObjectReference: corev1.LocalObjectReference{ Name: model.Spec.APIKeySecret, }, - Key: model.Spec.APIKeySecretKey, + Key: "AWS_BEARER_TOKEN_BEDROCK", }, }, }) } else { - // IAM credentials authentication (default) modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ Name: "AWS_ACCESS_KEY_ID", ValueFrom: &corev1.EnvVarSource{ @@ -984,18 +987,19 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC }, }) // AWS_SESSION_TOKEN is optional, only needed for temporary/SSO credentials - modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ - Name: "AWS_SESSION_TOKEN", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: model.Spec.APIKeySecret, + if _, hasSessionToken := secret.Data["AWS_SESSION_TOKEN"]; hasSessionToken { + modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{ + Name: "AWS_SESSION_TOKEN", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: model.Spec.APIKeySecret, + }, + Key: "AWS_SESSION_TOKEN", }, - Key: "AWS_SESSION_TOKEN", - Optional: ptr.To(true), }, - }, - }) + }) + } } } bedrock := &adk.Bedrock{ diff --git a/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml b/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml index 5d809c44d..c760ddcb0 100644 --- a/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml +++ b/go/internal/controller/translator/agent/testdata/inputs/bedrock_agent.yaml @@ -19,7 +19,6 @@ objects: provider: Bedrock model: us.anthropic.claude-sonnet-4-20250514-v1:0 apiKeySecret: bedrock-credentials - apiKeySecretKey: AWS_ACCESS_KEY_ID bedrock: region: us-east-1 - apiVersion: kagent.dev/v1alpha2 diff --git a/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json b/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json index e57b76b40..833b99e9f 100644 --- a/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json +++ b/go/internal/controller/translator/agent/testdata/outputs/bedrock_agent.json @@ -171,16 +171,6 @@ } } }, - { - "name": "AWS_SESSION_TOKEN", - "valueFrom": { - "secretKeyRef": { - "key": "AWS_SESSION_TOKEN", - "name": "bedrock-credentials", - "optional": true - } - } - }, { "name": "KAGENT_NAMESPACE", "valueFrom": { From 34b8417e3570d56d893ef3fd71a6e06765710337 Mon Sep 17 00:00:00 2001 From: Jet Chiang Date: Fri, 16 Jan 2026 10:48:13 -0500 Subject: [PATCH 6/6] add bedrock exception to crd validation rules Signed-off-by: Jet Chiang --- go/api/v1alpha2/modelconfig_types.go | 2 +- go/config/crd/bases/kagent.dev_modelconfigs.yaml | 6 ++++-- helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/go/api/v1alpha2/modelconfig_types.go b/go/api/v1alpha2/modelconfig_types.go index 1c84d2951..207af7bf0 100644 --- a/go/api/v1alpha2/modelconfig_types.go +++ b/go/api/v1alpha2/modelconfig_types.go @@ -265,7 +265,7 @@ type TLSConfig struct { // +kubebuilder:validation:XValidation:message="provider.anthropicVertexAI must be nil if the provider is not AnthropicVertexAI",rule="!(has(self.anthropicVertexAI) && self.provider != 'AnthropicVertexAI')" // +kubebuilder:validation:XValidation:message="provider.bedrock must be nil if the provider is not Bedrock",rule="!(has(self.bedrock) && self.provider != 'Bedrock')" // +kubebuilder:validation:XValidation:message="apiKeySecret must be set if apiKeySecretKey is set",rule="!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))" -// +kubebuilder:validation:XValidation:message="apiKeySecretKey must be set if apiKeySecret is set",rule="!(has(self.apiKeySecret) && !has(self.apiKeySecretKey))" +// +kubebuilder:validation:XValidation:message="apiKeySecretKey must be set if apiKeySecret is set (except for Bedrock provider)",rule="!(has(self.apiKeySecret) && !has(self.apiKeySecretKey) && self.provider != 'Bedrock')" // +kubebuilder:validation:XValidation:message="caCertSecretKey requires caCertSecretRef",rule="!(has(self.tls) && has(self.tls.caCertSecretKey) && size(self.tls.caCertSecretKey) > 0 && (!has(self.tls.caCertSecretRef) || size(self.tls.caCertSecretRef) == 0))" // +kubebuilder:validation:XValidation:message="caCertSecretKey requires caCertSecretRef (unless disableVerify is true)",rule="!(has(self.tls) && (!has(self.tls.disableVerify) || !self.tls.disableVerify) && has(self.tls.caCertSecretKey) && size(self.tls.caCertSecretKey) > 0 && (!has(self.tls.caCertSecretRef) || size(self.tls.caCertSecretRef) == 0))" // +kubebuilder:validation:XValidation:message="caCertSecretRef requires caCertSecretKey (unless disableVerify is true)",rule="!(has(self.tls) && (!has(self.tls.disableVerify) || !self.tls.disableVerify) && has(self.tls.caCertSecretRef) && size(self.tls.caCertSecretRef) > 0 && (!has(self.tls.caCertSecretKey) || size(self.tls.caCertSecretKey) == 0))" diff --git a/go/config/crd/bases/kagent.dev_modelconfigs.yaml b/go/config/crd/bases/kagent.dev_modelconfigs.yaml index 1d705700e..0bb40bb0e 100644 --- a/go/config/crd/bases/kagent.dev_modelconfigs.yaml +++ b/go/config/crd/bases/kagent.dev_modelconfigs.yaml @@ -651,8 +651,10 @@ spec: rule: '!(has(self.bedrock) && self.provider != ''Bedrock'')' - message: apiKeySecret must be set if apiKeySecretKey is set rule: '!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))' - - message: apiKeySecretKey must be set if apiKeySecret is set - rule: '!(has(self.apiKeySecret) && !has(self.apiKeySecretKey))' + - message: apiKeySecretKey must be set if apiKeySecret is set (except + for Bedrock provider) + rule: '!(has(self.apiKeySecret) && !has(self.apiKeySecretKey) && self.provider + != ''Bedrock'')' - message: caCertSecretKey requires caCertSecretRef rule: '!(has(self.tls) && has(self.tls.caCertSecretKey) && size(self.tls.caCertSecretKey) > 0 && (!has(self.tls.caCertSecretRef) || size(self.tls.caCertSecretRef) diff --git a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml index 1d705700e..0bb40bb0e 100644 --- a/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml +++ b/helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml @@ -651,8 +651,10 @@ spec: rule: '!(has(self.bedrock) && self.provider != ''Bedrock'')' - message: apiKeySecret must be set if apiKeySecretKey is set rule: '!(has(self.apiKeySecretKey) && !has(self.apiKeySecret))' - - message: apiKeySecretKey must be set if apiKeySecret is set - rule: '!(has(self.apiKeySecret) && !has(self.apiKeySecretKey))' + - message: apiKeySecretKey must be set if apiKeySecret is set (except + for Bedrock provider) + rule: '!(has(self.apiKeySecret) && !has(self.apiKeySecretKey) && self.provider + != ''Bedrock'')' - message: caCertSecretKey requires caCertSecretRef rule: '!(has(self.tls) && has(self.tls.caCertSecretKey) && size(self.tls.caCertSecretKey) > 0 && (!has(self.tls.caCertSecretRef) || size(self.tls.caCertSecretRef)