looprs 0.1.11

Concise coding assistant REPL
Documentation
use crate::agent::{Agent, RuntimeSettings};
use crate::app_config::AppConfig;
use crate::config_file::ProviderConfig;
use crate::providers::{ProviderOverrides, create_provider_with_overrides};
use crate::types::ModelId;

pub struct BootstrappedRuntime {
    pub app_config: AppConfig,
    pub provider_config: ProviderConfig,
    pub provider_name: String,
    pub model: String,
    pub agent: Agent,
}

pub async fn bootstrap_runtime(
    model_override: Option<ModelId>,
) -> anyhow::Result<BootstrappedRuntime> {
    let app_config = AppConfig::load().unwrap_or_default();

    let provider = create_provider_with_overrides(ProviderOverrides {
        model: model_override,
    })
    .await?;

    let provider_name = provider.name().to_string();
    let model = provider.model().as_str().to_string();

    let provider_config = ProviderConfig::load().unwrap_or_default();
    let max_tokens_override = provider_config.merged_settings(&provider_name).max_tokens;
    let runtime = RuntimeSettings {
        defaults: app_config.defaults.clone(),
        max_tokens_override,
        fs_mode: app_config.agents.fs_mode,
    };
    let agent = Agent::new_with_runtime(provider, runtime, app_config.file_ref_policy())?;

    Ok(BootstrappedRuntime {
        app_config,
        provider_config,
        provider_name,
        model,
        agent,
    })
}

#[cfg(test)]
mod live_llm_tests {
    use super::*;
    use crate::runtime::events::gui_turn_metadata;
    use crate::runtime::session::run_single_turn;

    fn live_tests_enabled() -> bool {
        std::env::var("LOOPRS_RUN_LIVE_LLM_TESTS")
            .ok()
            .is_some_and(|v| v == "1" || v == "true")
    }

    fn has_any_api_key() -> bool {
        std::env::var("ANTHROPIC_API_KEY").ok().is_some()
            || std::env::var("OPENAI_API_KEY").ok().is_some()
    }

    #[tokio::test]
    #[ignore]
    async fn live_llm_single_turn_smoke() {
        if !live_tests_enabled() || !has_any_api_key() {
            return;
        }

        let mut rt = bootstrap_runtime(None)
            .await
            .expect("bootstrap_runtime failed");

        rt.agent.clear_history();
        let response = run_single_turn(
            &mut rt.agent,
            "Reply with the single word OK.",
            gui_turn_metadata(),
        )
        .await
        .expect("run_single_turn failed");

        assert!(response.to_uppercase().contains("OK"));
    }
}