Skip to main content

lean_ctx/server/
schema_hook.rs

1//! Server bridge for Context Kernel list-tools schema optimization.
2
3use std::borrow::Cow;
4
5use crate::core::context_kernel::list_tools_opt;
6
7/// Optimizes tool descriptions when schema optimization supports the client.
8#[must_use]
9pub fn optimize_tools(tools: Vec<rmcp::model::Tool>, client_name: &str) -> Vec<rmcp::model::Tool> {
10    if !list_tools_opt::should_optimize_for_client(client_name) {
11        return tools;
12    }
13
14    let tuples = tools
15        .iter()
16        .map(|tool| {
17            let parameter_count = tool
18                .input_schema
19                .get("properties")
20                .and_then(serde_json::Value::as_object)
21                .map_or(0, serde_json::Map::len);
22            (
23                tool.name.to_string(),
24                tool.description.as_deref().unwrap_or("").to_owned(),
25                parameter_count,
26            )
27        })
28        .collect();
29    let optimized = list_tools_opt::optimize_descriptions(tuples, client_name);
30
31    tools
32        .into_iter()
33        .zip(optimized)
34        .map(|(mut tool, (_, description, _))| {
35            tool.description = Some(Cow::Owned(description));
36            tool
37        })
38        .collect()
39}
40
41/// Returns cumulative list-tools schema optimization statistics.
42#[must_use]
43pub fn summary() -> list_tools_opt::SchemaOptSummary {
44    list_tools_opt::schema_opt_summary()
45}
46
47#[cfg(test)]
48mod tests {
49    use std::sync::MutexGuard;
50
51    use super::list_tools_opt;
52    use crate::core::context_kernel::kernel_config::{self, KERNEL_TEST_LOCK, KernelFeatures};
53
54    fn setup() -> MutexGuard<'static, ()> {
55        let guard = KERNEL_TEST_LOCK
56            .lock()
57            .unwrap_or_else(std::sync::PoisonError::into_inner);
58        kernel_config::reset_features();
59        list_tools_opt::reset();
60        guard
61    }
62
63    #[test]
64    fn disabled_returns_same_count() {
65        let _guard = setup();
66        let features = KernelFeatures {
67            enabled: false,
68            ..KernelFeatures::default()
69        };
70        kernel_config::update_features(features);
71        let tools = vec![("tool".to_owned(), "description".to_owned(), 1)];
72
73        assert_eq!(
74            list_tools_opt::optimize_descriptions(tools, "cursor").len(),
75            1
76        );
77    }
78
79    #[test]
80    fn summary_works() {
81        let _guard = setup();
82        let summary = list_tools_opt::schema_opt_summary();
83
84        assert_eq!(summary.optimizations_applied, 0);
85        assert_eq!(summary.total_tokens_saved, 0);
86        assert_eq!(summary.avg_reduction_percent, 0.0);
87    }
88
89    #[test]
90    fn optimization_flag_check() {
91        let _guard = setup();
92
93        assert!(list_tools_opt::should_optimize_for_client("cursor"));
94        assert!(!list_tools_opt::should_optimize_for_client(
95            "unknown-client"
96        ));
97    }
98}