Skip to main content

lean_ctx/tools/
ctx_compile.rs

1//! ctx_compile -- Context compilation tool.
2//!
3//! Runs the context compiler to produce an optimal context package
4//! under budget constraints. Uses the plan from ctx_plan or builds
5//! one on-the-fly from the current ledger state.
6
7use serde_json::Value;
8
9use crate::core::context_compiler::{compile, format_compile_result, CompileMode};
10use crate::core::context_field::TokenBudget;
11use crate::core::context_handles::HandleRegistry;
12use crate::core::context_ledger::ContextLedger;
13use crate::core::context_policies::PolicySet;
14
15const DEFAULT_BUDGET: usize = 12_000;
16
17pub fn handle(
18    args: Option<&serde_json::Map<String, Value>>,
19    ledger: &ContextLedger,
20    policies: &PolicySet,
21) -> String {
22    let mode_str = get_str(args, "mode").unwrap_or_else(|| "handles".to_string());
23    let mode = CompileMode::parse(&mode_str);
24    let budget_tokens: usize = args
25        .and_then(|a| a.get("budget"))
26        .and_then(serde_json::Value::as_u64)
27        .map_or(DEFAULT_BUDGET, |b| b as usize);
28
29    let budget = TokenBudget {
30        total: budget_tokens,
31        used: 0,
32    };
33
34    let candidates = crate::tools::ctx_plan::plan_to_candidates(ledger, policies);
35    if candidates.is_empty() {
36        return "[ctx_compile] no context items in ledger — nothing to compile".to_string();
37    }
38
39    let result = compile(&candidates, budget, mode);
40
41    match mode {
42        CompileMode::HandleManifest => {
43            let mut registry = HandleRegistry::new();
44            for item in &result.selected {
45                let kind = candidates
46                    .iter()
47                    .find(|c| c.id.to_string() == item.id)
48                    .map_or(crate::core::context_field::ContextKind::File, |c| c.kind);
49
50                let view_costs = candidates
51                    .iter()
52                    .find(|c| c.id.to_string() == item.id)
53                    .map(|c| &c.view_costs)
54                    .cloned()
55                    .unwrap_or_default();
56
57                registry.register(
58                    crate::core::context_field::ContextItemId(item.id.clone()),
59                    kind,
60                    &item.path,
61                    &format!("{} {}", item.path, item.view),
62                    &view_costs,
63                    item.phi,
64                    item.pinned,
65                );
66            }
67            let mut out = registry.format_manifest(budget_tokens, result.budget_used);
68            out.push_str(&format!(
69                "\n\nRun ID: {} | Items: {} selected, {} excluded\n",
70                result.run_id, result.items_selected, result.items_excluded
71            ));
72            out
73        }
74        CompileMode::Compressed | CompileMode::FullPrompt => format_compile_result(&result),
75    }
76}
77
78fn get_str(args: Option<&serde_json::Map<String, Value>>, key: &str) -> Option<String> {
79    args?
80        .get(key)?
81        .as_str()
82        .map(std::string::ToString::to_string)
83}