Amazon Bedrock Provider

The Amazon Bedrock provider enables integration with foundation models through AWS Bedrock’s Converse API. It supports both synchronous and streaming message completion with full tool calling capabilities. Bedrock provides access to models from multiple providers (Anthropic, Meta, Mistral, Amazon) through a unified AWS-managed interface with enterprise features like VPC endpoints, CloudWatch logging, and model customization.

The provider handles AWS SigV4 request signing, the Bedrock Converse API format, and streaming via event-stream encoding. Authentication uses AWS credentials rather than API keys, supporting both permanent and temporary (STS) credentials.


BedrockProvider Struct

The provider is defined in src/client/providers/bedrock/mod.rs:

pub struct BedrockCredentials {
    pub access_key_id: String,
    pub secret_access_key: String,
    pub session_token: Option<String>,
}

pub struct BedrockProvider {
    credentials: BedrockCredentials,
    region: String,
    model: String,
}

impl BedrockProvider {
    pub fn new(credentials: BedrockCredentials, region: String, model: String) -> Self {
        Self { credentials, region, model }
    }

    pub fn model(&self) -> &str {
        &self.model
    }

    pub fn region(&self) -> &str {
        &self.region
    }
}

API Configuration

The Bedrock provider uses the Converse API:

SettingValue
Base URLhttps://bedrock-runtime.{region}.amazonaws.com
Converse/model/{model}/converse
Stream/model/{model}/converse-stream
AuthAWS SigV4

The model ID is URL-encoded in the path (e.g., colons become %3A).


LLMSessionConfig Builder

Create a Bedrock session configuration using the bedrock() builder method:

use agent_air::controller::LLMSessionConfig;

let config = LLMSessionConfig::bedrock(
    "AKIA...",                                    // AWS Access Key ID
    "secret...",                                  // AWS Secret Access Key
    "us-east-1",                                  // AWS Region
    "anthropic.claude-3-sonnet-20240229-v1:0"    // Model ID
);

The bedrock() method sets these defaults:

OptionDefault Value
max_tokens4096
streamingtrue
context_limit200,000
compactionThreshold (default)

Builder Methods

Customize the configuration using builder methods:

let config = LLMSessionConfig::bedrock(
    access_key_id,
    secret_access_key,
    "us-east-1",
    "anthropic.claude-3-sonnet-20240229-v1:0"
)
.with_bedrock_session_token(session_token)  // For temporary credentials
.with_max_tokens(4096)
.with_system_prompt("You are a helpful assistant.")
.with_temperature(0.7)
.with_streaming(true)
.with_context_limit(200_000);

Available methods:

MethodDescription
with_bedrock_session_token(impl Into<String>)Set session token for temp credentials
with_max_tokens(u32)Set maximum response tokens
with_system_prompt(impl Into<String>)Set the system prompt
with_temperature(f32)Set sampling temperature
with_streaming(bool)Enable or disable streaming
with_context_limit(i32)Set context window size
with_threshold_compaction(config)Configure compaction
without_compaction()Disable compaction

AWS Credentials

Permanent Credentials

Use IAM user credentials directly:

let config = LLMSessionConfig::bedrock(
    std::env::var("AWS_ACCESS_KEY_ID").unwrap(),
    std::env::var("AWS_SECRET_ACCESS_KEY").unwrap(),
    "us-east-1",
    "anthropic.claude-3-sonnet-20240229-v1:0"
);

Temporary Credentials (STS)

For assumed roles or temporary credentials, include the session token:

let config = LLMSessionConfig::bedrock(
    access_key_id,
    secret_access_key,
    "us-east-1",
    "anthropic.claude-3-sonnet-20240229-v1:0"
)
.with_bedrock_session_token(session_token);

BedrockCredentials Struct

For direct provider usage:

use agent_air::client::providers::bedrock::BedrockCredentials;

// Permanent credentials
let creds = BedrockCredentials::new(access_key_id, secret_access_key);

// Temporary credentials
let creds = BedrockCredentials::with_session_token(
    access_key_id,
    secret_access_key,
    session_token
);

Required IAM Permissions

The IAM user or role needs these permissions:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel",
        "bedrock:InvokeModelWithResponseStream"
      ],
      "Resource": "arn:aws:bedrock:*::foundation-model/*"
    }
  ]
}

For specific models only:

{
  "Resource": [
    "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0",
    "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-haiku-20240307-v1:0"
  ]
}

Streaming Support

The Bedrock provider fully supports streaming via the Converse Stream API. Unlike standard SSE, Bedrock uses AWS event-stream encoding:

pub enum StreamEvent {
    MessageStart { message_id: String, model: String },
    TextDelta(String),
    ToolUse { id: String, name: String, input: Value },
    MessageStop,
    Error(String),
}

The provider handles the binary event-stream parsing automatically.


Request Format (Converse API)

Bedrock uses the Converse API format which differs from direct provider APIs:

{
  "messages": [
    {
      "role": "user",
      "content": [{"text": "Hello"}]
    }
  ],
  "system": [
    {"text": "You are a helpful assistant."}
  ],
  "inferenceConfig": {
    "maxTokens": 4096,
    "temperature": 0.7,
    "topP": 0.9
  }
}

