lean-ctx-engine 3.12.1

LeanCTX | OSS library: the open-source runtime for the Context Gateway for AI agents behind the lean-ctx CLI, MCP server and proxy integrations.
Documentation
use super::decision_loop_runtime::DecisionLoopRuntime;
use super::triage::{
    ProfileHypothesis, TaskAnalysisInput, TaskAnalyzer, TriageEngine, TriageError,
};

#[derive(Debug)]
struct FailingAnalyzer;

impl TaskAnalyzer for FailingAnalyzer {
    fn analyze(&self, _: &TaskAnalysisInput) -> Result<ProfileHypothesis, TriageError> {
        Err(TriageError::InternalError("test failure".to_owned()))
    }

    fn name(&self) -> &'static str {
        "failing"
    }
}

#[test]
fn test_runtime_init() {
    assert!(std::ptr::eq(
        DecisionLoopRuntime::get_or_init(),
        DecisionLoopRuntime::get_or_init()
    ));
}

#[test]
fn test_on_tool_start() {
    let context = DecisionLoopRuntime::get_or_init().on_tool_start(
        "ctx_read",
        Some("read lib.rs"),
        "runtime-test",
        "agent",
    );
    assert!(!context.task_id.is_empty(), "`context.task_id` is empty");
    assert!(
        !context.profile_complexity.is_empty(),
        "`context.profile_complexity` is empty"
    );
}

#[test]
fn test_on_tool_end_success() {
    let _isolation = crate::core::data_dir::isolated_data_dir();
    let runtime = DecisionLoopRuntime::with_triage(TriageEngine::default());
    let context = runtime.on_tool_start("ctx_read", Some("read"), "runtime-test", "agent");
    assert!(
        runtime
            .on_tool_end(&context, 1, 1, "gpt-4o", true)
            .is_none()
    );
    assert_eq!(
        context.outcome().unwrap().accepted_outcome.accepted,
        lean_ctx_protocol::AcceptanceState::Unknown
    );
}

#[test]
fn test_on_tool_end_failure() {
    let _isolation = crate::core::data_dir::isolated_data_dir();
    let runtime = DecisionLoopRuntime::with_triage(TriageEngine::default());
    let context = runtime.on_tool_start("ctx_read", Some("read"), "runtime-test", "agent");
    assert!(
        runtime
            .on_tool_end(&context, 1, 1, "gpt-4o", false)
            .is_none()
    );
    let outcome = context
        .outcome()
        .expect("failure records a canonical outcome");
    assert_eq!(outcome.accepted_outcome.task_id.as_str(), context.task_id);
    assert_eq!(
        outcome.accepted_outcome.accepted,
        lean_ctx_protocol::AcceptanceState::Unknown
    );
    assert!(
        outcome.accepted_outcome.evidence_refs.is_empty(),
        "{:?}",
        outcome.accepted_outcome.evidence_refs
    );
    assert!(outcome.assessment.is_none());
    assert!(runtime.assessment_for(&context.task_id).is_none());
}

#[test]
fn duplicate_end_is_ignored() {
    let runtime = DecisionLoopRuntime::with_triage(TriageEngine::default());
    let context = runtime.on_tool_start("ctx_read", Some("read"), "runtime-once", "agent");

    assert!(
        runtime
            .on_tool_end(&context, 1, 1, "gpt-4o", false)
            .is_none()
    );
    let first = context
        .outcome()
        .expect("first completion records an outcome");
    let stages = context.stage_executions();
    assert!(!stages.is_empty(), "`stages` is empty");
    for success in [false, true] {
        assert!(
            runtime
                .on_tool_end(&context, 999, 999, "gpt-4o", success)
                .is_none()
        );
        assert_eq!(
            context.outcome().unwrap().accepted_outcome,
            first.accepted_outcome
        );
        assert_eq!(context.stage_executions(), stages);
        assert!(runtime.assessment_for(&context.task_id).is_none());
    }
}

#[test]
fn test_error_does_not_block() {
    let runtime =
        DecisionLoopRuntime::with_triage(TriageEngine::new(vec![Box::new(FailingAnalyzer)]));
    assert!(
        std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            runtime.on_tool_start("ctx_read", None, "test", "agent")
        }))
        .is_ok()
    );
}

#[test]
fn missing_task_text_yields_passthrough_profile() {
    use crate::core::triage::confidence::ACTIONABLE_FLOOR_MILLI;

    let runtime = DecisionLoopRuntime::with_triage(TriageEngine::default());
    let context = runtime.on_tool_start("ctx_read", None, "no-task-text", "agent");

    assert_eq!(context.profile_intent, "explore");
    let profile = runtime.profile_for_session("no-task-text").unwrap();
    // Below the actionable floor: the server's output filter passes it
    // through (asserted in `server::context_gate` tests).
    assert!(profile.confidence_milli < ACTIONABLE_FLOOR_MILLI);
}