lean-ctx 3.1.3

Context Runtime for AI Agents with CCP. 42 MCP tools, 10 read modes, 90+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing + diaries, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24 AI tools. Reduces LLM token consumption by up to 99%.
Documentation
use axum::extract::State;
use axum::http::{HeaderMap, StatusCode};
use axum::Json;
use serde::{Deserialize, Serialize};

use super::auth::{auth_user, AppState};
use super::helpers::internal_error;

#[derive(Deserialize)]
pub struct FeedbackEntry {
    pub language: String,
    pub entropy: f64,
    pub jaccard: f64,
    #[serde(default)]
    pub sample_count: i32,
    #[serde(default)]
    pub avg_efficiency: f64,
}

#[derive(Serialize)]
pub struct FeedbackOut {
    pub language: String,
    pub entropy: f64,
    pub jaccard: f64,
    pub sample_count: i32,
    pub avg_efficiency: f64,
}

pub async fn post_feedback(
    State(state): State<AppState>,
    headers: HeaderMap,
    Json(body): Json<Vec<FeedbackEntry>>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
    let (user_id, _) = auth_user(&state, &headers).await?;
    let client = state.pool.get().await.map_err(internal_error)?;

    let mut count = 0u32;
    for entry in &body {
        client
            .execute(
                r#"INSERT INTO feedback_thresholds (user_id, language, entropy, jaccard, sample_count, avg_efficiency)
                   VALUES ($1, $2, $3, $4, $5, $6)
                   ON CONFLICT (user_id, language) DO UPDATE SET
                     entropy = EXCLUDED.entropy,
                     jaccard = EXCLUDED.jaccard,
                     sample_count = EXCLUDED.sample_count,
                     avg_efficiency = EXCLUDED.avg_efficiency,
                     updated_at = NOW()"#,
                &[
                    &user_id,
                    &entry.language,
                    &entry.entropy,
                    &entry.jaccard,
                    &entry.sample_count,
                    &entry.avg_efficiency,
                ],
            )
            .await
            .map_err(internal_error)?;
        count += 1;
    }

    Ok(Json(serde_json::json!({"synced": count})))
}

pub async fn get_feedback(
    State(state): State<AppState>,
    headers: HeaderMap,
) -> Result<Json<Vec<FeedbackOut>>, (StatusCode, String)> {
    let (user_id, _) = auth_user(&state, &headers).await?;
    let client = state.pool.get().await.map_err(internal_error)?;

    let rows = client
        .query(
            "SELECT language, entropy, jaccard, sample_count, avg_efficiency FROM feedback_thresholds WHERE user_id = $1 ORDER BY language",
            &[&user_id],
        )
        .await
        .map_err(internal_error)?;

    let out: Vec<FeedbackOut> = rows
        .iter()
        .map(|r| FeedbackOut {
            language: r.get(0),
            entropy: r.get(1),
            jaccard: r.get(2),
            sample_count: r.get(3),
            avg_efficiency: r.get(4),
        })
        .collect();

    Ok(Json(out))
}