magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
use crate::{
    config::CompactionTimingSettings,
    providers::{MessageRole, ProviderConversationItem},
    typesafe::{JevAnswer, JevQuestion, NoulCriteriaOwned, TypeSafeClient},
};
use std::collections::BTreeMap;

const UNRELATED_WORK: &str = "starts_unrelated_work";
const RECENT_ITEMS: usize = 12;
const MAX_RECENT_CONTEXT_BYTES: usize = 16 * 1024;

/// Token count at which an early, Jev-gated compaction may happen.
pub(crate) fn soft_threshold_tokens(
    settings: &CompactionTimingSettings,
    max_tokens: usize,
) -> usize {
    max_tokens.saturating_mul(usize::from(settings.soft_threshold_percent)) / 100
}

/// Probability that `prompt` starts work unrelated to the recent conversation.
pub(crate) fn unrelated_work_probability(
    prompt: &str,
    conversation: &[&ProviderConversationItem],
) -> anyhow::Result<f64> {
    let state = serde_json::json!({
        "recent_conversation": recent_context(conversation),
        "new_request": prompt,
    });
    let questions = BTreeMap::from([(
        UNRELATED_WORK.to_string(),
        JevQuestion::Noul {
            instructions: serde_json::json!({
                "question": "Does `new_request` begin independent work that needs none of the prior task-specific details in `recent_conversation`?",
                "rules": ["Judge dependency, not shared repository or vocabulary.", "When history is insufficient or the request refers back ambiguously, do not infer independence."]
            }),
            criteria: Some(NoulCriteriaOwned {
                yes: serde_json::json!({"what": "Independent task; no dependency on earlier work.", "examples": ["Explicit change of topic", "A separate task in the same repository"]}),
                no: serde_json::json!({"what": "Continues or may depend on earlier work.", "examples": ["Continue", "Apply that fix elsewhere", "Why did that test fail?"]}),
            }),
        },
    )]);
    let mut result = TypeSafeClient::from_environment()?.ask_many(&state, questions)?;
    match result.value.remove(UNRELATED_WORK) {
        Some(JevAnswer::Noul { noul }) if (0.0..=1.0).contains(&noul) => Ok(noul),
        _ => anyhow::bail!("Jev compaction timing returned invalid {UNRELATED_WORK} answer"),
    }
}

fn recent_context(conversation: &[&ProviderConversationItem]) -> serde_json::Value {
    // Preflight's final item is the incoming prompt, not historical evidence.
    let history = &conversation[..conversation.len().saturating_sub(1)];
    let mut messages = history
        .iter()
        .copied()
        .filter(|item| {
            matches!(item,
                ProviderConversationItem::Message(message)
                    if matches!(message.role, MessageRole::User | MessageRole::Assistant)
            )
        })
        .rev()
        .take(RECENT_ITEMS)
        .collect::<Vec<_>>();
    messages.reverse();
    crate::typesafe::evidence::conversation_evidence(messages, MAX_RECENT_CONTEXT_BYTES)
}