Role Mapping

Generic RoleBedrock Role
Useruser
Assistantassistant
Systemsystem array (separate field)

Content Types

Bedrock content uses specific object structures:

Content TypeFormat
Text{"text": "..."}
Tool Use{"toolUse": {"toolUseId": "...", "name": "...", "input": {...}}}
Tool Result{"toolResult": {"toolUseId": "...", "content": [{"text": "..."}], "status": "success"}}

Tool Use Format

Tools are sent in the Bedrock toolConfig format:

{
  "toolConfig": {
    "tools": [{
      "toolSpec": {
        "name": "get_weather",
        "description": "Get weather for a location",
        "inputSchema": {
          "json": {
            "type": "object",
            "properties": {
              "location": {"type": "string"}
            },
            "required": ["location"]
          }
        }
      }
    }],
    "toolChoice": {"auto": {}}
  }
}

Tool choice options:

ChoiceFormat
Auto{"auto": {}}
Any{"any": {}}
Specific{"tool": {"name": "tool_name"}}

Environment Variables

Configure Bedrock via environment variables:

VariableDescriptionDefault
AWS_ACCESS_KEY_IDAWS access key (required)None
AWS_SECRET_ACCESS_KEYAWS secret key (required)None
AWS_SESSION_TOKENSession token (optional)None
AWS_REGIONAWS regionus-east-1
BEDROCK_MODELModel identifierNone

Available Models

Common Bedrock model identifiers:

ModelIDContext
Claude 3 Sonnetanthropic.claude-3-sonnet-20240229-v1:0200K
Claude 3 Haikuanthropic.claude-3-haiku-20240307-v1:0200K
Claude 3 Opusanthropic.claude-3-opus-20240229-v1:0200K
Claude 3.5 Sonnetanthropic.claude-3-5-sonnet-20240620-v1:0200K
Llama 3 70Bmeta.llama3-70b-instruct-v1:08K
Llama 3 8Bmeta.llama3-8b-instruct-v1:08K
Mistral Largemistral.mistral-large-2402-v1:032K

Note: Model availability varies by region. Check AWS documentation for current availability.


YAML Configuration

Configure in your agent’s config file:

providers:
  - provider: bedrock
    bedrock_access_key_id: AKIA...
    bedrock_secret_access_key: secret...
    bedrock_region: us-east-1
    model: anthropic.claude-3-sonnet-20240229-v1:0
    system_prompt: "You are a helpful coding assistant."

default_provider: bedrock

Complete Example

use agent_air::AgentAir;
use agent_air::controller::LLMSessionConfig;

struct MyConfig;

impl AgentConfig for MyConfig {
    fn config_path(&self) -> &str { ".myagent/config.yaml" }
    fn default_system_prompt(&self) -> &str { "You are helpful." }
    fn log_prefix(&self) -> &str { "myagent" }
    fn name(&self) -> &str { "MyAgent" }
}

fn main() -> std::io::Result<()> {
    let mut agent = AgentAir::new(&MyConfig)?;

    // Configuration is loaded automatically from:
    // 1. ~/.myagent/config.yaml (if exists)
    // 2. AWS_* environment variables (fallback)

    agent.run()
}

Programmatic Configuration

For direct configuration without files:

use agent_air::controller::{LLMSessionConfig, LLMController};

let config = LLMSessionConfig::bedrock(
    std::env::var("AWS_ACCESS_KEY_ID").expect("Access key required"),
    std::env::var("AWS_SECRET_ACCESS_KEY").expect("Secret key required"),
    "us-east-1",
    "anthropic.claude-3-sonnet-20240229-v1:0"
)
.with_system_prompt("You are a helpful assistant.")
.with_max_tokens(4096)
.with_streaming(true);

// Create session with this config
let controller = LLMController::new(None);
let session_id = controller.create_session(config).await?;

Error Handling

Bedrock API errors are converted to LlmError:

pub struct LlmError {
    pub error_code: String,
    pub error_message: String,
}

Common error codes:

Error CodeDescription
ValidationExceptionInvalid request parameters
AccessDeniedExceptionIAM permissions issue
ThrottlingExceptionRate limit exceeded
ModelNotReadyExceptionModel not available in region
ServiceUnavailableExceptionTemporary service issue

Regions and Availability

Bedrock is available in these AWS regions (as of 2024):

RegionCodeNotes
US East (N. Virginia)us-east-1Most models
US West (Oregon)us-west-2Most models
Europe (Frankfurt)eu-central-1Limited
Europe (Paris)eu-west-3Limited
Asia Pacific (Tokyo)ap-northeast-1Limited
Asia Pacific (Sydney)ap-southeast-2Limited

Check AWS documentation for current model availability per region.


Comparison with Direct Anthropic API

FeatureBedrockDirect Anthropic
AuthenticationAWS SigV4API Key
API FormatConverse APIMessages API
VPC SupportYes (PrivateLink)No
LoggingCloudWatchCustom
BillingAWS consolidatedSeparate
Rate LimitsPer-accountPer-API key
Model AccessRequest requiredInstant