use anyhow::Result;
use aws_config::BehaviorVersion;
use aws_sdk_bedrockruntime::{
types::{ContentBlock::Text, ConversationRole::*, Message as BedrockMessage},
Client as BedrockClient,
};
use serde_json::json;
use tracing::{info, Level};
use tracing_subscriber::FmtSubscriber;
use universal_bot_core::{Bot, BotConfig, Message};
async fn call_bedrock_claude(prompt: &str) -> Result<String> {
info!("๐ Calling AWS Bedrock with Claude Opus 4.1...");
let config = aws_config::defaults(BehaviorVersion::latest())
.region("us-east-1")
.load()
.await;
let client = BedrockClient::new(&config);
let messages = [BedrockMessage::builder()
.role(User)
.content(Text(prompt.to_string()))
.build()
.map_err(|e| anyhow::anyhow!("Failed to build message: {}", e))?];
let request_body = json!({
"anthropic_version": "bedrock-2023-05-31",
"messages": messages.iter().map(|m| {
json!({
"role": match m.role() {
User => "user",
Assistant => "assistant",
_ => "user",
},
"content": m.content().iter().map(|c| {
match c {
Text(text) => json!({
"type": "text",
"text": text
}),
_ => json!({
"type": "text",
"text": ""
})
}
}).collect::<Vec<_>>()
})
}).collect::<Vec<_>>(),
"max_tokens": 1024,
"temperature": 0.1,
"top_p": 0.9,
"top_k": 250,
"stop_sequences": []
});
info!("๐ค Sending request to Claude Opus 4.1 on Bedrock...");
let response = client
.invoke_model()
.model_id("us.anthropic.claude-opus-4-1-20250805-v1:0") .content_type("application/json")
.accept("application/json")
.body(aws_sdk_bedrockruntime::primitives::Blob::new(
serde_json::to_vec(&request_body)?,
))
.send()
.await
.map_err(|e| anyhow::anyhow!("Bedrock API call failed: {}", e))?;
let response_body = response.body().as_ref();
let response_json: serde_json::Value = serde_json::from_slice(response_body)?;
info!("โ
Received response from Claude Opus 4.1");
let text = response_json["content"]
.as_array()
.and_then(|arr| arr.first())
.and_then(|content| content["text"].as_str())
.unwrap_or("No response text found")
.to_string();
if let Some(usage) = response_json["usage"].as_object() {
info!("๐ Token Usage:");
info!(
" Input tokens: {}",
usage
.get("input_tokens")
.and_then(|v| v.as_u64())
.unwrap_or(0)
);
info!(
" Output tokens: {}",
usage
.get("output_tokens")
.and_then(|v| v.as_u64())
.unwrap_or(0)
);
}
Ok(text)
}
#[tokio::main]
async fn main() -> Result<()> {
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::INFO)
.finish();
tracing::subscriber::set_global_default(subscriber)?;
info!("๐ค Universal Bot - AWS Bedrock Integration Test");
info!("๐ Using Model: Claude Opus 4.1 (us.anthropic.claude-opus-4-1-20250805-v1:0)");
info!("๐ Region: us-east-1");
let config = BotConfig::builder()
.model("us.anthropic.claude-opus-4-1-20250805-v1:0") .temperature(0.1)
.max_tokens(1024)
.enable_logging(true)
.enable_cost_tracking(true)
.build()?;
let bot = Bot::new(config).await?;
info!("โ
Bot initialized with Bedrock configuration");
let test_prompts = [
"What is the capital of France? Give a one-sentence answer.",
"Write a haiku about artificial intelligence.",
"Explain quantum computing in simple terms (2-3 sentences max).",
"What are the three primary colors? List them.",
"Translate 'Hello, how are you?' to Spanish, French, and Japanese.",
];
info!("\n๐งช Starting Bedrock Integration Tests:\n");
for (i, prompt) in test_prompts.iter().enumerate() {
info!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
info!("Test {}: {}", i + 1, prompt);
info!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
let message = Message::text(*prompt);
match bot.process(message).await {
Ok(response) => {
info!("๐ Bot Framework Response: {}", response.content);
if let Some(usage) = &response.usage {
info!("๐ฐ Estimated Cost: ${:.4}", usage.estimated_cost);
}
}
Err(e) => {
info!("โ Bot Framework Error: {}", e);
}
}
info!("\n๐ Making real AWS Bedrock call...");
match call_bedrock_claude(prompt).await {
Ok(response) => {
info!("๐ฏ Claude Opus 4.1 Response: {}", response);
}
Err(e) => {
info!("โ Bedrock Error: {}", e);
info!("๐ก Note: Ensure AWS credentials are configured and you have access to Claude models");
}
}
info!("");
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
}
let metrics = bot.metrics();
info!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
info!("๐ Final Test Metrics:");
info!(" Total requests: {}", metrics.requests_total());
info!(" Success rate: {:.2}%", metrics.success_rate());
if let Some(avg_time) = metrics.average_response_time() {
info!(" Average response time: {:?}", avg_time);
}
info!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
info!("โ
AWS Bedrock Integration Test Complete!");
info!("๐ Successfully demonstrated Universal Bot with Claude Opus 4.1 on AWS Bedrock");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_bedrock_connection() {
let config = aws_config::defaults(BehaviorVersion::latest())
.region("us-east-1")
.load()
.await;
let client = BedrockClient::new(&config);
assert!(!client.config().region().unwrap().to_string().is_empty());
}
}