bedrock: Add Guardrail configuration support (#50084)

## Background: Amazon Bedrock Guardrails

AWS Bedrock Guardrails enables configurable safety and compliance
controls for generative AI applications:
- Evaluates both user inputs and model responses against policies.
:contentReference[oaicite:8]{index=8}
- Can block or filter content based on harmful categories, denied
topics, PII, or hallucination criteria.
:contentReference[oaicite:9]{index=9}
- Guardrails are applied during inference API calls by specifying
`guardrailIdentifier` and `guardrailVersion` in the request.
:contentReference[oaicite:10]{index=10}

Relevant AWS documentation:
- User Guide:
https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html
- How Guardrails Works:
https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-how.html
- API Reference (GuardrailConfiguration):
https://docs.aws.amazon.com/bedrock/latest/APIReference/API_GuardrailConfiguration.html


Some AWS environments enforce IAM policies that require a guardrail to
be specified on every Bedrock API call (via a `StringEquals` condition
on `bedrock:GuardrailIdentifier`). Without this, Zed returns
`AccessDenied` and Bedrock models are completely unusable in those
environments.

This adds two optional settings, `guardrail_identifier` and
`guardrail_version`, to the Bedrock provider config. When set, a
`GuardrailStreamConfiguration` is attached to every `converse_stream`
request. When unset, behaviour is identical to before.

```json
{
  "language_models": {
    "bedrock": {
      "guardrail_identifier": "arn:aws:bedrock:us-east-1:123456789012:guardrail/abc123",
      "guardrail_version": "DRAFT"
    }
  }
}
```

`guardrail_version` defaults to `"DRAFT"` if omitted.

Release Notes:

- agent: Added `guardrail_identifier` and `guardrail_version` settings
for AWS Bedrock, enabling use in environments where IAM policies require
a guardrail on all model requests

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
This commit is contained in:
Gunner Kwon 2026-05-12 02:43:54 +09:00 committed by GitHub
parent 7472c29de0
commit 5d3f275cbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 59 additions and 4 deletions

View file

@ -3,13 +3,13 @@ mod models;
use anyhow::{Result, anyhow};
use aws_sdk_bedrockruntime as bedrock;
pub use aws_sdk_bedrockruntime as bedrock_client;
use aws_sdk_bedrockruntime::types::InferenceConfiguration;
pub use aws_sdk_bedrockruntime::types::{
AnyToolChoice as BedrockAnyToolChoice, AutoToolChoice as BedrockAutoToolChoice,
ContentBlock as BedrockInnerContent, Tool as BedrockTool, ToolChoice as BedrockToolChoice,
ToolConfiguration as BedrockToolConfig, ToolInputSchema as BedrockToolInputSchema,
ToolSpecification as BedrockToolSpec,
};
use aws_sdk_bedrockruntime::types::{GuardrailStreamConfiguration, InferenceConfiguration};
pub use aws_smithy_types::Blob as BedrockBlob;
use aws_smithy_types::{Document, Number as AwsNumber};
pub use bedrock::operation::converse_stream::ConverseStreamInput as BedrockStreamingRequest;
@ -90,6 +90,17 @@ pub async fn stream_completion(
}
}
if let Some(guardrail_id) = &request.guardrail_identifier {
let version = request.guardrail_version.as_deref().unwrap_or("DRAFT");
response = response.guardrail_config(
GuardrailStreamConfiguration::builder()
.guardrail_identifier(guardrail_id)
.guardrail_version(version)
.build(),
);
}
let output = response.send().await.map_err(|err| match err {
bedrock::error::SdkError::ServiceError(ctx) => {
use bedrock::operation::converse_stream::ConverseStreamError;
@ -202,6 +213,8 @@ pub struct Request {
pub temperature: Option<f32>,
pub top_k: Option<u32>,
pub top_p: Option<f32>,
pub guardrail_identifier: Option<String>,
pub guardrail_version: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]

View file

@ -113,6 +113,8 @@ pub struct AmazonBedrockSettings {
pub role_arn: Option<String>,
pub authentication_method: Option<BedrockAuthMethod>,
pub allow_global: Option<bool>,
pub guardrail_identifier: Option<String>,
pub guardrail_version: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, EnumIter, IntoStaticStr, JsonSchema)]
@ -385,6 +387,12 @@ impl State {
.and_then(|s| s.allow_global)
.unwrap_or(false)
}
fn get_guardrail_config(&self) -> (Option<String>, Option<String>) {
self.settings.as_ref().map_or((None, None), |s| {
(s.guardrail_identifier.clone(), s.guardrail_version.clone())
})
}
}
pub struct BedrockLanguageModelProvider {
@ -710,9 +718,11 @@ impl LanguageModel for BedrockModel {
LanguageModelCompletionError,
>,
> {
let (region, allow_global) = cx.read_entity(&self.state, |state, _cx| {
(state.get_region(), state.get_allow_global())
});
let (region, allow_global, guardrail_identifier, guardrail_version) =
cx.read_entity(&self.state, |state, _cx| {
let (gid, gv) = state.get_guardrail_config();
(state.get_region(), state.get_allow_global(), gid, gv)
});
let model_id = match self.model.cross_region_inference_id(&region, allow_global) {
Ok(s) => s,
@ -731,6 +741,8 @@ impl LanguageModel for BedrockModel {
self.model.thinking_mode(),
self.model.supports_caching(),
self.model.supports_tool_use(),
guardrail_identifier,
guardrail_version,
) {
Ok(request) => request,
Err(err) => return futures::future::ready(Err(err.into())).boxed(),
@ -823,6 +835,8 @@ pub fn into_bedrock(
thinking_mode: BedrockModelMode,
supports_caching: bool,
supports_tool_use: bool,
guardrail_identifier: Option<String>,
guardrail_version: Option<String>,
) -> Result<bedrock::Request> {
let mut new_messages: Vec<BedrockMessage> = Vec::new();
let mut system_message = String::new();
@ -1127,6 +1141,8 @@ pub fn into_bedrock(
temperature: request.temperature.or(Some(default_temperature)),
top_k: None,
top_p: None,
guardrail_identifier,
guardrail_version,
})
}

View file

@ -61,6 +61,8 @@ impl settings::Settings for AllLanguageModelSettings {
role_arn: None, // todo(was never a setting for this...)
authentication_method: bedrock.authentication_method.map(Into::into),
allow_global: bedrock.allow_global,
guardrail_identifier: bedrock.guardrail_identifier,
guardrail_version: bedrock.guardrail_version,
},
deepseek: DeepSeekSettings {
api_url: deepseek.api_url.unwrap(),

View file

@ -65,6 +65,10 @@ pub struct AmazonBedrockSettingsContent {
pub profile: Option<String>,
pub authentication_method: Option<BedrockAuthMethodContent>,
pub allow_global: Option<bool>,
/// The guardrail identifier (ARN or ID) to apply to Bedrock API requests.
pub guardrail_identifier: Option<String>,
/// The guardrail version to use. Defaults to "DRAFT" if not specified.
pub guardrail_version: Option<String>,
}
#[with_fallible_options]

View file

@ -154,6 +154,26 @@ For the most up-to-date supported regions and models, refer to the [Supported Mo
Bedrock models that support vision (Claude 3 and later, Amazon Nova Pro and Lite, Meta Llama 3.2 Vision models, Mistral Pixtral) can receive images in conversations and tool results.
#### Guardrails {#bedrock-guardrails}
Some AWS environments enforce IAM policies that require a guardrail to be specified on every Bedrock API call. To apply a guardrail to all Bedrock requests, add `guardrail_identifier` to your Bedrock configuration:
```json [settings]
{
"language_models": {
"bedrock": {
"guardrail_identifier": "arn:aws:bedrock:us-east-1:123456789012:guardrail/abc123",
"guardrail_version": "DRAFT"
}
}
}
```
- `guardrail_identifier`: The ARN or ID of the guardrail to apply to every request.
- `guardrail_version`: The version of the guardrail to use. Defaults to `"DRAFT"` if omitted.
> **Note**: For more information, refer to the [AWS Bedrock Guardrails documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html).
### Anthropic {#anthropic}
You can use Anthropic models by choosing them via the model dropdown in the Agent Panel.