use crate::ir::{CacheControl, ToolSpec};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub enum ToolCacheMode {
#[default]
None,
Suffix(CacheControl),
PerSpec(CacheControl),
}
impl ToolCacheMode {
#[must_use]
pub fn apply(self, mut specs: Vec<ToolSpec>) -> Vec<ToolSpec> {
match self {
Self::None => specs,
Self::Suffix(cache) => {
if let Some(last) = specs.last_mut() {
last.cache_control = Some(cache);
}
specs
}
Self::PerSpec(cache) => {
for spec in &mut specs {
spec.cache_control = Some(cache);
}
specs
}
}
}
}
#[cfg(test)]
#[allow(clippy::indexing_slicing)]
mod tests {
use super::*;
use serde_json::json;
fn fake(name: &str) -> ToolSpec {
ToolSpec::function(
name.to_owned(),
format!("{name} description"),
json!({"type": "object"}),
)
}
#[test]
fn none_leaves_specs_unchanged() {
let specs = vec![fake("alpha"), fake("beta")];
let out = ToolCacheMode::None.apply(specs);
assert!(out.iter().all(|s| s.cache_control.is_none()));
}
#[test]
fn suffix_marks_only_the_last_spec() {
let cache = CacheControl::five_minutes();
let specs = vec![fake("alpha"), fake("beta"), fake("gamma")];
let out = ToolCacheMode::Suffix(cache).apply(specs);
assert!(out[0].cache_control.is_none());
assert!(out[1].cache_control.is_none());
assert_eq!(out[2].cache_control, Some(cache));
}
#[test]
fn per_spec_marks_every_spec() {
let cache = CacheControl::one_hour();
let specs = vec![fake("alpha"), fake("beta"), fake("gamma")];
let out = ToolCacheMode::PerSpec(cache).apply(specs);
assert!(out.iter().all(|s| s.cache_control == Some(cache)));
}
#[test]
fn apply_on_empty_input_is_a_noop() {
let out = ToolCacheMode::Suffix(CacheControl::five_minutes()).apply(Vec::new());
assert!(out.is_empty());
let out = ToolCacheMode::PerSpec(CacheControl::one_hour()).apply(Vec::new());
assert!(out.is_empty());
}
}