lean_ctx/core/engine_interface/
context_plan.rs1#[path = "context_plan/materialize.rs"]
6pub(crate) mod materialize_impl;
7pub mod presenter;
8pub mod sources;
9
10#[cfg(test)]
11#[path = "context_plan/source_handoff_tests.rs"]
12mod source_handoff_tests;
13
14use std::path::Path;
15
16use chrono::{DateTime, FixedOffset};
17
18use lean_ctx_protocol::{
19 EngineContextPlanRequestV1, EngineContextPlanResponseV1,
20 EngineContextSourceMaterializationRequestV1, EngineContextSourceMaterializationResponseV1,
21 SemanticVersion,
22};
23
24use super::{
25 ENGINE_INTERFACE_VERSION, ENGINE_TRANSPORT_VERSION, EngineTransportError, bind_transport_root,
26};
27use crate::core::context_field::TokenBudget;
28use crate::core::context_kernel::{
29 autopilot::{AutopilotController, TaskAutopilotDecision},
30 bridge::reference_input,
31 enforce::KernelMode,
32 types::RetrievalContext,
33};
34
35pub fn materialize(
42 root: &Path,
43 request: &EngineContextSourceMaterializationRequestV1,
44) -> Result<EngineContextSourceMaterializationResponseV1, &'static str> {
45 materialize_impl::materialize_source_plan(root, request)
46}
47
48pub(crate) fn materialize_sources_with_decision(
50 root: &Path,
51 request: &EngineContextSourceMaterializationRequestV1,
52) -> Result<
53 (
54 EngineContextSourceMaterializationResponseV1,
55 TaskAutopilotDecision,
56 ),
57 &'static str,
58> {
59 materialize_impl::materialize_source_plan_with_decision(root, request)
60}
61
62pub fn plan(
64 root: &Path,
65 request: EngineContextPlanRequestV1,
66) -> Result<EngineContextPlanResponseV1, &'static str> {
67 response(&plan_with_controller(root, request, None)?)
68}
69
70fn plan_with_controller(
71 root: &Path,
72 request: EngineContextPlanRequestV1,
73 controller: Option<AutopilotController>,
74) -> Result<TaskAutopilotDecision, &'static str> {
75 plan_with_controller_at(
76 root,
77 request,
78 controller,
79 Some(chrono::Utc::now().fixed_offset()),
80 )
81}
82
83pub(crate) fn plan_with_controller_at(
89 root: &Path,
90 request: EngineContextPlanRequestV1,
91 controller: Option<AutopilotController>,
92 evaluation_time: Option<DateTime<FixedOffset>>,
93) -> Result<TaskAutopilotDecision, &'static str> {
94 request.validate_payload().map_err(|_| "invalid_request")?;
95 let root = bind_transport_root(root).map_err(EngineTransportError::code)?;
96 let root = root.to_str().ok_or("unsafe_root")?;
97 let mut input = reference_input(
98 RetrievalContext {
99 task: Some(request.query.clone()),
100 query: request.query,
101 project_root: root.to_owned(),
102 budget: TokenBudget {
103 total: request.budget_tokens as usize,
104 used: 0,
105 },
106 max_candidates: usize::from(request.max_candidates),
107 },
108 KernelMode::Enforce,
110 )
111 .map_err(|_| "context_policy_unavailable")?;
112 input.evaluation_time = evaluation_time;
113 controller
114 .unwrap_or_else(|| AutopilotController::for_project(root))
115 .plan_for_task(request.task_id, &input, None)
116 .map_err(|_| "context_planning_failed")
117}
118
119fn response(decision: &TaskAutopilotDecision) -> Result<EngineContextPlanResponseV1, &'static str> {
120 Ok(EngineContextPlanResponseV1 {
121 schema_version: 1,
122 transport_version: ENGINE_TRANSPORT_VERSION,
123 engine_interface_version: SemanticVersion::new(ENGINE_INTERFACE_VERSION)
124 .map_err(|_| "internal")?,
125 plan: decision.context_projection().clone(),
126 })
127}