Skip to main content

mixtape_core/model/
runtime.rs

1//! Runtime-owned Bedrock model configuration.
2
3use super::{BedrockModel, Model};
4use crate::provider::ProviderError;
5
6/// A model selected at runtime, including an exact inference-profile ID or ARN.
7///
8/// Token ceilings are supplied by the caller; this type does not discover account
9/// access, service limits, or model capabilities. Constructing it performs no I/O.
10/// Unlike some historical typed models, it never opts into global routing.
11#[derive(Debug, Clone)]
12pub struct RuntimeBedrockModel {
13    name: String,
14    model_id: String,
15    context_tokens: usize,
16    output_tokens: usize,
17}
18
19impl RuntimeBedrockModel {
20    /// Build an owned configuration without leaking strings or selecting a route.
21    pub fn new(
22        name: impl Into<String>,
23        model_id: impl Into<String>,
24        context_tokens: usize,
25        output_tokens: usize,
26    ) -> Result<Self, ProviderError> {
27        let name = name.into();
28        let model_id = model_id.into();
29        if name.trim().is_empty() {
30            return Err(ProviderError::Configuration("Model name is empty".into()));
31        }
32        // IDs and ARNs are identifiers, not URLs. Bedrock remains authoritative
33        // for account access and supported routes; do not guess those here.
34        if model_id.is_empty()
35            || model_id.contains("://")
36            || (model_id.starts_with("arn:") && !model_id.contains(":bedrock:"))
37            || !model_id
38                .bytes()
39                .all(|c| c.is_ascii_alphanumeric() || b"._:/-".contains(&c))
40        {
41            return Err(ProviderError::Configuration(
42                "Expected a Bedrock model ID, inference-profile ID, or ARN".into(),
43            ));
44        }
45        if context_tokens == 0 || output_tokens == 0 || output_tokens > i32::MAX as usize {
46            return Err(ProviderError::Configuration(
47                "Token ceilings must be positive; output must fit Bedrock's i32 maxTokens".into(),
48            ));
49        }
50        Ok(Self {
51            name,
52            model_id,
53            context_tokens,
54            output_tokens,
55        })
56    }
57}
58
59impl Model for RuntimeBedrockModel {
60    fn name(&self) -> &str {
61        &self.name
62    }
63
64    fn max_context_tokens(&self) -> usize {
65        self.context_tokens
66    }
67
68    fn max_output_tokens(&self) -> usize {
69        self.output_tokens
70    }
71
72    fn estimate_token_count(&self, text: &str) -> usize {
73        text.len().div_ceil(4)
74    }
75}
76
77impl BedrockModel for RuntimeBedrockModel {
78    fn bedrock_id(&self) -> &str {
79        &self.model_id
80    }
81}