magi-code 0.96.2

Repository-aware CLI coding agent for terminal work
Documentation
//! Last explicitly selected model and requested thinking; never global defaults.
use super::{SessionEvent, SessionEventKind};
use crate::{config::EffectiveConfig, thinking::ThinkingLevel};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct SessionPreferences {
    pub(crate) provider: String,
    pub(crate) model: String,
    pub(crate) requested_thinking: ThinkingLevel,
}

pub(crate) fn observe(preferences: &mut Option<SessionPreferences>, event: &SessionEvent) {
    let value = match event.kind() {
        Some(SessionEventKind::SessionPreferences) => Some(&event.payload),
        Some(SessionEventKind::Compaction) => event.payload.get("session_preferences"),
        _ => None,
    };
    if let Some(value) = value
        && let Ok(saved) = serde_json::from_value::<SessionPreferences>(value.clone())
        && !saved.provider.trim().is_empty()
        && !saved.model.trim().is_empty()
    {
        *preferences = Some(saved);
    }
}

#[derive(Debug, Clone)]
pub(crate) struct RestoredSessionPreferences {
    pub(crate) saved: SessionPreferences,
    pub(crate) config: EffectiveConfig,
    pub(crate) notice: Option<String>,
    #[cfg_attr(
        not(unix),
        expect(dead_code, reason = "local-agent safe selection notice")
    )]
    pub(crate) selection_restored: bool,
}

pub(crate) fn restore(
    destination: &EffectiveConfig,
    saved: SessionPreferences,
) -> RestoredSessionPreferences {
    match crate::config::read_settings(&destination.paths) {
        Ok(settings) => restore_with_settings(destination, saved, &settings),
        Err(error) => finish_restoration(destination, saved, Err(error)),
    }
}

pub(crate) fn restore_with_settings(
    destination: &EffectiveConfig,
    saved: SessionPreferences,
    settings: &crate::config::Settings,
) -> RestoredSessionPreferences {
    let selection = crate::model_catalog::resolve_model_with_settings(
        &destination.paths,
        &destination.auth_state(),
        &format!("{}/{}", saved.provider, saved.model),
        settings,
    )
    .and_then(|(provider, model, notice, _)| {
        let config = crate::config::load_effective_provider_selection_with_settings(
            &destination.paths,
            &provider,
            &model,
            settings,
        )?;
        anyhow::ensure!(
            config.auth_state().is_ready(),
            "provider '{provider}' is not ready"
        );
        Ok((config, notice))
    });
    finish_restoration(destination, saved, selection)
}

fn finish_restoration(
    destination: &EffectiveConfig,
    saved: SessionPreferences,
    selection: anyhow::Result<(EffectiveConfig, Option<String>)>,
) -> RestoredSessionPreferences {
    let selection_restored = selection.is_ok();
    let (mut config, notice) = match selection {
        Ok(selection) => selection,
        Err(error) => (
            destination.clone(),
            Some(format!(
                "Saved selection {}/{} could not be restored: {error}. Using {}/{}; saved preference retained.",
                saved.provider,
                saved.model,
                destination.provider_id(),
                destination.model.as_deref().unwrap_or_default(),
            )),
        ),
    };
    config.thinking_level = saved.requested_thinking;
    RestoredSessionPreferences {
        saved,
        config,
        notice,
        selection_restored,
    }
}