Repository navigation
Description
📋 Prerequisites
- I have searched the existing issues to avoid creating a duplicate
- By submitting this issue, you agree to follow our Code of Conduct
📝 Feature Summary
Add an optional guardrail block to the Bedrock provider in ModelConfig so the controller can pass guardrailIdentifier and guardrailVersion to the Converse API natively, without requiring an external proxy.
❓ Problem Statement / Motivation
The Bedrock provider in ModelConfig only exposes region today.
If you want to apply AWS Bedrock Guardrails (content filtering, topic denial, PII redaction) to your agents, you're forced to deploy a separate OpenAI-compatible proxy that injects the guardrail config at the gateway level. This adds an extra service to maintain and forces you to use provider: "OpenAI" with a custom baseUrl instead of the native Bedrock path.
The Bedrock Converse API already accepts guardrailIdentifier and guardrailVersion in the request body — kagent just doesn't expose them.
💡 Proposed Solution
Add an optional guardrail block to the bedrock spec in ModelConfig:
bedrock:
region: "eu-central-1"
guardrail:
identifier: "abc123def456" # guardrail ID or ARN
version: "1" # guardrail version
trace: "enabled" # optional, defaults to disabledThe controller should pass these values as GuardrailConfiguration in the Converse API call (or as headers for InvokeModel). When a guardrail triggers INTERVENED, surface the blocked reason to the agent/user.
🔄 Alternatives Considered
- External proxy (what we do today): works but adds operational complexity and breaks native Bedrock provider usage
- Annotation-based config on the ModelConfig resource: not type-safe, hard to validate
- Separate GuardrailPolicy CRD referenced by ModelConfig: over-engineered for what's essentially two fields
🎯 Affected Service(s)
Controller Service
📚 Additional Context
Tested on kagent v0.9.0 with provider: Bedrock. The BedrockConfig struct currently only has Region — no guardrail-related fields exist in the CRD.
The AWS SDK Go v2 already exposes the relevant types in github.com/aws/aws-sdk-go-v2/service/bedrockruntime/types:
- GuardrailConfiguration{GuardrailIdentifier, GuardrailVersion, Trace}
So it's mostly wiring: add the field to the CRD, read it in the controller, pass it to the SDK call.
We're running kagent in production on AWS and would be happy to validate any implementation against real Bedrock Guardrails in our environment.
🙋 Are you willing to contribute?
- I am willing to submit a PR for this feature
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
sanskar-singh-2403 commentedon Jul 23, 2026
@dmitri-d @davidkarlsen
Happy to pick this up. I traced the wiring path on
mainand it looks clean. Wanted to confirm the CRD shape before writing code so we don't churn on the public API.Where it plugs in today:
go/api/v1alpha2/modelconfig_types.go:BedrockConfigcurrently exposesRegion,AdditionalModelRequestFields,PromptCaching,CacheTTL. This is where the newGuardrailfield plus kubebuilder validation would go.go/api/adk/types.go: theBedrocktransport struct mirrors those fields (region,additional_model_request_fields,prompt_caching,cache_ttl) and would need the matchingguardrailfield for the ADK JSON contract.go/adk/pkg/models/bedrock.go: the runtimeBedrockConfigand the actualm.Client.Converse(ctx, &bedrockruntime.ConverseInput{...})call (plus theConverseStreampath).ConverseInputtakes aGuardrailConfig *types.GuardrailConfigurationwhich isn't set today, so that's the one-line addition on the SDK side.So the flow is: add the field to the CRD, map it through the ADK types, build a
types.GuardrailConfiguration{GuardrailIdentifier, GuardrailVersion, Trace}and pass it into bothConverseandConverseStream. Plus deepcopy/CRD manifest regen and tests.Before I start, a couple of API shape questions so this lands the way you'd want:
guardrail: {identifier, version, trace}sub-block reads cleanly and matches the existing style. Good to lock that in? I'd make the whole block optional, withidentifierandversionrequired within it via a CELXValidationrule, consistent with the existing Bedrock validations in this file.trace. Expose it as an enum (enabled,enabled_full,disabled, defaultdisabled) mapping totypes.GuardrailTrace, rather than a free string? Keeps it type safe.INTERVENEDhandling. When a guardrail blocks, do you want the intervention reason surfaced as a normal assistant response so the agent sees it, or as an error/stopReason? I'd lean toward surfacing it in the response content with the block reason attached, but happy to follow whatever convention you prefer.GuardrailConfigon those two and leave InvokeModel out unless there's a reason to add it.If the shape above looks right, assign it to me and I'll open a PR with the CRD change, ADK mapping, both Converse paths wired, regenerated manifests, and unit tests. I can also validate against real Bedrock Guardrails since @GiGi-cloud-76 offered a prod environment, which would be great for an integration check.
GiGi-cloud-76 commentedon Jul 23, 2026
Thanks for picking this up, the analysis looks spot on.
On your questions:
Nested block vs flat — Yes,
guardrail: {identifier, version, trace}as an optional sub-block with identifier+version required within it is exactly what I had in mind. CEL validation consistent with the existing Bedrock rules makes sense.trace as enum — Agreed, typed enum is better than a free string.
enabled,enabled_full,disabled(default disabled) maps cleanly to the SDK.INTERVENED handling — I'd go with surfacing it in the response content (not as an error). The agent should see why the guardrail blocked so it can adjust or inform the user. A hard error would break agent loops unnecessarily. If you can include the guardrail trace output when trace is enabled, even better for debugging.
Converse only — Yes, scoping to Converse/ConverseStream is the right call. The current Bedrock path doesn't use InvokeModel, no reason to add it.
Shape looks good to me. Happy to validate against real guardrails once you have a branch — we have multiple guardrail configurations in production (content filters, topic denial, PII redaction) so we can cover a few scenarios.
feat: add native AWS Bedrock Guardrails support to ModelConfig
feat: add native AWS Bedrock Guardrails support to ModelConfig
feat: add native AWS Bedrock Guardrails support to ModelConfig
feat: add native AWS Bedrock Guardrails support to ModelConfig
feat: add native AWS Bedrock Guardrails support to ModelConfig (kagen…