#[cfg(all(test, not(feature = "bedrock")))]
use crate::classify::tiers::llm::SYSTEM_PROMPT;
use crate::classify::tiers::llm_prompt::LlmUsage;
pub struct BedrockClassifier {
#[allow(dead_code)] pub(crate) model: String,
#[cfg(feature = "bedrock")]
inner: trusty_common::inference::BedrockAdapter,
}
pub const DEFAULT_BEDROCK_MODEL: &str = "anthropic.claude-3-haiku-20240307-v1:0";
impl BedrockClassifier {
#[cfg(feature = "bedrock")]
pub async fn new(model: &str) -> Result<Self, String> {
Ok(Self {
model: model.to_string(),
inner: trusty_common::inference::BedrockAdapter::new(None),
})
}
#[cfg(feature = "bedrock")]
pub async fn with_region(model: &str, region: Option<&str>) -> Result<Self, String> {
Ok(Self {
model: model.to_string(),
inner: trusty_common::inference::BedrockAdapter::new(region),
})
}
#[cfg(not(feature = "bedrock"))]
pub async fn new(_model: &str) -> Result<Self, String> {
Err("bedrock feature not compiled in — rebuild with --features bedrock".to_string())
}
#[cfg(not(feature = "bedrock"))]
pub async fn with_region(_model: &str, _region: Option<&str>) -> Result<Self, String> {
Err("bedrock feature not compiled in — rebuild with --features bedrock".to_string())
}
#[cfg(feature = "bedrock")]
pub async fn complete(
&self,
system: &str,
message: &str,
) -> (Option<String>, Option<LlmUsage>) {
use tracing::warn;
use trusty_common::inference::{ChatMessage, ChatRequest, InferenceAdapter};
let mut req = ChatRequest::new(
self.model.clone(),
vec![
ChatMessage::system(system),
ChatMessage::user(format!("Classify this commit message:\n\n{message}")),
],
);
req.temperature = Some(0.0);
req.max_tokens = Some(256);
match self.inner.chat(&req).await {
Ok(resp) => {
let usage = LlmUsage {
input_tokens: u64::from(resp.usage.prompt_tokens),
output_tokens: u64::from(resp.usage.completion_tokens),
};
(resp.first_text(), Some(usage))
}
Err(e) => {
warn!(error = %e, "bedrock converse call failed");
(None, None)
}
}
}
#[cfg(not(feature = "bedrock"))]
pub async fn complete(
&self,
_system: &str,
_message: &str,
) -> (Option<String>, Option<LlmUsage>) {
(None, None)
}
}
#[cfg(all(test, not(feature = "bedrock")))]
mod tests {
use super::*;
#[tokio::test]
async fn bedrock_stub_returns_error_without_feature() {
let result = BedrockClassifier::new("anthropic.claude-3-haiku-20240307-v1:0").await;
let err = match result {
Err(e) => e,
Ok(_) => panic!("must error without feature"),
};
assert!(err.contains("bedrock feature not compiled in"));
}
#[test]
fn shared_system_prompt_contains_complexity_instruction() {
assert!(
SYSTEM_PROMPT.contains("complexity"),
"shared SYSTEM_PROMPT must instruct the model to return a complexity score"
);
}
}