rig_bedrock/
completion.rs1use crate::{
4 client::Client,
5 types::{
6 assistant_content::AwsConverseOutput, completion_request::AwsCompletionRequest,
7 converse_output::InternalConverseOutput, errors::AwsSdkConverseError,
8 },
9};
10
11use aws_sdk_bedrockruntime::types as aws_bedrock;
12use rig_core::completion::{self, CompletionError, CompletionRequest};
13use rig_core::streaming::StreamingCompletionResponse;
14use rig_core::telemetry::ProviderResponseExt;
15use rig_core::telemetry::{CompletionOperation, CompletionSpanBuilder, SpanCombinator};
16use tracing::Instrument;
17
18pub const AMAZON_NOVA_LITE: &str = "amazon.nova-lite-v1:0";
34pub const AMAZON_NOVA_MICRO: &str = "amazon.nova-micro-v1:0";
36pub const AMAZON_NOVA_PRO: &str = "amazon.nova-pro-v1:0";
38pub const AMAZON_NOVA_CANVAS: &str = "amazon.nova-canvas-v1:0";
40pub const AMAZON_NOVA_REEL_V1_0: &str = "amazon.nova-reel-v1:0";
42pub const AMAZON_NOVA_REEL_V1_1: &str = "amazon.nova-reel-v1:1";
44pub const AMAZON_NOVA_SONIC: &str = "amazon.nova-sonic-v1:0";
46pub const AMAZON_RERANK_1_0: &str = "amazon.rerank-v1:0";
48pub const AMAZON_TITAN_EMBEDDINGS_G1_TEXT: &str = "amazon.titan-embed-text-v1";
50pub const AMAZON_TITAN_MULTIMODAL_EMBEDDINGS_G1: &str = "amazon.titan-embed-image-v1";
52pub const AMAZON_TITAN_TEXT_EMBEDDINGS_V2: &str = "amazon.titan-embed-text-v2:0";
54
55pub const ANTHROPIC_CLAUDE_HAIKU_4_5: &str = "us.anthropic.claude-haiku-4-5-20251001-v1:0";
57pub const ANTHROPIC_CLAUDE_SONNET_4_5: &str = "us.anthropic.claude-sonnet-4-5-20250929-v1:0";
59pub const ANTHROPIC_CLAUDE_OPUS_4_5: &str = "us.anthropic.claude-opus-4-5-20251101-v1:0";
61pub const ANTHROPIC_CLAUDE_SONNET_4_6: &str = "us.anthropic.claude-sonnet-4-6";
63pub const ANTHROPIC_CLAUDE_SONNET_5: &str = "us.anthropic.claude-sonnet-5";
65pub const ANTHROPIC_CLAUDE_OPUS_5: &str = "us.anthropic.claude-opus-5";
67
68pub const COHERE_EMBED_ENGLISH: &str = "cohere.embed-english-v3";
70pub const COHERE_EMBED_MULTILINGUAL: &str = "cohere.embed-multilingual-v3";
72pub const COHERE_RERANK_V3_5: &str = "cohere.rerank-v3-5:0";
74
75pub const DEEPSEEK_R1: &str = "us.deepseek.r1-v1:0";
77
78pub const LUMA_RAY_V2_0: &str = "luma.ray-v2:0";
80
81pub const LLAMA_3_8B_INSTRUCT: &str = "meta.llama3-8b-instruct-v1:0";
83pub const LLAMA_3_70B_INSTRUCT: &str = "meta.llama3-70b-instruct-v1:0";
85pub const LLAMA_3_1_8B_INSTRUCT: &str = "meta.llama3-1-8b-instruct-v1:0";
87pub const LLAMA_3_1_70B_INSTRUCT: &str = "meta.llama3-1-70b-instruct-v1:0";
89pub const META_LLAMA_3_3_70B_INSTRUCT: &str = "us.meta.llama3-3-70b-instruct-v1:0";
91pub const META_LLAMA_4_MAVERICK_17B_INSTRUCT: &str = "us.meta.llama4-maverick-17b-instruct-v1:0";
93pub const META_LLAMA_4_SCOUT_17B_INSTRUCT: &str = "us.meta.llama4-scout-17b-instruct-v1:0";
95
96pub const MISTRAL_7B_INSTRUCT: &str = "mistral.mistral-7b-instruct-v0:2";
98pub const MISTRAL_LARGE_24_02: &str = "mistral.mistral-large-2402-v1:0";
100pub const MISTRAL_SMALL_24_02: &str = "mistral.mistral-small-2402-v1:0";
102pub const MISTRAL_MIXTRAL_8X7B_INSTRUCT_V0: &str = "mistral.mixtral-8x7b-instruct-v0:1";
104pub const MISTRAL_PIXTRAL_LARGE_2502: &str = "us.mistral.pixtral-large-2502-v1:0";
106
107pub const STABILITY_SD3_5_LARGE: &str = "stability.sd3-5-large-v1:0";
109pub const STABILITY_STABLE_IMAGE_CORE_1_0: &str = "stability.stable-image-core-v1:1";
111pub const STABILITY_STABLE_IMAGE_ULTRA_1_0: &str = "stability.stable-image-ultra-v1:1";
113
114pub const TWELVELABS_PEGASUS_V1_2: &str = "twelvelabs.pegasus-1-2-v1:0";
116
117pub const WRITER_PALMYRA_X4: &str = "us.writer.palmyra-x4-v1:0";
119pub const WRITER_PALMYRA_X5: &str = "us.writer.palmyra-x5-v1:0";
121
122#[derive(Clone)]
123pub struct CompletionModel {
124 pub(crate) client: Client,
125 pub model: String,
126 pub prompt_caching: bool,
131 pub guardrail: Option<aws_bedrock::GuardrailConfiguration>,
134}
135
136impl CompletionModel {
137 pub fn new(client: Client, model: impl Into<String>) -> Self {
138 Self {
139 client,
140 model: model.into(),
141 prompt_caching: false,
142 guardrail: None,
143 }
144 }
145
146 pub fn with_prompt_caching(mut self) -> Self {
162 self.prompt_caching = true;
163 self
164 }
165
166 pub fn with_guardrail(
178 mut self,
179 identifier: impl Into<String>,
180 version: impl Into<String>,
181 trace: aws_bedrock::GuardrailTrace,
182 ) -> Self {
183 self.guardrail = Some(
184 aws_bedrock::GuardrailConfiguration::builder()
185 .guardrail_identifier(identifier)
186 .guardrail_version(version)
187 .trace(trace)
188 .build(),
189 );
190 self
191 }
192}
193
194pub(crate) fn resolve_request_model(
195 default_model: &str,
196 completion_request: &CompletionRequest,
197) -> String {
198 completion_request
199 .model
200 .clone()
201 .unwrap_or_else(|| default_model.to_string())
202}
203
204impl CompletionModel {
205 pub async fn raw_completion(
211 &self,
212 completion_request: completion::CompletionRequest,
213 ) -> Result<AwsConverseOutput, CompletionError> {
214 let request_model = resolve_request_model(&self.model, &completion_request);
215
216 let span =
217 CompletionSpanBuilder::new("aws_bedrock", &request_model, CompletionOperation::Chat)
218 .system_instructions(
219 completion_request.preamble.as_deref(),
220 completion_request.record_telemetry_content,
221 )
222 .build();
223
224 let request = AwsCompletionRequest {
225 inner: completion_request,
226 prompt_caching: self.prompt_caching,
227 };
228
229 let mut converse_builder = self
230 .client
231 .get_inner()
232 .await
233 .converse()
234 .model_id(request_model.clone());
235
236 let tool_config = request.tools_config()?;
237 let messages = request.messages()?;
238 let output_config = request.output_config()?;
239 converse_builder = converse_builder
240 .set_additional_model_request_fields(request.additional_params())
241 .set_inference_config(request.inference_config())
242 .set_tool_config(tool_config)
243 .set_system(request.system_prompt()?)
244 .set_messages(Some(messages))
245 .set_output_config(output_config)
246 .set_guardrail_config(self.guardrail.clone());
247
248 async move {
249 let response = converse_builder.send().await.map_err(|sdk_error| {
250 Into::<CompletionError>::into(AwsSdkConverseError(sdk_error))
251 })?;
252
253 let response: InternalConverseOutput = response.try_into().map_err(|x| {
254 CompletionError::ProviderError(format!("Type conversion error: {x}"))
255 })?;
256
257 let aws_output = AwsConverseOutput(response);
258
259 let span = tracing::Span::current();
260 span.record_response_metadata(&aws_output);
261 span.record_token_usage(&aws_output.get_usage().unwrap_or_default());
262
263 Ok(aws_output)
264 }
265 .instrument(span)
266 .await
267 }
268}
269
270impl completion::CompletionModel for CompletionModel {
271 async fn completion(
272 &self,
273 completion_request: completion::CompletionRequest,
274 ) -> Result<completion::CompletionResponse, CompletionError> {
275 let raw = self.raw_completion(completion_request).await?;
277 let captured = serde_json::to_value(&raw)?;
278 let response: completion::CompletionResponse = raw.try_into()?;
279 Ok(response.with_raw(captured))
280 }
281
282 async fn stream(
283 &self,
284 request: CompletionRequest,
285 ) -> Result<StreamingCompletionResponse, CompletionError> {
286 CompletionModel::stream(self, request).await
287 }
288}